//===------- SemaTemplateInstantiate.cpp - C++ Template Instantiation ------===/ // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===/ // // This file implements C++ template instantiation. // //===----------------------------------------------------------------------===/ #include "TreeTransform.h" #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" #include using namespace clang; using namespace sema; //===----------------------------------------------------------------------===/ // Template Instantiation Support //===----------------------------------------------------------------------===/ namespace { namespace TemplateInstArgsHelpers { struct Response { const Decl *NextDecl = nullptr; bool IsDone = false; bool ClearRelativeToPrimary = true; static Response Done() { Response R; R.IsDone = true; return R; } static Response ChangeDecl(const Decl *ND) { Response R; R.NextDecl = ND; return R; } static Response ChangeDecl(const DeclContext *Ctx) { Response R; R.NextDecl = Decl::castFromDeclContext(Ctx); return R; } static Response UseNextDecl(const Decl *CurDecl) { return ChangeDecl(CurDecl->getDeclContext()); } static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) { Response R = Response::UseNextDecl(CurDecl); R.ClearRelativeToPrimary = false; return R; } }; // Retrieve the primary template for a lambda call operator. It's // unfortunate that we only have the mappings of call operators rather // than lambda classes. const FunctionDecl * getPrimaryTemplateOfGenericLambda(const FunctionDecl *LambdaCallOperator) { if (!isLambdaCallOperator(LambdaCallOperator)) return LambdaCallOperator; while (true) { if (auto *FTD = dyn_cast_if_present( LambdaCallOperator->getDescribedTemplate()); FTD && FTD->getInstantiatedFromMemberTemplate()) { LambdaCallOperator = FTD->getInstantiatedFromMemberTemplate()->getTemplatedDecl(); } else if (LambdaCallOperator->getPrimaryTemplate()) { // Cases where the lambda operator is instantiated in // TemplateDeclInstantiator::VisitCXXMethodDecl. LambdaCallOperator = LambdaCallOperator->getPrimaryTemplate()->getTemplatedDecl(); } else if (auto *Prev = cast(LambdaCallOperator) ->getInstantiatedFromMemberFunction()) LambdaCallOperator = Prev; else break; } return LambdaCallOperator; } struct EnclosingTypeAliasTemplateDetails { TypeAliasTemplateDecl *Template = nullptr; TypeAliasTemplateDecl *PrimaryTypeAliasDecl = nullptr; ArrayRef AssociatedTemplateArguments; explicit operator bool() noexcept { return Template; } }; // Find the enclosing type alias template Decl from CodeSynthesisContexts, as // well as its primary template and instantiating template arguments. EnclosingTypeAliasTemplateDetails getEnclosingTypeAliasTemplateDecl(Sema &SemaRef) { for (auto &CSC : llvm::reverse(SemaRef.CodeSynthesisContexts)) { if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind:: TypeAliasTemplateInstantiation) continue; EnclosingTypeAliasTemplateDetails Result; auto *TATD = cast(CSC.Entity), *Next = TATD->getInstantiatedFromMemberTemplate(); Result = { /*Template=*/TATD, /*PrimaryTypeAliasDecl=*/TATD, /*AssociatedTemplateArguments=*/CSC.template_arguments(), }; while (Next) { Result.PrimaryTypeAliasDecl = Next; Next = Next->getInstantiatedFromMemberTemplate(); } return Result; } return {}; } // Check if we are currently inside of a lambda expression that is // surrounded by a using alias declaration. e.g. // template using type = decltype([](auto) { ^ }()); // We have to do so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never // a DeclContext, nor does it have an associated specialization Decl from which // we could collect these template arguments. bool isLambdaEnclosedByTypeAliasDecl( const FunctionDecl *LambdaCallOperator, const TypeAliasTemplateDecl *PrimaryTypeAliasDecl) { struct Visitor : RecursiveASTVisitor { Visitor(const FunctionDecl *CallOperator) : CallOperator(CallOperator) {} bool VisitLambdaExpr(const LambdaExpr *LE) { // Return true to bail out of the traversal, implying the Decl contains // the lambda. return getPrimaryTemplateOfGenericLambda(LE->getCallOperator()) != CallOperator; } const FunctionDecl *CallOperator; }; QualType Underlying = PrimaryTypeAliasDecl->getTemplatedDecl()->getUnderlyingType(); return !Visitor(getPrimaryTemplateOfGenericLambda(LambdaCallOperator)) .TraverseType(Underlying); } // Add template arguments from a variable template instantiation. Response HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { // For a class-scope explicit specialization, there are no template arguments // at this level, but there may be enclosing template arguments. if (VarTemplSpec->isClassScopeExplicitSpecialization()) return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); // We're done when we hit an explicit specialization. if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa(VarTemplSpec)) return Response::Done(); // If this variable template specialization was instantiated from a // specialized member that is a variable template, we're done. assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?"); llvm::PointerUnion Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); if (VarTemplatePartialSpecializationDecl *Partial = Specialized.dyn_cast()) { if (!SkipForSpecialization) Result.addOuterTemplateArguments( Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), /*Final=*/false); if (Partial->isMemberSpecialization()) return Response::Done(); } else { VarTemplateDecl *Tmpl = Specialized.get(); if (!SkipForSpecialization) Result.addOuterTemplateArguments( Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), /*Final=*/false); if (Tmpl->isMemberSpecialization()) return Response::Done(); } return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); } // If we have a template template parameter with translation unit context, // then we're performing substitution into a default template argument of // this template template parameter before we've constructed the template // that will own this template template parameter. In this case, we // use empty template parameter lists for all of the outer templates // to avoid performing any substitutions. Response HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, MultiLevelTemplateArgumentList &Result) { for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) Result.addOuterTemplateArguments(std::nullopt); return Response::Done(); } Response HandlePartialClassTemplateSpec( const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec, MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { if (!SkipForSpecialization) Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth()); return Response::Done(); } // Add template arguments from a class template instantiation. Response HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa(ClassTemplSpec)) return Response::Done(); if (!SkipForSpecialization) Result.addOuterTemplateArguments( const_cast(ClassTemplSpec), ClassTemplSpec->getTemplateInstantiationArgs().asArray(), /*Final=*/false); // If this class template specialization was instantiated from a // specialized member that is a class template, we're done. assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) return Response::Done(); // If this was instantiated from a partial template specialization, we need // to get the next level of declaration context from the partial // specialization, as the ClassTemplateSpecializationDecl's // DeclContext/LexicalDeclContext will be for the primary template. if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial() .dyn_cast()) return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext()); } return Response::UseNextDecl(ClassTemplSpec); } Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, MultiLevelTemplateArgumentList &Result, const FunctionDecl *Pattern, bool RelativeToPrimary, bool ForConstraintInstantiation) { // Add template arguments from a function template specialization. if (!RelativeToPrimary && Function->getTemplateSpecializationKindForInstantiation() == TSK_ExplicitSpecialization) return Response::Done(); if (!RelativeToPrimary && Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { // This is an implicit instantiation of an explicit specialization. We // don't get any template arguments from this function but might get // some from an enclosing template. return Response::UseNextDecl(Function); } else if (const TemplateArgumentList *TemplateArgs = Function->getTemplateSpecializationArgs()) { // Add the template arguments for this specialization. Result.addOuterTemplateArguments(const_cast(Function), TemplateArgs->asArray(), /*Final=*/false); if (RelativeToPrimary && (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization || (Function->getFriendObjectKind() && !Function->getPrimaryTemplate()->getFriendObjectKind()))) return Response::UseNextDecl(Function); // If this function was instantiated from a specialized member that is // a function template, we're done. assert(Function->getPrimaryTemplate() && "No function template?"); if (Function->getPrimaryTemplate()->isMemberSpecialization()) return Response::Done(); // If this function is a generic lambda specialization, we are done. if (!ForConstraintInstantiation && isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) return Response::Done(); } else if (Function->getDescribedFunctionTemplate()) { assert( (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && "Outer template not instantiated?"); } // If this is a friend or local declaration and it declares an entity at // namespace scope, take arguments from its lexical parent // instead of its semantic parent, unless of course the pattern we're // instantiating actually comes from the file's context! if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && Function->getNonTransparentDeclContext()->isFileContext() && (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { return Response::ChangeDecl(Function->getLexicalDeclContext()); } if (ForConstraintInstantiation && Function->getFriendObjectKind()) return Response::ChangeDecl(Function->getLexicalDeclContext()); return Response::UseNextDecl(Function); } Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, MultiLevelTemplateArgumentList &Result) { if (!isa(FTD->getDeclContext())) { Result.addOuterTemplateArguments( const_cast(FTD), const_cast(FTD)->getInjectedTemplateArgs(), /*Final=*/false); NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { if (NNS->isInstantiationDependent()) { if (const auto *TSTy = Ty->getAs()) { ArrayRef Arguments = TSTy->template_arguments(); // Prefer template arguments from the injected-class-type if possible. // For example, // ```cpp // template struct S { // template void foo(); // }; // template template // ^^^^^^^^^^^^^ InjectedTemplateArgs // They're of kind TemplateArgument::Pack, not of // TemplateArgument::Type. // void S::foo() {} // ^^^^^^^ // TSTy->template_arguments() (which are of PackExpansionType) // ``` // This meets the contract in // TreeTransform::TryExpandParameterPacks that the template arguments // for unexpanded parameters should be of a Pack kind. if (TSTy->isCurrentInstantiation()) { auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl(); if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) Arguments = CTD->getInjectedTemplateArgs(); else if (auto *Specialization = dyn_cast(RD)) Arguments = Specialization->getTemplateInstantiationArgs().asArray(); } Result.addOuterTemplateArguments( const_cast(FTD), Arguments, /*Final=*/false); } } NNS = NNS->getPrefix(); } } return Response::ChangeDecl(FTD->getLexicalDeclContext()); } Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec, MultiLevelTemplateArgumentList &Result, ASTContext &Context, bool ForConstraintInstantiation) { if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { assert( (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && "Outer template not instantiated?"); if (ClassTemplate->isMemberSpecialization()) return Response::Done(); if (ForConstraintInstantiation) Result.addOuterTemplateArguments(const_cast(Rec), ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false); } if (const MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo()) if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return Response::Done(); bool IsFriend = Rec->getFriendObjectKind() || (Rec->getDescribedClassTemplate() && Rec->getDescribedClassTemplate()->getFriendObjectKind()); if (ForConstraintInstantiation && IsFriend && Rec->getNonTransparentDeclContext()->isFileContext()) { return Response::ChangeDecl(Rec->getLexicalDeclContext()); } // This is to make sure we pick up the VarTemplateSpecializationDecl or the // TypeAliasTemplateDecl that this lambda is defined inside of. if (Rec->isLambda()) { if (const Decl *LCD = Rec->getLambdaContextDecl()) return Response::ChangeDecl(LCD); // Retrieve the template arguments for a using alias declaration. // This is necessary for constraint checking, since we always keep // constraints relative to the primary template. if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef); ForConstraintInstantiation && TypeAlias) { if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(), TypeAlias.PrimaryTypeAliasDecl)) { Result.addOuterTemplateArguments(TypeAlias.Template, TypeAlias.AssociatedTemplateArguments, /*Final=*/false); // Visit the parent of the current type alias declaration rather than // the lambda thereof. // E.g., in the following example: // struct S { // template using T = decltype([] {} ()); // }; // void foo() { // S::T var; // } // The instantiated lambda expression (which we're visiting at 'var') // has a function DeclContext 'foo' rather than the Record DeclContext // S. This seems to be an oversight to me that we may want to set a // Sema Context from the CXXScopeSpec before substituting into T. return Response::ChangeDecl(TypeAlias.Template->getDeclContext()); } } } return Response::UseNextDecl(Rec); } Response HandleImplicitConceptSpecializationDecl( const ImplicitConceptSpecializationDecl *CSD, MultiLevelTemplateArgumentList &Result) { Result.addOuterTemplateArguments( const_cast(CSD), CSD->getTemplateArguments(), /*Final=*/false); return Response::UseNextDecl(CSD); } Response HandleGenericDeclContext(const Decl *CurDecl) { return Response::UseNextDecl(CurDecl); } } // namespace TemplateInstArgsHelpers } // namespace MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *ND, const DeclContext *DC, bool Final, std::optional> Innermost, bool RelativeToPrimary, const FunctionDecl *Pattern, bool ForConstraintInstantiation, bool SkipForSpecialization) { assert((ND || DC) && "Can't find arguments for a decl if one isn't provided"); // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; using namespace TemplateInstArgsHelpers; const Decl *CurDecl = ND; if (!CurDecl) CurDecl = Decl::castFromDeclContext(DC); if (Innermost) { Result.addOuterTemplateArguments(const_cast(ND), *Innermost, Final); // Populate placeholder template arguments for TemplateTemplateParmDecls. // This is essential for the case e.g. // // template concept Concept = false; // template