diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 44 |
3 files changed, 56 insertions, 2 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 3f48e798687..4dff88bbebe 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3318,8 +3318,6 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType Canon) const { - assert(NNS->isDependent() && "nested-name-specifier must be dependent"); - if (Canon.isNull()) { NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); ElaboratedTypeKeyword CanonKeyword = Keyword; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 65ec44c5775..92a13659ea3 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2227,6 +2227,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_class; if (Context == Declarator::FileContext) return DSC_top_level; + if (Context == Declarator::TemplateTypeArgContext) + return DSC_template_type_arg; if (Context == Declarator::TrailingReturnContext) return DSC_trailing; if (Context == Declarator::AliasDeclContext || @@ -2753,6 +2755,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); + // MSVC: If we weren't able to parse a default template argument, and it's + // just a simple identifier, create a DependentNameType. This will allow us + // to defer the name lookup to template instantiation time, as long we forge a + // NestedNameSpecifier for the current context. + if (!TypeRep && DSContext == DSC_template_type_arg && + getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) { + TypeRep = Actions.ActOnDelayedDefaultTemplateArg( + *Tok.getIdentifierInfo(), Tok.getLocation()); + } + // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ed7431ae3e4..ec0c27b2d2e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -343,6 +343,50 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, return ParsedType::make(T); } +// Builds a fake NNS for the given decl context. +static NestedNameSpecifier * +synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) { + for (;; DC = DC->getLookupParent()) { + DC = DC->getPrimaryContext(); + auto *ND = dyn_cast<NamespaceDecl>(DC); + if (ND && !ND->isInline() && !ND->isAnonymousNamespace()) + return NestedNameSpecifier::Create(Context, nullptr, ND); + else if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) + return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), + RD->getTypeForDecl()); + else if (isa<TranslationUnitDecl>(DC)) + return NestedNameSpecifier::GlobalSpecifier(Context); + } + llvm_unreachable("something isn't in TU scope?"); +} + +ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II, + SourceLocation NameLoc) { + // Accepting an undeclared identifier as a default argument for a template + // type parameter is a Microsoft extension. + Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II; + + // Build a fake DependentNameType that will perform lookup into CurContext at + // instantiation time. The name specifier isn't dependent, so template + // instantiation won't transform it. It will retry the lookup, however. + NestedNameSpecifier *NNS = + synthesizeCurrentNestedNameSpecifier(Context, CurContext); + QualType T = Context.getDependentNameType(ETK_None, NNS, &II); + + // Build type location information. We synthesized the qualifier, so we have + // to build a fake NestedNameSpecifierLoc. + NestedNameSpecifierLocBuilder NNSLocBuilder; + NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc)); + NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context); + + TypeLocBuilder Builder; + DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T); + DepTL.setNameLoc(NameLoc); + DepTL.setElaboratedKeywordLoc(SourceLocation()); + DepTL.setQualifierLoc(QualifierLoc); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); +} + /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, |