summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-11-22 00:24:47 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-11-22 00:24:47 +0000
commitf62c690c55fb920f3ba0a4f6e6e259e2ae7ce297 (patch)
treeed6b0bcd13706696b172aa2271d9877ee0a3f0be
parent1a6c43a9d215697dbe0418c145a6bd1c85ec654d (diff)
Fix CXXRecordDecl::forallBases to not look through bases which are dependent
and defined within the current instantiation, but which are not part of the current instantiation. Previously, it would look at bases which could be specialized separately from the current template. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168477 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h7
-rw-r--r--lib/AST/CXXInheritance.cpp16
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp12
-rw-r--r--lib/Sema/SemaExprMember.cpp62
-rw-r--r--test/CXX/class.derived/class.virtual/p3-0x.cpp30
-rw-r--r--test/CXX/temp/temp.res/temp.dep/p3.cpp38
6 files changed, 116 insertions, 49 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 15e2e3b558..91a26d885e 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -765,7 +765,8 @@ public:
return reverse_base_class_const_iterator(vbases_begin());
}
- /// \brief Determine whether this class has any dependent base classes.
+ /// \brief Determine whether this class has any dependent base classes which
+ /// are not the current instantiation.
bool hasAnyDependentBases() const;
/// Iterator access to method members. The method iterator visits
@@ -1308,6 +1309,10 @@ public:
return dyn_cast<FunctionDecl>(getDeclContext());
}
+ /// \brief Determine whether this dependent class is a current instantiation,
+ /// when viewed from within the given context.
+ bool isCurrentInstantiation(const DeclContext *CurContext) const;
+
/// \brief Determine whether this class is derived from the class \p Base.
///
/// This routine only determines whether this class is derived from \p Base,
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 213b214a4e..292b23dcc6 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -121,6 +121,17 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl());
}
+bool
+CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const {
+ assert(isDependentContext());
+
+ for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
+ if (CurContext->Equals(this))
+ return true;
+
+ return false;
+}
+
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
void *OpaqueData,
bool AllowShortCircuit) const {
@@ -140,7 +151,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
CXXRecordDecl *Base =
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
- if (!Base) {
+ if (!Base ||
+ (Base->isDependentContext() &&
+ !Base->isCurrentInstantiation(Record))) {
if (AllowShortCircuit) return false;
AllMatches = false;
continue;
@@ -725,4 +738,3 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
AddIndirectPrimaryBases(BaseDecl, Context, Bases);
}
}
-
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 15bfd1ce62..7db604d9cc 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -26,7 +26,7 @@
using namespace clang;
/// \brief Find the current instantiation that associated with the given type.
-static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
+static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
DeclContext *CurContext) {
if (T.isNull())
return 0;
@@ -34,16 +34,10 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!T->isDependentType())
+ if (!Record->isDependentContext() ||
+ Record->isCurrentInstantiation(CurContext))
return Record;
- // This may be a member of a class template or class template partial
- // specialization. If it's part of the current semantic context, then it's
- // an injected-class-name;
- for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
- if (CurContext->Equals(Record))
- return Record;
-
return 0;
} else if (isa<InjectedClassNameType>(Ty))
return cast<InjectedClassNameType>(Ty)->getDecl();
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index a7fd47183a..6bf5f2e3a2 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -24,30 +24,19 @@
using namespace clang;
using namespace sema;
+typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> BaseSet;
+static bool BaseIsNotInSet(const CXXRecordDecl *Base, void *BasesPtr) {
+ const BaseSet &Bases = *reinterpret_cast<const BaseSet*>(BasesPtr);
+ return !Bases.count(Base->getCanonicalDecl());
+}
+
/// Determines if the given class is provably not derived from all of
/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
+static bool isProvablyNotDerivedFrom(Sema &SemaRef, CXXRecordDecl *Record,
+ const BaseSet &Bases) {
+ void *BasesPtr = const_cast<void*>(reinterpret_cast<const void*>(&Bases));
+ return BaseIsNotInSet(Record, BasesPtr) &&
+ Record->forallBases(BaseIsNotInSet, BasesPtr);
}
enum IMAKind {
@@ -111,7 +100,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
bool isField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ BaseSet Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -169,16 +158,18 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// is ill-formed.
if (R.getNamingClass() &&
contextClass->getCanonicalDecl() !=
- R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return hasNonInstance ? IMA_Mixed_Unrelated :
- IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
- IMA_Error_Unrelated;
+ R.getNamingClass()->getCanonicalDecl()) {
+ // If the naming class is not the current context, this was a qualified
+ // member name lookup, and it's sufficient to check that we have the naming
+ // class as a base class.
+ Classes.clear();
+ Classes.insert(R.getNamingClass());
+ }
// If we can prove that the current context is unrelated to all the
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
+ if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
return hasNonInstance ? IMA_Mixed_Unrelated :
IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
IMA_Error_Unrelated;
@@ -491,14 +482,14 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
QualType BaseType,
const CXXScopeSpec &SS,
const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
+ CXXRecordDecl *BaseRecord =
+ cast_or_null<CXXRecordDecl>(computeDeclContext(BaseType));
+ if (!BaseRecord) {
// We can't check this yet because the base type is still
// dependent.
assert(BaseType->isDependentType());
return false;
}
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
// If this is an implicit member reference and we find a
@@ -513,11 +504,10 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
if (!DC->isRecord())
continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ CXXRecordDecl *MemberRecord = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ if (BaseRecord->getCanonicalDecl() == MemberRecord ||
+ !BaseRecord->isProvablyNotDerivedFrom(MemberRecord))
return false;
}
diff --git a/test/CXX/class.derived/class.virtual/p3-0x.cpp b/test/CXX/class.derived/class.virtual/p3-0x.cpp
index 16f98280ed..6a02a86731 100644
--- a/test/CXX/class.derived/class.virtual/p3-0x.cpp
+++ b/test/CXX/class.derived/class.virtual/p3-0x.cpp
@@ -100,3 +100,33 @@ namespace PR13499 {
Y<X> y;
Z<X> z; // expected-note {{in instantiation of}}
}
+
+namespace MemberOfUnknownSpecialization {
+ template<typename T> struct A {
+ struct B {};
+ struct C : B {
+ void f() override;
+ };
+ };
+
+ template<> struct A<int>::B {
+ virtual void f();
+ };
+ // ok
+ A<int>::C c1;
+
+ template<> struct A<char>::B {
+ void f();
+ };
+ // expected-error@-13 {{only virtual member functions can be marked 'override'}}
+ // expected-note@+1 {{in instantiation of}}
+ A<char>::C c2;
+
+ template<> struct A<double>::B {
+ virtual void f() final;
+ };
+ // expected-error@-20 {{declaration of 'f' overrides a 'final' function}}
+ // expected-note@-3 {{here}}
+ // expected-note@+1 {{in instantiation of}}
+ A<double>::C c3;
+}
diff --git a/test/CXX/temp/temp.res/temp.dep/p3.cpp b/test/CXX/temp/temp.res/temp.dep/p3.cpp
index 88b4752e6b..576e310985 100644
--- a/test/CXX/temp/temp.res/temp.dep/p3.cpp
+++ b/test/CXX/temp/temp.res/temp.dep/p3.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
struct A0 {
struct K { };
};
@@ -42,3 +41,40 @@ namespace E2 {
Y<A> ya;
}
+
+namespace PR14402 {
+ template<typename T>
+ struct A {
+ typedef int n;
+ int f();
+
+ struct B {};
+ struct C : B {
+ // OK, can't be sure whether we derive from A yet.
+ using A::n;
+ int g() { return f(); }
+ };
+
+ struct D {
+ using A::n; // expected-error {{using declaration refers into 'A<T>::', which is not a base class of 'D'}}
+ int g() { return f(); } // expected-error {{call to non-static member function 'f' of 'A' from nested type 'D'}}
+ };
+
+ struct E { char &f(); };
+ struct F : E {
+ // FIXME: Reject this prior to instantiation; f() is known to return int.
+ char &g() { return f(); }
+ // expected-error@-1 {{'PR14402::A<int>::f' is not a member of class 'PR14402::A<int>::F'}}
+ // expected-error@-2 {{non-const lvalue reference to type 'char' cannot bind to a temporary of type 'int'}}
+ };
+ };
+
+ template<> struct A<int>::B : A<int> {};
+ A<int>::C::n n = A<int>::C().g();
+
+ // 'not a member'
+ char &r = A<int>::F().g(); // expected-note {{in instantiation of}}
+ template<> struct A<char>::E : A<char> {};
+ // 'cannot bind to a temporary'
+ char &s = A<char>::F().g(); // expected-note {{in instantiation of}}
+}