llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Haojian Wu (hokein) <details> <summary>Changes</summary> Split out the deduction guide related code from SemaTemplate.cpp to a dedicated file. These code has grown significantly, and moving it to a separate file will improve code organization. --- Patch is 127.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/98524.diff 4 Files Affected: - (modified) clang/include/clang/Sema/Sema.h (+32-15) - (modified) clang/lib/Sema/CMakeLists.txt (+1) - (modified) clang/lib/Sema/SemaTemplate.cpp (+1-1380) - (added) clang/lib/Sema/SemaTemplateDeductionGuide.cpp (+1438) ``````````diff diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 57994f4033922..48dff1b76cc57 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -560,13 +560,14 @@ class Sema final : public SemaBase { // 23. Statement Attribute Handling (SemaStmtAttr.cpp) // 24. C++ Templates (SemaTemplate.cpp) // 25. C++ Template Argument Deduction (SemaTemplateDeduction.cpp) - // 26. C++ Template Instantiation (SemaTemplateInstantiate.cpp) - // 27. C++ Template Declaration Instantiation + // 26. C++ Template Deduction Guide (SemaTemplateDeductionGuide.cpp) + // 27. C++ Template Instantiation (SemaTemplateInstantiate.cpp) + // 28. C++ Template Declaration Instantiation // (SemaTemplateInstantiateDecl.cpp) - // 28. C++ Variadic Templates (SemaTemplateVariadic.cpp) - // 29. Constraints and Concepts (SemaConcept.cpp) - // 30. Types (SemaType.cpp) - // 31. FixIt Helpers (SemaFixItUtils.cpp) + // 29. C++ Variadic Templates (SemaTemplateVariadic.cpp) + // 30. Constraints and Concepts (SemaConcept.cpp) + // 31. Types (SemaType.cpp) + // 32. FixIt Helpers (SemaFixItUtils.cpp) /// \name Semantic Analysis /// Implementations are in Sema.cpp @@ -11356,6 +11357,10 @@ class Sema final : public SemaBase { bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic = false); + /// Returns the template parameter list with all default template argument + /// information. + TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD); + DeclResult CheckClassTemplate( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, @@ -12019,15 +12024,6 @@ class Sema final : public SemaBase { unsigned TemplateDepth, const Expr *Constraint); - /// Declare implicit deduction guides for a class template if we've - /// not already done so. - void DeclareImplicitDeductionGuides(TemplateDecl *Template, - SourceLocation Loc); - - FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList( - TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes, - SourceLocation Loc); - /// Find the failed Boolean condition within a given Boolean /// constant expression, and describe it with a string. std::pair<Expr *, std::string> findFailedBooleanCondition(Expr *Cond); @@ -12580,6 +12576,27 @@ class Sema final : public SemaBase { // // + /// \name C++ Template Deduction Guide + /// Implementations are in SemaTemplateDeductionGuide.cpp + ///@{ + + /// Declare implicit deduction guides for a class template if we've + /// not already done so. + void DeclareImplicitDeductionGuides(TemplateDecl *Template, + SourceLocation Loc); + + FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList( + TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes, + SourceLocation Loc); + + ///@} + + // + // + // ------------------------------------------------------------------------- + // + // + /// \name C++ Template Instantiation /// Implementations are in SemaTemplateInstantiate.cpp ///@{ diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 980a83d4431aa..5934c8c30daf9 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -82,6 +82,7 @@ add_clang_library(clangSema SemaSystemZ.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp + SemaTemplateDeductionGuide.cpp SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp SemaTemplateVariadic.cpp diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 29d668e4fd8d7..bb8ec9738f260 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1764,7 +1764,7 @@ static void SetNestedNameSpecifier(Sema &S, TagDecl *T, // Returns the template parameter list with all default template argument // information. -static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) { +TemplateParameterList *Sema::GetTemplateParameterList(TemplateDecl *TD) { // Make sure we get the template parameter list from the most // recent declaration, since that is the only one that is guaranteed to // have all the default template argument information. @@ -2173,1385 +2173,6 @@ DeclResult Sema::CheckClassTemplate( return NewTemplate; } -namespace { -/// Tree transform to "extract" a transformed type from a class template's -/// constructor to a deduction guide. -class ExtractTypeForDeductionGuide - : public TreeTransform<ExtractTypeForDeductionGuide> { - llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs; - ClassTemplateDecl *NestedPattern; - const MultiLevelTemplateArgumentList *OuterInstantiationArgs; - std::optional<TemplateDeclInstantiator> TypedefNameInstantiator; - -public: - typedef TreeTransform<ExtractTypeForDeductionGuide> Base; - ExtractTypeForDeductionGuide( - Sema &SemaRef, - llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs, - ClassTemplateDecl *NestedPattern, - const MultiLevelTemplateArgumentList *OuterInstantiationArgs) - : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs), - NestedPattern(NestedPattern), - OuterInstantiationArgs(OuterInstantiationArgs) { - if (OuterInstantiationArgs) - TypedefNameInstantiator.emplace( - SemaRef, SemaRef.getASTContext().getTranslationUnitDecl(), - *OuterInstantiationArgs); - } - - TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); } - - /// Returns true if it's safe to substitute \p Typedef with - /// \p OuterInstantiationArgs. - bool mightReferToOuterTemplateParameters(TypedefNameDecl *Typedef) { - if (!NestedPattern) - return false; - - static auto WalkUp = [](DeclContext *DC, DeclContext *TargetDC) { - if (DC->Equals(TargetDC)) - return true; - while (DC->isRecord()) { - if (DC->Equals(TargetDC)) - return true; - DC = DC->getParent(); - } - return false; - }; - - if (WalkUp(Typedef->getDeclContext(), NestedPattern->getTemplatedDecl())) - return true; - if (WalkUp(NestedPattern->getTemplatedDecl(), Typedef->getDeclContext())) - return true; - return false; - } - - QualType - RebuildTemplateSpecializationType(TemplateName Template, - SourceLocation TemplateNameLoc, - TemplateArgumentListInfo &TemplateArgs) { - if (!OuterInstantiationArgs || - !isa_and_present<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) - return Base::RebuildTemplateSpecializationType(Template, TemplateNameLoc, - TemplateArgs); - - auto *TATD = cast<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); - auto *Pattern = TATD; - while (Pattern->getInstantiatedFromMemberTemplate()) - Pattern = Pattern->getInstantiatedFromMemberTemplate(); - if (!mightReferToOuterTemplateParameters(Pattern->getTemplatedDecl())) - return Base::RebuildTemplateSpecializationType(Template, TemplateNameLoc, - TemplateArgs); - - Decl *NewD = - TypedefNameInstantiator->InstantiateTypeAliasTemplateDecl(TATD); - if (!NewD) - return QualType(); - - auto *NewTATD = cast<TypeAliasTemplateDecl>(NewD); - MaterializedTypedefs.push_back(NewTATD->getTemplatedDecl()); - - return Base::RebuildTemplateSpecializationType( - TemplateName(NewTATD), TemplateNameLoc, TemplateArgs); - } - - QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { - ASTContext &Context = SemaRef.getASTContext(); - TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); - TypedefNameDecl *Decl = OrigDecl; - // Transform the underlying type of the typedef and clone the Decl only if - // the typedef has a dependent context. - bool InDependentContext = OrigDecl->getDeclContext()->isDependentContext(); - - // A typedef/alias Decl within the NestedPattern may reference the outer - // template parameters. They're substituted with corresponding instantiation - // arguments here and in RebuildTemplateSpecializationType() above. - // Otherwise, we would have a CTAD guide with "dangling" template - // parameters. - // For example, - // template <class T> struct Outer { - // using Alias = S<T>; - // template <class U> struct Inner { - // Inner(Alias); - // }; - // }; - if (OuterInstantiationArgs && InDependentContext && - TL.getTypePtr()->isInstantiationDependentType()) { - Decl = cast_if_present<TypedefNameDecl>( - TypedefNameInstantiator->InstantiateTypedefNameDecl( - OrigDecl, /*IsTypeAlias=*/isa<TypeAliasDecl>(OrigDecl))); - if (!Decl) - return QualType(); - MaterializedTypedefs.push_back(Decl); - } else if (InDependentContext) { - TypeLocBuilder InnerTLB; - QualType Transformed = - TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc()); - TypeSourceInfo *TSI = InnerTLB.getTypeSourceInfo(Context, Transformed); - if (isa<TypeAliasDecl>(OrigDecl)) - Decl = TypeAliasDecl::Create( - Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), - OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); - else { - assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef"); - Decl = TypedefDecl::Create( - Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), - OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); - } - MaterializedTypedefs.push_back(Decl); - } - - QualType TDTy = Context.getTypedefType(Decl); - TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(TDTy); - TypedefTL.setNameLoc(TL.getNameLoc()); - - return TDTy; - } -}; - -// Build a deduction guide using the provided information. -// -// A deduction guide can be either a template or a non-template function -// declaration. If \p TemplateParams is null, a non-template function -// declaration will be created. -NamedDecl *buildDeductionGuide( - Sema &SemaRef, TemplateDecl *OriginalTemplate, - TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor, - ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart, - SourceLocation Loc, SourceLocation LocEnd, bool IsImplicit, - llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) { - DeclContext *DC = OriginalTemplate->getDeclContext(); - auto DeductionGuideName = - SemaRef.Context.DeclarationNames.getCXXDeductionGuideName( - OriginalTemplate); - - DeclarationNameInfo Name(DeductionGuideName, Loc); - ArrayRef<ParmVarDecl *> Params = - TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); - - // Build the implicit deduction guide template. - auto *Guide = - CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name, - TInfo->getType(), TInfo, LocEnd, Ctor); - Guide->setImplicit(IsImplicit); - Guide->setParams(Params); - - for (auto *Param : Params) - Param->setDeclContext(Guide); - for (auto *TD : MaterializedTypedefs) - TD->setDeclContext(Guide); - if (isa<CXXRecordDecl>(DC)) - Guide->setAccess(AS_public); - - if (!TemplateParams) { - DC->addDecl(Guide); - return Guide; - } - - auto *GuideTemplate = FunctionTemplateDecl::Create( - SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide); - GuideTemplate->setImplicit(IsImplicit); - Guide->setDescribedFunctionTemplate(GuideTemplate); - - if (isa<CXXRecordDecl>(DC)) - GuideTemplate->setAccess(AS_public); - - DC->addDecl(GuideTemplate); - return GuideTemplate; -} - -// Transform a given template type parameter `TTP`. -TemplateTypeParmDecl * -transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC, - TemplateTypeParmDecl *TTP, - MultiLevelTemplateArgumentList &Args, - unsigned NewDepth, unsigned NewIndex) { - // TemplateTypeParmDecl's index cannot be changed after creation, so - // substitute it directly. - auto *NewTTP = TemplateTypeParmDecl::Create( - SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(), NewDepth, - NewIndex, TTP->getIdentifier(), TTP->wasDeclaredWithTypename(), - TTP->isParameterPack(), TTP->hasTypeConstraint(), - TTP->isExpandedParameterPack() - ? std::optional<unsigned>(TTP->getNumExpansionParameters()) - : std::nullopt); - if (const auto *TC = TTP->getTypeConstraint()) - SemaRef.SubstTypeConstraint(NewTTP, TC, Args, - /*EvaluateConstraint=*/true); - if (TTP->hasDefaultArgument()) { - TemplateArgumentLoc InstantiatedDefaultArg; - if (!SemaRef.SubstTemplateArgument( - TTP->getDefaultArgument(), Args, InstantiatedDefaultArg, - TTP->getDefaultArgumentLoc(), TTP->getDeclName())) - NewTTP->setDefaultArgument(SemaRef.Context, InstantiatedDefaultArg); - } - SemaRef.CurrentInstantiationScope->InstantiatedLocal(TTP, NewTTP); - return NewTTP; -} -// Similar to above, but for non-type template or template template parameters. -template <typename NonTypeTemplateOrTemplateTemplateParmDecl> -NonTypeTemplateOrTemplateTemplateParmDecl * -transformTemplateParam(Sema &SemaRef, DeclContext *DC, - NonTypeTemplateOrTemplateTemplateParmDecl *OldParam, - MultiLevelTemplateArgumentList &Args, unsigned NewIndex, - unsigned NewDepth) { - // Ask the template instantiator to do the heavy lifting for us, then adjust - // the index of the parameter once it's done. - auto *NewParam = cast<NonTypeTemplateOrTemplateTemplateParmDecl>( - SemaRef.SubstDecl(OldParam, DC, Args)); - NewParam->setPosition(NewIndex); - NewParam->setDepth(NewDepth); - return NewParam; -} - -/// Transform to convert portions of a constructor declaration into the -/// corresponding deduction guide, per C++1z [over.match.class.deduct]p1. -struct ConvertConstructorToDeductionGuideTransform { - ConvertConstructorToDeductionGuideTransform(Sema &S, - ClassTemplateDecl *Template) - : SemaRef(S), Template(Template) { - // If the template is nested, then we need to use the original - // pattern to iterate over the constructors. - ClassTemplateDecl *Pattern = Template; - while (Pattern->getInstantiatedFromMemberTemplate()) { - if (Pattern->isMemberSpecialization()) - break; - Pattern = Pattern->getInstantiatedFromMemberTemplate(); - NestedPattern = Pattern; - } - - if (NestedPattern) - OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template); - } - - Sema &SemaRef; - ClassTemplateDecl *Template; - ClassTemplateDecl *NestedPattern = nullptr; - - DeclContext *DC = Template->getDeclContext(); - CXXRecordDecl *Primary = Template->getTemplatedDecl(); - DeclarationName DeductionGuideName = - SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(Template); - - QualType DeducedType = SemaRef.Context.getTypeDeclType(Primary); - - // Index adjustment to apply to convert depth-1 template parameters into - // depth-0 template parameters. - unsigned Depth1IndexAdjustment = Template->getTemplateParameters()->size(); - - // Instantiation arguments for the outermost depth-1 templates - // when the template is nested - MultiLevelTemplateArgumentList OuterInstantiationArgs; - - /// Transform a constructor declaration into a deduction guide. - NamedDecl *transformConstructor(FunctionTemplateDecl *FTD, - CXXConstructorDecl *CD) { - SmallVector<TemplateArgument, 16> SubstArgs; - - LocalInstantiationScope Scope(SemaRef); - - // C++ [over.match.class.deduct]p1: - // -- For each constructor of the class template designated by the - // template-name, a function template with the following properties: - - // -- The template parameters are the template parameters of the class - // template followed by the template parameters (including default - // template arguments) of the constructor, if any. - TemplateParameterList *TemplateParams = GetTemplateParameterList(Template); - if (FTD) { - TemplateParameterList *InnerParams = FTD->getTemplateParameters(); - SmallVector<NamedDecl *, 16> AllParams; - SmallVector<TemplateArgument, 16> Depth1Args; - AllParams.reserve(TemplateParams->size() + InnerParams->size()); - AllParams.insert(AllParams.begin(), - TemplateParams->begin(), TemplateParams->end()); - SubstArgs.reserve(InnerParams->size()); - Depth1Args.reserve(InnerParams->size()); - - // Later template parameters could refer to earlier ones, so build up - // a list of substituted template arguments as we go. - for (NamedDecl *Param : *InnerParams) { - MultiLevelTemplateArgumentList Args; - Args.setKind(TemplateSubstitutionKind::Rewrite); - Args.addOuterTemplateArguments(Depth1Args); - Args.addOuterRetainedLevel(); - if (NestedPattern) - Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth()); - NamedDecl *NewParam = transformTemplateParameter(Param, Args); - if (!NewParam) - return nullptr; - // Constraints require that we substitute depth-1 arguments - // to match depths when substituted for evaluation later - Depth1Args.push_back(SemaRef.Context.getCanonicalTemplateArgument( - SemaRef.Context.getInjectedTemplateArg(NewParam))); - - if (NestedPattern) { - TemplateDeclInstantiator Instantiator(SemaRef, DC, - OuterInstantiationArgs); - Instantiator.setEvaluateConstraints(false); - SemaRef.runWithSufficientStackSpace(NewParam->getLocation(), [&] { - NewParam = cast<NamedDecl>(Instantiator.Visit(NewParam)); - }); - } - - assert(NewParam->getTemplateDepth() == 0 && - "Unexpected template parameter depth"); - - AllParams.push_back(NewParam); - SubstArgs.push_back(SemaRef.Context.getCanonicalTemplateArgument( - SemaRef.Context.getInjectedTemplateArg(NewParam))); - } - - // Substitute new template parameters into requires-clause if present. - Expr *RequiresClause = nullptr; - if (Expr *InnerRC = InnerParams->getRequiresClause()) { - MultiLevelTemplateArgumentList Args; - Args.setKind(TemplateSubstitutionKind::Rewrite); - Args.addOuterTemplateArguments(Depth1Args); - Args.addOuterRetainedLevel(); - if (NestedPattern) - Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth()); - ExprResult E = SemaRef.SubstExpr(InnerRC, Args); - if (E.isInvalid()) - return nullptr; - RequiresClause = E.getAs<Expr>(); - } - - TemplateParams = TemplateParameterList::Create( - SemaRef.Context, InnerParams->getTemplateLoc(), - InnerParams->getLAngleLoc(), AllParams, InnerParams->getRAngleLoc(), - RequiresClause); - } - - // If we built a new template-parameter-list, track that we need to - // substitute references to the old parameters into references to the - // new ones. - MultiLevelTemplateArgumentList Args; - Args.setKind(TemplateSubstitutionKind::Rewrite); - if (FTD) { - Args.addOuterTemplateArguments(SubstArgs); - Args.addOuterRetainedLevel(); - } - - FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc() - .getAsAdjusted<FunctionProtoTypeLoc>(); - assert(FPTL && "no prototype for constructor declaration"); - - // Transform the type of the function, adjusting the return type and - // replacing references to the old parameters with references to the - // new ones. - TypeLocBuilder TLB; - SmallVector<ParmVarDecl*, 8> Params; - SmallVector<Typ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/98524 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits