[cfe-commits] r102999 - in /cfe/trunk: lib/Sema/SemaAccess.cpp test/CXX/class.access/p4.cpp

John McCall rjmccall at apple.com
Mon May 3 22:11:28 PDT 2010


Author: rjmccall
Date: Tue May  4 00:11:27 2010
New Revision: 102999

URL: http://llvm.org/viewvc/llvm-project?rev=102999&view=rev
Log:
An access is permitted if the current template instantiates to the appropriate
class.  Add some conservative support for the idea.  Fixes PR 7024.


Modified:
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/test/CXX/class.access/p4.cpp

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=102999&r1=102998&r2=102999&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Tue May  4 00:11:27 2010
@@ -222,6 +222,22 @@
 
 }
 
+/// Checks whether one class might instantiate to the other.
+static bool MightInstantiateTo(const CXXRecordDecl *From,
+                               const CXXRecordDecl *To) {
+  // Declaration names are always preserved by instantiation.
+  if (From->getDeclName() != To->getDeclName())
+    return false;
+
+  const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
+  const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
+  if (FromDC == ToDC) return true;
+  if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
+
+  // Be conservative.
+  return true;
+}
+
 /// Checks whether one class is derived from another, inclusively.
 /// Properly indicates when it couldn't be determined due to
 /// dependence.
@@ -234,6 +250,10 @@
 
   if (Derived == Target) return AR_accessible;
 
+  bool CheckDependent = Derived->isDependentContext();
+  if (CheckDependent && MightInstantiateTo(Derived, Target))
+    return AR_dependent;
+
   AccessResult OnFailure = AR_inaccessible;
   llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
 
@@ -246,10 +266,10 @@
       QualType T = I->getType();
       if (const RecordType *RT = T->getAs<RecordType>()) {
         RD = cast<CXXRecordDecl>(RT->getDecl());
+      } else if (const InjectedClassNameType *IT
+                   = T->getAs<InjectedClassNameType>()) {
+        RD = IT->getDecl();
       } else {
-        // It's possible for a base class to be the current
-        // instantiation of some enclosing template, but I'm guessing
-        // nobody will ever care that we just dependently delay here.
         assert(T->isDependentType() && "non-dependent base wasn't a record?");
         OnFailure = AR_dependent;
         continue;
@@ -257,6 +277,9 @@
 
       RD = RD->getCanonicalDecl();
       if (RD == Target) return AR_accessible;
+      if (CheckDependent && MightInstantiateTo(RD, Target))
+        OnFailure = AR_dependent;
+
       Queue.push_back(RD);
     }
 
@@ -563,6 +586,9 @@
       if (ECRecord == NamingClass)
         return AR_accessible;
 
+      if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
+        OnFailure = AR_dependent;
+
     // [B3] and [M3]
     } else {
       assert(Access == AS_protected);

Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=102999&r1=102998&r2=102999&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Tue May  4 00:11:27 2010
@@ -363,3 +363,58 @@
   }
 }
 
+// PR 7024
+namespace test15 {
+  template <class T> class A {
+  private:
+    int private_foo; // expected-note {{declared private here}}
+    static int private_sfoo; // expected-note {{declared private here}}
+  protected:
+    int protected_foo; // expected-note 4 {{declared protected here}}
+    static int protected_sfoo; // expected-note 3 {{declared protected here}}
+
+    int test1(A<int> &a) {
+      return a.private_foo; // expected-error {{private member}}
+    }
+
+    int test2(A<int> &a) {
+      return a.private_sfoo; // expected-error {{private member}}
+    }
+
+    int test3(A<int> &a) {
+      return a.protected_foo; // expected-error {{protected member}}
+    }
+
+    int test4(A<int> &a) {
+      return a.protected_sfoo; // expected-error {{protected member}}
+    }
+  };
+
+  template class A<int>;
+  template class A<long>; // expected-note 4 {{in instantiation}} 
+
+  template <class T> class B : public A<T> {
+    // TODO: These first two accesses can be detected as ill-formed at
+    // definition time because they're member accesses and A<int> can't
+    // be a subclass of B<T> for any T.
+
+    int test1(A<int> &a) {
+      return a.protected_foo; // expected-error 2 {{protected member}}
+    }
+
+    int test2(A<int> &a) {
+      return a.protected_sfoo; // expected-error {{protected member}}
+    }
+
+    int test3(B<int> &b) {
+      return b.protected_foo; // expected-error {{protected member}}
+    }
+
+    int test4(B<int> &b) {
+      return b.protected_sfoo; // expected-error {{protected member}}
+    }
+  };
+
+  template class B<int>;  // expected-note {{in instantiation}}
+  template class B<long>; // expected-note 4 {{in instantiation}}
+}





More information about the cfe-commits mailing list