[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