//===------- 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/Type.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/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; } }; // 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(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 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()) Result.addOuterTemplateArguments( const_cast(FTD), TSTy->template_arguments(), /*Final=*/false); } NNS = NNS->getPrefix(); } } return Response::ChangeDecl(FTD->getLexicalDeclContext()); } Response HandleRecordDecl(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 that this // lambda is defined inside of. if (Rec->isLambda()) if (const Decl *LCD = Rec->getLambdaContextDecl()) return Response::ChangeDecl(LCD); 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 /// Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// /// \param ND the declaration for which we are computing template instantiation /// arguments. /// /// \param DC In the event we don't HAVE a declaration yet, we instead provide /// the decl context where it will be created. In this case, the `Innermost` /// should likely be provided. If ND is non-null, this is ignored. /// /// \param Innermost if non-NULL, specifies a template argument list for the /// template declaration passed as ND. /// /// \param RelativeToPrimary true if we should get the template /// arguments relative to the primary template, even when we're /// dealing with a specialization. This is only relevant for function /// template specializations. /// /// \param Pattern If non-NULL, indicates the pattern from which we will be /// instantiating the definition of the given declaration, \p ND. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. /// /// \param ForConstraintInstantiation when collecting arguments, /// ForConstraintInstantiation indicates we should continue looking when /// encountering a lambda generic call operator, and continue looking for /// arguments on an enclosing class template. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *ND, const DeclContext *DC, bool Final, const TemplateArgumentList *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->asArray(), Final); // Populate placeholder template arguments for TemplateTemplateParmDecls. // This is essential for the case e.g. // // template concept Concept = false; // template