}
+/// 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.
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
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;
RD = RD->getCanonicalDecl();
if (RD == Target) return AR_accessible;
+ if (CheckDependent && MightInstantiateTo(RD, Target))
+ OnFailure = AR_dependent;
+
Queue.push_back(RD);
}
if (ECRecord == NamingClass)
return AR_accessible;
+ if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
+ OnFailure = AR_dependent;
+
// [B3] and [M3]
} else {
assert(Access == AS_protected);
}
}
+// 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}}
+}