diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp | 542 |
1 files changed, 339 insertions, 203 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp index e12186d7d82f..c2e8ed0c602e 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -20,7 +20,9 @@ #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" @@ -35,6 +37,7 @@ #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" @@ -79,6 +82,94 @@ struct Response { 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<FunctionTemplateDecl>( + 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<CXXMethodDecl>(LambdaCallOperator) + ->getInstantiatedFromMemberFunction()) + LambdaCallOperator = Prev; + else + break; + } + return LambdaCallOperator; +} + +struct EnclosingTypeAliasTemplateDetails { + TypeAliasTemplateDecl *Template = nullptr; + TypeAliasTemplateDecl *PrimaryTypeAliasDecl = nullptr; + ArrayRef<TemplateArgument> 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<TypeAliasTemplateDecl>(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 <class> 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> { + 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, @@ -175,10 +266,11 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, return Response::UseNextDecl(ClassTemplSpec); } -Response HandleFunction(const FunctionDecl *Function, +Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, MultiLevelTemplateArgumentList &Result, const FunctionDecl *Pattern, bool RelativeToPrimary, - bool ForConstraintInstantiation) { + bool ForConstraintInstantiation, + bool ForDefaultArgumentSubstitution) { // Add template arguments from a function template specialization. if (!RelativeToPrimary && Function->getTemplateSpecializationKindForInstantiation() == @@ -198,10 +290,18 @@ Response HandleFunction(const FunctionDecl *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()) + if (!ForDefaultArgumentSubstitution && + Function->getPrimaryTemplate()->isMemberSpecialization()) return Response::Done(); // If this function is a generic lambda specialization, we are done. @@ -241,10 +341,38 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { if (NNS->isInstantiationDependent()) { - if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) + if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) { + ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments(); + // Prefer template arguments from the injected-class-type if possible. + // For example, + // ```cpp + // template <class... Pack> struct S { + // template <class T> void foo(); + // }; + // template <class... Pack> template <class T> + // ^^^^^^^^^^^^^ InjectedTemplateArgs + // They're of kind TemplateArgument::Pack, not of + // TemplateArgument::Type. + // void S<Pack...>::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<ClassTemplateSpecializationDecl>(RD)) + Arguments = + Specialization->getTemplateInstantiationArgs().asArray(); + } Result.addOuterTemplateArguments( - const_cast<FunctionTemplateDecl *>(FTD), TSTy->template_arguments(), + const_cast<FunctionTemplateDecl *>(FTD), Arguments, /*Final=*/false); + } } NNS = NNS->getPrefix(); @@ -254,7 +382,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, return Response::ChangeDecl(FTD->getLexicalDeclContext()); } -Response HandleRecordDecl(const CXXRecordDecl *Rec, +Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec, MultiLevelTemplateArgumentList &Result, ASTContext &Context, bool ForConstraintInstantiation) { @@ -283,11 +411,38 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec, 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()) + // 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 <class> using T = decltype([]<Concept> {} ()); + // }; + // 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); } @@ -308,39 +463,11 @@ Response HandleGenericDeclContext(const Decl *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, + std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary, const FunctionDecl *Pattern, bool ForConstraintInstantiation, - bool SkipForSpecialization) { + bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) { 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; @@ -352,8 +479,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( CurDecl = Decl::castFromDeclContext(DC); if (Innermost) { - Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), - Innermost->asArray(), Final); + Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost, + Final); // Populate placeholder template arguments for TemplateTemplateParmDecls. // This is essential for the case e.g. // @@ -381,10 +508,12 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( R = HandleClassTemplateSpec(ClassTemplSpec, Result, SkipForSpecialization); } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) { - R = HandleFunction(Function, Result, Pattern, RelativeToPrimary, - ForConstraintInstantiation); + R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation, + ForDefaultArgumentSubstitution); } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) { - R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation); + R = HandleRecordDecl(*this, Rec, Result, Context, + ForConstraintInstantiation); } else if (const auto *CSD = dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) { R = HandleImplicitConceptSpecializationDecl(CSD, Result); @@ -441,6 +570,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case BuildingBuiltinDumpStructCall: case LambdaExpressionSubstitution: case BuildingDeductionGuides: + case TypeAliasTemplateInstantiation: return false; // This function should never be called when Kind's value is Memoization. @@ -519,9 +649,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation, InstantiationRange, FunctionTemplate, nullptr, TemplateArgs, &DeductionInfo) { - assert( - Kind == CodeSynthesisContext::ExplicitTemplateArgumentSubstitution || - Kind == CodeSynthesisContext::DeducedTemplateArgumentSubstitution); + assert(Kind == CodeSynthesisContext::ExplicitTemplateArgumentSubstitution || + Kind == CodeSynthesisContext::DeducedTemplateArgumentSubstitution || + Kind == CodeSynthesisContext::BuildingDeductionGuides); } Sema::InstantiatingTemplate::InstantiatingTemplate( @@ -587,6 +717,15 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + TypeAliasTemplateDecl *Entity, ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::TypeAliasTemplateInstantiation, + PointOfInstantiation, InstantiationRange, /*Entity=*/Entity, + /*Template=*/nullptr, TemplateArgs) {} + +Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, NamedDecl *Param, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) @@ -758,8 +897,6 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( return true; } -/// Prints the current instantiation stack through a series of -/// notes. void Sema::PrintInstantiationStack() { // Determine which template instantiations to skip, if any. unsigned SkipStart = CodeSynthesisContexts.size(), SkipEnd = SkipStart; @@ -825,11 +962,6 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, diag::note_template_class_instantiation_here) << CTD << Active->InstantiationRange; - } else { - Diags.Report(Active->PointOfInstantiation, - diag::note_template_type_alias_instantiation_here) - << cast<TypeAliasTemplateDecl>(D) - << Active->InstantiationRange; } break; } @@ -989,7 +1121,8 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::DeclaringSpecialMember: Diags.Report(Active->PointOfInstantiation, diag::note_in_declaration_of_implicit_special_member) - << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember; + << cast<CXXRecordDecl>(Active->Entity) + << llvm::to_underlying(Active->SpecialMember); break; case CodeSynthesisContext::DeclaringImplicitEqualityComparison: @@ -1007,7 +1140,8 @@ void Sema::PrintInstantiationStack() { auto *MD = cast<CXXMethodDecl>(FD); Diags.Report(Active->PointOfInstantiation, diag::note_member_synthesized_at) - << MD->isExplicitlyDefaulted() << DFK.asSpecialMember() + << MD->isExplicitlyDefaulted() + << llvm::to_underlying(DFK.asSpecialMember()) << Context.getTagDeclType(MD->getParent()); } else if (DFK.isComparison()) { QualType RecordType = FD->getParamDecl(0) @@ -1103,6 +1237,12 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, diag::note_building_deduction_guide_here); break; + case CodeSynthesisContext::TypeAliasTemplateInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_type_alias_instantiation_here) + << cast<TypeAliasTemplateDecl>(Active->Entity) + << Active->InstantiationRange; + break; } } } @@ -1118,12 +1258,13 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { ++Active) { switch (Active->Kind) { - case CodeSynthesisContext::TemplateInstantiation: + case CodeSynthesisContext::TypeAliasTemplateInstantiation: // An instantiation of an alias template may or may not be a SFINAE // context, depending on what else is on the stack. if (isa<TypeAliasTemplateDecl>(Active->Entity)) break; [[fallthrough]]; + case CodeSynthesisContext::TemplateInstantiation: case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: case CodeSynthesisContext::ExceptionSpecInstantiation: case CodeSynthesisContext::ConstraintsCheck: @@ -1382,6 +1523,7 @@ namespace { NamedDecl *FirstQualifierInScope = nullptr, bool AllowInjectedClassName = false); + const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA); const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS, const Stmt *InstS, @@ -1418,6 +1560,54 @@ namespace { return inherited::TransformFunctionProtoType(TLB, TL); } + QualType TransformInjectedClassNameType(TypeLocBuilder &TLB, + InjectedClassNameTypeLoc TL) { + auto Type = inherited::TransformInjectedClassNameType(TLB, TL); + // Special case for transforming a deduction guide, we return a + // transformed TemplateSpecializationType. + if (Type.isNull() && + SemaRef.CodeSynthesisContexts.back().Kind == + Sema::CodeSynthesisContext::BuildingDeductionGuides) { + // Return a TemplateSpecializationType for transforming a deduction + // guide. + if (auto *ICT = TL.getType()->getAs<InjectedClassNameType>()) { + auto Type = + inherited::TransformType(ICT->getInjectedSpecializationType()); + TLB.pushTrivial(SemaRef.Context, Type, TL.getNameLoc()); + return Type; + } + } + return Type; + } + // Override the default version to handle a rewrite-template-arg-pack case + // for building a deduction guide. + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, + bool Uneval = false) { + const TemplateArgument &Arg = Input.getArgument(); + std::vector<TemplateArgument> TArgs; + switch (Arg.getKind()) { + case TemplateArgument::Pack: + // Literally rewrite the template argument pack, instead of unpacking + // it. + for (auto &pack : Arg.getPackAsArray()) { + TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc( + pack, QualType(), SourceLocation{}); + TemplateArgumentLoc Output; + if (SemaRef.SubstTemplateArgument(Input, TemplateArgs, Output)) + return true; // fails + TArgs.push_back(Output.getArgument()); + } + Output = SemaRef.getTrivialTemplateArgumentLoc( + TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)), + QualType(), SourceLocation{}); + return false; + default: + break; + } + return inherited::TransformTemplateArgument(Input, Output, Uneval); + } + template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, @@ -1451,6 +1641,23 @@ namespace { SubstTemplateTypeParmPackTypeLoc TL, bool SuppressObjCLifetime); + CXXRecordDecl::LambdaDependencyKind + ComputeLambdaDependency(LambdaScopeInfo *LSI) { + if (auto TypeAlias = + TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl( + getSema()); + TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl( + LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) { + unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth(); + if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels()) + return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent; + for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments) + if (TA.isDependent()) + return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent; + } + return inherited::ComputeLambdaDependency(LSI); + } + ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this); @@ -1625,7 +1832,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); + TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); return Template.getAsTemplateDecl(); @@ -1798,10 +2005,8 @@ TemplateName TemplateInstantiator::TransformTemplateName( Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); + TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); - assert(!Template.getAsQualifiedTemplateName() && - "template decl to substitute is qualified?"); if (Final) return Template; @@ -1821,8 +2026,8 @@ TemplateName TemplateInstantiator::TransformTemplateName( if (SubstPack->getFinal()) return Template; return getSema().Context.getSubstTemplateTemplateParm( - Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(), - SubstPack->getIndex(), getPackIndex(Pack)); + Template, SubstPack->getAssociatedDecl(), SubstPack->getIndex(), + getPackIndex(Pack)); } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, @@ -1898,6 +2103,21 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, Arg, PackIndex); } +const CXXAssumeAttr * +TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) { + ExprResult Res = getDerived().TransformExpr(AA->getAssumption()); + if (!Res.isUsable()) + return AA; + + Res = getSema().BuildCXXAssumeExpr(Res.get(), AA->getAttrName(), + AA->getRange()); + if (!Res.isUsable()) + return AA; + + return CXXAssumeAttr::CreateImplicit(getSema().Context, Res.get(), + AA->getRange()); +} + const LoopHintAttr * TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get(); @@ -1906,13 +2126,26 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { return LH; // Generate error if there is a problem with the value. - if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation())) + if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation(), + LH->getSemanticSpelling() == + LoopHintAttr::Pragma_unroll)) return LH; + LoopHintAttr::OptionType Option = LH->getOption(); + LoopHintAttr::LoopHintState State = LH->getState(); + + llvm::APSInt ValueAPS = + TransformedExpr->EvaluateKnownConstInt(getSema().getASTContext()); + // The values of 0 and 1 block any unrolling of the loop. + if (ValueAPS.isZero() || ValueAPS.isOne()) { + Option = LoopHintAttr::Unroll; + State = LoopHintAttr::Disable; + } + // Create new LoopHintValueAttr with integral expression in place of the // non-type template parameter. - return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(), - LH->getState(), TransformedExpr, *LH); + return LoopHintAttr::CreateImplicit(getSema().Context, Option, State, + TransformedExpr, *LH); } const NoInlineAttr *TemplateInstantiator::TransformStmtNoInlineAttr( const Stmt *OrigS, const Stmt *InstS, const NoInlineAttr *A) { @@ -2257,10 +2490,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, assert(Arg.getKind() == TemplateArgument::Type && "unexpected nontype template argument kind in template rewrite"); QualType NewT = Arg.getAsType(); - assert(isa<TemplateTypeParmType>(NewT) && - "type parm not rewritten to type parm"); - auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT); - NewTL.setNameLoc(TL.getNameLoc()); + TLB.pushTrivial(SemaRef.Context, NewT, TL.getNameLoc()); return NewT; } @@ -2352,16 +2582,12 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info, } else { ErrorLoc = Info.getLocation(); } - char *MessageBuf = new (S.Context) char[Message.size()]; - std::copy(Message.begin(), Message.end(), MessageBuf); SmallString<128> Entity; llvm::raw_svector_ostream OS(Entity); Printer(OS); - char *EntityBuf = new (S.Context) char[Entity.size()]; - std::copy(Entity.begin(), Entity.end(), EntityBuf); - return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{ - StringRef(EntityBuf, Entity.size()), ErrorLoc, - StringRef(MessageBuf, Message.size())}; + const ASTContext &C = S.Context; + return new (C) concepts::Requirement::SubstitutionDiagnostic{ + C.backupStr(Entity), ErrorLoc, C.backupStr(Message)}; } concepts::Requirement::SubstitutionDiagnostic * @@ -2370,10 +2596,9 @@ concepts::createSubstDiagAt(Sema &S, SourceLocation Location, SmallString<128> Entity; llvm::raw_svector_ostream OS(Entity); Printer(OS); - char *EntityBuf = new (S.Context) char[Entity.size()]; - llvm::copy(Entity, EntityBuf); - return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{ - /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()), + const ASTContext &C = S.Context; + return new (C) concepts::Requirement::SubstitutionDiagnostic{ + /*SubstitutedEntity=*/C.backupStr(Entity), /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()}; } @@ -2481,7 +2706,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { if (TPLInst.isInvalid()) return nullptr; TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL); - if (!TPL) + if (!TPL || Trap.hasErrorOccurred()) TransRetReq.emplace(createSubstDiag(SemaRef, Info, [&] (llvm::raw_ostream& OS) { RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint() @@ -2549,56 +2774,23 @@ TemplateInstantiator::TransformNestedRequirement( assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled " "by CheckConstraintSatisfaction."); } + ASTContext &C = SemaRef.Context; if (TransConstraint.isUsable() && TransConstraint.get()->isInstantiationDependent()) - return new (SemaRef.Context) - concepts::NestedRequirement(TransConstraint.get()); + return new (C) concepts::NestedRequirement(TransConstraint.get()); if (TransConstraint.isInvalid() || !TransConstraint.get() || Satisfaction.HasSubstitutionFailure()) { SmallString<128> Entity; llvm::raw_svector_ostream OS(Entity); Req->getConstraintExpr()->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); - char *EntityBuf = new (SemaRef.Context) char[Entity.size()]; - std::copy(Entity.begin(), Entity.end(), EntityBuf); - return new (SemaRef.Context) concepts::NestedRequirement( - SemaRef.Context, StringRef(EntityBuf, Entity.size()), Satisfaction); + return new (C) concepts::NestedRequirement( + SemaRef.Context, C.backupStr(Entity), Satisfaction); } - return new (SemaRef.Context) concepts::NestedRequirement( - SemaRef.Context, TransConstraint.get(), Satisfaction); + return new (C) + concepts::NestedRequirement(C, TransConstraint.get(), Satisfaction); } - -/// Perform substitution on the type T with a given set of template -/// arguments. -/// -/// This routine substitutes the given template arguments into the -/// type T and produces the instantiated type. -/// -/// \param T the type into which the template arguments will be -/// substituted. If this type is not dependent, it will be returned -/// immediately. -/// -/// \param Args the template arguments that will be -/// substituted for the top-level template parameters within T. -/// -/// \param Loc the location in the source code where this substitution -/// is being performed. It will typically be the location of the -/// declarator (if we're instantiating the type of some declaration) -/// or the location of the type in the source code (if, e.g., we're -/// instantiating the type of a cast expression). -/// -/// \param Entity the name of the entity associated with a declaration -/// being instantiated (if any). May be empty to indicate that there -/// is no such entity (if, e.g., this is a type that occurs as part of -/// a cast expression) or that the entity has no name (e.g., an -/// unnamed function parameter). -/// -/// \param AllowDeducedTST Whether a DeducedTemplateSpecializationType is -/// acceptable as the top level type of the result. -/// -/// \returns If the instantiation succeeds, the instantiated -/// type. Otherwise, produces diagnostics and returns a NULL type. TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, @@ -2686,10 +2878,6 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { return false; } -/// A form of SubstType intended specifically for instantiating the -/// type of a FunctionDecl. Its purpose is solely to force the -/// instantiation of default-argument expressions and to avoid -/// instantiating an exception-specification. TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, @@ -2872,7 +3060,8 @@ bool Sema::SubstTypeConstraint( } return AttachTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &InstArgs, Inst, + TC->getNamedConcept(), + /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst, Inst->isParameterPack() ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() @@ -3000,9 +3189,6 @@ ParmVarDecl *Sema::SubstParmVarDecl( return NewParm; } -/// Substitute the given template arguments into the given set of -/// parameters, producing the set of parameter types that would be generated -/// from such a substitution. bool Sema::SubstParmTypes( SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, const FunctionProtoType::ExtParameterInfo *ExtParamInfos, @@ -3020,7 +3206,6 @@ bool Sema::SubstParmTypes( Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos); } -/// Substitute the given template arguments into the default argument. bool Sema::SubstDefaultArgument( SourceLocation Loc, ParmVarDecl *Param, @@ -3065,7 +3250,7 @@ bool Sema::SubstDefaultArgument( runWithSufficientStackSpace(Loc, [&] { Result = SubstInitializer(PatternExpr, TemplateArgs, - /*DirectInit*/false); + /*DirectInit*/ false); }); } if (Result.isInvalid()) @@ -3102,12 +3287,6 @@ bool Sema::SubstDefaultArgument( return false; } -/// Perform substitution on the base class specifiers of the -/// given class template specialization. -/// -/// Produces a diagnostic and returns true on error, returns false and -/// attaches the instantiated base classes to the class template -/// specialization if successful. bool Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, @@ -3222,28 +3401,6 @@ namespace clang { } } -/// Instantiate the definition of a class from a given pattern. -/// -/// \param PointOfInstantiation The point of instantiation within the -/// source code. -/// -/// \param Instantiation is the declaration whose definition is being -/// instantiated. This will be either a class template specialization -/// or a member class of a class template specialization. -/// -/// \param Pattern is the pattern from which the instantiation -/// occurs. This will be either the declaration of a class template or -/// the declaration of a member class of a class template. -/// -/// \param TemplateArgs The template arguments to be substituted into -/// the pattern. -/// -/// \param TSK the kind of implicit or explicit instantiation to perform. -/// -/// \param Complain whether to complain if the class cannot be instantiated due -/// to the lack of a definition. -/// -/// \returns true if an error occurred, false otherwise. bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, @@ -3258,11 +3415,16 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, return true; llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() { - std::string Name; - llvm::raw_string_ostream OS(Name); + llvm::TimeTraceMetadata M; + llvm::raw_string_ostream OS(M.Detail); Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(), /*Qualified=*/true); - return Name; + if (llvm::isTimeTraceVerbose()) { + auto Loc = SourceMgr.getExpansionLoc(Instantiation->getLocation()); + M.File = SourceMgr.getFilename(Loc); + M.Line = SourceMgr.getExpansionLineNumber(Loc); + } + return M; }); Pattern = PatternDef; @@ -3489,21 +3651,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, return Instantiation->isInvalidDecl(); } -/// Instantiate the definition of an enum from a given pattern. -/// -/// \param PointOfInstantiation The point of instantiation within the -/// source code. -/// \param Instantiation is the declaration whose definition is being -/// instantiated. This will be a member enumeration of a class -/// temploid specialization, or a local enumeration within a -/// function temploid specialization. -/// \param Pattern The templated declaration from which the instantiation -/// occurs. -/// \param TemplateArgs The template arguments to be substituted into -/// the pattern. -/// \param TSK The kind of implicit or explicit instantiation to perform. -/// -/// \return \c true if an error occurred, \c false otherwise. bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3554,21 +3701,6 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, return Instantiation->isInvalidDecl(); } - -/// Instantiate the definition of a field from the given pattern. -/// -/// \param PointOfInstantiation The point of instantiation within the -/// source code. -/// \param Instantiation is the declaration whose definition is being -/// instantiated. This will be a class of a class temploid -/// specialization, or a local enumeration within a function temploid -/// specialization. -/// \param Pattern The templated declaration from which the instantiation -/// occurs. -/// \param TemplateArgs The template arguments to be substituted into -/// the pattern. -/// -/// \return \c true if an error occurred, \c false otherwise. bool Sema::InstantiateInClassInitializer( SourceLocation PointOfInstantiation, FieldDecl *Instantiation, FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -3655,8 +3787,9 @@ bool Sema::usesPartialOrExplicitSpecialization( ->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { TemplateDeductionInfo Info(Loc); - if (!DeduceTemplateArguments(PartialSpecs[I], - ClassTemplateSpec->getTemplateArgs(), Info)) + if (DeduceTemplateArguments(PartialSpecs[I], + ClassTemplateSpec->getTemplateArgs().asArray(), + Info) == TemplateDeductionResult::Success) return true; } @@ -3700,8 +3833,9 @@ getPatternForClassTemplateSpecialization( for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; TemplateDeductionInfo Info(FailedCandidates.getLocation()); - if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments( - Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { + if (TemplateDeductionResult Result = S.DeduceTemplateArguments( + Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info); + Result != TemplateDeductionResult::Success) { // Store the failed-deduction information for use in diagnostics, later. // TODO: Actually use the failed-deduction info? FailedCandidates.addCandidate().set( @@ -3834,9 +3968,6 @@ bool Sema::InstantiateClassTemplateSpecialization( getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain); } -/// Instantiates the definitions of all of the member -/// of the given class, which is an instantiation of a class template -/// or a member class of a template. void Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, @@ -4066,9 +4197,6 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, } } -/// Instantiate the definitions of all of the members of the -/// given class template specialization, which was named as part of an -/// explicit instantiation. void Sema::InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, @@ -4098,6 +4226,15 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformStmt(S); } +bool Sema::SubstTemplateArgument( + const TemplateArgumentLoc &Input, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateArgumentLoc &Output, SourceLocation Loc, + const DeclarationName &Entity) { + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); + return Instantiator.TransformTemplateArgument(Input, Output); +} + bool Sema::SubstTemplateArguments( ArrayRef<TemplateArgumentLoc> Args, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -4169,7 +4306,6 @@ Sema::SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, return Instantiator.TransformNestedNameSpecifierLoc(NNS); } -/// Do template substitution on declaration name info. DeclarationNameInfo Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs) { |