[clang] [clang] Implement CTAD for type alias template. (PR #77890)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 29 01:03:42 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Haojian Wu (hokein)

<details>
<summary>Changes</summary>

Fixes #<!-- -->54051

This patch implements the C++20 feature -- CTAD for alias templates.
It is an initial patch, which covers most of pieces, the major missing piece is to implement the associated constraints (over.match.class.deduct#<!-- -->3.3) for the synthesized deduction guides (we can address it in a followup).

This patch also refactors the existing `ConvertConstructorToDeductionGuideTransform` to allow code reuse.

CC @<!-- -->ilya-biryukov, @<!-- -->sam-mccall , @<!-- -->usx95 

---

Patch is 52.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/77890.diff


10 Files Affected:

- (modified) clang/include/clang/Sema/Sema.h (+11-3) 
- (modified) clang/lib/Sema/CMakeLists.txt (+1) 
- (added) clang/lib/Sema/CTAD.cpp (+209) 
- (added) clang/lib/Sema/CTAD.h (+65) 
- (modified) clang/lib/Sema/SemaInit.cpp (+367-7) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+23-145) 
- (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+9) 
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+22-3) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+16-9) 
- (added) clang/test/SemaCXX/cxx20-ctad-type-alias.cpp (+133) 


``````````diff
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b5946e3f3178ff..c3fba8add4b660 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9305,6 +9305,12 @@ class Sema final {
                           const TemplateArgumentList &TemplateArgs,
                           sema::TemplateDeductionInfo &Info);
 
+  TemplateDeductionResult DeduceTemplateArguments(
+      TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
+      ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
+      SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+      bool NumberOfArgumentsMustMatch);
+
   TemplateDeductionResult SubstituteExplicitTemplateArguments(
       FunctionTemplateDecl *FunctionTemplate,
       TemplateArgumentListInfo &ExplicitTemplateArgs,
@@ -10457,9 +10463,11 @@ class Sema final {
       SourceLocation PointOfInstantiation, FunctionDecl *Decl,
       ArrayRef<TemplateArgument> TemplateArgs,
       ConstraintSatisfaction &Satisfaction);
-  FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
-                                               const TemplateArgumentList *Args,
-                                               SourceLocation Loc);
+  FunctionDecl *InstantiateFunctionDeclaration(
+      FunctionTemplateDecl *FTD, const TemplateArgumentList *Args,
+      SourceLocation Loc,
+      CodeSynthesisContext::SynthesisKind CSC =
+          CodeSynthesisContext::ExplicitTemplateArgumentSubstitution);
   void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
                                      FunctionDecl *Function,
                                      bool Recursive = false,
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 1856a88e9a3271..7a55406171ac74 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -14,6 +14,7 @@ clang_tablegen(OpenCLBuiltins.inc -gen-clang-opencl-builtins
 
 add_clang_library(clangSema
   AnalysisBasedWarnings.cpp
+  CTAD.cpp
   CodeCompleteConsumer.cpp
   DeclSpec.cpp
   DelayedDiagnostic.cpp
diff --git a/clang/lib/Sema/CTAD.cpp b/clang/lib/Sema/CTAD.cpp
new file mode 100644
index 00000000000000..745878c717fc4c
--- /dev/null
+++ b/clang/lib/Sema/CTAD.cpp
@@ -0,0 +1,209 @@
+//===--- CTAD.cpp - -------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CTAD.h"
+#include "TreeTransform.h"
+#include "TypeLocBuilder.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <optional>
+
+namespace clang {
+
+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;
+
+public:
+  typedef TreeTransform<ExtractTypeForDeductionGuide> Base;
+  ExtractTypeForDeductionGuide(
+      Sema &SemaRef,
+      llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs)
+      : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {}
+
+  TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); }
+
+  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.
+    if (OrigDecl->getDeclContext()->isDependentContext()) {
+      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;
+  }
+};
+} // namespace
+
+ParmVarDecl *transformFunctionTypeParam(
+    Sema &SemaRef, ParmVarDecl *OldParam, DeclContext *DC,
+    MultiLevelTemplateArgumentList &Args,
+    llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
+  TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
+  TypeSourceInfo *NewDI;
+  if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
+    // Expand out the one and only element in each inner pack.
+    Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0);
+    NewDI = SemaRef.SubstType(PackTL.getPatternLoc(), Args,
+                              OldParam->getLocation(), OldParam->getDeclName());
+    if (!NewDI)
+      return nullptr;
+    NewDI = SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(),
+                                       PackTL.getTypePtr()->getNumExpansions());
+  } else
+    NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
+                              OldParam->getDeclName());
+  if (!NewDI)
+    return nullptr;
+
+  // Extract the type. This (for instance) replaces references to typedef
+  // members of the current instantiations with the definitions of those
+  // typedefs, avoiding triggering instantiation of the deduced type during
+  // deduction.
+  NewDI = ExtractTypeForDeductionGuide(SemaRef, MaterializedTypedefs)
+              .transform(NewDI);
+
+  // Resolving a wording defect, we also inherit default arguments from the
+  // constructor.
+  ExprResult NewDefArg;
+  if (OldParam->hasDefaultArg()) {
+    // We don't care what the value is (we won't use it); just create a
+    // placeholder to indicate there is a default argument.
+    QualType ParamTy = NewDI->getType();
+    NewDefArg = new (SemaRef.Context)
+        OpaqueValueExpr(OldParam->getDefaultArgRange().getBegin(),
+                        ParamTy.getNonLValueExprType(SemaRef.Context),
+                        ParamTy->isLValueReferenceType()   ? VK_LValue
+                        : ParamTy->isRValueReferenceType() ? VK_XValue
+                                                           : VK_PRValue);
+  }
+  // Handle arrays and functions decay.
+  auto NewType = NewDI->getType();
+  if (NewType->isArrayType() || NewType->isFunctionType())
+    NewType = SemaRef.Context.getDecayedType(NewType);
+
+  ParmVarDecl *NewParam = ParmVarDecl::Create(
+      SemaRef.Context, DC, OldParam->getInnerLocStart(),
+      OldParam->getLocation(), OldParam->getIdentifier(), NewType, NewDI,
+      OldParam->getStorageClass(), NewDefArg.get());
+  NewParam->setScopeInfo(OldParam->getFunctionScopeDepth(),
+                         OldParam->getFunctionScopeIndex());
+  SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam, NewParam);
+  return NewParam;
+}
+
+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()) {
+    TypeSourceInfo *InstantiatedDefaultArg =
+        SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
+                          TTP->getDefaultArgumentLoc(), TTP->getDeclName());
+    if (InstantiatedDefaultArg)
+      NewTTP->setDefaultArgument(InstantiatedDefaultArg);
+  }
+  SemaRef.CurrentInstantiationScope->InstantiatedLocal(TTP, NewTTP);
+  return NewTTP;
+}
+
+FunctionTemplateDecl *
+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);
+
+  auto *GuideTemplate = FunctionTemplateDecl::Create(
+      SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide);
+  GuideTemplate->setImplicit(IsImplicit);
+  Guide->setDescribedFunctionTemplate(GuideTemplate);
+
+  if (isa<CXXRecordDecl>(DC)) {
+    Guide->setAccess(AS_public);
+    GuideTemplate->setAccess(AS_public);
+  }
+
+  DC->addDecl(GuideTemplate);
+  return GuideTemplate;
+}
+
+} // namespace clang
diff --git a/clang/lib/Sema/CTAD.h b/clang/lib/Sema/CTAD.h
new file mode 100644
index 00000000000000..88110230318f81
--- /dev/null
+++ b/clang/lib/Sema/CTAD.h
@@ -0,0 +1,65 @@
+//===--- CTAD.h - Helper functions for CTAD -------------------------------===//
+//
+// 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 defines helper functions for the class template argument deduction
+//  (CTAD) implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace clang {
+
+// Transform a given function parameter decl into a deduction guide parameter
+// decl.
+ParmVarDecl *transformFunctionTypeParam(
+    Sema &SemaRef, ParmVarDecl *OldParam, DeclContext *DC,
+    MultiLevelTemplateArgumentList &Args,
+    llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs);
+
+// Transform a given template type parameter into a deduction guide template
+// parameter, rebuilding any internal references to earlier parameters and
+// re-indexing as we go.
+TemplateTypeParmDecl *transformTemplateTypeParam(
+    Sema &SemaRef, DeclContext *DC, TemplateTypeParmDecl *TPT,
+    MultiLevelTemplateArgumentList &Args, unsigned NewDepth, unsigned NewIndex);
+// 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) {
+  // 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);
+  return NewParam;
+}
+
+// Build a deduction guide with the specified parameter types.
+FunctionTemplateDecl *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 = {});
+
+} // namespace clang
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 457fa377355a97..e6105040af8111 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10,13 +10,19 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "CTAD.h"
+#include "TypeLocBuilder.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclAccessPair.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/AST/IgnoreExpr.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/SourceManager.h"
@@ -28,7 +34,9 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Ownership.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/SmallString.h"
@@ -10583,6 +10591,213 @@ static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
   return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization));
 }
 
+// Transform to form a corresponding deduction guide for type alias template
+// decl.
+//
+// This class implements the C++ [over.match.class.deduct]p3:
+//   ... Let g denote the result of substituting these deductions into f. If
+//   substitution succeeds, form a function or function template f' with the
+//   following properties and add it to the set of guides of A...
+class AliasTemplateDeductionGuideTransform {
+public:
+  AliasTemplateDeductionGuideTransform(Sema &S, TypeAliasTemplateDecl *Alias)
+      : SemaRef(S), AliasTemplate(Alias), DC(Alias->getDeclContext()) {}
+  // Returns the result of substituting the deduced template arguments into F.
+  NamedDecl *transform(CXXDeductionGuideDecl *F,
+                       ArrayRef<TemplateArgument> DeducedArgs,
+                       ArrayRef<NamedDecl *> NonDeducedTemplateParamsInF) {
+    // Template parameters of the f'.
+    //
+    // C++ [over.match.class.deduct]p3.2:
+    //   If f is a function template, f' is a function template whose template
+    //   parameter list consists of all the template parameters of A (including
+    //   their default template arguments) that appear in the above deductions
+    //   or (recursively) in their default template arguments
+    SmallVector<NamedDecl *> TemplateParamsInFPrime =
+        FindAppearedTemplateParamsInAlias(DeducedArgs);
+    //   ...followed by the template parameters of f that were not deduced
+    //   (including their default template arguments)
+    TemplateParamsInFPrime.append(NonDeducedTemplateParamsInF.begin(),
+                                  NonDeducedTemplateParamsInF.end());
+
+    LocalInstantiationScope Scope(SemaRef);
+    SmallVector<TemplateArgument, 16> Depth1Args;
+    SmallVector<NamedDecl *, 16> AllParams;
+    SmallVector<TemplateArgument, 16> SubstArgs;
+    unsigned TemplateParamIndex = 0;
+    TemplateParameterList *TemplateParams = nullptr;
+
+    for (NamedDecl *Param : TemplateParamsInFPrime) {
+      MultiLevelTemplateArgumentList Args;
+
+      Args.setKind(TemplateSubstitutionKind::Rewrite);
+      Args.addOuterTemplateArguments(Depth1Args);
+      Args.addOuterRetainedLevel();
+      NamedDecl *NewParam =
+          transformTemplateParameter(Param, Args, TemplateParamIndex++);
+      if (!NewParam) {
+        llvm::errs() << "Faile to generate new param!\n";
+        return nullptr;
+      }
+      auto NewArgumentForNewParam =
+          SemaRef.Context.getCanonicalTemplateArgument(
+              SemaRef.Context.getInjectedTemplateArg(NewParam));
+      Depth1Args.push_back(NewArgumentForNewParam);
+      AllParams.push_back(NewParam);
+      SubstArgs.push_back(NewArgumentForNewParam);
+    }
+    // FIXME: substitute new template parameters into the requires-clause.
+    TemplateParams = TemplateParameterList::Create(
+        SemaRef.Context,
+        AliasTemplate->getTemplateParameters()->getTemplateLoc(),
+        AliasTemplate->getTemplateParameters()->getLAngleLoc(), AllParams,
+        AliasTemplate->getTemplateParameters()->getRAngleLoc(),
+        /*RequiresClause=*/nullptr);
+
+    MultiLevelTemplateArgumentList Args;
+    Args.setKind(TemplateSubstitutionKind::Rewrite);
+    Args.addOuterTemplateArguments(SubstArgs);
+    Args.addOuterRetainedLevel();
+
+    FunctionProtoTypeLoc FPTL = F->getTypeSourceInfo()
+                                    ->getTypeLoc()
+                                    .getAsAdjusted<FunctionProtoTypeLoc>();
+    assert(FPTL && "no prototype for underlying deduction guides");
+
+    // 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<TypedefNameDecl *, 4> MaterializedTypedefs;
+    QualType NewType = transformFunctionProtoType(
+        TLB, FPTL, Params, Args, F->getReturnType(), MaterializedTypedefs);
+    if (NewType.isNull())
+      return nullptr;
+    TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
+
+    return clang::buildDeductionGuide(
+        SemaRef, AliasTemplate, TemplateParams,
+        F->getCorrespondingConstructor(), F->getExplicitSpecifier(), NewTInfo,
+        AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
+        AliasTemplate->getEndLoc(), F->isImplicit(), MaterializedTypedefs);
+  }
+
+private:
+  // Find all template parameters of the AliasTemplate that appear in the
+  // DeducedArgs.
+  SmallVector<NamedDecl *>
+  FindAppearedTemplateParamsInAlias(ArrayRef<TemplateArgument> DeducedArgs) {
+    struct FindAppearedTemplateParams
+        : public RecursiveASTVisitor<FindAppearedTemplateParams> {
+      llvm::DenseSet<NamedDecl *> TemplateParamsInAlias...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/77890


More information about the cfe-commits mailing list