[clang] [clang] Refactor: Move CTAD code from SemaTemplate.cpp to a dedicated file, NFC (PR #98524)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 11 12:20:16 PDT 2024
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
More information about the cfe-commits
mailing list