From: Richard Smith Date: Thu, 9 Jul 2020 21:57:30 +0000 (-0700) Subject: Push parameters into the local instantiation scope before instantiating X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a5569f089844209dbea2e3241460173d7b6b1420;p=android-x86%2Fexternal-llvm-project.git Push parameters into the local instantiation scope before instantiating a default argument. Default arguments can (after recent language changes) refer to parameters of the same function. Make sure they're added to the local instantiation scope before transforming a default argument so that we can remap such references to them properly. --- diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 6c39f6aab1b..28faa2c1fc7 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2618,7 +2618,13 @@ public: /// Retrieve the function declaration from which this function could /// be instantiated, if it is an instantiation (rather than a non-template /// or a specialization, for example). - FunctionDecl *getTemplateInstantiationPattern() const; + /// + /// If \p ForDefinition is \c false, explicit specializations will be treated + /// as if they were implicit instantiations. This will then find the pattern + /// corresponding to non-definition portions of the declaration, such as + /// default arguments and the exception specification. + FunctionDecl * + getTemplateInstantiationPattern(bool ForDefinition = true) const; /// Retrieve the primary template that this function template /// specialization either specializes or was instantiated from. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 1676f319394..5c0a98815dd 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3623,7 +3623,8 @@ bool FunctionDecl::isTemplateInstantiation() const { return clang::isTemplateInstantiation(getTemplateSpecializationKind()); } -FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { +FunctionDecl * +FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const { // If this is a generic lambda call operator specialization, its // instantiation pattern is always its primary template's pattern // even if its primary template was instantiated from another @@ -3640,18 +3641,20 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { } if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) { - if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind())) + if (ForDefinition && + !clang::isTemplateInstantiation(Info->getTemplateSpecializationKind())) return nullptr; return getDefinitionOrSelf(cast(Info->getInstantiatedFrom())); } - if (!clang::isTemplateInstantiation(getTemplateSpecializationKind())) + if (ForDefinition && + !clang::isTemplateInstantiation(getTemplateSpecializationKind())) return nullptr; if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { // If we hit a point where the user provided a specialization of this // template, we're done looking. - while (!Primary->isMemberSpecialization()) { + while (!ForDefinition || !Primary->isMemberSpecialization()) { auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); if (!NewPrimary) break; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1098a9aa782..6179d90d54f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4273,6 +4273,13 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); + + FunctionDecl *Pattern = FD->getTemplateInstantiationPattern( + /*ForDefinition*/ false); + if (addInstantiatedParametersToScope(*this, FD, Pattern, Local, + TemplateArgs)) + return true; + runWithSufficientStackSpace(CallLoc, [&] { Result = SubstInitializer(UninstExpr, TemplateArgs, /*DirectInit*/false); @@ -4338,6 +4345,10 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + // FIXME: We can't use getTemplateInstantiationPattern(false) in general + // here, because for a non-defining friend declaration in a class template, + // we don't store enough information to map back to the friend declaration in + // the template. FunctionDecl *Template = Proto->getExceptionSpecTemplate(); if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs)) { diff --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp index 2114cc94e6c..02696a80bc0 100644 --- a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp +++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp @@ -116,6 +116,11 @@ namespace rdar34167492 { }; } +namespace use_of_earlier_param { + template void f(T a, int = decltype(a)()); + void g() { f(0); } +} + #if __cplusplus >= 201402L namespace lambda { // Verify that a default argument in a lambda can refer to the type of a