forked from OSchip/llvm-project
Implement basic support for friend types and functions in non-dependent
contexts. llvm-svn: 98321
This commit is contained in:
parent
90e2fc2fb3
commit
16927f6274
clang
include/clang/AST
lib
test/CXX/class.access/class.friend
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue