class CXXMethodDecl;
class CXXRecordDecl;
class CXXMemberLookupCriteria;
+class FriendDecl;
/// \brief Represents any kind of function declaration, whether it is a
/// concrete function or a function template.
/// Definition - The declaration which defines this record.
CXXRecordDecl *Definition;
+ /// FirstFriend - The first friend declaration in this class, or
+ /// null if there aren't any. This is actually currently stored
+ /// in reverse order.
+ FriendDecl *FirstFriend;
+
} *DefinitionData;
struct DefinitionData &data() {
return ctor_iterator(decls_end());
}
+ /// An iterator over friend declarations. All of these are defined
+ /// in DeclFriend.h.
+ class friend_iterator;
+ friend_iterator friend_begin() const;
+ friend_iterator friend_end() const;
+ void pushFriendDecl(FriendDecl *FD);
+
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
bool hasConstCopyConstructor(ASTContext &Context) const;
// The declaration that's a friend of this class.
FriendUnion Friend;
+ // A pointer to the next friend in the sequence.
+ FriendDecl *NextFriend;
+
// Location of the 'friend' specifier.
SourceLocation FriendLoc;
// template specialization.
bool WasSpecialization;
+ friend class CXXRecordDecl::friend_iterator;
+ friend class CXXRecordDecl;
+
FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
SourceLocation FriendL)
: Decl(Decl::Friend, DC, L),
Friend(Friend),
+ NextFriend(0),
FriendLoc(FriendL),
WasSpecialization(false) {
}
static bool classof(const FriendDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Decl::Friend; }
};
+
+/// An iterator over the friend declarations of a class.
+class CXXRecordDecl::friend_iterator {
+ FriendDecl *Ptr;
+
+ friend class CXXRecordDecl;
+ explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {}
+public:
+ friend_iterator() {}
+
+ typedef FriendDecl *value_type;
+ typedef FriendDecl *reference;
+ typedef FriendDecl *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ reference operator*() const { return Ptr; }
+
+ friend_iterator &operator++() {
+ assert(Ptr && "attempt to increment past end of friend list");
+ Ptr = Ptr->NextFriend;
+ return *this;
+ }
+
+ friend_iterator operator++(int) {
+ friend_iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ bool operator==(const friend_iterator &Other) const {
+ return Ptr == Other.Ptr;
+ }
+
+ bool operator!=(const friend_iterator &Other) const {
+ return Ptr != Other.Ptr;
+ }
+
+ friend_iterator &operator+=(difference_type N) {
+ assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator");
+ while (N--)
+ ++*this;
+ return *this;
+ }
+
+ friend_iterator operator+(difference_type N) const {
+ friend_iterator tmp = *this;
+ tmp += N;
+ return tmp;
+ }
+};
+
+inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
+ return friend_iterator(data().FirstFriend);
+}
+
+inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
+ return friend_iterator(0);
+}
+
+inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
+ assert(FD->NextFriend == 0 && "friend already has next friend?");
+ FD->NextFriend = data().FirstFriend;
+ data().FirstFriend = FD;
+}
}
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
- Definition(D) {
+ Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
}
#endif
- return new (C) FriendDecl(DC, L, Friend, FriendL);
+ FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL);
+ cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
+ return FD;
}
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/ExprCXX.h"
using namespace clang;
explicit EffectiveContext(DeclContext *DC) {
if (isa<FunctionDecl>(DC)) {
- Function = cast<FunctionDecl>(DC);
+ Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
DC = Function->getDeclContext();
} else
Function = 0;
static Sema::AccessResult GetFriendKind(Sema &S,
const EffectiveContext &EC,
const CXXRecordDecl *Class) {
+ // A class always has access to its own members.
if (EC.isClass(Class))
return Sema::AR_accessible;
- // FIXME: implement
+ // Okay, check friends.
+ for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
+ E = Class->friend_end(); I != E; ++I) {
+ FriendDecl *Friend = *I;
+
+ if (Type *T = Friend->getFriendType()) {
+ if (EC.Record &&
+ S.Context.hasSameType(QualType(T, 0),
+ S.Context.getTypeDeclType(EC.Record)))
+ return Sema::AR_accessible;
+ } else {
+ NamedDecl *D
+ = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
+
+ // The decl pointers in EC have been canonicalized, so pointer
+ // equality is sufficient.
+ if (D == EC.Function || D == EC.Record)
+ return Sema::AR_accessible;
+ }
+
+ // FIXME: templates! templated contexts! dependent delay!
+ }
+
+ // That's it, give up.
return Sema::AR_inaccessible;
}
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
// C++'0x [class.friend] p1:
// A friend of a class is a function or class that is given permission to use
x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
}
}
+
+namespace test0 {
+ class ClassFriend {
+ void test();
+ };
+
+ class MemberFriend {
+ void test();
+ };
+
+ void declared_test();
+
+ class Class {
+ static void member(); // expected-note {{declared private here}}
+
+ friend class ClassFriend;
+ friend class UndeclaredClassFriend;
+
+ friend void undeclared_test();
+ friend void declared_test();
+ friend void MemberFriend::test();
+ };
+
+ void declared_test() {
+ Class::member();
+ }
+
+ void undeclared_test() {
+ Class::member();
+ }
+
+ void unfriended_test() {
+ Class::member(); // expected-error {{'member' is a private member of 'test0::Class'}}
+ }
+
+ void ClassFriend::test() {
+ Class::member();
+ }
+
+ void MemberFriend::test() {
+ Class::member();
+ }
+
+ class UndeclaredClassFriend {
+ void test() {
+ Class::member();
+ }
+ };
+}