Implement basic support for friend types and functions in non-dependent

contexts.

llvm-svn: 98321
This commit is contained in:
John McCall 2010-03-12 01:19:31 +00:00
parent 90e2fc2fb3
commit 16927f6274
6 changed files with 166 additions and 5 deletions
clang
include/clang/AST
lib
test/CXX/class.access/class.friend

View File

@ -33,6 +33,7 @@ class CXXDestructorDecl;
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.
@ -299,6 +300,11 @@ class CXXRecordDecl : public RecordDecl {
/// 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() {
@ -459,6 +465,13 @@ public:
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;

View File

@ -42,6 +42,9 @@ private:
// 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;
@ -49,10 +52,14 @@ private:
// 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) {
}
@ -89,6 +96,71 @@ public:
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;
}
}

View File

@ -33,7 +33,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
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,

View File

@ -35,5 +35,7 @@ FriendDecl *FriendDecl::Create(ASTContext &C, 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;
}

View File

@ -16,6 +16,7 @@
#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;
@ -55,7 +56,7 @@ struct EffectiveContext {
explicit EffectiveContext(DeclContext *DC) {
if (isa<FunctionDecl>(DC)) {
Function = cast<FunctionDecl>(DC);
Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
DC = Function->getDeclContext();
} else
Function = 0;
@ -85,10 +86,34 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
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;
}

View File

@ -1,4 +1,4 @@
// 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
@ -60,3 +60,52 @@ namespace N {
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();
}
};
}