Fix and test for a problem caught by the clang-on-clang buildbot: qualified
IDs in dependent contexts are not dependent if the context names a namespace.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90171 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3a97ee5..55adbb5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -689,24 +689,32 @@
return true;
}
-/// Determines whether the given scope is "fully-formed": i.e. we can
-/// look into it because it's either non-dependent or is the current
-/// instantiation and has no dependent base classes.
-static bool IsFullyFormedScope(Sema &SemaRef, const CXXScopeSpec &SS) {
+/// Determines whether we can lookup this id-expression now or whether
+/// we have to wait until template instantiation is complete.
+static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) {
DeclContext *DC = SemaRef.computeDeclContext(SS, false);
- if (!DC) return false;
- if (!DC->isDependentContext()) return true;
- return IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC));
-}
-static bool IsFullyFormedScope(Sema &SemaRef, DeclContext *DC) {
- if (isa<CXXMethodDecl>(DC))
- return IsFullyFormedScope(SemaRef,
- cast<CXXRecordDecl>(cast<CXXMethodDecl>(DC)->getParent()));
- else if (isa<CXXRecordDecl>(DC))
- return IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC));
+ // If the qualifier scope isn't computable, it's definitely dependent.
+ if (!DC) return true;
+
+ // If the qualifier scope doesn't name a record, we can always look into it.
+ if (!isa<CXXRecordDecl>(DC)) return false;
+
+ // We can't look into record types unless they're fully-formed.
+ if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC))) return true;
+
+ // We can always look into fully-formed record types, but if we're
+ // in a dependent but not fully-formed context, we can't decide
+ // whether the qualifier names a base class. We shouldn't be trying
+ // to decide that yet anyway, but we are, so we need to delay that
+ // decision.
+ CXXRecordDecl *CurRecord;
+ if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
+ CurRecord = cast<CXXRecordDecl>(CurMethod->getParent());
else
- return true;
+ CurRecord = dyn_cast<CXXRecordDecl>(SemaRef.CurContext);
+
+ return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord);
}
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
@@ -737,8 +745,7 @@
// names a dependent type.
// Determine whether this is a member of an unknown specialization;
// we need to handle these differently.
- if (SS.isSet() && !(IsFullyFormedScope(*this, SS) &&
- IsFullyFormedScope(*this, CurContext))) {
+ if (SS.isSet() && IsDependentIdExpression(*this, SS)) {
bool CheckForImplicitMember = !isAddressOfOperand;
return ActOnDependentIdExpression(SS, Name, NameLoc,
diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp
index 85efab2..a07f05c 100644
--- a/test/SemaTemplate/qualified-id.cpp
+++ b/test/SemaTemplate/qualified-id.cpp
@@ -7,3 +7,14 @@
namespace b {
template<typename T> void f0(a::C<T> &a0) { }
}
+
+
+namespace test1 {
+ int a = 0;
+ template <class T> class Base { };
+ template <class T> class Derived : public Base<T> {
+ int foo() {
+ return test1::a;
+ }
+ };
+}