]> granicus.if.org Git - clang/commitdiff
That's not the right direction to compute notional accessibility in at all.
authorJohn McCall <rjmccall@apple.com>
Sat, 28 Aug 2010 08:47:21 +0000 (08:47 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 28 Aug 2010 08:47:21 +0000 (08:47 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112360 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaAccess.cpp
test/CXX/class.access/class.protected/p1.cpp

index a7c0561bbd44a0eb5e02c22b977f622025a67d5e..4625cb15ea3d0a58514b7733380b32b8d56eb82b 100644 (file)
@@ -586,11 +586,12 @@ struct ProtectedFriendContext {
                      NamingClass->isDependentContext()),
       EverDependent(false) {}
 
-  /// Check everything in the current path for friendship.
-  bool checkFriendshipAlongPath() {
-    for (llvm::SmallVectorImpl<const CXXRecordDecl*>::iterator
-           I = CurPath.begin(), E = CurPath.end(); I != E; ++I) {
-      switch (GetFriendKind(S, EC, *I)) {
+  /// Check classes in the current path for friendship, starting at
+  /// the given index.
+  bool checkFriendshipAlongPath(unsigned I) {
+    assert(I < CurPath.size());
+    for (unsigned E = CurPath.size(); I != E; ++I) {
+      switch (GetFriendKind(S, EC, CurPath[I])) {
       case AR_accessible:   return true;
       case AR_inaccessible: continue;
       case AR_dependent:    EverDependent = true; continue;
@@ -600,17 +601,16 @@ struct ProtectedFriendContext {
   }
 
   /// Perform a search starting at the given class.
-  bool findFriendship(const CXXRecordDecl *Cur) {
-    CurPath.push_back(Cur);
-
+  ///
+  /// PrivateDepth is the index of the last (least derived) class
+  /// along the current path such that a notional public member of
+  /// the final class in the path would have access in that class.
+  bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {
     // If we ever reach the naming class, check the current path for
     // friendship.  We can also stop recursing because we obviously
     // won't find the naming class there again.
-    if (Cur == NamingClass) {
-      bool Result = checkFriendshipAlongPath();
-      CurPath.pop_back();
-      return Result;
-    }
+    if (Cur == NamingClass)
+      return checkFriendshipAlongPath(PrivateDepth);
 
     if (CheckDependent && MightInstantiateTo(Cur, NamingClass))
       EverDependent = true;
@@ -619,12 +619,11 @@ struct ProtectedFriendContext {
     for (CXXRecordDecl::base_class_const_iterator
            I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) {
 
-      // If this base specifier has private access, and this isn't the
-      // first step in the derivation chain, then the base does not
-      // have natural access along this derivation path and we should
-      // ignore it.
-      if (I->getAccessSpecifier() == AS_private && CurPath.size() != 1)
-          continue;
+      // If this is private inheritance, then a public member of the
+      // base will not have any access in classes derived from Cur.
+      unsigned BasePrivateDepth = PrivateDepth;
+      if (I->getAccessSpecifier() == AS_private)
+        BasePrivateDepth = CurPath.size() - 1;
 
       const CXXRecordDecl *RD;
 
@@ -641,12 +640,20 @@ struct ProtectedFriendContext {
       }
 
       // Recurse.  We don't need to clean up if this returns true.
-      if (findFriendship(RD->getCanonicalDecl())) return true;
+      CurPath.push_back(RD);
+      if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth))
+        return true;
+      CurPath.pop_back();
     }
 
-    CurPath.pop_back();
     return false;
   }
+
+  bool findFriendship(const CXXRecordDecl *Cur) {
+    assert(CurPath.empty());
+    CurPath.push_back(Cur);
+    return findFriendship(Cur, 0);
+  }
 };
 }
 
index a19326421371c428f8b968d7d99c80876c16f53c..ab7a7dce3c52c042519d3f8938dbc3ebb8aa84c1 100644 (file)
@@ -405,3 +405,31 @@ namespace test11 {
     }
   };
 }
+
+// This friendship is considered because a public member of A would be
+// a private member of C.
+namespace test12 {
+  class A { protected: int foo(); };
+  class B : public virtual A {};
+  class C : private B { friend void test(); };
+  class D : private C, public virtual A {};
+
+  void test() {
+    D d;
+    d.A::foo();
+  }
+}
+
+// This friendship is not considered because a public member of A is
+// inaccessible in C.
+namespace test13 {
+  class A { protected: int foo(); }; // expected-note {{declared protected here}}
+  class B : private virtual A {};
+  class C : private B { friend void test(); };
+  class D : public virtual A {};
+
+  void test() {
+    D d;
+    d.A::foo(); // expected-error {{protected member}}
+  }
+}