diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 12 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 18 |
5 files changed, 62 insertions, 4 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index b30d335918a..1cce35c0b39 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -144,6 +144,19 @@ CXXRecordDecl::setBases(ASTContext &C, } } +/// Callback function for CXXRecordDecl::forallBases that acknowledges +/// that it saw a base class. +static bool SawBase(const CXXRecordDecl *, void *) { + return true; +} + +bool CXXRecordDecl::hasAnyDependentBases() const { + if (!isDependentContext()) + return false; + + return !forallBases(SawBase, 0); +} + bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { return getCopyConstructor(Context, Qualifiers::Const) != 0; } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 8fc34880c11..44bf48915ea 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2032,6 +2032,7 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); + bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index a8f118ebdd6..8594583ec3e 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -210,6 +210,28 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { return getCurrentInstantiationOf(NNS) == 0; } +/// \brief Determine whether the given scope specifier refers to a +/// current instantiation that has any dependent base clases. +/// +/// This check is typically used when we've performed lookup into the +/// current instantiation of a template, but that lookup failed. When +/// there are dependent bases present, however, the lookup needs to be +/// delayed until template instantiation time. +bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) { + if (!SS.isSet()) + return false; + + NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep(); + if (!NNS->isDependent()) + return false; + + CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS); + if (!CurrentInstantiation) + return false; + + return CurrentInstantiation->hasAnyDependentBases(); +} + /// \brief If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 75fe7fd00fc..c54745f552e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4785,8 +4785,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.isAmbiguous()) return DeclPtrTy(); - // A tag 'foo::bar' must already exist. if (Previous.empty()) { + // Name lookup did not find anything. However, if the + // nested-name-specifier refers to the current instantiation, + // and that current instantiation has any dependent base + // classes, we might find something at instantiation time: treat + // this as a dependent elaborated-type-specifier. + if (isCurrentInstantiationWithDependentBases(SS)) { + IsDependent = true; + return DeclPtrTy(); + } + + // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); Name = 0; Invalid = true; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index e75277e823e..d2e70cf9ad6 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1608,15 +1608,19 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, EnteringContext, Template); - if (TNK == TNK_Non_template) { + if (TNK == TNK_Non_template && + isCurrentInstantiationWithDependentBases(SS)) { + // This is a dependent template. + } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) << Name.getSourceRange(); return TemplateTy(); + } else { + // We found something; return it. + return Template; } - - return Template; } NestedNameSpecifier *Qualifier @@ -4765,6 +4769,14 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, Decl *Referenced = 0; switch (Result.getResultKind()) { case LookupResult::NotFound: + if (CurrentInstantiation && CurrentInstantiation->hasAnyDependentBases()) { + // We performed a lookup in the current instantiation and didn't + // find anything. However, this current instantiation has + // dependent bases, so we might be able to find something at + // instantiation time: just build a TypenameType and move on. + return Context.getTypenameType(NNS, &II); + } + DiagID = diag::err_typename_nested_not_found; break; |

