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

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 6 06:51:46 PST 2024


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

>From 334cb49012443961720e29df92211213f5a7c043 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 24 Jan 2024 14:55:03 +0100
Subject: [PATCH 01/11] [clang] Implement Class Template Argument Deduction
 (CTAD) for type alias templates P1814R0.

This patch implements the C++20 feature -- CTAD for alias templates.
This 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 in a followup).

This patch also refactors the existing `ConvertConstructorToDeductionGuideTransform`
to allow code reuse.
---
 clang/include/clang/Sema/Sema.h               |  14 +-
 clang/lib/Sema/CMakeLists.txt                 |   1 +
 clang/lib/Sema/CTAD.cpp                       | 209 ++++++++++
 clang/lib/Sema/CTAD.h                         |  65 +++
 clang/lib/Sema/SemaInit.cpp                   | 374 +++++++++++++++++-
 clang/lib/Sema/SemaTemplate.cpp               | 168 ++------
 clang/lib/Sema/SemaTemplateDeduction.cpp      |   9 +
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  25 +-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  25 +-
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  | 133 +++++++
 10 files changed, 856 insertions(+), 167 deletions(-)
 create mode 100644 clang/lib/Sema/CTAD.cpp
 create mode 100644 clang/lib/Sema/CTAD.h
 create mode 100644 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 53f06bcaeca166..6ad80e6f4b1b05 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9335,6 +9335,12 @@ class Sema final {
                           ArrayRef<TemplateArgument> 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,
@@ -10525,9 +10531,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 862f9d4ffb825d..ef8d2aed07d112 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 0fd458837163e5..812cb870180321 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"
@@ -10587,6 +10595,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;
+      llvm::DenseSet<const NamedDecl *> AppearedTemplateParams;
+
+      FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParamsInAlias)
+          : TemplateParamsInAlias(TemplateParamsInAlias.begin(),
+                                  TemplateParamsInAlias.end()) {}
+
+      bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
+        MarkAppeared(TTP->getDecl());
+        return true;
+      }
+      bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+        MarkAppeared(DRE->getFoundDecl());
+        return true;
+      }
+
+      void MarkAppeared(NamedDecl *ND) {
+        if (TemplateParamsInAlias.contains(ND))
+          AppearedTemplateParams.insert(ND);
+      }
+    };
+    ArrayRef<NamedDecl *> TemplateParamsInAlias =
+        AliasTemplate->getTemplateParameters()->asArray();
+    FindAppearedTemplateParams MarkAppeared(TemplateParamsInAlias);
+    MarkAppeared.TraverseTemplateArguments(DeducedArgs);
+
+    SmallVector<NamedDecl *> Results;
+    for (auto *TP : TemplateParamsInAlias)
+      if (MarkAppeared.AppearedTemplateParams.contains(TP))
+        Results.push_back(TP);
+    return Results;
+  }
+
+  // Transform a template parameter of f into a template parameter of f'
+  // rebuilding any internal references to earlier parameters and renumbering as
+  // we go.
+  NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam,
+                                        MultiLevelTemplateArgumentList &Args,
+                                        int NewIndex) {
+    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
+      return clang::transformTemplateTypeParam(SemaRef, DC, TTP, Args,
+                                               TTP->getDepth(), NewIndex);
+
+    if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
+      return clang::transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex);
+    auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParam);
+    return clang::transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex);
+  }
+
+  // Transform the function proto type of f into a function prototype of f'.
+  QualType transformFunctionProtoType(
+      TypeLocBuilder &TLB, FunctionProtoTypeLoc TL,
+      SmallVectorImpl<ParmVarDecl *> &Params,
+      MultiLevelTemplateArgumentList &Args, QualType ReturnType,
+      SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
+    SmallVector<QualType, 4> ParamTypes;
+    const FunctionProtoType *T = TL.getTypePtr();
+
+    for (auto *OldParam : TL.getParams()) {
+      ParmVarDecl *NewParam = clang::transformFunctionTypeParam(
+          SemaRef, OldParam, DC, Args, MaterializedTypedefs);
+      if (!NewParam)
+        return QualType();
+      ParamTypes.push_back(NewParam->getType());
+      Params.push_back(NewParam);
+    }
+
+    // The return type of the deduction guide f is InjectedClassNameType,
+    // transform it to a TemplateSpecializationType.
+    if (const auto *ET = ReturnType->getAs<InjectedClassNameType>())
+      ReturnType = ET->getInjectedSpecializationType();
+    auto DeductionGuideName =
+        SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(
+            AliasTemplate);
+    ReturnType = SemaRef.SubstType(ReturnType, Args, SourceLocation(),
+                                   DeductionGuideName);
+
+    // Resolving a wording defect, we also inherit the variadicness of the
+    // constructor.
+    FunctionProtoType::ExtProtoInfo EPI;
+    EPI.Variadic = T->isVariadic();
+    EPI.HasTrailingReturn = true;
+
+    QualType FunctionTy = SemaRef.BuildFunctionType(
+        ReturnType, ParamTypes, TL.getBeginLoc(), DeductionGuideName, EPI);
+    if (FunctionTy.isNull())
+      return QualType();
+    assert(FunctionTy->getTypeClass() == Type::FunctionProto);
+    // Pushes spaces for the new FunctionProtoTypeLoc.
+    TLB.pushTrivial(SemaRef.Context,
+                    TypeLoc(FunctionTy, nullptr).getNextTypeLoc().getType(),
+                    SourceLocation());
+    FunctionProtoTypeLoc TargetTL = TLB.push<FunctionProtoTypeLoc>(FunctionTy);
+    TargetTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+    TargetTL.setLParenLoc(TL.getLParenLoc());
+    TargetTL.setRParenLoc(TL.getRParenLoc());
+    TargetTL.setExceptionSpecRange(SourceRange());
+    TargetTL.setLocalRangeEnd(TL.getLocalRangeEnd());
+    for (unsigned I = 0, E = TargetTL.getNumParams(); I != E; ++I)
+      TargetTL.setParam(I, Params[I]);
+    return FunctionTy;
+  }
+
+  Sema &SemaRef;
+  TypeAliasTemplateDecl *AliasTemplate = nullptr;
+  DeclContext *DC = nullptr;
+};
+
 QualType Sema::DeduceTemplateSpecializationFromInitializer(
     TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
     const InitializationKind &Kind, MultiExprArg Inits) {
@@ -10598,10 +10813,48 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   if (TemplateName.isDependent())
     return SubstAutoTypeDependent(TSInfo->getType());
 
-  // We can only perform deduction for class templates.
+  // We can only perform deduction for class templates or alias templates.
   auto *Template =
       dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
+
+  TypeAliasTemplateDecl *AliasTemplate = nullptr;
+  llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
+  if (!Template && getLangOpts().CPlusPlus20) { // type alias template
+    if (AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
+            TemplateName.getAsTemplateDecl());
+        AliasTemplate) {
+      // Unrap the sugar ElaboratedType.
+      auto RhsType = AliasTemplate->getTemplatedDecl()
+                         ->getUnderlyingType()
+                         .getSingleStepDesugaredType(Context);
+      if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
+        // TemplateName in TEST can be a TypeAliasTemplateDecl if
+        // the right hand side of the alias is also a type alias, e.g.
+        //
+        // template<typename T>
+        // using AliasFoo1 = Foo<T>;  // Foo<T> is a class template
+        // specialization
+        //
+        // template<typename T>
+        // using AliasFoo2 = AliasFoo1<T>; // AliasFoo1<T> is a type alias
+        // FIXME: support this case, we need to recursively perform deductions.
+        Template = dyn_cast_or_null<ClassTemplateDecl>(
+            TST->getTemplateName().getAsTemplateDecl());
+        AliasRhsTemplateArgs = TST->template_arguments();
+      } else if (const auto *RT = RhsType->getAs<RecordType>()) {
+        // Cases where template arguments in the RHS of the alias are not
+        // dependent. e.g.
+        //   using AliasFoo = Foo<bool>;
+        if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
+                RT->getAsCXXRecordDecl())) {
+          Template = CTSD->getSpecializedTemplate();
+          AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray();
+        }
+      }
+    }
+  }
   if (!Template) {
+    // FIXME: update the diagnostic message to include C++20 alias templates
     Diag(Kind.getLocation(),
          diag::err_deduced_non_class_template_specialization_type)
       << (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
@@ -10640,6 +10893,113 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   // clear on this, but they're not found by name so access does not apply.
   Guides.suppressDiagnostics();
 
+  SmallVector<DeclAccessPair> GuidesCandidates;
+  if (AliasTemplate) {
+    for (auto *G : Guides) {
+      FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
+      if (!F)
+        // FIXME: handle the non-template deduction guide case.
+        continue;
+      auto RType = F->getTemplatedDecl()->getReturnType();
+      // The (trailing) return type of the deduction guide.
+      const TemplateSpecializationType *FReturnType = nullptr;
+      if (const auto *InjectedCNT = RType->getAs<InjectedClassNameType>()) {
+        // implicitly-generated deduction guide.
+        FReturnType = InjectedCNT->getInjectedTST();
+      } else if (const auto *ET = RType->getAs<ElaboratedType>()) {
+        // explicit deduction guide.
+        FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
+      }
+      assert(FReturnType);
+      if (FReturnType) {
+        sema::TemplateDeductionInfo TDeduceInfo(Kind.getLocation());
+        SmallVector<DeducedTemplateArgument> DeduceResults;
+        // DeduceResults.resize(FReturnType->template_arguments().size());
+        DeduceResults.resize(F->getTemplateParameters()->size());
+
+        // Deduce template arguments of the deduction guide f from the RHS of
+        // the alias.
+        //
+        // C++ [over.match.class.deduct]p3: ...For each function or function
+        // template f in the guides of the template named by the
+        // simple-template-id of the defining-type-id, the template arguments
+        // of the return type of f are deduced from the defining-type-id of A
+        // according to the process in [temp.deduct.type] with the exception
+        // that deduction does not fail if not all template arguments are
+        // deduced.
+        //
+        //
+        //  template<typename X, typename Y>
+        //  f(X, Y) -> f<Y, X>;
+        //
+        //  template<typename U>
+        //  using alias = f<int, U>;
+        //
+        // The RHS of alias is f<int, U>, we deduced the template arguments of
+        // the return type of the deduction guide from it: Y->int, X->U
+        //
+        // FIXME: DeduceTemplateArguments stops immediately at the first
+        // non-deduced template parameter, extend it to continue performing
+        // deduction for rest of parameters.
+        DeduceTemplateArguments(
+            F->getTemplateParameters(), FReturnType->template_arguments(),
+            AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
+            /*NumberOfArgumentsMustMatch=*/false);
+
+        SmallVector<TemplateArgument> DeducedArgs;
+        SmallVector<NamedDecl *> NonDeducedTemplateParamsInF;
+        // !!NOTE: DeduceResults respects the sequence of template parameters.
+        for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
+          const auto &D = DeduceResults[Index];
+          if (!D.isNull()) // Deduced
+            DeducedArgs.push_back(D);
+          else
+            NonDeducedTemplateParamsInF.push_back(
+                F->getTemplateParameters()->getParam(Index));
+        }
+        auto *DeducedArgList =
+            TemplateArgumentList::CreateCopy(this->Context, DeducedArgs);
+
+        // Let g denote the result of substituting these deductions into f.
+        //
+        // FIXME: is using the InstantiateFunctionDeclaration API a right
+        // implement choice? It has some side effects which creates a
+        // specialization for the deduction guide function template, and
+        // the specialization is added to the the FunctionTemplateDecl, this
+        // is not specified by the standard.
+        //
+        // FIXME: Cache the result.
+        if (auto *G = InstantiateFunctionDeclaration(
+                F, DeducedArgList, AliasTemplate->getLocation(),
+                Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
+          InstantiatingTemplate BuildingDeductionGuides(
+              *this, AliasTemplate->getLocation(), AliasTemplate,
+              Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{});
+          AliasTemplateDeductionGuideTransform Transform(*this, AliasTemplate);
+          // If substitution succeeds, form a function or function template
+          // f' with the following properties and add it to the set of
+          // guides of A:
+          if (auto *FPrime = Transform.transform(
+                  dyn_cast<CXXDeductionGuideDecl>(G), DeducedArgs,
+                  NonDeducedTemplateParamsInF)) {
+            // FIXME: implement the assoicated constraint per C++
+            // [over.match.class.deduct]p3.3:
+            //    The associated constraints ([temp.constr.decl]) are the
+            //    conjunction of the associated constraints of g and a
+            //    constraint that is satisfied if and only if the arguments
+            //    of A are deducible (see below) from the return type.
+            // This could be implemented as part of function overload
+            // resolution below.
+            GuidesCandidates.push_back(
+                DeclAccessPair::make(FPrime, AccessSpecifier::AS_public));
+          }
+        }
+      }
+    }
+  } else {
+    for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I)
+      GuidesCandidates.push_back(I.getPair());
+  }
   // Figure out if this is list-initialization.
   InitListExpr *ListInit =
       (Inits.size() == 1 && Kind.getKind() != InitializationKind::IK_Direct)
@@ -10797,9 +11157,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
         HasAnyDeductionGuide = true;
       }
     };
-
-    for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
-      NamedDecl *D = (*I)->getUnderlyingDecl();
+    for (auto I : GuidesCandidates) {
+      NamedDecl *D = (I)->getUnderlyingDecl();
       if (D->isInvalidDecl())
         continue;
 
@@ -10812,7 +11171,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
       if (!GD->isImplicit())
         HasAnyDeductionGuide = true;
 
-      addDeductionCandidate(TD, GD, I.getPair(), OnlyListConstructors,
+      addDeductionCandidate(TD, GD, I, OnlyListConstructors,
                             /*AllowAggregateDeductionCandidate=*/false);
     }
 
@@ -10852,7 +11211,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     // Try list constructors unless the list is empty and the class has one or
     // more default constructors, in which case those constructors win.
     if (!ListInit->getNumInits()) {
-      for (NamedDecl *D : Guides) {
+      for (auto D : GuidesCandidates) {
+
         auto *FD = dyn_cast<FunctionDecl>(D->getUnderlyingDecl());
         if (FD && FD->getMinRequiredArguments() == 0) {
           TryListConstructors = false;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9e516da2aa27a1..c93563b2047b10 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -8,10 +8,12 @@
 //  This file implements semantic analysis for C++ templates.
 //===----------------------------------------------------------------------===//
 
+#include "CTAD.h"
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
@@ -2334,7 +2336,6 @@ struct ConvertConstructorToDeductionGuideTransform {
         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(
@@ -2407,9 +2408,10 @@ struct ConvertConstructorToDeductionGuideTransform {
       return nullptr;
     TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
 
-    return buildDeductionGuide(TemplateParams, CD, CD->getExplicitSpecifier(),
-                               NewTInfo, CD->getBeginLoc(), CD->getLocation(),
-                               CD->getEndLoc(), MaterializedTypedefs);
+    return clang::buildDeductionGuide(
+        SemaRef, Template, TemplateParams, CD, CD->getExplicitSpecifier(),
+        NewTInfo, CD->getBeginLoc(), CD->getLocation(), CD->getEndLoc(),
+        /*IsImplicit=*/true, MaterializedTypedefs);
   }
 
   /// Build a deduction guide with the specified parameter types.
@@ -2444,8 +2446,9 @@ struct ConvertConstructorToDeductionGuideTransform {
       Params.push_back(NewParam);
     }
 
-    return buildDeductionGuide(GetTemplateParameterList(Template), nullptr,
-                               ExplicitSpecifier(), TSI, Loc, Loc, Loc);
+    return clang::buildDeductionGuide(
+        SemaRef, Template, GetTemplateParameterList(Template), nullptr,
+        ExplicitSpecifier(), TSI, Loc, Loc, Loc, /*IsImplicit=*/true);
   }
 
 private:
@@ -2454,50 +2457,16 @@ struct ConvertConstructorToDeductionGuideTransform {
   /// renumbering as we go.
   NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam,
                                         MultiLevelTemplateArgumentList &Args) {
-    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam)) {
-      // TemplateTypeParmDecl's index cannot be changed after creation, so
-      // substitute it directly.
-      auto *NewTTP = TemplateTypeParmDecl::Create(
-          SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(),
-          TTP->getDepth() - 1, Depth1IndexAdjustment + TTP->getIndex(),
-          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(TemplateParam,
-                                                           NewTTP);
-      return NewTTP;
-    }
-
+    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
+      return clang::transformTemplateTypeParam(
+          SemaRef, DC, TTP, Args, TTP->getDepth() - 1,
+          Depth1IndexAdjustment + TTP->getIndex());
     if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
-      return transformTemplateParameterImpl(TTP, Args);
-
-    return transformTemplateParameterImpl(
-        cast<NonTypeTemplateParmDecl>(TemplateParam), Args);
-  }
-  template<typename TemplateParmDecl>
-  TemplateParmDecl *
-  transformTemplateParameterImpl(TemplateParmDecl *OldParam,
-                                 MultiLevelTemplateArgumentList &Args) {
-    // 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<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
-    assert(NewParam->getDepth() == OldParam->getDepth() - 1 &&
-           "unexpected template param depth");
-    NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment);
-    return NewParam;
+      return clang::transformTemplateParam(
+          SemaRef, DC, TTP, Args, Depth1IndexAdjustment + TTP->getIndex());
+    auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParam);
+    return clang::transformTemplateParam(
+        SemaRef, DC, NTTP, Args, Depth1IndexAdjustment + NTTP->getIndex());
   }
 
   QualType transformFunctionProtoType(
@@ -2510,11 +2479,12 @@ struct ConvertConstructorToDeductionGuideTransform {
 
     //    -- The types of the function parameters are those of the constructor.
     for (auto *OldParam : TL.getParams()) {
-      ParmVarDecl *NewParam =
-          transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
+      ParmVarDecl *NewParam = clang::transformFunctionTypeParam(
+          SemaRef, OldParam, DC, Args, MaterializedTypedefs);
       if (NestedPattern && NewParam)
-        NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
-                                              MaterializedTypedefs);
+        NewParam = clang::transformFunctionTypeParam(SemaRef, NewParam, DC,
+                                                     OuterInstantiationArgs,
+                                                     MaterializedTypedefs);
       if (!NewParam)
         return QualType();
       ParamTypes.push_back(NewParam->getType());
@@ -2555,98 +2525,6 @@ struct ConvertConstructorToDeductionGuideTransform {
 
     return Result;
   }
-
-  ParmVarDecl *transformFunctionTypeParam(
-      ParmVarDecl *OldParam, 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->getDefaultArg()->getBeginLoc(),
-                          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;
-  }
-
-  FunctionTemplateDecl *buildDeductionGuide(
-      TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor,
-      ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart,
-      SourceLocation Loc, SourceLocation LocEnd,
-      llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) {
-    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();
-    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();
-    Guide->setDescribedFunctionTemplate(GuideTemplate);
-
-    if (isa<CXXRecordDecl>(DC)) {
-      Guide->setAccess(AS_public);
-      GuideTemplate->setAccess(AS_public);
-    }
-
-    DC->addDecl(GuideTemplate);
-    return GuideTemplate;
-  }
 };
 }
 
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 47cc22310c4eec..4024d3708ab311 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2531,6 +2531,15 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
   return TemplateDeductionResult::Success;
 }
 
+Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
+    TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
+    ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
+    SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+    bool NumberOfArgumentsMustMatch) {
+  return ::DeduceTemplateArguments(*this, TemplateParams, Ps, As, Info, Deduced,
+                                   NumberOfArgumentsMustMatch);
+}
+
 /// Determine whether two template arguments are the same.
 static bool isSameTemplateArg(ASTContext &Context,
                               TemplateArgument X,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 371378485626c2..32b5f3756307bf 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -21,6 +21,7 @@
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/PrettyDeclStackTrace.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"
@@ -547,9 +548,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(
@@ -1446,6 +1447,24 @@ namespace {
       return inherited::TransformFunctionProtoType(TLB, TL);
     }
 
+    QualType TransformInjectedClassNameType(TypeLocBuilder &TLB,
+                                            InjectedClassNameTypeLoc TL) {
+      auto Type = inherited::TransformInjectedClassNameType(TLB, TL);
+      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 TST = SemaRef.Context.getTemplateSpecializationType(
+              ICT->getTemplateName(), TemplateArgs.getOutermost());
+          TLB.pushTrivial(SemaRef.Context, TST, TL.getNameLoc());
+          return TST;
+        }
+      }
+      return Type;
+    }
+
     template<typename Fn>
     QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
                                         FunctionProtoTypeLoc TL,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9c696e072ba4a7..5e17abb92941e1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4853,16 +4853,13 @@ bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New,
 ///
 /// Usually this should not be used, and template argument deduction should be
 /// used in its place.
-FunctionDecl *
-Sema::InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
-                                     const TemplateArgumentList *Args,
-                                     SourceLocation Loc) {
+FunctionDecl *Sema::InstantiateFunctionDeclaration(
+    FunctionTemplateDecl *FTD, const TemplateArgumentList *Args,
+    SourceLocation Loc, CodeSynthesisContext::SynthesisKind CSC) {
   FunctionDecl *FD = FTD->getTemplatedDecl();
 
   sema::TemplateDeductionInfo Info(Loc);
-  InstantiatingTemplate Inst(
-      *this, Loc, FTD, Args->asArray(),
-      CodeSynthesisContext::ExplicitTemplateArgumentSubstitution, Info);
+  InstantiatingTemplate Inst(*this, Loc, FTD, Args->asArray(), CSC, Info);
   if (Inst.isInvalid())
     return nullptr;
 
@@ -6286,8 +6283,18 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
           QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
           if (T.isNull())
             return nullptr;
-          auto *SubstRecord = T->getAsCXXRecordDecl();
-          assert(SubstRecord && "class template id not a class type?");
+          CXXRecordDecl *SubstRecord = T->getAsCXXRecordDecl();
+
+          if (!SubstRecord) {
+            // The template id T is a TemplateSpecializationType when performing
+            // a substitution for a deduction guide,
+            assert(CodeSynthesisContexts.back().Kind ==
+                   CodeSynthesisContext::BuildingDeductionGuides);
+            // Return a nullptr as a sentinel value, we handle it properly in
+            // the TemplateInstantiator::TransformInjectedClassNameType
+            // override.
+            return nullptr;
+          }
           // Check that this template-id names the primary template and not a
           // partial or explicit specialization. (In the latter cases, it's
           // meaningless to attempt to find an instantiation of D within the
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
new file mode 100644
index 00000000000000..5a5691e48fd17e
--- /dev/null
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -0,0 +1,133 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-c++11-narrowing -Wno-literal-conversion -std=c++20 -verify %s
+
+namespace test1 {
+template <typename T>
+struct Foo {
+  T t;
+};
+template <typename U>
+using Bar = Foo<U>;
+
+Bar s = {1};
+}  // namespace test1
+
+namespace test2 {
+template <typename X, typename Y>
+struct XYpair {
+  X x;
+  Y y;
+};
+// A tricky explicit deduction guide that swapping X and Y.
+template <typename X, typename Y>
+XYpair(X, Y) -> XYpair<Y, X>;
+template <typename U, typename V>
+using AliasXYpair = XYpair<U, V>;
+
+AliasXYpair xy = {1.1, 2};  // XYpair<int, double>
+static_assert(__is_same(decltype(xy.x), int));
+static_assert(__is_same(decltype(xy.y), double));
+}  // namespace test2
+
+namespace test3 {
+template <typename T, class>
+struct container {
+  // test with default arguments.
+  container(T a, T b = T());
+};
+
+template <class T>
+using vector = container<T, int>;
+vector v(0, 0);
+}  // namespace test3
+
+namespace test4 {
+template <class T>
+struct X {
+  T t;
+  X(T);
+};
+
+template <class T>
+X(T) -> X<double>;
+
+template <class T>
+using AX = X<T>;
+
+AX s = {1};
+static_assert(__is_same(decltype(s.t), double));
+}  // namespace test4
+
+namespace test5 {
+template <int B>
+struct Foo {};
+
+template <int... C>
+using AF = Foo<1>;
+auto a = AF{};
+}  // namespace test5
+
+namespace test6 {
+template <typename T, bool B = false>
+struct Foo {
+  Foo(T);
+};
+// non-type template argument.
+template <typename T>
+using AF = Foo<T, 1>;
+
+AF b{0};  //
+}  // namespace test6
+
+namespace test7 {
+template <typename T>
+struct Foo {
+  Foo(T);
+};
+
+template <typename U>
+using AF1 = Foo<U>;
+template <typename K>
+using AF2 = AF1<K>;  // expected-note {{template is declared here}}
+// FIXME: support this case.
+AF2 b = 1;  // expected-error {{alias template 'AF2' requires template arguments; argument deduction only allowed for class templates}}
+}  // namespace test7
+
+namespace test8 {
+template <typename T, int N>
+struct Foo {
+  Foo(T const (&)[N]);
+};
+
+template <typename X, int Y>
+using Bar = Foo<X, Y>;
+
+Bar s = {{1}};
+}  // namespace test8
+
+namespace test9 {
+template <typename T, int N>
+struct Foo {
+  Foo(T const (&)[N]);
+};
+
+template <typename X, int Y>
+using Bar = Foo<X, sizeof(X)>;
+
+// FIXME: should we reject this case? GCC rejects it, MSVC accepts it.
+Bar s = {{1}};
+}  // namespace test9
+
+namespace test10 {
+template <typename T>
+struct Foo {
+  template <typename U>
+  Foo(U);
+};
+
+template <typename U>
+Foo(U) -> Foo<U*>;
+
+template <typename K>
+using A = Foo<K>;
+A a(2);  // Foo<int*>
+}  // namespace test10

>From 05740ec2add59e99d159ec250d8959e7039c48a9 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Tue, 6 Feb 2024 09:40:51 +0100
Subject: [PATCH 02/11] Rewrite the implementations:

- Move the implementation to SemaTemplate.cpp where the typical CTAD
  implementation lives, thus no sepatate CTAD.h/.cpp;
- Rewrite the implementation, we leverage more on clang's template
  instantatiation mechanism to build the deduction guide, it
  implementation is simplier;
- Some enhancements on TreeTransform and TemplateInstantiator to allow
  running on BuildingDeductionGuides mode;
- Added more tests;
---
 clang/include/clang/Sema/Sema.h               |   3 +
 clang/lib/Sema/CMakeLists.txt                 |   1 -
 clang/lib/Sema/CTAD.cpp                       | 209 --------
 clang/lib/Sema/CTAD.h                         |  65 ---
 clang/lib/Sema/SemaInit.cpp                   | 372 +------------
 clang/lib/Sema/SemaTemplate.cpp               | 493 +++++++++++++++++-
 clang/lib/Sema/SemaTemplateDeduction.cpp      |   2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  51 +-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   9 +-
 clang/lib/Sema/TreeTransform.h                |   8 +
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  |  79 ++-
 11 files changed, 622 insertions(+), 670 deletions(-)
 delete mode 100644 clang/lib/Sema/CTAD.cpp
 delete mode 100644 clang/lib/Sema/CTAD.h

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ad80e6f4b1b05..e3f350ac8bfa92 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10424,6 +10424,9 @@ class Sema final {
                       const MultiLevelTemplateArgumentList &TemplateArgs,
                       bool EvaluateConstraints = true);
 
+  bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
+                             const MultiLevelTemplateArgumentList &TemplateArgs,
+                             TemplateArgumentLoc &Output);
   bool
   SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
                          const MultiLevelTemplateArgumentList &TemplateArgs,
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index ef8d2aed07d112..862f9d4ffb825d 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -14,7 +14,6 @@ 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
deleted file mode 100644
index 745878c717fc4c..00000000000000
--- a/clang/lib/Sema/CTAD.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-//===--- 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
deleted file mode 100644
index 88110230318f81..00000000000000
--- a/clang/lib/Sema/CTAD.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//===--- 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 812cb870180321..6d288d74761319 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10,19 +10,13 @@
 //
 //===----------------------------------------------------------------------===//
 
-#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"
@@ -34,9 +28,7 @@
 #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"
@@ -10595,213 +10587,6 @@ 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;
-      llvm::DenseSet<const NamedDecl *> AppearedTemplateParams;
-
-      FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParamsInAlias)
-          : TemplateParamsInAlias(TemplateParamsInAlias.begin(),
-                                  TemplateParamsInAlias.end()) {}
-
-      bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
-        MarkAppeared(TTP->getDecl());
-        return true;
-      }
-      bool VisitDeclRefExpr(DeclRefExpr *DRE) {
-        MarkAppeared(DRE->getFoundDecl());
-        return true;
-      }
-
-      void MarkAppeared(NamedDecl *ND) {
-        if (TemplateParamsInAlias.contains(ND))
-          AppearedTemplateParams.insert(ND);
-      }
-    };
-    ArrayRef<NamedDecl *> TemplateParamsInAlias =
-        AliasTemplate->getTemplateParameters()->asArray();
-    FindAppearedTemplateParams MarkAppeared(TemplateParamsInAlias);
-    MarkAppeared.TraverseTemplateArguments(DeducedArgs);
-
-    SmallVector<NamedDecl *> Results;
-    for (auto *TP : TemplateParamsInAlias)
-      if (MarkAppeared.AppearedTemplateParams.contains(TP))
-        Results.push_back(TP);
-    return Results;
-  }
-
-  // Transform a template parameter of f into a template parameter of f'
-  // rebuilding any internal references to earlier parameters and renumbering as
-  // we go.
-  NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam,
-                                        MultiLevelTemplateArgumentList &Args,
-                                        int NewIndex) {
-    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
-      return clang::transformTemplateTypeParam(SemaRef, DC, TTP, Args,
-                                               TTP->getDepth(), NewIndex);
-
-    if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
-      return clang::transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex);
-    auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParam);
-    return clang::transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex);
-  }
-
-  // Transform the function proto type of f into a function prototype of f'.
-  QualType transformFunctionProtoType(
-      TypeLocBuilder &TLB, FunctionProtoTypeLoc TL,
-      SmallVectorImpl<ParmVarDecl *> &Params,
-      MultiLevelTemplateArgumentList &Args, QualType ReturnType,
-      SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
-    SmallVector<QualType, 4> ParamTypes;
-    const FunctionProtoType *T = TL.getTypePtr();
-
-    for (auto *OldParam : TL.getParams()) {
-      ParmVarDecl *NewParam = clang::transformFunctionTypeParam(
-          SemaRef, OldParam, DC, Args, MaterializedTypedefs);
-      if (!NewParam)
-        return QualType();
-      ParamTypes.push_back(NewParam->getType());
-      Params.push_back(NewParam);
-    }
-
-    // The return type of the deduction guide f is InjectedClassNameType,
-    // transform it to a TemplateSpecializationType.
-    if (const auto *ET = ReturnType->getAs<InjectedClassNameType>())
-      ReturnType = ET->getInjectedSpecializationType();
-    auto DeductionGuideName =
-        SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(
-            AliasTemplate);
-    ReturnType = SemaRef.SubstType(ReturnType, Args, SourceLocation(),
-                                   DeductionGuideName);
-
-    // Resolving a wording defect, we also inherit the variadicness of the
-    // constructor.
-    FunctionProtoType::ExtProtoInfo EPI;
-    EPI.Variadic = T->isVariadic();
-    EPI.HasTrailingReturn = true;
-
-    QualType FunctionTy = SemaRef.BuildFunctionType(
-        ReturnType, ParamTypes, TL.getBeginLoc(), DeductionGuideName, EPI);
-    if (FunctionTy.isNull())
-      return QualType();
-    assert(FunctionTy->getTypeClass() == Type::FunctionProto);
-    // Pushes spaces for the new FunctionProtoTypeLoc.
-    TLB.pushTrivial(SemaRef.Context,
-                    TypeLoc(FunctionTy, nullptr).getNextTypeLoc().getType(),
-                    SourceLocation());
-    FunctionProtoTypeLoc TargetTL = TLB.push<FunctionProtoTypeLoc>(FunctionTy);
-    TargetTL.setLocalRangeBegin(TL.getLocalRangeBegin());
-    TargetTL.setLParenLoc(TL.getLParenLoc());
-    TargetTL.setRParenLoc(TL.getRParenLoc());
-    TargetTL.setExceptionSpecRange(SourceRange());
-    TargetTL.setLocalRangeEnd(TL.getLocalRangeEnd());
-    for (unsigned I = 0, E = TargetTL.getNumParams(); I != E; ++I)
-      TargetTL.setParam(I, Params[I]);
-    return FunctionTy;
-  }
-
-  Sema &SemaRef;
-  TypeAliasTemplateDecl *AliasTemplate = nullptr;
-  DeclContext *DC = nullptr;
-};
-
 QualType Sema::DeduceTemplateSpecializationFromInitializer(
     TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
     const InitializationKind &Kind, MultiExprArg Inits) {
@@ -10816,40 +10601,26 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   // We can only perform deduction for class templates or alias templates.
   auto *Template =
       dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
-
-  TypeAliasTemplateDecl *AliasTemplate = nullptr;
-  llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
+  TemplateDecl* LookupTemplateDecl = Template;
   if (!Template && getLangOpts().CPlusPlus20) { // type alias template
-    if (AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
+    if (auto *AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
             TemplateName.getAsTemplateDecl());
         AliasTemplate) {
-      // Unrap the sugar ElaboratedType.
-      auto RhsType = AliasTemplate->getTemplatedDecl()
-                         ->getUnderlyingType()
-                         .getSingleStepDesugaredType(Context);
-      if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
-        // TemplateName in TEST can be a TypeAliasTemplateDecl if
-        // the right hand side of the alias is also a type alias, e.g.
-        //
-        // template<typename T>
-        // using AliasFoo1 = Foo<T>;  // Foo<T> is a class template
-        // specialization
-        //
-        // template<typename T>
-        // using AliasFoo2 = AliasFoo1<T>; // AliasFoo1<T> is a type alias
-        // FIXME: support this case, we need to recursively perform deductions.
+      LookupTemplateDecl = AliasTemplate;
+      auto UnderlyingType = AliasTemplate->getTemplatedDecl()
+                                ->getUnderlyingType()
+                                .getDesugaredType(Context);
+      if (const auto *TST =
+              UnderlyingType->getAs<TemplateSpecializationType>()) {
         Template = dyn_cast_or_null<ClassTemplateDecl>(
             TST->getTemplateName().getAsTemplateDecl());
-        AliasRhsTemplateArgs = TST->template_arguments();
-      } else if (const auto *RT = RhsType->getAs<RecordType>()) {
+      } else if (const auto *RT = UnderlyingType->getAs<RecordType>()) {
         // Cases where template arguments in the RHS of the alias are not
         // dependent. e.g.
         //   using AliasFoo = Foo<bool>;
         if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
-                RT->getAsCXXRecordDecl())) {
+                RT->getAsCXXRecordDecl()))
           Template = CTSD->getSpecializedTemplate();
-          AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray();
-        }
       }
     }
   }
@@ -10884,122 +10655,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   //     template-name, a function template [...]
   //  - For each deduction-guide, a function or function template [...]
   DeclarationNameInfo NameInfo(
-      Context.DeclarationNames.getCXXDeductionGuideName(Template),
+      Context.DeclarationNames.getCXXDeductionGuideName(LookupTemplateDecl),
       TSInfo->getTypeLoc().getEndLoc());
   LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
-  LookupQualifiedName(Guides, Template->getDeclContext());
+  LookupQualifiedName(Guides, LookupTemplateDecl->getDeclContext());
 
   // FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
   // clear on this, but they're not found by name so access does not apply.
   Guides.suppressDiagnostics();
 
-  SmallVector<DeclAccessPair> GuidesCandidates;
-  if (AliasTemplate) {
-    for (auto *G : Guides) {
-      FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
-      if (!F)
-        // FIXME: handle the non-template deduction guide case.
-        continue;
-      auto RType = F->getTemplatedDecl()->getReturnType();
-      // The (trailing) return type of the deduction guide.
-      const TemplateSpecializationType *FReturnType = nullptr;
-      if (const auto *InjectedCNT = RType->getAs<InjectedClassNameType>()) {
-        // implicitly-generated deduction guide.
-        FReturnType = InjectedCNT->getInjectedTST();
-      } else if (const auto *ET = RType->getAs<ElaboratedType>()) {
-        // explicit deduction guide.
-        FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
-      }
-      assert(FReturnType);
-      if (FReturnType) {
-        sema::TemplateDeductionInfo TDeduceInfo(Kind.getLocation());
-        SmallVector<DeducedTemplateArgument> DeduceResults;
-        // DeduceResults.resize(FReturnType->template_arguments().size());
-        DeduceResults.resize(F->getTemplateParameters()->size());
-
-        // Deduce template arguments of the deduction guide f from the RHS of
-        // the alias.
-        //
-        // C++ [over.match.class.deduct]p3: ...For each function or function
-        // template f in the guides of the template named by the
-        // simple-template-id of the defining-type-id, the template arguments
-        // of the return type of f are deduced from the defining-type-id of A
-        // according to the process in [temp.deduct.type] with the exception
-        // that deduction does not fail if not all template arguments are
-        // deduced.
-        //
-        //
-        //  template<typename X, typename Y>
-        //  f(X, Y) -> f<Y, X>;
-        //
-        //  template<typename U>
-        //  using alias = f<int, U>;
-        //
-        // The RHS of alias is f<int, U>, we deduced the template arguments of
-        // the return type of the deduction guide from it: Y->int, X->U
-        //
-        // FIXME: DeduceTemplateArguments stops immediately at the first
-        // non-deduced template parameter, extend it to continue performing
-        // deduction for rest of parameters.
-        DeduceTemplateArguments(
-            F->getTemplateParameters(), FReturnType->template_arguments(),
-            AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
-            /*NumberOfArgumentsMustMatch=*/false);
-
-        SmallVector<TemplateArgument> DeducedArgs;
-        SmallVector<NamedDecl *> NonDeducedTemplateParamsInF;
-        // !!NOTE: DeduceResults respects the sequence of template parameters.
-        for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
-          const auto &D = DeduceResults[Index];
-          if (!D.isNull()) // Deduced
-            DeducedArgs.push_back(D);
-          else
-            NonDeducedTemplateParamsInF.push_back(
-                F->getTemplateParameters()->getParam(Index));
-        }
-        auto *DeducedArgList =
-            TemplateArgumentList::CreateCopy(this->Context, DeducedArgs);
-
-        // Let g denote the result of substituting these deductions into f.
-        //
-        // FIXME: is using the InstantiateFunctionDeclaration API a right
-        // implement choice? It has some side effects which creates a
-        // specialization for the deduction guide function template, and
-        // the specialization is added to the the FunctionTemplateDecl, this
-        // is not specified by the standard.
-        //
-        // FIXME: Cache the result.
-        if (auto *G = InstantiateFunctionDeclaration(
-                F, DeducedArgList, AliasTemplate->getLocation(),
-                Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
-          InstantiatingTemplate BuildingDeductionGuides(
-              *this, AliasTemplate->getLocation(), AliasTemplate,
-              Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{});
-          AliasTemplateDeductionGuideTransform Transform(*this, AliasTemplate);
-          // If substitution succeeds, form a function or function template
-          // f' with the following properties and add it to the set of
-          // guides of A:
-          if (auto *FPrime = Transform.transform(
-                  dyn_cast<CXXDeductionGuideDecl>(G), DeducedArgs,
-                  NonDeducedTemplateParamsInF)) {
-            // FIXME: implement the assoicated constraint per C++
-            // [over.match.class.deduct]p3.3:
-            //    The associated constraints ([temp.constr.decl]) are the
-            //    conjunction of the associated constraints of g and a
-            //    constraint that is satisfied if and only if the arguments
-            //    of A are deducible (see below) from the return type.
-            // This could be implemented as part of function overload
-            // resolution below.
-            GuidesCandidates.push_back(
-                DeclAccessPair::make(FPrime, AccessSpecifier::AS_public));
-          }
-        }
-      }
-    }
-  } else {
-    for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I)
-      GuidesCandidates.push_back(I.getPair());
-  }
   // Figure out if this is list-initialization.
   InitListExpr *ListInit =
       (Inits.size() == 1 && Kind.getKind() != InitializationKind::IK_Direct)
@@ -11157,8 +10821,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
         HasAnyDeductionGuide = true;
       }
     };
-    for (auto I : GuidesCandidates) {
-      NamedDecl *D = (I)->getUnderlyingDecl();
+
+    for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
+      NamedDecl *D = (*I)->getUnderlyingDecl();
       if (D->isInvalidDecl())
         continue;
 
@@ -11171,7 +10836,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
       if (!GD->isImplicit())
         HasAnyDeductionGuide = true;
 
-      addDeductionCandidate(TD, GD, I, OnlyListConstructors,
+      addDeductionCandidate(TD, GD, I.getPair(), OnlyListConstructors,
                             /*AllowAggregateDeductionCandidate=*/false);
     }
 
@@ -11211,8 +10876,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     // Try list constructors unless the list is empty and the class has one or
     // more default constructors, in which case those constructors win.
     if (!ListInit->getNumInits()) {
-      for (auto D : GuidesCandidates) {
-
+      for (NamedDecl *D : Guides) {
         auto *FD = dyn_cast<FunctionDecl>(D->getUnderlyingDecl());
         if (FD && FD->getMinRequiredArguments() == 0) {
           TryListConstructors = false;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c93563b2047b10..bbecb5e70804e0 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -8,7 +8,6 @@
 //  This file implements semantic analysis for C++ templates.
 //===----------------------------------------------------------------------===//
 
-#include "CTAD.h"
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -41,6 +40,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
 
 #include <iterator>
 #include <optional>
@@ -2260,6 +2260,94 @@ class ExtractTypeForDeductionGuide
   }
 };
 
+// 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 = {}) {
+  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;
+}
+
+// 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()) {
+    TypeSourceInfo *InstantiatedDefaultArg =
+        SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
+                          TTP->getDefaultArgumentLoc(), TTP->getDeclName());
+    if (InstantiatedDefaultArg)
+      NewTTP->setDefaultArgument(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 {
@@ -2408,7 +2496,7 @@ struct ConvertConstructorToDeductionGuideTransform {
       return nullptr;
     TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
 
-    return clang::buildDeductionGuide(
+    return buildDeductionGuide(
         SemaRef, Template, TemplateParams, CD, CD->getExplicitSpecifier(),
         NewTInfo, CD->getBeginLoc(), CD->getLocation(), CD->getEndLoc(),
         /*IsImplicit=*/true, MaterializedTypedefs);
@@ -2446,7 +2534,7 @@ struct ConvertConstructorToDeductionGuideTransform {
       Params.push_back(NewParam);
     }
 
-    return clang::buildDeductionGuide(
+    return buildDeductionGuide(
         SemaRef, Template, GetTemplateParameterList(Template), nullptr,
         ExplicitSpecifier(), TSI, Loc, Loc, Loc, /*IsImplicit=*/true);
   }
@@ -2458,15 +2546,17 @@ struct ConvertConstructorToDeductionGuideTransform {
   NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam,
                                         MultiLevelTemplateArgumentList &Args) {
     if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
-      return clang::transformTemplateTypeParam(
+      return transformTemplateTypeParam(
           SemaRef, DC, TTP, Args, TTP->getDepth() - 1,
           Depth1IndexAdjustment + TTP->getIndex());
     if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
-      return clang::transformTemplateParam(
-          SemaRef, DC, TTP, Args, Depth1IndexAdjustment + TTP->getIndex());
+      return transformTemplateParam(
+          SemaRef, DC, TTP, Args, Depth1IndexAdjustment + TTP->getIndex(),
+          TTP->getDepth() - 1);
     auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParam);
-    return clang::transformTemplateParam(
-        SemaRef, DC, NTTP, Args, Depth1IndexAdjustment + NTTP->getIndex());
+    return transformTemplateParam(
+        SemaRef, DC, NTTP, Args, Depth1IndexAdjustment + NTTP->getIndex(),
+          NTTP->getDepth() - 1);
   }
 
   QualType transformFunctionProtoType(
@@ -2479,12 +2569,11 @@ struct ConvertConstructorToDeductionGuideTransform {
 
     //    -- The types of the function parameters are those of the constructor.
     for (auto *OldParam : TL.getParams()) {
-      ParmVarDecl *NewParam = clang::transformFunctionTypeParam(
-          SemaRef, OldParam, DC, Args, MaterializedTypedefs);
+      ParmVarDecl *NewParam =
+          transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
       if (NestedPattern && NewParam)
-        NewParam = clang::transformFunctionTypeParam(SemaRef, NewParam, DC,
-                                                     OuterInstantiationArgs,
-                                                     MaterializedTypedefs);
+        NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
+                                              MaterializedTypedefs);
       if (!NewParam)
         return QualType();
       ParamTypes.push_back(NewParam->getType());
@@ -2525,9 +2614,366 @@ struct ConvertConstructorToDeductionGuideTransform {
 
     return Result;
   }
+
+  ParmVarDecl *transformFunctionTypeParam(
+      ParmVarDecl *OldParam, 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->getDefaultArg()->getBeginLoc(),
+                          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;
+  }
 };
+
+// Find all template parameters of the AliasTemplate that appear in the
+// given DeducedArgs.
+SmallVector<unsigned>
+FindAppearedTemplateParamsInAlias(ArrayRef<TemplateArgument> DeducedArgs,
+                                  TypeAliasTemplateDecl *AliasTemplate) {
+  struct FindAppearedTemplateParams
+      : public RecursiveASTVisitor<FindAppearedTemplateParams> {
+    llvm::DenseSet<NamedDecl *> TemplateParamsInAlias;
+    llvm::DenseSet<const NamedDecl *> AppearedTemplateParams;
+
+    FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParamsInAlias)
+        : TemplateParamsInAlias(TemplateParamsInAlias.begin(),
+                                TemplateParamsInAlias.end()) {}
+
+    bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
+      TTP->getIndex();
+      MarkAppeared(TTP->getDecl());
+      return true;
+    }
+    bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+      MarkAppeared(DRE->getFoundDecl());
+      return true;
+    }
+
+    void MarkAppeared(NamedDecl *ND) {
+      if (TemplateParamsInAlias.contains(ND))
+        AppearedTemplateParams.insert(ND);
+    }
+  };
+  ArrayRef<NamedDecl *> TemplateParamsInAlias =
+      AliasTemplate->getTemplateParameters()->asArray();
+  FindAppearedTemplateParams MarkAppeared(TemplateParamsInAlias);
+  MarkAppeared.TraverseTemplateArguments(DeducedArgs);
+
+  SmallVector<unsigned> Results;
+  for (unsigned Index = 0; Index < TemplateParamsInAlias.size(); ++Index) {
+    if (MarkAppeared.AppearedTemplateParams.contains(
+            TemplateParamsInAlias[Index]))
+      Results.push_back(Index);
+  }
+  return Results;
+}
+
+bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext* DC) {
+  // Check whether we've already declared deduction guides for this template.
+  // FIXME: Consider storing a flag on the template to indicate this.
+  auto Existing = DC->lookup(Name);
+  for (auto *D : Existing)
+    if (D->isImplicit())
+      return true;
+  return false;
+}
+
+// Build deduction guides for a type alias template.
+void DeclareImplicitDeductionGuidesForTypeAlias(
+    Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) {
+  auto &Context = SemaRef.Context;
+  // FIXME: if there is an explicit deduction guide after the first use of the
+  // type alias usage, we will not cover this explicit deduction guide. fix this
+  // case.
+  if (hasDeclaredDeductionGuides(
+          Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
+          AliasTemplate->getDeclContext()))
+    return;
+  // Unrap the sugar ElaboratedType.
+  auto RhsType = AliasTemplate->getTemplatedDecl()
+                     ->getUnderlyingType()
+                     .getSingleStepDesugaredType(Context);
+  TemplateDecl *Template = nullptr;
+  llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
+  if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
+    // TemplateName in TEST can be a TypeAliasTemplateDecl if
+    // the right hand side of the alias is also a type alias, e.g.
+    //
+    // template<typename T>
+    // using AliasFoo1 = Foo<T>;  // Foo<T> is a class template
+    // specialization
+    //
+    // template<typename T>
+    // using AliasFoo2 = AliasFoo1<T>; // AliasFoo1<T> is a type alias
+    Template = TST->getTemplateName().getAsTemplateDecl();
+    AliasRhsTemplateArgs = TST->template_arguments();
+  } else if (const auto *RT = RhsType->getAs<RecordType>()) {
+    // Cases where template arguments in the RHS of the alias are not
+    // dependent. e.g.
+    //   using AliasFoo = Foo<bool>;
+    if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
+            RT->getAsCXXRecordDecl())) {
+      Template = CTSD->getSpecializedTemplate();
+      AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray();
+    }
+  }
+  if (!Template)
+    return;
+  DeclarationNameInfo NameInfo(
+      Context.DeclarationNames.getCXXDeductionGuideName(Template), Loc);
+  LookupResult Guides(SemaRef, NameInfo, clang::Sema::LookupOrdinaryName);
+  SemaRef.LookupQualifiedName(Guides, Template->getDeclContext());
+  Guides.suppressDiagnostics();
+
+  for (auto *G : Guides) {
+    FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
+    if (!F)
+      continue;
+    auto RType = F->getTemplatedDecl()->getReturnType();
+    // The (trailing) return type of the deduction guide.
+    const TemplateSpecializationType *FReturnType =
+        RType->getAs<TemplateSpecializationType>();
+    if (const auto *InjectedCNT = RType->getAs<InjectedClassNameType>())
+      // implicitly-generated deduction guide.
+      FReturnType = InjectedCNT->getInjectedTST();
+    else if (const auto *ET = RType->getAs<ElaboratedType>())
+      // explicit deduction guide.
+      FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
+    assert(FReturnType);
+    // Deduce template arguments of the deduction guide f from the RHS of
+    // the alias.
+    //
+    // C++ [over.match.class.deduct]p3: ...For each function or function
+    // template f in the guides of the template named by the
+    // simple-template-id of the defining-type-id, the template arguments
+    // of the return type of f are deduced from the defining-type-id of A
+    // according to the process in [temp.deduct.type] with the exception
+    // that deduction does not fail if not all template arguments are
+    // deduced.
+    //
+    //
+    //  template<typename X, typename Y>
+    //  f(X, Y) -> f<Y, X>;
+    //
+    //  template<typename U>
+    //  using alias = f<int, U>;
+    //
+    // The RHS of alias is f<int, U>, we deduced the template arguments of
+    // the return type of the deduction guide from it: Y->int, X->U
+    sema::TemplateDeductionInfo TDeduceInfo(Loc);
+    // Must initialize n elements, this is required by DeduceTemplateArguments.
+    SmallVector<DeducedTemplateArgument> DeduceResults(
+        F->getTemplateParameters()->size());
+    // FIXME: DeduceTemplateArguments stops immediately at the first
+    // non-deducible template parameter, extend it to continue performing
+    // deduction for rest of parameters.
+    SemaRef.DeduceTemplateArguments(
+        F->getTemplateParameters(), FReturnType->template_arguments(),
+        AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
+        /*NumberOfArgumentsMustMatch=*/false);
+
+    SmallVector<TemplateArgument> DeducedArgs;
+    SmallVector<unsigned> NonDeducedTemplateParamsInFIndex;
+    // !!NOTE: DeduceResults respects the sequence of template parameters of
+    // the deduction guide f.
+    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
+      if (const auto &D = DeduceResults[Index]; !D.isNull()) // Deduced
+        DeducedArgs.push_back(D);
+      else
+        NonDeducedTemplateParamsInFIndex.push_back(Index);
+    }
+    auto DeducedAliasTemplateParams =
+        FindAppearedTemplateParamsInAlias(DeducedArgs, AliasTemplate);
+    // All template arguments null by default.
+    SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
+        F->getTemplateParameters()->size());
+
+    Sema::InstantiatingTemplate BuildingDeductionGuides(
+        SemaRef, AliasTemplate->getLocation(), F,
+        Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{});
+    if (BuildingDeductionGuides.isInvalid())
+      return;
+    LocalInstantiationScope Scope(SemaRef);
+
+    // Create a template parameter list for the synthesized deduction guide 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 *> FPrimeTemplateParams;
+    // Store template arguments that refer to the newly-created template
+    // parameters, used for building `TemplateArgsForBuildingFPrime`.
+    SmallVector<TemplateArgument, 16> TransformedDeducedAliasArgs(
+        AliasTemplate->getTemplateParameters()->size());
+    auto TransformTemplateParameter =
+        [&SemaRef](DeclContext *DC, NamedDecl *TemplateParam,
+                   MultiLevelTemplateArgumentList &Args,
+                   unsigned NewIndex) -> NamedDecl * {
+      if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
+        return transformTemplateTypeParam(SemaRef, DC, TTP, Args,
+                                          TTP->getDepth(), NewIndex);
+      if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
+        return transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex,
+                                      TTP->getDepth());
+      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
+        return transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex,
+                                      NTTP->getDepth());
+      return nullptr;
+    };
+
+    for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams) {
+      auto *TP = AliasTemplate->getTemplateParameters()->getParam(
+          AliasTemplateParamIdx);
+      // Rebuild any internal references to earlier parameters and reindex as
+      // we go.
+      MultiLevelTemplateArgumentList Args;
+      Args.setKind(TemplateSubstitutionKind::Rewrite);
+      Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
+      NamedDecl *NewParam =
+          TransformTemplateParameter(AliasTemplate->getDeclContext(), TP, Args,
+                                     /*NewIndex*/ FPrimeTemplateParams.size());
+      FPrimeTemplateParams.push_back(NewParam);
+
+      auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
+          Context.getInjectedTemplateArg(NewParam));
+      TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
+    }
+    //   ...followed by the template parameters of f that were not deduced
+    //   (including their default template arguments)
+    for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
+      auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
+      MultiLevelTemplateArgumentList Args;
+      Args.setKind(TemplateSubstitutionKind::Rewrite);
+      // We take a shortcut here, it is ok to reuse the
+      // TemplateArgsForBuildingFPrime.
+      Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
+      NamedDecl *NewParam = TransformTemplateParameter(
+          F->getDeclContext(), TP, Args, FPrimeTemplateParams.size());
+      FPrimeTemplateParams.push_back(NewParam);
+
+      assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
+             "InstantiatedArgs must be null before setting");
+      TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
+          Context.getCanonicalTemplateArgument(
+              Context.getInjectedTemplateArg(NewParam));
+    }
+    // FIXME: support require clause.
+    auto *FPrimeTemplateParamList = TemplateParameterList::Create(
+        Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
+        AliasTemplate->getTemplateParameters()->getLAngleLoc(),
+        FPrimeTemplateParams,
+        AliasTemplate->getTemplateParameters()->getRAngleLoc(),
+        /*RequiresClause=*/nullptr);
+
+    // To form a deduction guide f' from f, we leverage clang's instantiation
+    // mechanism, we construct a template argument list where the template
+    // arguments refer to the newly-created template parameters of f', and
+    // then apply instantiation on this template argument list to instantiate
+    // f, this ensures all template parameter occurrences are updated
+    // correctly.
+    //
+    // The template argument list is formed from the `DeducedArgs`, two parts:
+    //  1) appeared template parameters of alias: transfrom the deduced
+    //  template argument 2) non-deduced template parameters of f: rebuild a
+    //  template argument
+    //
+    // 2) has been built already (when rebuilding the new template
+    // parameters), we now perform 1).
+    MultiLevelTemplateArgumentList Args;
+    Args.setKind(TemplateSubstitutionKind::Rewrite);
+    Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
+    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
+      const auto &D = DeduceResults[Index];
+      if (D.isNull()) {
+        // 2): Non-deduced template parameter has been built already.
+        assert(!TemplateArgsForBuildingFPrime[Index].isNull());
+        continue;
+      }
+      TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
+          D, QualType(), SourceLocation{});
+      TemplateArgumentLoc Output;
+      if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
+        assert(TemplateArgsForBuildingFPrime[Index].isNull() &&
+               "InstantiatedArgs must be null before setting");
+        TemplateArgsForBuildingFPrime[Index] = (Output.getArgument());
+      }
+    }
+
+    auto *TemplateArgListForBuildingFPrime = TemplateArgumentList::CreateCopy(
+        Context, TemplateArgsForBuildingFPrime);
+    // Form the f' by substituting the template arguments into f.
+    if (auto *FPrime = SemaRef.InstantiateFunctionDeclaration(
+            F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(),
+            Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
+      auto *GG = dyn_cast<CXXDeductionGuideDecl>(FPrime);
+      // FIXME: implement the assoicated constraint per C++
+      // [over.match.class.deduct]p3.3:
+      //    The associated constraints ([temp.constr.decl]) are the
+      //    conjunction of the associated constraints of g and a
+      //    constraint that is satisfied if and only if the arguments
+      //    of A are deducible (see below) from the return type.
+      buildDeductionGuide(SemaRef, AliasTemplate, FPrimeTemplateParamList,
+                          GG->getCorrespondingConstructor(),
+                          GG->getExplicitSpecifier(), GG->getTypeSourceInfo(),
+                          AliasTemplate->getBeginLoc(),
+                          AliasTemplate->getLocation(),
+                          AliasTemplate->getEndLoc(), F->isImplicit());
+    }
+  }
 }
 
+} // namespace
+
 FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList(
     TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes,
     SourceLocation Loc) {
@@ -2571,6 +3017,10 @@ FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList(
 
 void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
                                           SourceLocation Loc) {
+  if (auto* AliasTemplate = llvm::dyn_cast<TypeAliasTemplateDecl>(Template)) {
+      DeclareImplicitDeductionGuidesForTypeAlias(*this, AliasTemplate, Loc);
+     return;
+  } 
   if (CXXRecordDecl *DefRecord =
           cast<CXXRecordDecl>(Template->getTemplatedDecl())->getDefinition()) {
     if (TemplateDecl *DescribedTemplate = DefRecord->getDescribedClassTemplate())
@@ -2586,12 +3036,8 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   if (!isCompleteType(Loc, Transform.DeducedType))
     return;
 
-  // Check whether we've already declared deduction guides for this template.
-  // FIXME: Consider storing a flag on the template to indicate this.
-  auto Existing = DC->lookup(Transform.DeductionGuideName);
-  for (auto *D : Existing)
-    if (D->isImplicit())
-      return;
+  if (hasDeclaredDeductionGuides(Transform.DeductionGuideName, DC))
+    return;
 
   // In case we were expanding a pack when we attempted to declare deduction
   // guides, turn off pack expansion for everything we're about to do.
@@ -5242,6 +5688,15 @@ bool Sema::CheckTemplateTypeArgument(
     [[fallthrough]];
   }
   default: {
+    // We allow instantiateing a template with template argument packs when
+    // building deduction guides.
+    if (Arg.getKind() == TemplateArgument::Pack &&
+        CodeSynthesisContexts.back().Kind ==
+            Sema::CodeSynthesisContext::BuildingDeductionGuides) {
+      SugaredConverted.push_back(Arg);
+      CanonicalConverted.push_back(Arg);
+      return false;
+    }
     // We have a template type parameter but the template argument
     // is not a type.
     SourceRange SR = AL.getSourceRange();
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 4024d3708ab311..d7e3904ddc11c5 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2531,7 +2531,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
   return TemplateDeductionResult::Success;
 }
 
-Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
+TemplateDeductionResult Sema::DeduceTemplateArguments(
     TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
     ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 32b5f3756307bf..e03b3530119704 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1450,20 +1450,54 @@ namespace {
     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 TST = SemaRef.Context.getTemplateSpecializationType(
-              ICT->getTemplateName(), TemplateArgs.getOutermost());
-          TLB.pushTrivial(SemaRef.Context, TST, TL.getNameLoc());
-          return TST;
+          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:
+        // Iterially rewrite the template argument pack, instead of unpacking
+        // it.
+        assert(
+            SemaRef.CodeSynthesisContexts.back().Kind ==
+                Sema::CodeSynthesisContext::BuildingDeductionGuides &&
+            "Transforming a template argument pack is only allowed in building "
+            "deduction guide");
+        for (auto &pack : Arg.getPackAsArray()) {
+          TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
+              pack, QualType(), SourceLocation{});
+          TemplateArgumentLoc Output;
+          if (!SemaRef.SubstTemplateArgument(Input, TemplateArgs, Output))
+            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,
@@ -4157,6 +4191,15 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
   return Instantiator.TransformStmt(S);
 }
 
+bool Sema::SubstTemplateArgument(
+    const TemplateArgumentLoc &Input,
+    const MultiLevelTemplateArgumentList &TemplateArgs,
+    TemplateArgumentLoc &Output) {
+  TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+                                    DeclarationName());
+  return Instantiator.TransformTemplateArgument(Input, Output);
+}
+
 bool Sema::SubstTemplateArguments(
     ArrayRef<TemplateArgumentLoc> Args,
     const MultiLevelTemplateArgumentList &TemplateArgs,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5e17abb92941e1..1b45327f718ed7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2219,7 +2219,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
       FunctionTemplate->setInstantiatedFromMemberTemplate(
                                            D->getDescribedFunctionTemplate());
     }
-  } else if (FunctionTemplate) {
+  } else if (FunctionTemplate && SemaRef.CodeSynthesisContexts.back().Kind !=
+                   Sema::CodeSynthesisContext::BuildingDeductionGuides) {
     // Record this function template specialization.
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
     Function->setFunctionTemplateSpecialization(FunctionTemplate,
@@ -6286,13 +6287,13 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
           CXXRecordDecl *SubstRecord = T->getAsCXXRecordDecl();
 
           if (!SubstRecord) {
-            // The template id T is a TemplateSpecializationType when performing
-            // a substitution for a deduction guide,
+            // The T can be a dependent TemplateSpecializationType when
+            // performing a substitution for building a deduction guide,
             assert(CodeSynthesisContexts.back().Kind ==
                    CodeSynthesisContext::BuildingDeductionGuides);
             // Return a nullptr as a sentinel value, we handle it properly in
             // the TemplateInstantiator::TransformInjectedClassNameType
-            // override.
+            // override, which we transform it to a TemplateSpecializationType.
             return nullptr;
           }
           // Check that this template-id names the primary template and not a
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 6e5ae123a6ba2c..36687dd64fc807 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4776,6 +4776,14 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
     TemplateArgumentLoc In = *First;
 
     if (In.getArgument().getKind() == TemplateArgument::Pack) {
+      // When building the deduction guides, we rewrite the argument packs
+      // instead of unpacking.
+      if (getSema().CodeSynthesisContexts.back().Kind ==
+          Sema::CodeSynthesisContext::BuildingDeductionGuides) {
+        if (getDerived().TransformTemplateArgument(In, Out, Uneval))
+          return true;
+        continue;
+      }
       // Unpack argument packs, which we translate them into separate
       // arguments.
       // FIXME: We could do much better if we could guarantee that the
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 5a5691e48fd17e..169061ff556f4b 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -1,10 +1,8 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-c++11-narrowing -Wno-literal-conversion -std=c++20 -verify %s
-
+// expected-no-diagnostics
 namespace test1 {
 template <typename T>
-struct Foo {
-  T t;
-};
+struct Foo { T t; };
 template <typename U>
 using Bar = Foo<U>;
 
@@ -41,6 +39,7 @@ vector v(0, 0);
 }  // namespace test3
 
 namespace test4 {
+// Explicit deduction guide.
 template <class T>
 struct X {
   T t;
@@ -54,28 +53,28 @@ template <class T>
 using AX = X<T>;
 
 AX s = {1};
-static_assert(__is_same(decltype(s.t), double));
+static_assert(__is_same(decltype(s.t), double)); // explicit one is picked.
 }  // namespace test4
 
 namespace test5 {
 template <int B>
 struct Foo {};
-
+// Template parameter pack
 template <int... C>
 using AF = Foo<1>;
 auto a = AF{};
 }  // namespace test5
 
 namespace test6 {
+// non-type template argument.
 template <typename T, bool B = false>
 struct Foo {
   Foo(T);
 };
-// non-type template argument.
 template <typename T>
 using AF = Foo<T, 1>;
 
-AF b{0};  //
+AF b{0}; 
 }  // namespace test6
 
 namespace test7 {
@@ -83,13 +82,12 @@ template <typename T>
 struct Foo {
   Foo(T);
 };
-
+// using alias chain.
 template <typename U>
 using AF1 = Foo<U>;
 template <typename K>
-using AF2 = AF1<K>;  // expected-note {{template is declared here}}
-// FIXME: support this case.
-AF2 b = 1;  // expected-error {{alias template 'AF2' requires template arguments; argument deduction only allowed for class templates}}
+using AF2 = AF1<K>;  
+AF2 b = 1;  
 }  // namespace test7
 
 namespace test8 {
@@ -113,7 +111,7 @@ struct Foo {
 template <typename X, int Y>
 using Bar = Foo<X, sizeof(X)>;
 
-// FIXME: should we reject this case? GCC rejects it, MSVC accepts it.
+// FIXME: we should reject this case? GCC rejects it, MSVC accepts it.
 Bar s = {{1}};
 }  // namespace test9
 
@@ -131,3 +129,58 @@ template <typename K>
 using A = Foo<K>;
 A a(2);  // Foo<int*>
 }  // namespace test10
+
+namespace test11 {
+struct A {};
+template<class T> struct Foo { T c; };
+// FIXME: we have an out-bound crash on instantating the synthesized deduction guide `auto (B<C2>) -> B<C2>`
+// where C2 should be at the index 0, however, it is still refers the original one where index is 1
+template<class X, class Y=A> using AFoo = Foo<Y>;
+
+AFoo s = {1};
+} // namespace test11
+
+namespace test12 {
+// no crash on null access attribute
+template<typename X>
+struct Foo {
+  template<typename K>
+  struct Bar { 
+    Bar(K);
+  };
+
+  template<typename U>
+  using ABar = Bar<U>;
+  void test() { ABar k = 2; }
+};
+
+void func(Foo<int> s) {
+  s.test();
+}
+} // namespace test12
+
+namespace test13 {
+template <typename... Ts>
+struct Foo {
+  Foo(Ts...);
+};
+
+template <typename... Ts>
+using AFoo = Foo<Ts...>;
+
+auto b = AFoo{};
+} // namespace test13
+
+namespace test14 {
+template <class T> struct Foo { Foo(T); };
+
+template<class V> using AFoo = Foo<V *>;
+template<typename> concept False = false;
+template<False W> using BFoo = AFoo<W>;
+int i = 0;
+AFoo a1(&i); // OK, deduce Foo<int *>
+
+// FIXME: we should reject this case as the W is not deduced from the deduced
+// type Foo<int *>.
+BFoo b2(&i); 
+} // namespace test14

>From 59e12637bb299b8ae453578b31519a3f18a3b83e Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Fri, 23 Feb 2024 15:02:02 +0100
Subject: [PATCH 03/11] Address review comments, and add more tests.

---
 clang/lib/Sema/SemaInit.cpp                  |  2 +
 clang/lib/Sema/SemaTemplate.cpp              | 28 ++++++++------
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 40 +++++++++++++++++++-
 3 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 6d288d74761319..e72e40fa019b07 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10621,6 +10621,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
         if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
                 RT->getAsCXXRecordDecl()))
           Template = CTSD->getSpecializedTemplate();
+      } else {
+        assert(false && "unexpected underlying type of alias template");
       }
     }
   }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index bbecb5e70804e0..0d0f785baf97ba 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -12,7 +12,6 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
@@ -40,7 +39,6 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Casting.h"
 
 #include <iterator>
 #include <optional>
@@ -2716,9 +2714,12 @@ FindAppearedTemplateParamsInAlias(ArrayRef<TemplateArgument> DeducedArgs,
   return Results;
 }
 
-bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext* DC) {
+bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
   // Check whether we've already declared deduction guides for this template.
   // FIXME: Consider storing a flag on the template to indicate this.
+  assert(Name.getNameKind() ==
+             DeclarationName::NameKind::CXXDeductionGuideName &&
+         "name must be a deduction guide name");
   auto Existing = DC->lookup(Name);
   for (auto *D : Existing)
     if (D->isImplicit())
@@ -2737,14 +2738,14 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
           Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
           AliasTemplate->getDeclContext()))
     return;
-  // Unrap the sugar ElaboratedType.
+  // Unwrap the sugared ElaboratedType.
   auto RhsType = AliasTemplate->getTemplatedDecl()
                      ->getUnderlyingType()
                      .getSingleStepDesugaredType(Context);
   TemplateDecl *Template = nullptr;
   llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
   if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
-    // TemplateName in TEST can be a TypeAliasTemplateDecl if
+    // TemplateName in TST can be a TypeAliasTemplateDecl if
     // the right hand side of the alias is also a type alias, e.g.
     //
     // template<typename T>
@@ -2787,7 +2788,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
     else if (const auto *ET = RType->getAs<ElaboratedType>())
       // explicit deduction guide.
       FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
-    assert(FReturnType);
+    assert(FReturnType && "expected to see a return type");
     // Deduce template arguments of the deduction guide f from the RHS of
     // the alias.
     //
@@ -2812,9 +2813,12 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
     // Must initialize n elements, this is required by DeduceTemplateArguments.
     SmallVector<DeducedTemplateArgument> DeduceResults(
         F->getTemplateParameters()->size());
+
     // FIXME: DeduceTemplateArguments stops immediately at the first
-    // non-deducible template parameter, extend it to continue performing
-    // deduction for rest of parameters.
+    // non-deducible template argument. However, this doesn't seem to casue
+    // issues for practice cases, we probably need to extend it to continue
+    // performing deduction for rest of arguments to align with the C++
+    // standard.
     SemaRef.DeduceTemplateArguments(
         F->getTemplateParameters(), FReturnType->template_arguments(),
         AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
@@ -2902,7 +2906,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
       FPrimeTemplateParams.push_back(NewParam);
 
       assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
-             "InstantiatedArgs must be null before setting");
+             "The argument must be null before setting");
       TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
           Context.getCanonicalTemplateArgument(
               Context.getInjectedTemplateArg(NewParam));
@@ -2936,7 +2940,9 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
       const auto &D = DeduceResults[Index];
       if (D.isNull()) {
         // 2): Non-deduced template parameter has been built already.
-        assert(!TemplateArgsForBuildingFPrime[Index].isNull());
+        assert(!TemplateArgsForBuildingFPrime[Index].isNull() &&
+               "template arguments for non-deduced template parameters should "
+               "be been set!");
         continue;
       }
       TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
@@ -2956,7 +2962,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
             F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(),
             Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
       auto *GG = dyn_cast<CXXDeductionGuideDecl>(FPrime);
-      // FIXME: implement the assoicated constraint per C++
+      // FIXME: implement the associated constraint per C++
       // [over.match.class.deduct]p3.3:
       //    The associated constraints ([temp.constr.decl]) are the
       //    conjunction of the associated constraints of g and a
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 169061ff556f4b..820ceb83100273 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-c++11-narrowing -Wno-literal-conversion -std=c++20 -verify %s
-// expected-no-diagnostics
+
 namespace test1 {
 template <typename T>
 struct Foo { T t; };
@@ -172,6 +172,22 @@ auto b = AFoo{};
 } // namespace test13
 
 namespace test14 {
+template<typename T>
+concept IsInt = __is_same(decltype(T()), int);
+
+template<IsInt T, int N>
+struct Foo {
+  Foo(T const (&)[N]);
+};
+
+template <int K>
+using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
+// expected-note at -1 {{candidate template ignored: could not match}}
+double abc[3];
+Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
+} // namespace test14
+
+namespace test15 {
 template <class T> struct Foo { Foo(T); };
 
 template<class V> using AFoo = Foo<V *>;
@@ -183,4 +199,24 @@ AFoo a1(&i); // OK, deduce Foo<int *>
 // FIXME: we should reject this case as the W is not deduced from the deduced
 // type Foo<int *>.
 BFoo b2(&i); 
-} // namespace test14
+} // namespace test15
+
+namespace test16 {
+struct X { X(int); X(const X&); };
+template<class T>
+struct Foo {
+  T t;
+  Foo(T t) : t(t) {}
+};
+template<class T>
+using AFoo = Foo<T>;
+int i = 0;
+AFoo s{i};
+static_assert(__is_same(decltype(s.t), int));
+
+// explicit deduction guide.
+Foo(int) -> Foo<X>;
+AFoo s2{i};
+// FIXME: the type should be X because of the above explicit deduction guide.
+static_assert(__is_same(decltype(s2.t), int));
+} // namespace test16

>From 4d00c17d3f95624730672f708fadf23eac266afc Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Fri, 23 Feb 2024 15:18:37 +0100
Subject: [PATCH 04/11] Bailout when SubstTemplateArgument fails.

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index e03b3530119704..37306fbf5b1579 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1486,8 +1486,9 @@ namespace {
           TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
               pack, QualType(), SourceLocation{});
           TemplateArgumentLoc Output;
-          if (!SemaRef.SubstTemplateArgument(Input, TemplateArgs, Output))
-            TArgs.push_back(Output.getArgument());
+          if (SemaRef.SubstTemplateArgument(Input, TemplateArgs, Output))
+            return true; // fails
+          TArgs.push_back(Output.getArgument());
         }
         Output = SemaRef.getTrivialTemplateArgumentLoc(
             TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)),

>From a53b93f693786d7333b7a605d09d6501932d11da Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Mon, 26 Feb 2024 19:32:52 +0100
Subject: [PATCH 05/11] Add assertion on unhandled RHS type of the type alias.

---
 clang/lib/Sema/SemaTemplate.cpp | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0d0f785baf97ba..23c8ae4605b23f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2745,15 +2745,9 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
   TemplateDecl *Template = nullptr;
   llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
   if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
-    // TemplateName in TST can be a TypeAliasTemplateDecl if
-    // the right hand side of the alias is also a type alias, e.g.
-    //
-    // template<typename T>
-    // using AliasFoo1 = Foo<T>;  // Foo<T> is a class template
-    // specialization
-    //
-    // template<typename T>
-    // using AliasFoo2 = AliasFoo1<T>; // AliasFoo1<T> is a type alias
+    // Cases where the RHS of the alias is dependent. e.g.
+    //   template<typename T>
+    //   using AliasFoo1 = Foo<T>; // a class/type alias template specialization
     Template = TST->getTemplateName().getAsTemplateDecl();
     AliasRhsTemplateArgs = TST->template_arguments();
   } else if (const auto *RT = RhsType->getAs<RecordType>()) {
@@ -2765,6 +2759,8 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
       Template = CTSD->getSpecializedTemplate();
       AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray();
     }
+  } else {
+    assert(false && "unhandled RHS type of the alias");
   }
   if (!Template)
     return;

>From 2a32997d2b7758b9df964870c3ab8b8722df6cbf Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Tue, 27 Feb 2024 20:23:16 +0100
Subject: [PATCH 06/11] Address review comments:

- simplify the if
- add a release note
---
 clang/docs/ReleaseNotes.rst     | 4 ++++
 clang/lib/Sema/SemaInit.cpp     | 3 +--
 clang/lib/Sema/SemaTemplate.cpp | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 16f79a349c20c8..8ee6a309ab585f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -96,6 +96,10 @@ C++20 Feature Support
   behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
   (`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).
 
+- Initial support for class template argument deduciton (CTAD) for type alias
+  templates.
+  (`#54051 https://github.com/llvm/llvm-project/issues/54051`_).
+
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e72e40fa019b07..59cb741b289c21 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10604,8 +10604,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   TemplateDecl* LookupTemplateDecl = Template;
   if (!Template && getLangOpts().CPlusPlus20) { // type alias template
     if (auto *AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
-            TemplateName.getAsTemplateDecl());
-        AliasTemplate) {
+            TemplateName.getAsTemplateDecl())) {
       LookupTemplateDecl = AliasTemplate;
       auto UnderlyingType = AliasTemplate->getTemplatedDecl()
                                 ->getUnderlyingType()
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 23c8ae4605b23f..42844a97d05e3c 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2318,7 +2318,7 @@ transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC,
           : std::nullopt);
   if (const auto *TC = TTP->getTypeConstraint())
     SemaRef.SubstTypeConstraint(NewTTP, TC, Args,
-                                /*EvaluateConstraint*/ true);
+                                /*EvaluateConstraint=*/true);
   if (TTP->hasDefaultArgument()) {
     TypeSourceInfo *InstantiatedDefaultArg =
         SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,

>From cf60e5fd25251f44bd245919c79c58db7162ea01 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 28 Feb 2024 19:04:43 +0100
Subject: [PATCH 07/11] - add a C++20-compat diagnostic warning - add more
 tests

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td   |  5 +++++
 clang/lib/Sema/SemaInit.cpp                        | 11 +++++++----
 clang/test/SemaCXX/cxx17-compat.cpp                | 11 +++++++++++
 .../cxx1z-class-template-argument-deduction.cpp    |  6 +++---
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp       | 14 ++++++++++++--
 5 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fb44495199ee56..9e8bb555458964 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8180,6 +8180,11 @@ let CategoryName = "Lambda Issue" in {
   def warn_cxx17_compat_lambda_def_ctor_assign : Warning<
     "%select{default construction|assignment}0 of lambda is incompatible with "
     "C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
+
+  // C++20 class template argument deduction for alias templates.
+  def warn_cxx17_compat_ctad_for_alias_templates : Warning<
+  "class template argument deduction for alias templates is incompatible with "
+  "C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
 }
 
 def err_return_in_captured_stmt : Error<
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 59cb741b289c21..6a0d1c62f1c0f8 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10602,13 +10602,18 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   auto *Template =
       dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
   TemplateDecl* LookupTemplateDecl = Template;
-  if (!Template && getLangOpts().CPlusPlus20) { // type alias template
+  if (!Template) {
     if (auto *AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
             TemplateName.getAsTemplateDecl())) {
+      Diag(Kind.getLocation(),
+           diag::warn_cxx17_compat_ctad_for_alias_templates);
       LookupTemplateDecl = AliasTemplate;
       auto UnderlyingType = AliasTemplate->getTemplatedDecl()
                                 ->getUnderlyingType()
-                                .getDesugaredType(Context);
+                                .getCanonicalType();
+      // C++ [over.match.class.deduct#3]: ..., the defining-type-id of A must be
+      // of the form
+      //   [typename] [nested-name-specifier] [template] simple-template-id
       if (const auto *TST =
               UnderlyingType->getAs<TemplateSpecializationType>()) {
         Template = dyn_cast_or_null<ClassTemplateDecl>(
@@ -10620,8 +10625,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
         if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
                 RT->getAsCXXRecordDecl()))
           Template = CTSD->getSpecializedTemplate();
-      } else {
-        assert(false && "unexpected underlying type of alias template");
       }
     }
   }
diff --git a/clang/test/SemaCXX/cxx17-compat.cpp b/clang/test/SemaCXX/cxx17-compat.cpp
index d53d80f0d42ca9..54ea3384022d42 100644
--- a/clang/test/SemaCXX/cxx17-compat.cpp
+++ b/clang/test/SemaCXX/cxx17-compat.cpp
@@ -131,3 +131,14 @@ namespace NTTP {
   // expected-warning at -4 {{non-type template parameter of type 'A' is incompatible with C++ standards before C++20}}
 #endif
 }
+
+namespace CTADForAliasTemplate {
+template<typename T> struct A { A(T); };
+template<typename T> using B = A<T>;
+B b = {1};
+#if __cplusplus <= 201703L
+  // FIXME: diagnose as well
+#else
+  // expected-warning at -4 {{class template argument deduction for alias templates is incompatible with C++ standards before C++20}}
+#endif
+}
diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 33ed4295c2e48c..2f067ea53a5029 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -101,13 +101,13 @@ namespace dependent {
   struct B {
     template<typename T> struct X { X(T); };
     X(int) -> X<int>;
-    template<typename T> using Y = X<T>; // expected-note {{template}}
+    template<typename T> using Y = X<T>;
   };
   template<typename T> void f() {
     typename T::X tx = 0;
-    typename T::Y ty = 0; // expected-error {{alias template 'Y' requires template arguments; argument deduction only allowed for class templates}}
+    typename T::Y ty = 0;
   }
-  template void f<B>(); // expected-note {{in instantiation of}}
+  template void f<B>();
 
   template<typename T> struct C { C(T); };
   template<typename T> C(T) -> C<T>;
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 820ceb83100273..794496ed418489 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -133,8 +133,6 @@ A a(2);  // Foo<int*>
 namespace test11 {
 struct A {};
 template<class T> struct Foo { T c; };
-// FIXME: we have an out-bound crash on instantating the synthesized deduction guide `auto (B<C2>) -> B<C2>`
-// where C2 should be at the index 0, however, it is still refers the original one where index is 1
 template<class X, class Y=A> using AFoo = Foo<Y>;
 
 AFoo s = {1};
@@ -220,3 +218,15 @@ AFoo s2{i};
 // FIXME: the type should be X because of the above explicit deduction guide.
 static_assert(__is_same(decltype(s2.t), int));
 } // namespace test16
+
+namespace test17 {
+template <typename T>
+struct Foo { T t; };
+
+// CTAD for alias templates only works for the RHS of the alias of form of
+//  [typename] [nested-name-specifier] [template] simple-template-id
+template <typename U>
+using AFoo = Foo<U>*; // expected-note {{template is declared here}}
+
+AFoo s = {1}; // expected-error {{alias template 'AFoo' requires template arguments; argument deduction only allowed for}}
+} // namespace test17

>From f91c4daff6e804a3f83dac6d22608a2d202a96b3 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 6 Mar 2024 09:44:48 +0100
Subject: [PATCH 08/11] Rename FindAppearedTemplateParamsInAlias =>
 TemplateParamsReferencedInTemplateArgumentList

---
 clang/lib/Sema/SemaTemplate.cpp | 35 ++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 42844a97d05e3c..dcd0b5d07d76bc 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2671,19 +2671,18 @@ struct ConvertConstructorToDeductionGuideTransform {
   }
 };
 
-// Find all template parameters of the AliasTemplate that appear in the
-// given DeducedArgs.
-SmallVector<unsigned>
-FindAppearedTemplateParamsInAlias(ArrayRef<TemplateArgument> DeducedArgs,
-                                  TypeAliasTemplateDecl *AliasTemplate) {
+// Find all template parameters that appear in the given DeducedArgs.
+// Return the indices of the template parameters in the TemplateParams.
+SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
+    ArrayRef<NamedDecl *> TemplateParams,
+    ArrayRef<TemplateArgument> DeducedArgs) {
   struct FindAppearedTemplateParams
       : public RecursiveASTVisitor<FindAppearedTemplateParams> {
-    llvm::DenseSet<NamedDecl *> TemplateParamsInAlias;
+    llvm::DenseSet<NamedDecl *> TemplateParams;
     llvm::DenseSet<const NamedDecl *> AppearedTemplateParams;
 
-    FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParamsInAlias)
-        : TemplateParamsInAlias(TemplateParamsInAlias.begin(),
-                                TemplateParamsInAlias.end()) {}
+    FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParams)
+        : TemplateParams(TemplateParams.begin(), TemplateParams.end()) {}
 
     bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
       TTP->getIndex();
@@ -2696,19 +2695,17 @@ FindAppearedTemplateParamsInAlias(ArrayRef<TemplateArgument> DeducedArgs,
     }
 
     void MarkAppeared(NamedDecl *ND) {
-      if (TemplateParamsInAlias.contains(ND))
+      if (TemplateParams.contains(ND))
         AppearedTemplateParams.insert(ND);
     }
   };
-  ArrayRef<NamedDecl *> TemplateParamsInAlias =
-      AliasTemplate->getTemplateParameters()->asArray();
-  FindAppearedTemplateParams MarkAppeared(TemplateParamsInAlias);
+  FindAppearedTemplateParams MarkAppeared(TemplateParams);
   MarkAppeared.TraverseTemplateArguments(DeducedArgs);
 
   SmallVector<unsigned> Results;
-  for (unsigned Index = 0; Index < TemplateParamsInAlias.size(); ++Index) {
+  for (unsigned Index = 0; Index < TemplateParams.size(); ++Index) {
     if (MarkAppeared.AppearedTemplateParams.contains(
-            TemplateParamsInAlias[Index]))
+            TemplateParams[Index]))
       Results.push_back(Index);
   }
   return Results;
@@ -2831,7 +2828,8 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
         NonDeducedTemplateParamsInFIndex.push_back(Index);
     }
     auto DeducedAliasTemplateParams =
-        FindAppearedTemplateParamsInAlias(DeducedArgs, AliasTemplate);
+        TemplateParamsReferencedInTemplateArgumentList(
+            AliasTemplate->getTemplateParameters()->asArray(), DeducedArgs);
     // All template arguments null by default.
     SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
         F->getTemplateParameters()->size());
@@ -2924,8 +2922,9 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
     //
     // The template argument list is formed from the `DeducedArgs`, two parts:
     //  1) appeared template parameters of alias: transfrom the deduced
-    //  template argument 2) non-deduced template parameters of f: rebuild a
-    //  template argument
+    //  template argument;
+    //  2) non-deduced template parameters of f: rebuild a
+    //  template argument;
     //
     // 2) has been built already (when rebuilding the new template
     // parameters), we now perform 1).

>From bae51e2140745bf4893fb703cf50a09e42bdcf25 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 6 Mar 2024 11:22:33 +0100
Subject: [PATCH 09/11] Address review comments.

---
 clang/docs/ReleaseNotes.rst                   |  2 +-
 clang/lib/Sema/SemaTemplate.cpp               | 29 +++++++++----------
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  2 +-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  4 +--
 4 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8ee6a309ab585f..022a9cd0052b4e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -97,7 +97,7 @@ C++20 Feature Support
   (`#79240 <https://github.com/llvm/llvm-project/issues/79240>`_).
 
 - Initial support for class template argument deduciton (CTAD) for type alias
-  templates.
+  templates (`P1814R0 <https://wg21.link/p1814r0>`_).
   (`#54051 https://github.com/llvm/llvm-project/issues/54051`_).
 
 C++23 Feature Support
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dcd0b5d07d76bc..33afb2fea6a2af 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2676,12 +2676,12 @@ struct ConvertConstructorToDeductionGuideTransform {
 SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
     ArrayRef<NamedDecl *> TemplateParams,
     ArrayRef<TemplateArgument> DeducedArgs) {
-  struct FindAppearedTemplateParams
-      : public RecursiveASTVisitor<FindAppearedTemplateParams> {
+  struct ReferenceFinder
+      : public RecursiveASTVisitor<ReferenceFinder> {
     llvm::DenseSet<NamedDecl *> TemplateParams;
-    llvm::DenseSet<const NamedDecl *> AppearedTemplateParams;
+    llvm::DenseSet<const NamedDecl *> ReferencedTemplateParams;
 
-    FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParams)
+    ReferenceFinder(ArrayRef<NamedDecl *> TemplateParams)
         : TemplateParams(TemplateParams.begin(), TemplateParams.end()) {}
 
     bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
@@ -2696,15 +2696,15 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
 
     void MarkAppeared(NamedDecl *ND) {
       if (TemplateParams.contains(ND))
-        AppearedTemplateParams.insert(ND);
+        ReferencedTemplateParams.insert(ND);
     }
   };
-  FindAppearedTemplateParams MarkAppeared(TemplateParams);
-  MarkAppeared.TraverseTemplateArguments(DeducedArgs);
+  ReferenceFinder Finder(TemplateParams);
+  Finder.TraverseTemplateArguments(DeducedArgs);
 
   SmallVector<unsigned> Results;
   for (unsigned Index = 0; Index < TemplateParams.size(); ++Index) {
-    if (MarkAppeared.AppearedTemplateParams.contains(
+    if (Finder.ReferencedTemplateParams.contains(
             TemplateParams[Index]))
       Results.push_back(Index);
   }
@@ -2905,7 +2905,12 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
           Context.getCanonicalTemplateArgument(
               Context.getInjectedTemplateArg(NewParam));
     }
-    // FIXME: support require clause.
+    // FIXME: implement the associated constraint per C++
+    // [over.match.class.deduct]p3.3:
+    //    The associated constraints ([temp.constr.decl]) are the
+    //    conjunction of the associated constraints of g and a
+    //    constraint that is satisfied if and only if the arguments
+    //    of A are deducible (see below) from the return type.
     auto *FPrimeTemplateParamList = TemplateParameterList::Create(
         Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
         AliasTemplate->getTemplateParameters()->getLAngleLoc(),
@@ -2957,12 +2962,6 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
             F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(),
             Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
       auto *GG = dyn_cast<CXXDeductionGuideDecl>(FPrime);
-      // FIXME: implement the associated constraint per C++
-      // [over.match.class.deduct]p3.3:
-      //    The associated constraints ([temp.constr.decl]) are the
-      //    conjunction of the associated constraints of g and a
-      //    constraint that is satisfied if and only if the arguments
-      //    of A are deducible (see below) from the return type.
       buildDeductionGuide(SemaRef, AliasTemplate, FPrimeTemplateParamList,
                           GG->getCorrespondingConstructor(),
                           GG->getExplicitSpecifier(), GG->getTypeSourceInfo(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 37306fbf5b1579..6fed47b51c8fbe 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1475,7 +1475,7 @@ namespace {
       std::vector<TemplateArgument> TArgs;
       switch (Arg.getKind()) {
       case TemplateArgument::Pack:
-        // Iterially rewrite the template argument pack, instead of unpacking
+        // Literally rewrite the template argument pack, instead of unpacking
         // it.
         assert(
             SemaRef.CodeSynthesisContexts.back().Kind ==
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1b45327f718ed7..c099c43f3a67af 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6287,8 +6287,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
           CXXRecordDecl *SubstRecord = T->getAsCXXRecordDecl();
 
           if (!SubstRecord) {
-            // The T can be a dependent TemplateSpecializationType when
-            // performing a substitution for building a deduction guide,
+            // T can be a dependent TemplateSpecializationType when performing a
+            // substitution for building a deduction guide.
             assert(CodeSynthesisContexts.back().Kind ==
                    CodeSynthesisContext::BuildingDeductionGuides);
             // Return a nullptr as a sentinel value, we handle it properly in

>From a36bc6039f6bf27e72682ad50258a1066a3ff27c Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 6 Mar 2024 12:01:15 +0100
Subject: [PATCH 10/11] Fix the link in release note.

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 022a9cd0052b4e..447bf885f97580 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -98,7 +98,7 @@ C++20 Feature Support
 
 - Initial support for class template argument deduciton (CTAD) for type alias
   templates (`P1814R0 <https://wg21.link/p1814r0>`_).
-  (`#54051 https://github.com/llvm/llvm-project/issues/54051`_).
+  (#GH54051).
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^

>From dc15d1f49f845702679eccc5a7c01619edd13218 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 6 Mar 2024 15:51:08 +0100
Subject: [PATCH 11/11] address comment.

---
 clang/lib/Sema/SemaTemplate.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 33afb2fea6a2af..7dfae0aef5a4f9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2676,12 +2676,12 @@ struct ConvertConstructorToDeductionGuideTransform {
 SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
     ArrayRef<NamedDecl *> TemplateParams,
     ArrayRef<TemplateArgument> DeducedArgs) {
-  struct ReferenceFinder
-      : public RecursiveASTVisitor<ReferenceFinder> {
+  struct TemplateParamsReferencedFinder
+      : public RecursiveASTVisitor<TemplateParamsReferencedFinder> {
     llvm::DenseSet<NamedDecl *> TemplateParams;
     llvm::DenseSet<const NamedDecl *> ReferencedTemplateParams;
 
-    ReferenceFinder(ArrayRef<NamedDecl *> TemplateParams)
+    TemplateParamsReferencedFinder(ArrayRef<NamedDecl *> TemplateParams)
         : TemplateParams(TemplateParams.begin(), TemplateParams.end()) {}
 
     bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
@@ -2699,7 +2699,7 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
         ReferencedTemplateParams.insert(ND);
     }
   };
-  ReferenceFinder Finder(TemplateParams);
+  TemplateParamsReferencedFinder Finder(TemplateParams);
   Finder.TraverseTemplateArguments(DeducedArgs);
 
   SmallVector<unsigned> Results;



More information about the cfe-commits mailing list