[cfe-commits] r98321 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/DeclFriend.h lib/AST/DeclCXX.cpp lib/AST/DeclFriend.cpp lib/Sema/SemaAccess.cpp test/CXX/class.access/class.friend/p1.cpp
John McCall
rjmccall at apple.com
Thu Mar 11 17:19:31 PST 2010
Author: rjmccall
Date: Thu Mar 11 19:19:31 2010
New Revision: 98321
URL: http://llvm.org/viewvc/llvm-project?rev=98321&view=rev
Log:
Implement basic support for friend types and functions in non-dependent
contexts.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclFriend.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/DeclFriend.cpp
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=98321&r1=98320&r2=98321&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Mar 11 19:19:31 2010
@@ -33,6 +33,7 @@
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 @@
/// 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 @@
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;
Modified: cfe/trunk/include/clang/AST/DeclFriend.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclFriend.h?rev=98321&r1=98320&r2=98321&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclFriend.h (original)
+++ cfe/trunk/include/clang/AST/DeclFriend.h Thu Mar 11 19:19:31 2010
@@ -42,6 +42,9 @@
// 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 @@
// 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 @@
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;
+}
}
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=98321&r1=98320&r2=98321&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Mar 11 19:19:31 2010
@@ -33,7 +33,7 @@
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,
Modified: cfe/trunk/lib/AST/DeclFriend.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclFriend.cpp?rev=98321&r1=98320&r2=98321&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclFriend.cpp (original)
+++ cfe/trunk/lib/AST/DeclFriend.cpp Thu Mar 11 19:19:31 2010
@@ -35,5 +35,7 @@
}
#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;
}
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=98321&r1=98320&r2=98321&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Thu Mar 11 19:19:31 2010
@@ -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 @@
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 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;
}
Modified: cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p1.cpp?rev=98321&r1=98320&r2=98321&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Thu Mar 11 19:19:31 2010
@@ -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 @@
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();
+ }
+ };
+}
More information about the cfe-commits
mailing list