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.

llvm-svn: 90171
This commit is contained in:
John McCall
2009-11-30 23:50:49 +00:00
parent cc71783b32
commit f786fb13f5
2 changed files with 35 additions and 17 deletions

View File

@@ -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<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 @@ 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,

View File

@@ -7,3 +7,14 @@ namespace a {
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;
}
};
}