diff options
author | John McCall <rjmccall@apple.com> | 2010-05-04 05:11:27 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-05-04 05:11:27 +0000 |
commit | 01ebd9d1883e82c4188325900a4eb9c1e16353bb (patch) | |
tree | be62d9b946d1950c07ae9e62f2798d3e098449b6 | |
parent | 3d6c1782c4fc2ed3e6a924c15042edb1f56fee36 (diff) |
An access is permitted if the current template instantiates to the appropriate
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
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 32 | ||||
-rw-r--r-- | test/CXX/class.access/p4.cpp | 55 |
2 files changed, 84 insertions, 3 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 30c53ed75a..444ee79858 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -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); diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index 4bf6249483..1cd8966136 100644 --- a/test/CXX/class.access/p4.cpp +++ b/test/CXX/class.access/p4.cpp @@ -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}} +} |