From: John McCall Date: Mon, 30 Nov 2009 23:50:49 +0000 (+0000) Subject: Fix and test for a problem caught by the clang-on-clang buildbot: qualified X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e1599cee9310e523af40c3c8a5f21be6f7302981;p=clang 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 3a97ee5d9d..55adbb59e3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -689,24 +689,32 @@ static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { 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(DC)); -} -static bool IsFullyFormedScope(Sema &SemaRef, DeclContext *DC) { - if (isa(DC)) - return IsFullyFormedScope(SemaRef, - cast(cast(DC)->getParent())); - else if (isa(DC)) - return IsFullyFormedScope(SemaRef, cast(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(DC)) return false; + + // We can't look into record types unless they're fully-formed. + if (!IsFullyFormedScope(SemaRef, cast(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(SemaRef.CurContext)) + CurRecord = cast(CurMethod->getParent()); else - return true; + CurRecord = dyn_cast(SemaRef.CurContext); + + return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord); } Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, @@ -737,8 +745,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // 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 85efab2b5c..a07f05ca78 100644 --- a/test/SemaTemplate/qualified-id.cpp +++ b/test/SemaTemplate/qualified-id.cpp @@ -7,3 +7,14 @@ namespace a { namespace b { template void f0(a::C &a0) { } } + + +namespace test1 { + int a = 0; + template class Base { }; + template class Derived : public Base { + int foo() { + return test1::a; + } + }; +}