]> granicus.if.org Git - clang/commitdiff
An access is permitted if the current template instantiates to the appropriate
authorJohn McCall <rjmccall@apple.com>
Tue, 4 May 2010 05:11:27 +0000 (05:11 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 4 May 2010 05:11:27 +0000 (05:11 +0000)
class.  Add some conservative support for the idea.  Fixes PR 7024.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102999 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaAccess.cpp
test/CXX/class.access/p4.cpp

index 30c53ed75aea1045550aedb7c8be6a3341d222f2..444ee798587de594810aa895d0c22cff2d01f0bc 100644 (file)
@@ -222,6 +222,22 @@ private:
 
 }
 
+/// 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 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
 
   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 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
       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 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
 
       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 @@ static AccessResult HasAccess(Sema &S,
       if (ECRecord == NamingClass)
         return AR_accessible;
 
+      if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
+        OnFailure = AR_dependent;
+
     // [B3] and [M3]
     } else {
       assert(Access == AS_protected);
index 4bf624948306005ea39d7d477a5e0653b4e8c184..1cd89661367955a1c798be099217d79daaf88443 100644 (file)
@@ -363,3 +363,58 @@ namespace test14 {
   }
 }
 
+// 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}}
+}