[clang] [clang] Implement P2582R1: CTAD from inherited constructors (PR #98788)

via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 10 15:59:37 PDT 2024


https://github.com/antangelo updated https://github.com/llvm/llvm-project/pull/98788

>From 3f0dfdfdbad3921da42be23fb0bbf1f1f00a42fb Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Sat, 1 Jun 2024 13:15:40 -0400
Subject: [PATCH 01/15] [clang] Implement P2582R1: CTAD from inherited
 constructors

---
 clang/docs/ReleaseNotes.rst                   |   2 +
 clang/include/clang/AST/DeclCXX.h             |  36 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   4 +
 clang/lib/AST/ASTImporter.cpp                 |   8 +-
 clang/lib/AST/DeclCXX.cpp                     |  10 +-
 clang/lib/Sema/SemaOverload.cpp               |  67 +++
 clang/lib/Sema/SemaTemplate.cpp               | 389 ++++++++++++++++--
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   3 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |   2 +
 clang/lib/Serialization/ASTWriterDecl.cpp     |   2 +
 .../SemaCXX/cxx23-ctad-inherited-ctors.cpp    | 260 ++++++++++++
 clang/unittests/AST/ASTImporterTest.cpp       |  43 ++
 clang/www/cxx_status.html                     |   2 +-
 13 files changed, 786 insertions(+), 42 deletions(-)
 create mode 100644 clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5dc0f8b7e0bbb8..b6924f61814fb9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -263,6 +263,8 @@ C++23 Feature Support
 - Implemented `P2797R0: Static and explicit object member functions with the same parameter-type-lists <https://wg21.link/P2797R0>`_.
   This completes the support for "deducing this".
 
+- Implemented `P2582R1: Wording for class template argument deduction from inherited constructors <https://wg21.link/P2582R1>`_.
+
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d8..c8e74f32b2ccbc 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1957,10 +1957,14 @@ class CXXDeductionGuideDecl : public FunctionDecl {
                         ExplicitSpecifier ES,
                         const DeclarationNameInfo &NameInfo, QualType T,
                         TypeSourceInfo *TInfo, SourceLocation EndLocation,
-                        CXXConstructorDecl *Ctor, DeductionCandidate Kind)
+                        CXXConstructorDecl *Ctor, DeductionCandidate Kind,
+                        CXXDeductionGuideDecl *GeneratedFrom,
+                        bool IsGeneratedFromInheritedConstructor)
       : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
                      SC_None, false, false, ConstexprSpecKind::Unspecified),
-        Ctor(Ctor), ExplicitSpec(ES) {
+        Ctor(Ctor), ExplicitSpec(ES),
+        SourceDeductionGuide(GeneratedFrom,
+                             IsGeneratedFromInheritedConstructor) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
     setDeductionCandidateKind(Kind);
@@ -1968,6 +1972,11 @@ class CXXDeductionGuideDecl : public FunctionDecl {
 
   CXXConstructorDecl *Ctor;
   ExplicitSpecifier ExplicitSpec;
+  // The deduction guide, if any, that this deduction guide was generated from,
+  // in the case of alias template deduction or CTAD from inherited
+  // constructors. The bool member indicates whether this deduction guide is
+  // generated from an inherited constructor.
+  llvm::PointerIntPair<CXXDeductionGuideDecl *, 1, bool> SourceDeductionGuide;
   void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
 
 public:
@@ -1979,7 +1988,9 @@ class CXXDeductionGuideDecl : public FunctionDecl {
          ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
          TypeSourceInfo *TInfo, SourceLocation EndLocation,
          CXXConstructorDecl *Ctor = nullptr,
-         DeductionCandidate Kind = DeductionCandidate::Normal);
+         DeductionCandidate Kind = DeductionCandidate::Normal,
+         CXXDeductionGuideDecl *SourceDG = nullptr,
+         bool IsGeneratedFromInheritedConstructor = false);
 
   static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C,
                                                    GlobalDeclID ID);
@@ -1999,6 +2010,25 @@ class CXXDeductionGuideDecl : public FunctionDecl {
   /// this is an implicit deduction guide.
   CXXConstructorDecl *getCorrespondingConstructor() const { return Ctor; }
 
+  /// Get the deduction guide from which this deduction guide was generated,
+  /// if it was generated as part of alias template deduction or from an
+  /// inherited constructor.
+  CXXDeductionGuideDecl *getSourceDeductionGuide() const {
+    return SourceDeductionGuide.getPointer();
+  }
+
+  void setSourceDeductionGuide(CXXDeductionGuideDecl *DG) {
+    SourceDeductionGuide.setPointer(DG);
+  }
+
+  bool isGeneratedFromInheritedConstructor() const {
+    return SourceDeductionGuide.getInt();
+  }
+
+  void setGeneratedFromInheritedConstructor(bool G = true) {
+    SourceDeductionGuide.setInt(G);
+  }
+
   void setDeductionCandidateKind(DeductionCandidate K) {
     FunctionDeclBits.DeductionCandidateKind = static_cast<unsigned char>(K);
   }
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0ea3677355169f..da144704957ca7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4808,6 +4808,10 @@ def note_ovl_candidate_underqualified : Note<
     "make %2 equal %1">;
 def note_ovl_candidate_substitution_failure : Note<
     "candidate template ignored: substitution failure%0%1">;
+def note_ovl_candidate_inherited_constructor_deduction_failure: Note<
+    "candidate template ignored: could not deduce template arguments for %0 from %1%2">;
+def note_ovl_candidate_inherited_constructor_deduction_failure_source: Note<
+    "generated from %0 constructor">;
 def note_ovl_candidate_disabled_by_enable_if : Note<
     "candidate template ignored: disabled by %0%1">;
 def note_ovl_candidate_disabled_by_requirement : Note<
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 9bb035c07b8ae1..e4c6ef256872ab 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3937,14 +3937,16 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
         importExplicitSpecifier(Err, Guide->getExplicitSpecifier());
     CXXConstructorDecl *Ctor =
         importChecked(Err, Guide->getCorrespondingConstructor());
+    CXXDeductionGuideDecl *SourceDG =
+        importChecked(Err, Guide->getSourceDeductionGuide());
     if (Err)
       return std::move(Err);
     if (GetImportedOrCreateDecl<CXXDeductionGuideDecl>(
             ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, ESpec,
-            NameInfo, T, TInfo, ToEndLoc, Ctor))
+            NameInfo, T, TInfo, ToEndLoc, Ctor,
+            Guide->getDeductionCandidateKind(), SourceDG,
+            Guide->isGeneratedFromInheritedConstructor()))
       return ToFunction;
-    cast<CXXDeductionGuideDecl>(ToFunction)
-        ->setDeductionCandidateKind(Guide->getDeductionCandidateKind());
   } else {
     if (GetImportedOrCreateDecl(
             ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index d5c140fd343895..91877a49dcf5eb 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2157,9 +2157,11 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
     ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
     ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
     TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor,
-    DeductionCandidate Kind) {
-  return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
-                                           TInfo, EndLocation, Ctor, Kind);
+    DeductionCandidate Kind, CXXDeductionGuideDecl *SourceDG,
+    bool IsGeneratedFromInheritedConstructor) {
+  return new (C, DC) CXXDeductionGuideDecl(
+      C, DC, StartLoc, ES, NameInfo, T, TInfo, EndLocation, Ctor, Kind,
+      SourceDG, IsGeneratedFromInheritedConstructor);
 }
 
 CXXDeductionGuideDecl *
@@ -2167,7 +2169,7 @@ CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
   return new (C, ID) CXXDeductionGuideDecl(
       C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
       QualType(), nullptr, SourceLocation(), nullptr,
-      DeductionCandidate::Normal);
+      DeductionCandidate::Normal, nullptr, false);
 }
 
 RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d4a48858ec4196..df2b00edaf9400 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10531,6 +10531,40 @@ bool clang::isBetterOverloadCandidate(
     auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
     auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
     if (Guide1 && Guide2) {
+      //  -- F1 and F2 are generated from class template argument deduction
+      //  for a class D, and F2 is generated from inheriting constructors
+      //  from a base class of D while F1 is not, ...
+      if (Guide1->isImplicit() && Guide2->isImplicit() &&
+          Guide1->isGeneratedFromInheritedConstructor() !=
+              Guide2->isGeneratedFromInheritedConstructor()) {
+        const FunctionProtoType *FPT1 =
+            Guide1->getType()->getAs<FunctionProtoType>();
+        const FunctionProtoType *FPT2 =
+            Guide2->getType()->getAs<FunctionProtoType>();
+        assert(FPT1 && FPT2);
+
+        // ... and for each explicit function argument, the parameters of F1 and
+        // F2 are either both ellipses or have the same type
+        if (FPT1->isVariadic() == FPT2->isVariadic() &&
+            FPT1->getNumParams() == FPT2->getNumParams()) {
+          bool ParamsHaveSameType = true;
+          const auto &A1 = FPT1->getParamTypes();
+          const auto &A2 = FPT2->getParamTypes();
+          for (unsigned I = 0, N = FPT1->getNumParams(); I != N; ++I) {
+            llvm::FoldingSetNodeID ID1, ID2;
+            S.Context.getCanonicalType(A1[I]).Profile(ID1);
+            S.Context.getCanonicalType(A2[I]).Profile(ID2);
+            if (ID1 != ID2) {
+              ParamsHaveSameType = false;
+              break;
+            }
+          }
+
+          if (ParamsHaveSameType)
+            return Guide2->isGeneratedFromInheritedConstructor();
+        }
+      }
+
       //  -- F1 is generated from a deduction-guide and F2 is not
       if (Guide1->isImplicit() != Guide2->isImplicit())
         return Guide2->isImplicit();
@@ -11671,6 +11705,39 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
       return;
     }
 
+    // Errors in deduction guides from inherited constructors
+    // will present as substitution failures in the mapping
+    // partial specialization, so we show a generic diagnostic
+    // in this case.
+    if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(Templated);
+        DG && DG->isGeneratedFromInheritedConstructor()) {
+      CXXDeductionGuideDecl *Source = DG->getSourceDeductionGuide();
+      assert(Source &&
+             "Inherited constructor deduction guides must have a source");
+      auto DeducedRecordType =
+          QualType(cast<ClassTemplateDecl>(DG->getDeducedTemplate())
+                       ->getTemplatedDecl()
+                       ->getTypeForDecl(),
+                   0);
+      auto InheritedRecordType =
+          QualType(cast<ClassTemplateDecl>(Source->getDeducedTemplate())
+                       ->getTemplatedDecl()
+                       ->getTypeForDecl(),
+                   0);
+      S.Diag(Templated->getLocation(),
+             diag::note_ovl_candidate_inherited_constructor_deduction_failure)
+          << DeducedRecordType << InheritedRecordType << TemplateArgString;
+
+      CXXConstructorDecl *Ctor = DG->getCorrespondingConstructor();
+      if (Ctor && Ctor->getBeginLoc().isValid())
+        S.Diag(
+            Ctor->getBeginLoc(),
+            diag::
+                note_ovl_candidate_inherited_constructor_deduction_failure_source)
+            << InheritedRecordType;
+      return;
+    }
+
     // Format the SFINAE diagnostic into the argument string.
     // FIXME: Add a general mechanism to include a PartialDiagnostic *'s
     //        formatted message in another diagnostic.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9296cc66d69187..ec939a2fb718d1 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2746,7 +2746,7 @@ struct ConvertConstructorToDeductionGuideTransform {
   }
 };
 
-unsigned getTemplateParameterDepth(NamedDecl *TemplateParam) {
+unsigned getTemplateParameterDepth(const NamedDecl *TemplateParam) {
   if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
     return TTP->getDepth();
   if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
@@ -2768,7 +2768,7 @@ unsigned getTemplateParameterIndex(NamedDecl *TemplateParam) {
 
 // Find all template parameters that appear in the given DeducedArgs.
 // Return the indices of the template parameters in the TemplateParams.
-SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
+llvm::SmallSet<unsigned, 8> TemplateParamsReferencedInTemplateArgumentList(
     const TemplateParameterList *TemplateParamsList,
     ArrayRef<TemplateArgument> DeducedArgs) {
   struct TemplateParamsReferencedFinder
@@ -2806,17 +2806,19 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
     }
     void Mark(unsigned Depth, unsigned Index) {
       if (Index < TemplateParamList->size() &&
-          TemplateParamList->getParam(Index)->getTemplateDepth() == Depth)
+          getTemplateParameterDepth(TemplateParamList->getParam(Index)) ==
+              Depth) {
         ReferencedTemplateParams.set(Index);
+      }
     }
   };
   TemplateParamsReferencedFinder Finder(TemplateParamsList);
   Finder.TraverseTemplateArguments(DeducedArgs);
 
-  SmallVector<unsigned> Results;
+  llvm::SmallSet<unsigned, 8> Results;
   for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
     if (Finder.ReferencedTemplateParams[Index])
-      Results.push_back(Index);
+      Results.insert(Index);
   }
   return Results;
 }
@@ -3011,9 +3013,12 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
 Expr *buildIsDeducibleConstraint(Sema &SemaRef,
                                  TypeAliasTemplateDecl *AliasTemplate,
                                  QualType ReturnType,
-                                 SmallVector<NamedDecl *> TemplateParams) {
+                                 SmallVector<NamedDecl *> TemplateParams,
+                                 TemplateDecl *DeducingTemplate = nullptr) {
   ASTContext &Context = SemaRef.Context;
   // Constraint AST nodes must use uninstantiated depth.
+  assert(!DeducingTemplate || DeducingTemplate->getTemplateDepth() ==
+                                  AliasTemplate->getTemplateDepth());
   if (auto *PrimaryTemplate =
           AliasTemplate->getInstantiatedFromMemberTemplate();
       PrimaryTemplate && TemplateParams.size() > 0) {
@@ -3046,19 +3051,21 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
         Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate));
   };
 
+  TemplateDecl *TD = DeducingTemplate ? DeducingTemplate : AliasTemplate;
+
   SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = {
       Context.getTrivialTypeSourceInfo(
           Context.getDeducedTemplateSpecializationType(
-              TemplateName(AliasTemplate), /*DeducedType=*/QualType(),
+              TemplateName(TD), /*DeducedType=*/QualType(),
               /*IsDependent=*/true)), // template specialization type whose
                                       // arguments will be deduced.
       Context.getTrivialTypeSourceInfo(
           ReturnType), // type from which template arguments are deduced.
   };
-  return TypeTraitExpr::Create(
-      Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(),
-      TypeTrait::BTT_IsDeducible, IsDeducibleTypeTraitArgs,
-      AliasTemplate->getLocation(), /*Value*/ false);
+  return TypeTraitExpr::Create(Context, Context.getLogicalOperationType(),
+                               TD->getLocation(), TypeTrait::BTT_IsDeducible,
+                               IsDeducibleTypeTraitArgs, TD->getLocation(),
+                               /*Value*/ false);
 }
 
 std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>>
@@ -3090,12 +3097,59 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
   return {Template, AliasRhsTemplateArgs};
 }
 
+// Build the type for a deduction guide generated from an inherited constructor
+// [over.match.class.deduct]p1.10:
+// ... the set contains the guides of A with the return type R
+// of each guide replaced with `typename CC<R>::type` ...
+std::pair<TypeSourceInfo *, QualType>
+buildInheritedConstructorDeductionGuideType(
+    Sema &SemaRef, TypeSourceInfo *DerivedClassMapperType,
+    TemplateDecl *DeducingTemplate, TypeSourceInfo *SourceGuideTSI) {
+  auto &Context = SemaRef.Context;
+  const auto *FPT = SourceGuideTSI->getType()->getAs<FunctionProtoType>();
+  assert(FPT && "Source Guide type should be a FunctionProtoType");
+
+  // This substitution can fail in cases where the source return type
+  // is not dependent and the derived class is not deducible
+  Sema::SFINAETrap Trap(SemaRef);
+
+  MultiLevelTemplateArgumentList Args;
+  Args.addOuterTemplateArguments(DeducingTemplate,
+                                 TemplateArgument(FPT->getReturnType()), false);
+  Args.addOuterRetainedLevels(DeducingTemplate->getTemplateDepth());
+  TypeSourceInfo *ReturnTypeTSI =
+      SemaRef.SubstType(DerivedClassMapperType, Args,
+                        DeducingTemplate->getBeginLoc(), DeclarationName());
+  if (!ReturnTypeTSI || Trap.hasErrorOccurred())
+    return {nullptr, QualType()};
+  const QualType &ReturnType = ReturnTypeTSI->getType();
+
+  TypeLocBuilder TLB;
+  TLB.pushFullCopy(ReturnTypeTSI->getTypeLoc());
+
+  QualType FT = Context.getFunctionType(ReturnType, FPT->getParamTypes(),
+                                        FPT->getExtProtoInfo());
+  FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(FT);
+  const auto &TL = SourceGuideTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+  NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+  NewTL.setLParenLoc(TL.getLParenLoc());
+  NewTL.setRParenLoc(TL.getRParenLoc());
+  NewTL.setExceptionSpecRange(TL.getExceptionSpecRange());
+  NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
+  for (unsigned I = 0, E = NewTL.getNumParams(); I != E; ++I)
+    NewTL.setParam(I, TL.getParam(I));
+
+  TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, FT);
+  return {TSI, ReturnType};
+}
+
 // Build deduction guides for a type alias template from the given underlying
 // deduction guide F.
-FunctionTemplateDecl *
-BuildDeductionGuideForTypeAlias(Sema &SemaRef,
-                                TypeAliasTemplateDecl *AliasTemplate,
-                                FunctionTemplateDecl *F, SourceLocation Loc) {
+FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
+    Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
+    FunctionTemplateDecl *F, SourceLocation Loc,
+    TemplateDecl *DeducingTemplate = nullptr,
+    TypeSourceInfo *DerivedClassMapperType = nullptr) {
   LocalInstantiationScope Scope(SemaRef);
   Sema::InstantiatingTemplate BuildingDeductionGuides(
       SemaRef, AliasTemplate->getLocation(), F,
@@ -3103,6 +3157,9 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
   if (BuildingDeductionGuides.isInvalid())
     return nullptr;
 
+  if (!DeducingTemplate)
+    DeducingTemplate = AliasTemplate;
+
   auto &Context = SemaRef.Context;
   auto [Template, AliasRhsTemplateArgs] =
       getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
@@ -3268,8 +3325,17 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
           Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
     auto *GG = cast<CXXDeductionGuideDecl>(FPrime);
 
-    Expr *IsDeducible = buildIsDeducibleConstraint(
-        SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
+    TypeSourceInfo *TSI = GG->getTypeSourceInfo();
+    QualType ReturnType = FPrime->getReturnType();
+    if (DerivedClassMapperType)
+      std::tie(TSI, ReturnType) = buildInheritedConstructorDeductionGuideType(
+          SemaRef, DerivedClassMapperType, DeducingTemplate, TSI);
+    if (!TSI)
+      return nullptr;
+
+    Expr *IsDeducible =
+        buildIsDeducibleConstraint(SemaRef, AliasTemplate, ReturnType,
+                                   FPrimeTemplateParams, DeducingTemplate);
     Expr *RequiresClause =
         buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults,
                                    FirstUndeducedParamIdx, IsDeducible);
@@ -3281,27 +3347,37 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
         AliasTemplate->getTemplateParameters()->getRAngleLoc(),
         /*RequiresClause=*/RequiresClause);
     auto *Result = cast<FunctionTemplateDecl>(buildDeductionGuide(
-        SemaRef, AliasTemplate, FPrimeTemplateParamList,
-        GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(),
-        GG->getTypeSourceInfo(), AliasTemplate->getBeginLoc(),
-        AliasTemplate->getLocation(), AliasTemplate->getEndLoc(),
-        F->isImplicit()));
-    cast<CXXDeductionGuideDecl>(Result->getTemplatedDecl())
-        ->setDeductionCandidateKind(GG->getDeductionCandidateKind());
+        SemaRef, DeducingTemplate, FPrimeTemplateParamList,
+        GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(), TSI,
+        AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
+        AliasTemplate->getEndLoc(), F->isImplicit()));
+    auto *DGuide = cast<CXXDeductionGuideDecl>(Result->getTemplatedDecl());
+    DGuide->setDeductionCandidateKind(GG->getDeductionCandidateKind());
+    DGuide->setSourceDeductionGuide(
+        cast<CXXDeductionGuideDecl>(F->getTemplatedDecl()));
+    if (DerivedClassMapperType)
+      DGuide->setGeneratedFromInheritedConstructor();
     return Result;
   }
   return nullptr;
 }
 
 void DeclareImplicitDeductionGuidesForTypeAlias(
-    Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) {
+    Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc,
+    TemplateDecl *DeducingTemplate = nullptr,
+    TypeSourceInfo *DerivedClassMapperType = nullptr) {
   if (AliasTemplate->isInvalidDecl())
     return;
+  if (!DeducingTemplate)
+    DeducingTemplate = AliasTemplate;
   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(
+  // This check is already performed in the inherited constructor case by
+  // DeclareImplicitDeductionGuides
+  if (!DerivedClassMapperType &&
+      hasDeclaredDeductionGuides(
           Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
           AliasTemplate->getDeclContext()))
     return;
@@ -3334,17 +3410,29 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
         NewParam->setScopeInfo(0, I);
         FPTL.setParam(I, NewParam);
       }
-      auto *Transformed = cast<FunctionDecl>(buildDeductionGuide(
-          SemaRef, AliasTemplate, /*TemplateParams=*/nullptr,
+
+      QualType ReturnType =
+          cast<FunctionProtoType>(FunctionType->getType())->getReturnType();
+      if (DerivedClassMapperType)
+        std::tie(FunctionType, ReturnType) =
+            buildInheritedConstructorDeductionGuideType(
+                SemaRef, DerivedClassMapperType, DeducingTemplate,
+                FunctionType);
+      if (!FunctionType)
+        continue;
+
+      auto *Transformed = cast<CXXDeductionGuideDecl>(buildDeductionGuide(
+          SemaRef, DeducingTemplate, /*TemplateParams=*/nullptr,
           /*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType,
           AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
           AliasTemplate->getEndLoc(), DG->isImplicit()));
+      Transformed->setSourceDeductionGuide(DG);
 
       // FIXME: Here the synthesized deduction guide is not a templated
       // function. Per [dcl.decl]p4, the requires-clause shall be present only
       // if the declarator declares a templated function, a bug in standard?
       auto *Constraint = buildIsDeducibleConstraint(
-          SemaRef, AliasTemplate, Transformed->getReturnType(), {});
+          SemaRef, AliasTemplate, ReturnType, {}, DeducingTemplate);
       if (auto *RC = DG->getTrailingRequiresClause()) {
         auto Conjunction =
             SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{},
@@ -3364,8 +3452,221 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
             ->getDeductionCandidateKind() == DeductionCandidate::Aggregate)
       continue;
 
-    BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc);
+    BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc,
+                                    DeducingTemplate, DerivedClassMapperType);
+  }
+}
+
+void DeclareImplicitDeductionGuidesFromInheritedConstructors(
+    Sema &SemaRef, TemplateDecl *Template, ClassTemplateDecl *Pattern,
+    const CXXBaseSpecifier &Base, unsigned BaseIdx) {
+  auto &Context = SemaRef.Context;
+  DeclContext *DC = Template->getDeclContext();
+  const auto *BaseTST = Base.getType()->getAs<TemplateSpecializationType>();
+  if (!BaseTST)
+    return;
+
+  TemplateDecl *BaseTD = BaseTST->getTemplateName().getAsTemplateDecl();
+  if (!BaseTD)
+    return;
+
+  // Subsitute any parameters with default arguments not present in the base,
+  // since partial specializations cannot have default parameters
+  TemplateParameterList *TemplateTPL = Pattern->getTemplateParameters();
+  auto BaseDeducedTemplateParams =
+      TemplateParamsReferencedInTemplateArgumentList(
+          TemplateTPL, BaseTST->template_arguments());
+  SmallVector<NamedDecl *, 8> PartialSpecParams;
+  SmallVector<TemplateArgument, 8> SubstArgs;
+  PartialSpecParams.reserve(TemplateTPL->size());
+  SubstArgs.reserve(TemplateTPL->size());
+  LocalInstantiationScope Scope(SemaRef);
+  for (unsigned I = 0, N = TemplateTPL->size(); I < N; ++I) {
+    NamedDecl *Param = TemplateTPL->getParam(I);
+    if (!BaseDeducedTemplateParams.contains(I)) {
+      if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param);
+          TTP && TTP->hasDefaultArgument()) {
+        SubstArgs.push_back(TTP->getDefaultArgument().getArgument());
+        continue;
+      }
+
+      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param);
+          NTTP && NTTP->hasDefaultArgument()) {
+        SubstArgs.push_back(NTTP->getDefaultArgument().getArgument());
+        continue;
+      }
+
+      if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param);
+          TTP && TTP->hasDefaultArgument()) {
+        SubstArgs.push_back(TTP->getDefaultArgument().getArgument());
+        continue;
+      }
+
+      // We have a template parameter that is not present in the base
+      // and does not have a default argument. We create the deduction
+      // guide anyway to display a diagnostic.
+    }
+
+    MultiLevelTemplateArgumentList Args;
+    Args.setKind(TemplateSubstitutionKind::Rewrite);
+    Args.addOuterTemplateArguments(SubstArgs);
+    Args.addOuterRetainedLevels(Template->getTemplateDepth());
+
+    NamedDecl *NewParam = transformTemplateParameter(
+        SemaRef, DC, Param, Args, PartialSpecParams.size(),
+        Template->getTemplateDepth());
+    if (!NewParam)
+      return;
+
+    PartialSpecParams.push_back(NewParam);
+    SubstArgs.push_back(Context.getInjectedTemplateArg(NewParam));
   }
+
+  Expr *RequiresClause = nullptr;
+  MultiLevelTemplateArgumentList Args;
+  Args.setKind(TemplateSubstitutionKind::Rewrite);
+  Args.addOuterTemplateArguments(SubstArgs);
+  Args.addOuterRetainedLevels(Template->getTemplateDepth());
+  if (Expr *TemplateRC = TemplateTPL->getRequiresClause()) {
+    ExprResult E = SemaRef.SubstExpr(TemplateRC, Args);
+    if (E.isInvalid())
+      return;
+    RequiresClause = E.getAs<Expr>();
+  }
+  auto *PartialSpecTPL = TemplateParameterList::Create(
+      Context, TemplateTPL->getTemplateLoc(), TemplateTPL->getLAngleLoc(),
+      PartialSpecParams, TemplateTPL->getRAngleLoc(), RequiresClause);
+
+  // [over.match.class.deduct]p1.10
+  // Let A be an alias template whose template parameter list is that of
+  // [Template] and whose defining-type-id is [Base] ...
+  auto *TransformedBase =
+      SemaRef.SubstType(Base.getTypeSourceInfo(), Args, Base.getBaseTypeLoc(),
+                        DeclarationName(), true);
+  auto *BaseAD = TypeAliasDecl::Create(
+      Context, DC, SourceLocation(), Base.getBaseTypeLoc(),
+      TransformedBase->getType().getBaseTypeIdentifier(), TransformedBase);
+  std::string AliasDeclName =
+      (Twine("__ctad_alias_") + BaseTD->getName() + "_to_" +
+       Template->getName() + "_" + Twine(BaseIdx))
+          .str();
+  IdentifierInfo *AliasIdentifier = &Context.Idents.get(AliasDeclName);
+  auto *BaseATD = TypeAliasTemplateDecl::Create(
+      Context, DC, Base.getBaseTypeLoc(), DeclarationName(AliasIdentifier),
+      PartialSpecTPL, BaseAD);
+  BaseAD->setDescribedAliasTemplate(BaseATD);
+  BaseAD->setImplicit();
+  BaseATD->setImplicit();
+
+  DC->addDecl(BaseATD);
+
+  // ... given a class template `template <typename> class CC;`
+  // whose primary template is not defined ...
+  auto *TParam = TemplateTypeParmDecl::Create(
+      Context, DC, SourceLocation(), SourceLocation(),
+      Template->getTemplateDepth(), 0, nullptr, false, false);
+  auto *MapperTPL = TemplateParameterList::Create(
+      Context, SourceLocation(), SourceLocation(),
+      ArrayRef<NamedDecl *>(TParam), SourceLocation(), nullptr);
+
+  std::string MapperDeclName =
+      (Twine("__ctad_mapper_") + BaseTD->getName() + "_to_" +
+       Template->getName() + "_" + Twine(BaseIdx))
+          .str();
+  IdentifierInfo *MapperII = &Context.Idents.get(MapperDeclName);
+  CXXRecordDecl *MapperRD = CXXRecordDecl::Create(
+      Context, CXXRecordDecl::TagKind::Struct, DC, SourceLocation(),
+      SourceLocation(), nullptr, nullptr);
+  ClassTemplateDecl *MapperTD =
+      ClassTemplateDecl::Create(Context, DC, SourceLocation(),
+                                DeclarationName(MapperII), MapperTPL, MapperRD);
+  MapperRD->setDescribedClassTemplate(MapperTD);
+  MapperTD->setImplicit();
+  MapperRD->setImplicit();
+
+  DC->addDecl(MapperTD);
+
+  // ... and with a single partial specialization whose template parameter list
+  // is that of A with the template argument list of A ...
+  TemplateArgument AliasTA(TransformedBase->getType());
+  ArrayRef<TemplateArgument> TAL(AliasTA);
+  auto MapperTemplateName =
+      Context.getCanonicalTemplateName(TemplateName(MapperTD));
+  QualType CanonType =
+      Context.getTemplateSpecializationType(MapperTemplateName, TAL);
+
+  auto *MapperSpecialization = ClassTemplatePartialSpecializationDecl::Create(
+      Context, ClassTemplatePartialSpecializationDecl::TagKind::Struct, DC,
+      SourceLocation(), SourceLocation(), PartialSpecTPL, MapperTD, TAL,
+      CanonType, nullptr);
+  MapperSpecialization->setImplicit();
+  MapperSpecialization->startDefinition();
+
+  TemplateArgumentListInfo TemplateArgs;
+  TemplateArgs.addArgument({AliasTA, TransformedBase});
+  MapperSpecialization->setTemplateArgsAsWritten(TemplateArgs);
+
+  // ... having a member typedef `type` designating a template specialization
+  // with the template argument list of A
+  // but with [Template] as the template
+  auto DerivedTN = Context.getCanonicalTemplateName(TemplateName(Template));
+  QualType DerivedTST =
+      Context.getTemplateSpecializationType(DerivedTN, SubstArgs);
+
+  TypeLocBuilder MapperTypedefTLB;
+  TemplateSpecializationTypeLoc TSTL =
+      MapperTypedefTLB.push<TemplateSpecializationTypeLoc>(DerivedTST);
+  TSTL.setTemplateNameLoc(Template->getLocation());
+  TSTL.setLAngleLoc(Template->getTemplateParameters()->getLAngleLoc());
+  TSTL.setRAngleLoc(Template->getTemplateParameters()->getRAngleLoc());
+  TSTL.setTemplateKeywordLoc(Template->getBeginLoc());
+  for (unsigned I = 0, C = SubstArgs.size(); I < C; ++I)
+    TSTL.setArgLocInfo(I,
+                       TemplateArgumentLocInfo(Context.getTrivialTypeSourceInfo(
+                           SubstArgs[I].getAsType(),
+                           TemplateTPL->getParam(I)->getLocation())));
+
+  const auto &MapperTypedefII = Context.Idents.get("type");
+  TypeSourceInfo *MapperTypedefTSI =
+      MapperTypedefTLB.getTypeSourceInfo(Context, DerivedTST);
+  TypedefDecl *DerivedTypedef = TypedefDecl::Create(
+      Context, MapperSpecialization, Base.getBeginLoc(), Base.getBeginLoc(),
+      &MapperTypedefII, MapperTypedefTSI);
+
+  DerivedTypedef->setImplicit();
+  DerivedTypedef->setAccess(AS_public);
+  MapperSpecialization->addDecl(DerivedTypedef);
+
+  MapperSpecialization->completeDefinition();
+
+  MapperTD->AddPartialSpecialization(MapperSpecialization, nullptr);
+  DC->addDecl(MapperSpecialization);
+
+  // ... the set contains the guides of A with the return type R
+  // of each guide replaced with `typename CC<R>::type` ...
+  QualType MapperSpecializationType = Context.getTemplateSpecializationType(
+      MapperTemplateName, Context.getInjectedTemplateArg(TParam));
+
+  auto *NNS = NestedNameSpecifier::Create(
+      Context, nullptr, false, MapperSpecializationType.getTypePtr());
+  QualType MapperReturnType = Context.getDependentNameType(
+      ElaboratedTypeKeyword::Typename, NNS, &MapperTypedefII);
+
+  NestedNameSpecifierLocBuilder NNSLocBuilder;
+  NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(Template->getBeginLoc()));
+  NestedNameSpecifierLoc QualifierLoc =
+      NNSLocBuilder.getWithLocInContext(Context);
+
+  TypeLocBuilder ReturnTypeTLB;
+  DependentNameTypeLoc DepTL =
+      ReturnTypeTLB.push<DependentNameTypeLoc>(MapperReturnType);
+  DepTL.setQualifierLoc(QualifierLoc);
+
+  TypeSourceInfo *MapperTSI =
+      ReturnTypeTLB.getTypeSourceInfo(Context, MapperReturnType);
+
+  DeclareImplicitDeductionGuidesForTypeAlias(
+      SemaRef, BaseATD, Base.getBeginLoc(), Template, MapperTSI);
 }
 
 // Build an aggregate deduction guide for a type alias template.
@@ -3535,6 +3836,34 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   if (!AddedAny)
     Transform.buildSimpleDeductionGuide(std::nullopt);
 
+  // FIXME: Handle explicit deduction guides from inherited constructors
+  // when the base deduction guides are declared after this has first run
+  if (getLangOpts().CPlusPlus23 &&
+      Pattern->getTemplatedDecl()->hasDefinition()) {
+    unsigned BaseIdx = 0;
+    for (const auto &Base : Pattern->getTemplatedDecl()->bases()) {
+      ++BaseIdx;
+      if (!Base.getType()->isDependentType())
+        continue;
+
+      // The InheritConstructors field is not set for dependent
+      // bases because a using decl that inherits constructors
+      // for that base is unresolved.
+      // FIXME: This does not work for name specifiers
+      // like `using Derived::Base::Base;`
+      CanQualType T = Context.getCanonicalType(Base.getType());
+      DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T);
+      auto LR = Pattern->getTemplatedDecl()->lookup(Name);
+      assert((LR.empty() || LR.isSingleResult()) &&
+             "Expected at most one UsingDecl for a given base");
+      if (LR.empty() || !isa<UnresolvedUsingValueDecl>(LR.front()))
+        continue;
+
+      DeclareImplicitDeductionGuidesFromInheritedConstructors(
+          *this, Template, Pattern, Base, BaseIdx - 1);
+    }
+  }
+
   //    -- An additional function template derived as above from a hypothetical
   //    constructor C(C), called the copy deduction candidate.
   cast<CXXDeductionGuideDecl>(
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 01432301633ed2..1378b0664601aa 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2192,7 +2192,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         SemaRef.Context, DC, D->getInnerLocStart(),
         InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
         D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(),
-        DGuide->getDeductionCandidateKind());
+        DGuide->getDeductionCandidateKind(), DGuide->getSourceDeductionGuide(),
+        DGuide->isGeneratedFromInheritedConstructor());
     Function->setAccess(D->getAccess());
   } else {
     Function = FunctionDecl::Create(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index cbaf1b0a98c614..509a04708c0595 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2293,6 +2293,8 @@ void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
   VisitFunctionDecl(D);
   D->setDeductionCandidateKind(
       static_cast<DeductionCandidate>(Record.readInt()));
+  D->SourceDeductionGuide.setPointer(readDeclAs<CXXDeductionGuideDecl>());
+  D->setGeneratedFromInheritedConstructor(Record.readBool());
 }
 
 void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index b6583c54c9ba1f..5b165096dbb50c 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -790,6 +790,8 @@ void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
   Record.AddDeclRef(D->Ctor);
   VisitFunctionDecl(D);
   Record.push_back(static_cast<unsigned char>(D->getDeductionCandidateKind()));
+  Record.AddDeclRef(D->SourceDeductionGuide.getPointer());
+  Record.push_back(D->isGeneratedFromInheritedConstructor());
   Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
 }
 
diff --git a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
new file mode 100644
index 00000000000000..cd55af91467341
--- /dev/null
+++ b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
@@ -0,0 +1,260 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -verify %s
+
+namespace test1 {
+  template<typename T> struct Base {
+    template<typename V = T> requires true
+    Base(T);
+  };
+
+  template<typename T> struct InheritsCtors : public Base<T> {
+    using Base<T>::Base;
+  };
+
+  InheritsCtors inheritsCtors(1);
+  using IC = InheritsCtors<int>;
+  using IC = decltype(inheritsCtors);
+
+  template<typename T> struct DoesNotInheritCtors : public Base<T> {}; // expected-note {{candidate template ignored: could not match 'DoesNotInheritCtors<T>' against 'int'}} \
+                                                                       // expected-note 3{{implicit deduction guide declared as}} \
+                                                                       // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                                                                       // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}}
+  DoesNotInheritCtors doesNotInheritCtors(100); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
+
+  template<typename T> struct InheritsSecond : public Base<T> {
+    using Base<T>::Base;
+  };
+
+  InheritsSecond inheritsSecond('a');
+  using IS = InheritsSecond<char>;
+  using IS = decltype(inheritsSecond);
+
+  template<typename T> struct NonTemplateDGuideBase {
+    NonTemplateDGuideBase(T); // expected-note {{generated from 'NonTemplateDGuideBase<T>' constructor}}
+  };
+  NonTemplateDGuideBase(int) -> NonTemplateDGuideBase<char>;
+  NonTemplateDGuideBase(const char *) -> NonTemplateDGuideBase<const char *>;
+
+  template<typename T>
+  concept NoPointers = !requires (T t) { *t; };
+
+  template<NoPointers T>
+  struct NonTemplateDGuideDerived : public NonTemplateDGuideBase<T> { // expected-note {{candidate function not viable: no known conversion from 'const char[1]' to 'int' for 1st argument}} \
+                                                                      // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideDerived<T>' against 'const char *'}} \
+                                                                      // expected-note {{candidate template ignored: could not deduce template arguments for 'NonTemplateDGuideDerived<T>' from 'NonTemplateDGuideBase<T>' [with T = const char *]}} \
+                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type) NonTemplateDGuideDerived(type-parameter-0-0) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type'}} \
+                                                                      // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideBase<type-parameter-0-0>' against 'const char *'}} \
+                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<type-parameter-0-0>) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type'}} \
+                                                                      // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                                                                      // expected-note 2{{implicit deduction guide declared as }}
+    using NonTemplateDGuideBase<T>::NonTemplateDGuideBase;
+  };
+
+  NonTemplateDGuideDerived ntdg(1);
+  using NTDG = NonTemplateDGuideDerived<char>;
+  using NTDG = decltype(ntdg);
+
+  NonTemplateDGuideDerived ntdg_char(""); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
+
+  template<typename T>
+  struct ExplicitBase {
+    template<typename V>
+    ExplicitBase(V);
+  };
+
+  template<typename T>
+  ExplicitBase(T) -> ExplicitBase<T>;
+
+  template<NoPointers T>
+  struct ExplicitDerived : public ExplicitBase<T> { // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
+                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type) ExplicitDerived(type-parameter-0-1) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type'}} \
+                                                    // expected-note {{candidate template ignored: could not match 'ExplicitDerived<T>' against 'const char *'}} \
+                                                    // expected-note {{candidate template ignored: could not match 'ExplicitBase<type-parameter-0-0>' against 'const char *'}} \
+                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type) ExplicitDerived(ExplicitBase<type-parameter-0-0>) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type'}} \
+                                                    // expected-note {{candidate template ignored: could not deduce template arguments for 'ExplicitDerived<T>' from 'ExplicitBase<T>' [with T = const char *]}} \
+                                                    // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                                                    // expected-note 2{{implicit deduction guide declared as }}
+
+    using ExplicitBase<T>::ExplicitBase;
+  };
+
+  ExplicitDerived ed(10);
+  using ED = ExplicitDerived<int>;
+  using ED = decltype(ed);
+
+  ExplicitDerived substFail(""); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
+
+  // FIXME: Support deduction guides that were declared
+  // after the initial implicit guides are declared for
+  // the derived template.
+#if 0
+  Base(int) -> Base<char>;
+
+  InheritsCtors ic2(1);
+  using IC2 = InheritsCtors<char>;
+  using IC2 = decltype(ic2);
+#endif
+}
+
+namespace test2 {
+  template<typename T, typename U, typename V> struct Base {
+    Base(T, U, V);
+  };
+
+  template<typename T, typename U> struct Derived : public Base<U, T, int> {
+    // FIXME: Current implementation does not find Base's constructors correctly
+    // with the below using decl
+    //using Derived::Base::Base;
+
+    using Base<U, T, int>::Base;
+  };
+
+  Derived derived(true, 'a', 1);
+  using D = Derived<char, bool>;
+  using D = decltype(derived);
+}
+
+namespace test3 {
+  template<typename T> struct Base {
+    Base(T); // expected-note {{generated from 'Base<T>' constructor}}
+  };
+
+  template<typename T, typename U> struct NotEnoughParams : public Base<T> { // expected-note {{candidate template ignored: could not deduce template arguments for 'NotEnoughParams<T, U>' from 'Base<T>' [with T = int]}} \
+                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type) NotEnoughParams(type-parameter-0-0) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type'}} \
+                                                                             // expected-note {{candidate template ignored: could not match 'Base<type-parameter-0-0>' against 'int'}} \
+                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type) NotEnoughParams(Base<type-parameter-0-0>) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type'}} \
+                                                                             // expected-note {{candidate template ignored: could not match 'NotEnoughParams<T, U>' against 'int'}} \
+                                                                             // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
+                                                                             // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                                                                             // expected-note 3{{implicit deduction guide declared as}}
+    using Base<T>::Base;
+  };
+
+  NotEnoughParams notEnoughParams(1); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
+}
+
+namespace test4 {
+  template<typename T> struct B {
+    B(T t);
+  };
+
+  template<typename T = int, typename V = int>
+  struct DefaultArgsNotInBase : public B<V> {
+    using B<V>::B;
+  };
+
+  DefaultArgsNotInBase d('d');
+  using D = DefaultArgsNotInBase<int, char>;
+  using D = decltype(d);
+
+  template<typename T> struct BaseEmptyCtor {
+    BaseEmptyCtor();
+  };
+
+  template<typename T = int, typename V = int>
+  struct DefaultArgsNotInBaseEmpty : public BaseEmptyCtor<V> {
+    using BaseEmptyCtor<V>::BaseEmptyCtor;
+  };
+
+  DefaultArgsNotInBaseEmpty d2;
+  using D2 = DefaultArgsNotInBaseEmpty<>;
+  using D2 = decltype(d2);
+}
+
+namespace test5 {
+  template<typename T> struct Base {
+    Base(T);
+  };
+  template<typename T> struct Outer {
+    template<typename U> struct Inner : public Base<U> {
+      using Base<U>::Base;
+    };
+  };
+
+  Outer<int>::Inner i(10);
+  using I = Outer<int>::Inner<int>;
+  using I = decltype(i);
+}
+
+namespace test6 {
+  template<typename T>
+    concept False = false;
+
+  template<typename T>
+    concept True = true;
+
+  template<typename T>
+  struct Base {
+    Base(T); // expected-note {{generated from 'Base<T>' constructor}}
+  };
+
+  template<False F>
+  struct DerivedFalse : public Base<F> { // expected-note {{candidate template ignored: could not deduce template arguments for 'DerivedFalse<F>' from 'Base<T>' [with F = int]}} \
+                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type) DerivedFalse(type-parameter-0-0) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type'}} \
+                                           // expected-note {{candidate template ignored: could not match 'Base<type-parameter-0-0>' against 'int'}} \
+                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type) DerivedFalse(Base<type-parameter-0-0>) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type'}} \
+                                           // expected-note {{candidate template ignored: could not match 'DerivedFalse<F>' against 'int'}} \
+                                           // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
+                                           // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                                           // expected-note 3{{implicit deduction guide declared as}}
+      using Base<F>::Base;
+    };
+
+  template<True F>
+  struct DerivedTrue : public Base<F> {
+    using Base<F>::Base;
+  };
+
+  DerivedFalse df(10); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
+
+  DerivedTrue dt(10);
+  using DT = DerivedTrue<int>;
+  using DT = decltype(dt);
+}
+
+namespace test7 {
+  template<typename T, typename U>
+  struct Base1 {
+    Base1();
+    Base1(T, U);
+  };
+
+  template<typename T, typename U>
+  struct Base2 {
+    Base2();
+    Base2(T, U);
+  };
+
+  template<typename T = int, typename U = int>
+  struct MultipleInheritance : public Base1<T, U*> , Base2<U*, T> { // expected-note {{candidate function [with T = int, U = int]}} \
+                                                                    // expected-note {{candidate function [with T = int, U = int]}}
+    using Base1<T, U*>::Base1;
+    using Base2<U*, T>::Base2;
+  };
+
+  MultipleInheritance mi1(1, "");
+  using MI1 = MultipleInheritance<int, const char>;
+  using MI1 = decltype(mi1);
+
+  MultipleInheritance mi2("", 1);
+  using MI2 = MultipleInheritance<int, const char>;
+  using MI2 = decltype(mi2);
+
+  // This is an odd case.
+  // Since the base DGs have the deducible constraint, they are more specialized than MultipleInheritance's
+  // ctor, and take priority before the new clause in P2582R1 is applied.
+  MultipleInheritance mi3; // expected-error {{ambiguous deduction for template arguments of 'MultipleInheritance'}}
+
+  template<typename T>
+  struct MultipleInheritanceSameBase : public Base1<T, const T*>, Base1<const T*, T> {
+    using Base1<T, const T*>::Base1;
+    using Base1<const T*, T>::Base1;
+  };
+
+  MultipleInheritanceSameBase misb1('a', "");
+  using MISB1 = MultipleInheritanceSameBase<char>;
+  using MISB1 = decltype(misb1);
+
+  MultipleInheritanceSameBase misb2("", 'a');
+  using MISB2 = MultipleInheritanceSameBase<char>;
+  using MISB2 = decltype(misb2);
+}
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 92f9bae6cb064b..bb27280303c9b8 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -8077,6 +8077,8 @@ TEST_P(ImportFunctions, CTADImplicit) {
   auto *ToD = Import(FromD, Lang_CXX17);
   ASSERT_TRUE(ToD);
   EXPECT_EQ(ToD->getDeductionCandidateKind(), DeductionCandidate::Copy);
+  EXPECT_EQ(ToD->getSourceDeductionGuide(), nullptr);
+  EXPECT_FALSE(ToD->isGeneratedFromInheritedConstructor());
   // Check that the deduced class template is also imported.
   EXPECT_TRUE(findFromTU(FromD)->Importer->GetAlreadyImportedOrNull(
       FromD->getDeducedTemplate()));
@@ -8101,6 +8103,8 @@ TEST_P(ImportFunctions, CTADUserDefinedExplicit) {
   ASSERT_TRUE(ToD);
   EXPECT_FALSE(FromD->isImplicit());
   EXPECT_TRUE(ToD->isExplicit());
+  EXPECT_EQ(ToD->getSourceDeductionGuide(), nullptr);
+  EXPECT_FALSE(ToD->isGeneratedFromInheritedConstructor());
 }
 
 TEST_P(ImportFunctions, CTADWithLocalTypedef) {
@@ -8119,6 +8123,45 @@ TEST_P(ImportFunctions, CTADWithLocalTypedef) {
   ASSERT_TRUE(ToD);
 }
 
+TEST_P(ImportFunctions, CTADAliasTemplate) {
+  Decl *TU = getTuDecl(
+      R"(
+      template <typename T> struct A {
+        A(T);
+      };
+      template<typename T>
+      using B = A<T>;
+      B b{(int)0};
+      )",
+      Lang_CXX20, "input.cc");
+  auto *FromD = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
+      TU, cxxDeductionGuideDecl(hasParameter(0, hasType(asString("int")))));
+  auto *ToD = Import(FromD, Lang_CXX20);
+  ASSERT_TRUE(ToD);
+  EXPECT_FALSE(ToD->isGeneratedFromInheritedConstructor());
+  EXPECT_TRUE(ToD->getSourceDeductionGuide());
+}
+
+TEST_P(ImportFunctions, CTADInheritedCtor) {
+  Decl *TU = getTuDecl(
+      R"(
+      template <typename T> struct A {
+        A(T);
+      };
+      template <typename T> struct B : public A<T> {
+        using A<T>::A;
+      };
+      B b{(int)0};
+      )",
+      Lang_CXX23, "input.cc");
+  auto *FromD = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
+      TU, cxxDeductionGuideDecl(hasParameter(0, hasType(asString("int")))));
+  auto *ToD = Import(FromD, Lang_CXX23);
+  ASSERT_TRUE(ToD);
+  EXPECT_TRUE(ToD->isGeneratedFromInheritedConstructor());
+  EXPECT_TRUE(ToD->getSourceDeductionGuide());
+}
+
 TEST_P(ImportFunctions, ParmVarDeclDeclContext) {
   constexpr auto FromTUCode = R"(
       void f(int P);
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 27e2213e54caa8..241e250e2bcc5b 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -429,7 +429,7 @@ <h2 id="cxx23">C++23 implementation status</h2>
     <tr>
       <td>Class template argument deduction from inherited constructors</td>
       <td><a href="https://wg21.link/P2582R1">P2582R1</a></td>
-      <td class="none" align="center">No</td>
+      <td class="unreleased" align="center">Clang 20</td>
     </tr>
     <tr>
       <td>Portable assumptions</td>

>From 9d3c66426bed5d751c5fdecfa96c083595e8bbd9 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 15 Jul 2024 23:32:12 -0400
Subject: [PATCH 02/15] Fix PR comment

---
 clang/lib/AST/DeclCXX.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 91877a49dcf5eb..87b64b95f1f5ba 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2157,11 +2157,11 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
     ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
     ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
     TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor,
-    DeductionCandidate Kind, CXXDeductionGuideDecl *SourceDG,
+    DeductionCandidate Kind, CXXDeductionGuideDecl *GeneratedFrom,
     bool IsGeneratedFromInheritedConstructor) {
   return new (C, DC) CXXDeductionGuideDecl(
       C, DC, StartLoc, ES, NameInfo, T, TInfo, EndLocation, Ctor, Kind,
-      SourceDG, IsGeneratedFromInheritedConstructor);
+      GeneratedFrom, IsGeneratedFromInheritedConstructor);
 }
 
 CXXDeductionGuideDecl *
@@ -2169,7 +2169,8 @@ CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
   return new (C, ID) CXXDeductionGuideDecl(
       C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
       QualType(), nullptr, SourceLocation(), nullptr,
-      DeductionCandidate::Normal, nullptr, false);
+      DeductionCandidate::Normal, /*GeneratedFrom=*/nullptr,
+      /*IsGeneratedFromInheritedConstructor=*/false);
 }
 
 RequiresExprBodyDecl *RequiresExprBodyDecl::Create(

>From 2b537b57e20ca634ef4d7a88c1781f15055f8628 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Tue, 16 Jul 2024 00:18:07 -0400
Subject: [PATCH 03/15] clang-format

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 3867c7cfafebc0..bf80bbbc7ae3b5 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -951,10 +951,10 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
       Context.getTrivialTypeSourceInfo(
           ReturnType), // type from which template arguments are deduced.
   };
-  return TypeTraitExpr::Create(
-      Context, Context.getLogicalOperationType(), TD->getLocation(),
-      TypeTrait::BTT_IsDeducible, IsDeducibleTypeTraitArgs,
-      TD->getLocation(), /*Value*/ false);
+  return TypeTraitExpr::Create(Context, Context.getLogicalOperationType(),
+                               TD->getLocation(), TypeTrait::BTT_IsDeducible,
+                               IsDeducibleTypeTraitArgs, TD->getLocation(),
+                               /*Value*/ false);
 }
 
 std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>>
@@ -1650,7 +1650,8 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   }
   if (CXXRecordDecl *DefRecord =
           cast<CXXRecordDecl>(Template->getTemplatedDecl())->getDefinition()) {
-    if (TemplateDecl *DescribedTemplate = DefRecord->getDescribedClassTemplate())
+    if (TemplateDecl *DescribedTemplate =
+            DefRecord->getDescribedClassTemplate())
       Template = DescribedTemplate;
   }
 

>From c17fe150e39101bfa7fd0eb9e5cc7031fd746156 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Fri, 19 Jul 2024 03:15:37 -0400
Subject: [PATCH 04/15] Remove QualType reference and set mapper template param
 to implicit

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index bf80bbbc7ae3b5..f13a13345e9d72 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1011,7 +1011,7 @@ buildInheritedConstructorDeductionGuideType(
                         DeducingTemplate->getBeginLoc(), DeclarationName());
   if (!ReturnTypeTSI || Trap.hasErrorOccurred())
     return {nullptr, QualType()};
-  const QualType &ReturnType = ReturnTypeTSI->getType();
+  QualType ReturnType = ReturnTypeTSI->getType();
 
   TypeLocBuilder TLB;
   TLB.pushFullCopy(ReturnTypeTSI->getTypeLoc());
@@ -1454,6 +1454,7 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   auto *TParam = TemplateTypeParmDecl::Create(
       Context, DC, SourceLocation(), SourceLocation(),
       Template->getTemplateDepth(), 0, nullptr, false, false);
+  TParam->setImplicit();
   auto *MapperTPL = TemplateParameterList::Create(
       Context, SourceLocation(), SourceLocation(),
       ArrayRef<NamedDecl *>(TParam), SourceLocation(), nullptr);

>From 2ede0b30bf114b9ef47cbbc7dbb2ed1bb9ad2fcb Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 22 Jul 2024 19:50:41 -0400
Subject: [PATCH 05/15] Update test notes to account for canonical template arg
 changes

---
 .../SemaCXX/cxx23-ctad-inherited-ctors.cpp    | 24 +++++++++----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
index cd55af91467341..e48cb0c4163296 100644
--- a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
+++ b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
@@ -41,9 +41,9 @@ namespace test1 {
   struct NonTemplateDGuideDerived : public NonTemplateDGuideBase<T> { // expected-note {{candidate function not viable: no known conversion from 'const char[1]' to 'int' for 1st argument}} \
                                                                       // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideDerived<T>' against 'const char *'}} \
                                                                       // expected-note {{candidate template ignored: could not deduce template arguments for 'NonTemplateDGuideDerived<T>' from 'NonTemplateDGuideBase<T>' [with T = const char *]}} \
-                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type) NonTemplateDGuideDerived(type-parameter-0-0) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type'}} \
-                                                                      // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideBase<type-parameter-0-0>' against 'const char *'}} \
-                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<type-parameter-0-0>) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<type-parameter-0-0>>::type'}} \
+                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(T) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
+                                                                      // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideBase<T>' against 'const char *'}} \
+                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<T>) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
                                                                       // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                                                       // expected-note 2{{implicit deduction guide declared as }}
     using NonTemplateDGuideBase<T>::NonTemplateDGuideBase;
@@ -66,10 +66,10 @@ namespace test1 {
 
   template<NoPointers T>
   struct ExplicitDerived : public ExplicitBase<T> { // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
-                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type) ExplicitDerived(type-parameter-0-1) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type'}} \
+                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(V) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
                                                     // expected-note {{candidate template ignored: could not match 'ExplicitDerived<T>' against 'const char *'}} \
-                                                    // expected-note {{candidate template ignored: could not match 'ExplicitBase<type-parameter-0-0>' against 'const char *'}} \
-                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type) ExplicitDerived(ExplicitBase<type-parameter-0-0>) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<type-parameter-0-0>>::type'}} \
+                                                    // expected-note {{candidate template ignored: could not match 'ExplicitBase<T>' against 'const char *'}} \
+                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(ExplicitBase<T>) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
                                                     // expected-note {{candidate template ignored: could not deduce template arguments for 'ExplicitDerived<T>' from 'ExplicitBase<T>' [with T = const char *]}} \
                                                     // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                                     // expected-note 2{{implicit deduction guide declared as }}
@@ -119,9 +119,9 @@ namespace test3 {
   };
 
   template<typename T, typename U> struct NotEnoughParams : public Base<T> { // expected-note {{candidate template ignored: could not deduce template arguments for 'NotEnoughParams<T, U>' from 'Base<T>' [with T = int]}} \
-                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type) NotEnoughParams(type-parameter-0-0) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type'}} \
-                                                                             // expected-note {{candidate template ignored: could not match 'Base<type-parameter-0-0>' against 'int'}} \
-                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type) NotEnoughParams(Base<type-parameter-0-0>) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<type-parameter-0-0>>::type'}} \
+                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(T) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
+                                                                             // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
+                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(Base<T>) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
                                                                              // expected-note {{candidate template ignored: could not match 'NotEnoughParams<T, U>' against 'int'}} \
                                                                              // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
                                                                              // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
@@ -189,9 +189,9 @@ namespace test6 {
 
   template<False F>
   struct DerivedFalse : public Base<F> { // expected-note {{candidate template ignored: could not deduce template arguments for 'DerivedFalse<F>' from 'Base<T>' [with F = int]}} \
-                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type) DerivedFalse(type-parameter-0-0) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type'}} \
-                                           // expected-note {{candidate template ignored: could not match 'Base<type-parameter-0-0>' against 'int'}} \
-                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type) DerivedFalse(Base<type-parameter-0-0>) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<type-parameter-0-0>>::type'}} \
+                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(F) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}} \
+                                           // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
+                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(Base<F>) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}} \
                                            // expected-note {{candidate template ignored: could not match 'DerivedFalse<F>' against 'int'}} \
                                            // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
                                            // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \

>From cd0e4dedf1f5c2b393e40d8e79d045353f3d6428 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 22 Jul 2024 20:30:19 -0400
Subject: [PATCH 06/15] Rely on Using decls instead of bases for determining
 inherited constructors

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 59 +++++++-------
 .../SemaCXX/cxx23-ctad-inherited-ctors.cpp    | 78 +++++++++++--------
 2 files changed, 74 insertions(+), 63 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 5d2884fb88b3f5..93c46666c91b9a 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1345,12 +1345,13 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
 
 void DeclareImplicitDeductionGuidesFromInheritedConstructors(
     Sema &SemaRef, TemplateDecl *Template, ClassTemplateDecl *Pattern,
-    const CXXBaseSpecifier &Base, unsigned BaseIdx) {
+    TypeSourceInfo *BaseTSI, unsigned BaseIdx) {
   auto &Context = SemaRef.Context;
   DeclContext *DC = Template->getDeclContext();
-  const auto *BaseTST = Base.getType()->getAs<TemplateSpecializationType>();
+  const auto *BaseTST = BaseTSI->getType()->getAs<TemplateSpecializationType>();
   if (!BaseTST)
     return;
+  SourceLocation BaseLoc = BaseTSI->getTypeLoc().getBeginLoc();
 
   TemplateDecl *BaseTD = BaseTST->getTemplateName().getAsTemplateDecl();
   if (!BaseTD)
@@ -1425,12 +1426,11 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
 
   // [over.match.class.deduct]p1.10
   // Let A be an alias template whose template parameter list is that of
-  // [Template] and whose defining-type-id is [Base] ...
+  // [Template] and whose defining-type-id is [BaseTSI] ...
   auto *TransformedBase =
-      SemaRef.SubstType(Base.getTypeSourceInfo(), Args, Base.getBaseTypeLoc(),
-                        DeclarationName(), true);
+      SemaRef.SubstType(BaseTSI, Args, BaseLoc, DeclarationName(), true);
   auto *BaseAD = TypeAliasDecl::Create(
-      Context, DC, SourceLocation(), Base.getBaseTypeLoc(),
+      Context, DC, SourceLocation(), BaseLoc,
       TransformedBase->getType().getBaseTypeIdentifier(), TransformedBase);
   std::string AliasDeclName =
       (Twine("__ctad_alias_") + BaseTD->getName() + "_to_" +
@@ -1438,8 +1438,8 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
           .str();
   IdentifierInfo *AliasIdentifier = &Context.Idents.get(AliasDeclName);
   auto *BaseATD = TypeAliasTemplateDecl::Create(
-      Context, DC, Base.getBaseTypeLoc(), DeclarationName(AliasIdentifier),
-      PartialSpecTPL, BaseAD);
+      Context, DC, BaseLoc, DeclarationName(AliasIdentifier), PartialSpecTPL,
+      BaseAD);
   BaseAD->setDescribedAliasTemplate(BaseATD);
   BaseAD->setImplicit();
   BaseATD->setImplicit();
@@ -1516,9 +1516,9 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   const auto &MapperTypedefII = Context.Idents.get("type");
   TypeSourceInfo *MapperTypedefTSI =
       MapperTypedefTLB.getTypeSourceInfo(Context, DerivedTST);
-  TypedefDecl *DerivedTypedef = TypedefDecl::Create(
-      Context, MapperSpecialization, Base.getBeginLoc(), Base.getBeginLoc(),
-      &MapperTypedefII, MapperTypedefTSI);
+  TypedefDecl *DerivedTypedef =
+      TypedefDecl::Create(Context, MapperSpecialization, BaseLoc, BaseLoc,
+                          &MapperTypedefII, MapperTypedefTSI);
 
   DerivedTypedef->setImplicit();
   DerivedTypedef->setAccess(AS_public);
@@ -1552,8 +1552,8 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   TypeSourceInfo *MapperTSI =
       ReturnTypeTLB.getTypeSourceInfo(Context, MapperReturnType);
 
-  DeclareImplicitDeductionGuidesForTypeAlias(
-      SemaRef, BaseATD, Base.getBeginLoc(), Template, MapperTSI);
+  DeclareImplicitDeductionGuidesForTypeAlias(SemaRef, BaseATD, BaseLoc,
+                                             Template, MapperTSI);
 }
 
 // Build an aggregate deduction guide for a type alias template.
@@ -1726,29 +1726,28 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
 
   // FIXME: Handle explicit deduction guides from inherited constructors
   // when the base deduction guides are declared after this has first run
-  if (getLangOpts().CPlusPlus23 &&
-      Pattern->getTemplatedDecl()->hasDefinition()) {
+  CXXRecordDecl *TemplatedDecl = Pattern->getTemplatedDecl();
+  if (getLangOpts().CPlusPlus23 && TemplatedDecl->hasDefinition()) {
     unsigned BaseIdx = 0;
-    for (const auto &Base : Pattern->getTemplatedDecl()->bases()) {
-      ++BaseIdx;
-      if (!Base.getType()->isDependentType())
+    for (Decl *D : TemplatedDecl->decls()) {
+      auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(D);
+      if (!UUVD || UUVD->getDeclName().getNameKind() !=
+                       DeclarationName::CXXConstructorName)
         continue;
 
-      // The InheritConstructors field is not set for dependent
-      // bases because a using decl that inherits constructors
-      // for that base is unresolved.
-      // FIXME: This does not work for name specifiers
-      // like `using Derived::Base::Base;`
-      CanQualType T = Context.getCanonicalType(Base.getType());
-      DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T);
-      auto LR = Pattern->getTemplatedDecl()->lookup(Name);
-      assert((LR.empty() || LR.isSingleResult()) &&
-             "Expected at most one UsingDecl for a given base");
-      if (LR.empty() || !isa<UnresolvedUsingValueDecl>(LR.front()))
+      // FIXME: Handle identifier qualifiers, like in
+      // `using Derived::Base::Base;`
+      TypeLoc TL = UUVD->getQualifierLoc().getTypeLoc();
+      if (!TL)
         continue;
 
+      ++BaseIdx;
+      unsigned Size = TL.getFullDataSize();
+      auto *TSI = Context.CreateTypeSourceInfo(TL.getType(), Size);
+      TSI->getTypeLoc().initializeFullCopy(TL, Size);
+
       DeclareImplicitDeductionGuidesFromInheritedConstructors(
-          *this, Template, Pattern, Base, BaseIdx - 1);
+          *this, Template, Pattern, TSI, BaseIdx - 1);
     }
   }
 
diff --git a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
index e48cb0c4163296..91cf8d5036e5d1 100644
--- a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
+++ b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
@@ -38,15 +38,14 @@ namespace test1 {
   concept NoPointers = !requires (T t) { *t; };
 
   template<NoPointers T>
-  struct NonTemplateDGuideDerived : public NonTemplateDGuideBase<T> { // expected-note {{candidate function not viable: no known conversion from 'const char[1]' to 'int' for 1st argument}} \
-                                                                      // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideDerived<T>' against 'const char *'}} \
-                                                                      // expected-note {{candidate template ignored: could not deduce template arguments for 'NonTemplateDGuideDerived<T>' from 'NonTemplateDGuideBase<T>' [with T = const char *]}} \
-                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(T) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
-                                                                      // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideBase<T>' against 'const char *'}} \
-                                                                      // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<T>) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
+  struct NonTemplateDGuideDerived : public NonTemplateDGuideBase<T> { // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideDerived<T>' against 'const char *'}} \
                                                                       // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                                                       // expected-note 2{{implicit deduction guide declared as }}
-    using NonTemplateDGuideBase<T>::NonTemplateDGuideBase;
+    using NonTemplateDGuideBase<T>::NonTemplateDGuideBase; // expected-note {{candidate function not viable: no known conversion from 'const char[1]' to 'int' for 1st argument}} \
+                                                           // expected-note {{candidate template ignored: could not deduce template arguments for 'NonTemplateDGuideDerived<T>' from 'NonTemplateDGuideBase<T>' [with T = const char *]}} \
+                                                           // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(T) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
+                                                           // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideBase<T>' against 'const char *'}} \
+                                                           // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<T>) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}}
   };
 
   NonTemplateDGuideDerived ntdg(1);
@@ -65,16 +64,15 @@ namespace test1 {
   ExplicitBase(T) -> ExplicitBase<T>;
 
   template<NoPointers T>
-  struct ExplicitDerived : public ExplicitBase<T> { // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
-                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(V) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
-                                                    // expected-note {{candidate template ignored: could not match 'ExplicitDerived<T>' against 'const char *'}} \
-                                                    // expected-note {{candidate template ignored: could not match 'ExplicitBase<T>' against 'const char *'}} \
-                                                    // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(ExplicitBase<T>) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
-                                                    // expected-note {{candidate template ignored: could not deduce template arguments for 'ExplicitDerived<T>' from 'ExplicitBase<T>' [with T = const char *]}} \
+  struct ExplicitDerived : public ExplicitBase<T> { // expected-note {{candidate template ignored: could not match 'ExplicitDerived<T>' against 'const char *'}} \
                                                     // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                                     // expected-note 2{{implicit deduction guide declared as }}
 
-    using ExplicitBase<T>::ExplicitBase;
+    using ExplicitBase<T>::ExplicitBase; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
+                                         // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(V) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
+                                         // expected-note {{candidate template ignored: could not match 'ExplicitBase<T>' against 'const char *'}} \
+                                         // expected-note {{candidate template ignored: could not deduce template arguments for 'ExplicitDerived<T>' from 'ExplicitBase<T>' [with T = const char *]}} \
+                                         // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(ExplicitBase<T>) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}}
   };
 
   ExplicitDerived ed(10);
@@ -118,15 +116,14 @@ namespace test3 {
     Base(T); // expected-note {{generated from 'Base<T>' constructor}}
   };
 
-  template<typename T, typename U> struct NotEnoughParams : public Base<T> { // expected-note {{candidate template ignored: could not deduce template arguments for 'NotEnoughParams<T, U>' from 'Base<T>' [with T = int]}} \
-                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(T) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
-                                                                             // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
-                                                                             // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(Base<T>) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
-                                                                             // expected-note {{candidate template ignored: could not match 'NotEnoughParams<T, U>' against 'int'}} \
+  template<typename T, typename U> struct NotEnoughParams : public Base<T> { // expected-note {{candidate template ignored: could not match 'NotEnoughParams<T, U>' against 'int'}} \
                                                                              // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
                                                                              // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                                                              // expected-note 3{{implicit deduction guide declared as}}
-    using Base<T>::Base;
+    using Base<T>::Base; // expected-note {{candidate template ignored: could not deduce template arguments for 'NotEnoughParams<T, U>' from 'Base<T>' [with T = int]}} \
+                         // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(T) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
+                         // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
+                         // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(Base<T>) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}}
   };
 
   NotEnoughParams notEnoughParams(1); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
@@ -188,15 +185,14 @@ namespace test6 {
   };
 
   template<False F>
-  struct DerivedFalse : public Base<F> { // expected-note {{candidate template ignored: could not deduce template arguments for 'DerivedFalse<F>' from 'Base<T>' [with F = int]}} \
-                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(F) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}} \
-                                           // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
-                                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(Base<F>) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}} \
-                                           // expected-note {{candidate template ignored: could not match 'DerivedFalse<F>' against 'int'}} \
-                                           // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
-                                           // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
-                                           // expected-note 3{{implicit deduction guide declared as}}
-      using Base<F>::Base;
+  struct DerivedFalse : public Base<F> { // expected-note {{candidate template ignored: could not match 'DerivedFalse<F>' against 'int'}} \
+                                         // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
+                                         // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                                         // expected-note 3{{implicit deduction guide declared as}}
+      using Base<F>::Base; // expected-note {{candidate template ignored: could not deduce template arguments for 'DerivedFalse<F>' from 'Base<T>' [with F = int]}} \
+                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(F) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}} \
+                           // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
+                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(Base<F>) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}}
     };
 
   template<True F>
@@ -225,10 +221,9 @@ namespace test7 {
   };
 
   template<typename T = int, typename U = int>
-  struct MultipleInheritance : public Base1<T, U*> , Base2<U*, T> { // expected-note {{candidate function [with T = int, U = int]}} \
-                                                                    // expected-note {{candidate function [with T = int, U = int]}}
-    using Base1<T, U*>::Base1;
-    using Base2<U*, T>::Base2;
+  struct MultipleInheritance : public Base1<T, U*> , Base2<U*, T> { 
+    using Base1<T, U*>::Base1; // expected-note {{candidate function [with T = int, U = int]}}
+    using Base2<U*, T>::Base2; // expected-note {{candidate function [with T = int, U = int]}}
   };
 
   MultipleInheritance mi1(1, "");
@@ -258,3 +253,20 @@ namespace test7 {
   using MISB2 = MultipleInheritanceSameBase<char>;
   using MISB2 = decltype(misb2);
 }
+
+namespace test8 {
+  template<typename T>
+  struct Base {
+    Base(T);
+  };
+
+  template<typename T>
+  struct SpecializedBase : Base<int> {
+    using Base<T>::Base; // expected-error {{using declaration refers into 'Base<char>::', which is not a base class of 'SpecializedBase<char>'}}
+  };
+
+  SpecializedBase sb1(10);
+  static_assert(__is_same(decltype(sb1), SpecializedBase<int>));
+
+  SpecializedBase sb2('a'); // expected-note {{in instantiation of template class 'test8::SpecializedBase<char>' requested here}}
+}

>From d77c3d28741e41fb0abbeb09d44dd95463b68cb0 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 22 Jul 2024 20:34:56 -0400
Subject: [PATCH 07/15] Use static_assert(__is_same(...)) to verify types in
 tests

---
 .../SemaCXX/cxx23-ctad-inherited-ctors.cpp    | 44 +++++++------------
 1 file changed, 15 insertions(+), 29 deletions(-)

diff --git a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
index 91cf8d5036e5d1..2b9298a449b9f5 100644
--- a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
+++ b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
@@ -11,8 +11,7 @@ namespace test1 {
   };
 
   InheritsCtors inheritsCtors(1);
-  using IC = InheritsCtors<int>;
-  using IC = decltype(inheritsCtors);
+  static_assert(__is_same(InheritsCtors<int>, decltype(inheritsCtors)));
 
   template<typename T> struct DoesNotInheritCtors : public Base<T> {}; // expected-note {{candidate template ignored: could not match 'DoesNotInheritCtors<T>' against 'int'}} \
                                                                        // expected-note 3{{implicit deduction guide declared as}} \
@@ -25,8 +24,7 @@ namespace test1 {
   };
 
   InheritsSecond inheritsSecond('a');
-  using IS = InheritsSecond<char>;
-  using IS = decltype(inheritsSecond);
+  static_assert(__is_same(InheritsSecond<char>, decltype(inheritsSecond)));
 
   template<typename T> struct NonTemplateDGuideBase {
     NonTemplateDGuideBase(T); // expected-note {{generated from 'NonTemplateDGuideBase<T>' constructor}}
@@ -49,8 +47,7 @@ namespace test1 {
   };
 
   NonTemplateDGuideDerived ntdg(1);
-  using NTDG = NonTemplateDGuideDerived<char>;
-  using NTDG = decltype(ntdg);
+  static_assert(__is_same(NonTemplateDGuideDerived<char>, decltype(ntdg)));
 
   NonTemplateDGuideDerived ntdg_char(""); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
 
@@ -76,8 +73,7 @@ namespace test1 {
   };
 
   ExplicitDerived ed(10);
-  using ED = ExplicitDerived<int>;
-  using ED = decltype(ed);
+  static_assert(__is_same(ExplicitDerived<int>, decltype(ed)));
 
   ExplicitDerived substFail(""); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
 
@@ -88,8 +84,7 @@ namespace test1 {
   Base(int) -> Base<char>;
 
   InheritsCtors ic2(1);
-  using IC2 = InheritsCtors<char>;
-  using IC2 = decltype(ic2);
+  static_assert(__is_same(InheritsCtors<char>, decltype(ic2)));
 #endif
 }
 
@@ -107,8 +102,7 @@ namespace test2 {
   };
 
   Derived derived(true, 'a', 1);
-  using D = Derived<char, bool>;
-  using D = decltype(derived);
+  static_assert(__is_same(Derived<char, bool>, decltype(derived)));
 }
 
 namespace test3 {
@@ -140,8 +134,7 @@ namespace test4 {
   };
 
   DefaultArgsNotInBase d('d');
-  using D = DefaultArgsNotInBase<int, char>;
-  using D = decltype(d);
+  static_assert(__is_same(DefaultArgsNotInBase<int, char>, decltype(d)));
 
   template<typename T> struct BaseEmptyCtor {
     BaseEmptyCtor();
@@ -153,8 +146,7 @@ namespace test4 {
   };
 
   DefaultArgsNotInBaseEmpty d2;
-  using D2 = DefaultArgsNotInBaseEmpty<>;
-  using D2 = decltype(d2);
+  static_assert(__is_same(DefaultArgsNotInBaseEmpty<>, decltype(d2)));
 }
 
 namespace test5 {
@@ -168,8 +160,7 @@ namespace test5 {
   };
 
   Outer<int>::Inner i(10);
-  using I = Outer<int>::Inner<int>;
-  using I = decltype(i);
+  static_assert(__is_same(Outer<int>::Inner<int>, decltype(i)));
 }
 
 namespace test6 {
@@ -203,8 +194,7 @@ namespace test6 {
   DerivedFalse df(10); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
 
   DerivedTrue dt(10);
-  using DT = DerivedTrue<int>;
-  using DT = decltype(dt);
+  static_assert(__is_same(DerivedTrue<int>, decltype(dt)));
 }
 
 namespace test7 {
@@ -227,12 +217,10 @@ namespace test7 {
   };
 
   MultipleInheritance mi1(1, "");
-  using MI1 = MultipleInheritance<int, const char>;
-  using MI1 = decltype(mi1);
+  static_assert(__is_same(MultipleInheritance<int, const char>, decltype(mi1)));
 
   MultipleInheritance mi2("", 1);
-  using MI2 = MultipleInheritance<int, const char>;
-  using MI2 = decltype(mi2);
+  static_assert(__is_same(MultipleInheritance<int, const char>, decltype(mi2)));
 
   // This is an odd case.
   // Since the base DGs have the deducible constraint, they are more specialized than MultipleInheritance's
@@ -246,12 +234,10 @@ namespace test7 {
   };
 
   MultipleInheritanceSameBase misb1('a', "");
-  using MISB1 = MultipleInheritanceSameBase<char>;
-  using MISB1 = decltype(misb1);
+  static_assert(__is_same(MultipleInheritanceSameBase<char>, decltype(misb1)));
 
   MultipleInheritanceSameBase misb2("", 'a');
-  using MISB2 = MultipleInheritanceSameBase<char>;
-  using MISB2 = decltype(misb2);
+  static_assert(__is_same(MultipleInheritanceSameBase<char>, decltype(misb2)));
 }
 
 namespace test8 {
@@ -266,7 +252,7 @@ namespace test8 {
   };
 
   SpecializedBase sb1(10);
-  static_assert(__is_same(decltype(sb1), SpecializedBase<int>));
+  static_assert(__is_same(SpecializedBase<int>, decltype(sb1)));
 
   SpecializedBase sb2('a'); // expected-note {{in instantiation of template class 'test8::SpecializedBase<char>' requested here}}
 }

>From 5c272cfc3ac8848c444a5d378d269825f127b0f1 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 22 Jul 2024 20:42:07 -0400
Subject: [PATCH 08/15] Update comment for BuildDeductionGuideForTypeAlias and
 fix nits

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 93c46666c91b9a..e9cf9f5d89b50c 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1032,6 +1032,10 @@ buildInheritedConstructorDeductionGuideType(
 
 // Build deduction guides for a type alias template from the given underlying
 // deduction guide F.
+// If F is synthesized from a base class (as an inherited constructor),
+// then the return type will be transformed using DerivedClassMapperType.
+// The resulting deduction guide is added to the DeducingTemplate argument,
+// defaulting to AliasTemplate.
 FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     FunctionTemplateDecl *F, SourceLocation Loc,
@@ -1044,9 +1048,6 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
   if (BuildingDeductionGuides.isInvalid())
     return nullptr;
 
-  if (!DeducingTemplate)
-    DeducingTemplate = AliasTemplate;
-
   auto &Context = SemaRef.Context;
   auto [Template, AliasRhsTemplateArgs] =
       getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
@@ -1213,6 +1214,8 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
     TypeSourceInfo *TSI = GG->getTypeSourceInfo();
     QualType ReturnType = FPrime->getReturnType();
+    if (!DeducingTemplate)
+      DeducingTemplate = AliasTemplate;
     if (DerivedClassMapperType)
       std::tie(TSI, ReturnType) = buildInheritedConstructorDeductionGuideType(
           SemaRef, DerivedClassMapperType, DeducingTemplate, TSI);

>From c89b4eaec20ec26ed5fc844024549b4f364b398a Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 22 Jul 2024 21:10:49 -0400
Subject: [PATCH 09/15] Use enum to specify deduction guide source kind

---
 clang/include/clang/AST/DeclCXX.h             | 30 +++++++++----------
 clang/lib/AST/ASTImporter.cpp                 |  2 +-
 clang/lib/AST/DeclCXX.cpp                     | 10 +++----
 clang/lib/Sema/SemaOverload.cpp               | 16 +++++++---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  6 ++--
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  2 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |  3 +-
 clang/lib/Serialization/ASTWriterDecl.cpp     |  2 +-
 clang/unittests/AST/ASTImporterTest.cpp       |  7 ++---
 9 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index c8e74f32b2ccbc..5739b594023a74 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1952,19 +1952,22 @@ class ExplicitSpecifier {
 class CXXDeductionGuideDecl : public FunctionDecl {
   void anchor() override;
 
+public:
+  enum class SourceKind : bool {
+    Alias,
+    InheritedConstructor,
+  };
+
 private:
   CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
                         ExplicitSpecifier ES,
                         const DeclarationNameInfo &NameInfo, QualType T,
                         TypeSourceInfo *TInfo, SourceLocation EndLocation,
                         CXXConstructorDecl *Ctor, DeductionCandidate Kind,
-                        CXXDeductionGuideDecl *GeneratedFrom,
-                        bool IsGeneratedFromInheritedConstructor)
+                        CXXDeductionGuideDecl *GeneratedFrom, SourceKind SK)
       : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
                      SC_None, false, false, ConstexprSpecKind::Unspecified),
-        Ctor(Ctor), ExplicitSpec(ES),
-        SourceDeductionGuide(GeneratedFrom,
-                             IsGeneratedFromInheritedConstructor) {
+        Ctor(Ctor), ExplicitSpec(ES), SourceDeductionGuide(GeneratedFrom, SK) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
     setDeductionCandidateKind(Kind);
@@ -1974,9 +1977,10 @@ class CXXDeductionGuideDecl : public FunctionDecl {
   ExplicitSpecifier ExplicitSpec;
   // The deduction guide, if any, that this deduction guide was generated from,
   // in the case of alias template deduction or CTAD from inherited
-  // constructors. The bool member indicates whether this deduction guide is
-  // generated from an inherited constructor.
-  llvm::PointerIntPair<CXXDeductionGuideDecl *, 1, bool> SourceDeductionGuide;
+  // constructors. The SourceKind member indicates which of these two sources
+  // applies, if there is a source, otherwise it is meaningless.
+  llvm::PointerIntPair<CXXDeductionGuideDecl *, 1, SourceKind>
+      SourceDeductionGuide;
   void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
 
 public:
@@ -1990,7 +1994,7 @@ class CXXDeductionGuideDecl : public FunctionDecl {
          CXXConstructorDecl *Ctor = nullptr,
          DeductionCandidate Kind = DeductionCandidate::Normal,
          CXXDeductionGuideDecl *SourceDG = nullptr,
-         bool IsGeneratedFromInheritedConstructor = false);
+         SourceKind SK = SourceKind::Alias);
 
   static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C,
                                                    GlobalDeclID ID);
@@ -2021,13 +2025,9 @@ class CXXDeductionGuideDecl : public FunctionDecl {
     SourceDeductionGuide.setPointer(DG);
   }
 
-  bool isGeneratedFromInheritedConstructor() const {
-    return SourceDeductionGuide.getInt();
-  }
+  SourceKind getSourceKind() const { return SourceDeductionGuide.getInt(); }
 
-  void setGeneratedFromInheritedConstructor(bool G = true) {
-    SourceDeductionGuide.setInt(G);
-  }
+  void setSourceKind(SourceKind SK) { SourceDeductionGuide.setInt(SK); }
 
   void setDeductionCandidateKind(DeductionCandidate K) {
     FunctionDeclBits.DeductionCandidateKind = static_cast<unsigned char>(K);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 5f2945e8a3dc2b..68146f52df68d6 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3945,7 +3945,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, ESpec,
             NameInfo, T, TInfo, ToEndLoc, Ctor,
             Guide->getDeductionCandidateKind(), SourceDG,
-            Guide->isGeneratedFromInheritedConstructor()))
+            Guide->getSourceKind()))
       return ToFunction;
   } else {
     if (GetImportedOrCreateDecl(
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 9398ce129eaa52..917fed90a59ac3 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2158,10 +2158,10 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
     ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
     TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor,
     DeductionCandidate Kind, CXXDeductionGuideDecl *GeneratedFrom,
-    bool IsGeneratedFromInheritedConstructor) {
-  return new (C, DC) CXXDeductionGuideDecl(
-      C, DC, StartLoc, ES, NameInfo, T, TInfo, EndLocation, Ctor, Kind,
-      GeneratedFrom, IsGeneratedFromInheritedConstructor);
+    SourceKind SK) {
+  return new (C, DC)
+      CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T, TInfo,
+                            EndLocation, Ctor, Kind, GeneratedFrom, SK);
 }
 
 CXXDeductionGuideDecl *
@@ -2170,7 +2170,7 @@ CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
       C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
       QualType(), nullptr, SourceLocation(), nullptr,
       DeductionCandidate::Normal, /*GeneratedFrom=*/nullptr,
-      /*IsGeneratedFromInheritedConstructor=*/false);
+      /*SK=*/SourceKind::Alias);
 }
 
 RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 43339510b34d88..67eed020c3ce5a 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10535,9 +10535,16 @@ bool clang::isBetterOverloadCandidate(
       //  -- F1 and F2 are generated from class template argument deduction
       //  for a class D, and F2 is generated from inheriting constructors
       //  from a base class of D while F1 is not, ...
+      bool G1Inherited =
+          Guide1->getSourceDeductionGuide() &&
+          Guide1->getSourceKind() ==
+              CXXDeductionGuideDecl::SourceKind::InheritedConstructor;
+      bool G2Inherited =
+          Guide2->getSourceDeductionGuide() &&
+          Guide2->getSourceKind() ==
+              CXXDeductionGuideDecl::SourceKind::InheritedConstructor;
       if (Guide1->isImplicit() && Guide2->isImplicit() &&
-          Guide1->isGeneratedFromInheritedConstructor() !=
-              Guide2->isGeneratedFromInheritedConstructor()) {
+          G1Inherited != G2Inherited) {
         const FunctionProtoType *FPT1 =
             Guide1->getType()->getAs<FunctionProtoType>();
         const FunctionProtoType *FPT2 =
@@ -10562,7 +10569,7 @@ bool clang::isBetterOverloadCandidate(
           }
 
           if (ParamsHaveSameType)
-            return Guide2->isGeneratedFromInheritedConstructor();
+            return G2Inherited;
         }
       }
 
@@ -11711,7 +11718,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
     // partial specialization, so we show a generic diagnostic
     // in this case.
     if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(Templated);
-        DG && DG->isGeneratedFromInheritedConstructor()) {
+        DG && DG->getSourceKind() ==
+                  CXXDeductionGuideDecl::SourceKind::InheritedConstructor) {
       CXXDeductionGuideDecl *Source = DG->getSourceDeductionGuide();
       assert(Source &&
              "Inherited constructor deduction guides must have a source");
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index e9cf9f5d89b50c..a59126129dfe31 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1244,8 +1244,10 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     DGuide->setDeductionCandidateKind(GG->getDeductionCandidateKind());
     DGuide->setSourceDeductionGuide(
         cast<CXXDeductionGuideDecl>(F->getTemplatedDecl()));
-    if (DerivedClassMapperType)
-      DGuide->setGeneratedFromInheritedConstructor();
+    DGuide->setSourceKind(
+        DerivedClassMapperType
+            ? CXXDeductionGuideDecl::SourceKind::InheritedConstructor
+            : CXXDeductionGuideDecl::SourceKind::Alias);
     return Result;
   }
   return nullptr;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 43adfbf6cde482..0bafd5032d3d5b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2193,7 +2193,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
         D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(),
         DGuide->getDeductionCandidateKind(), DGuide->getSourceDeductionGuide(),
-        DGuide->isGeneratedFromInheritedConstructor());
+        DGuide->getSourceKind());
     Function->setAccess(D->getAccess());
   } else {
     Function = FunctionDecl::Create(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 5003f2b43cb4c0..cfff42e4d7eea2 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2275,7 +2275,8 @@ void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
   D->setDeductionCandidateKind(
       static_cast<DeductionCandidate>(Record.readInt()));
   D->SourceDeductionGuide.setPointer(readDeclAs<CXXDeductionGuideDecl>());
-  D->setGeneratedFromInheritedConstructor(Record.readBool());
+  D->SourceDeductionGuide.setInt(
+      static_cast<CXXDeductionGuideDecl::SourceKind>(Record.readBool()));
 }
 
 void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 82d7115439e6b5..c7a7e84bc64cbe 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -783,7 +783,7 @@ void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
   VisitFunctionDecl(D);
   Record.push_back(static_cast<unsigned char>(D->getDeductionCandidateKind()));
   Record.AddDeclRef(D->SourceDeductionGuide.getPointer());
-  Record.push_back(D->isGeneratedFromInheritedConstructor());
+  Record.push_back(static_cast<bool>(D->getSourceKind()));
   Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
 }
 
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index bb27280303c9b8..f4e79b2156293d 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -8078,7 +8078,6 @@ TEST_P(ImportFunctions, CTADImplicit) {
   ASSERT_TRUE(ToD);
   EXPECT_EQ(ToD->getDeductionCandidateKind(), DeductionCandidate::Copy);
   EXPECT_EQ(ToD->getSourceDeductionGuide(), nullptr);
-  EXPECT_FALSE(ToD->isGeneratedFromInheritedConstructor());
   // Check that the deduced class template is also imported.
   EXPECT_TRUE(findFromTU(FromD)->Importer->GetAlreadyImportedOrNull(
       FromD->getDeducedTemplate()));
@@ -8104,7 +8103,6 @@ TEST_P(ImportFunctions, CTADUserDefinedExplicit) {
   EXPECT_FALSE(FromD->isImplicit());
   EXPECT_TRUE(ToD->isExplicit());
   EXPECT_EQ(ToD->getSourceDeductionGuide(), nullptr);
-  EXPECT_FALSE(ToD->isGeneratedFromInheritedConstructor());
 }
 
 TEST_P(ImportFunctions, CTADWithLocalTypedef) {
@@ -8138,7 +8136,7 @@ TEST_P(ImportFunctions, CTADAliasTemplate) {
       TU, cxxDeductionGuideDecl(hasParameter(0, hasType(asString("int")))));
   auto *ToD = Import(FromD, Lang_CXX20);
   ASSERT_TRUE(ToD);
-  EXPECT_FALSE(ToD->isGeneratedFromInheritedConstructor());
+  EXPECT_TRUE(ToD->getSourceKind() == CXXDeductionGuideDecl::SourceKind::Alias);
   EXPECT_TRUE(ToD->getSourceDeductionGuide());
 }
 
@@ -8158,7 +8156,8 @@ TEST_P(ImportFunctions, CTADInheritedCtor) {
       TU, cxxDeductionGuideDecl(hasParameter(0, hasType(asString("int")))));
   auto *ToD = Import(FromD, Lang_CXX23);
   ASSERT_TRUE(ToD);
-  EXPECT_TRUE(ToD->isGeneratedFromInheritedConstructor());
+  EXPECT_TRUE(ToD->getSourceKind() ==
+              CXXDeductionGuideDecl::SourceKind::InheritedConstructor);
   EXPECT_TRUE(ToD->getSourceDeductionGuide());
 }
 

>From b9fb81b2750430824c32a69d5750f9e3a5605af3 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Mon, 22 Jul 2024 21:46:25 -0400
Subject: [PATCH 10/15] Fix parameter pack case

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp     |  9 +++++----
 clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp | 13 +++++++++++++
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index a59126129dfe31..15aa7d7fb37769 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1513,10 +1513,11 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   TSTL.setRAngleLoc(Template->getTemplateParameters()->getRAngleLoc());
   TSTL.setTemplateKeywordLoc(Template->getBeginLoc());
   for (unsigned I = 0, C = SubstArgs.size(); I < C; ++I)
-    TSTL.setArgLocInfo(I,
-                       TemplateArgumentLocInfo(Context.getTrivialTypeSourceInfo(
-                           SubstArgs[I].getAsType(),
-                           TemplateTPL->getParam(I)->getLocation())));
+    TSTL.setArgLocInfo(I, SemaRef
+                              .getTrivialTemplateArgumentLoc(
+                                  SubstArgs[I], QualType(),
+                                  TemplateTPL->getParam(I)->getBeginLoc())
+                              .getLocInfo());
 
   const auto &MapperTypedefII = Context.Idents.get("type");
   TypeSourceInfo *MapperTypedefTSI =
diff --git a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
index 2b9298a449b9f5..0adf465ef014b1 100644
--- a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
+++ b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
@@ -256,3 +256,16 @@ namespace test8 {
 
   SpecializedBase sb2('a'); // expected-note {{in instantiation of template class 'test8::SpecializedBase<char>' requested here}}
 }
+
+namespace test9 {
+  template <typename U, typename ...T> struct B {
+    B(U, T...);
+  };
+
+  template <typename U, typename ...T> struct C : public B<U, T...> {
+    using B<U, T...>::B;
+  };
+
+  C c('1', 2, 3, 4, 5);
+  static_assert(__is_same(C<char, int, int, int, int>, decltype(c)));
+}

>From b44f26ae9eb110a8d2b0a4c036d26d12bc8dfb2a Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Sun, 28 Jul 2024 13:02:40 -0400
Subject: [PATCH 11/15] clang-format

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 7b01ece90b25de..61ea80604155cd 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -673,9 +673,9 @@ llvm::SmallSet<unsigned, 8> TemplateParamsReferencedInTemplateArgumentList(
       }
     }
     void Mark(unsigned Depth, unsigned Index) {
-      auto [ParamDepth, _] = getDepthAndIndex(TemplateParamList->getParam(Index));
-      if (Index < TemplateParamList->size() &&
-          ParamDepth == Depth)
+      auto [ParamDepth, _] =
+          getDepthAndIndex(TemplateParamList->getParam(Index));
+      if (Index < TemplateParamList->size() && ParamDepth == Depth)
         ReferencedTemplateParams.set(Index);
     }
   };

>From ea6a946a62ecfdccc47c369c50d35e2f81ca73a8 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Sat, 24 Aug 2024 00:06:41 -0400
Subject: [PATCH 12/15] Address PR feedback

- Get ReturnType from FPT TSI instead of returning it in pair
- Rename DerivedClassMapperType to CCType
- Rename DeducingTemplate to DeducedTemplate to match
  CXXDeductionGuideDecl member function `getDeducedTemplate()`
- Address nits
- Move FIXME for generating inherited ctor dguides declared after the
  first time DeclareImplicitDeductionGuides runs to the
  hasDeclaredDeductionGuides check
- Move inherited constructor relater parameters to the alias deduction
  guide functions into an optional struct
---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 104 +++++++++---------
 1 file changed, 55 insertions(+), 49 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 61ea80604155cd..548c343599b864 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -867,10 +867,10 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
                                  TypeAliasTemplateDecl *AliasTemplate,
                                  QualType ReturnType,
                                  SmallVector<NamedDecl *> TemplateParams,
-                                 TemplateDecl *DeducingTemplate = nullptr) {
+                                 TemplateDecl *DeducedTemplate = nullptr) {
   ASTContext &Context = SemaRef.Context;
   // Constraint AST nodes must use uninstantiated depth.
-  assert(!DeducingTemplate || DeducingTemplate->getTemplateDepth() ==
+  assert(!DeducedTemplate || DeducedTemplate->getTemplateDepth() ==
                                   AliasTemplate->getTemplateDepth());
   if (auto *PrimaryTemplate =
           AliasTemplate->getInstantiatedFromMemberTemplate();
@@ -904,7 +904,7 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
         Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate));
   };
 
-  TemplateDecl *TD = DeducingTemplate ? DeducingTemplate : AliasTemplate;
+  TemplateDecl *TD = DeducedTemplate ? DeducedTemplate : AliasTemplate;
 
   SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = {
       Context.getTrivialTypeSourceInfo(
@@ -950,14 +950,19 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
   return {Template, AliasRhsTemplateArgs};
 }
 
+struct InheritedConstructorDeductionInfo {
+  TemplateDecl *DerivedClassTemplate;
+  TypeSourceInfo *CCType;
+};
+
 // Build the type for a deduction guide generated from an inherited constructor
 // [over.match.class.deduct]p1.10:
 // ... the set contains the guides of A with the return type R
 // of each guide replaced with `typename CC<R>::type` ...
-std::pair<TypeSourceInfo *, QualType>
+TypeSourceInfo *
 buildInheritedConstructorDeductionGuideType(
-    Sema &SemaRef, TypeSourceInfo *DerivedClassMapperType,
-    TemplateDecl *DeducingTemplate, TypeSourceInfo *SourceGuideTSI) {
+    Sema &SemaRef, InheritedConstructorDeductionInfo Info,
+    TypeSourceInfo *SourceGuideTSI) {
   auto &Context = SemaRef.Context;
   const auto *FPT = SourceGuideTSI->getType()->getAs<FunctionProtoType>();
   assert(FPT && "Source Guide type should be a FunctionProtoType");
@@ -967,14 +972,14 @@ buildInheritedConstructorDeductionGuideType(
   Sema::SFINAETrap Trap(SemaRef);
 
   MultiLevelTemplateArgumentList Args;
-  Args.addOuterTemplateArguments(DeducingTemplate,
+  Args.addOuterTemplateArguments(Info.DerivedClassTemplate,
                                  TemplateArgument(FPT->getReturnType()), false);
-  Args.addOuterRetainedLevels(DeducingTemplate->getTemplateDepth());
+  Args.addOuterRetainedLevels(Info.DerivedClassTemplate->getTemplateDepth());
   TypeSourceInfo *ReturnTypeTSI =
-      SemaRef.SubstType(DerivedClassMapperType, Args,
-                        DeducingTemplate->getBeginLoc(), DeclarationName());
+      SemaRef.SubstType(Info.CCType, Args,
+                        Info.DerivedClassTemplate->getBeginLoc(), DeclarationName());
   if (!ReturnTypeTSI || Trap.hasErrorOccurred())
-    return {nullptr, QualType()};
+    return nullptr;
   QualType ReturnType = ReturnTypeTSI->getType();
 
   TypeLocBuilder TLB;
@@ -993,7 +998,7 @@ buildInheritedConstructorDeductionGuideType(
     NewTL.setParam(I, TL.getParam(I));
 
   TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, FT);
-  return {TSI, ReturnType};
+  return TSI;
 }
 
 // Build deduction guides for a type alias template from the given underlying
@@ -1005,8 +1010,7 @@ buildInheritedConstructorDeductionGuideType(
 FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     FunctionTemplateDecl *F, SourceLocation Loc,
-    TemplateDecl *DeducingTemplate = nullptr,
-    TypeSourceInfo *DerivedClassMapperType = nullptr) {
+    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor = std::nullopt) {
   LocalInstantiationScope Scope(SemaRef);
   Sema::InstantiatingTemplate BuildingDeductionGuides(
       SemaRef, AliasTemplate->getLocation(), F,
@@ -1179,17 +1183,18 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
     TypeSourceInfo *TSI = GG->getTypeSourceInfo();
     QualType ReturnType = FPrime->getReturnType();
-    if (!DeducingTemplate)
-      DeducingTemplate = AliasTemplate;
-    if (DerivedClassMapperType)
-      std::tie(TSI, ReturnType) = buildInheritedConstructorDeductionGuideType(
-          SemaRef, DerivedClassMapperType, DeducingTemplate, TSI);
-    if (!TSI)
-      return nullptr;
+    TemplateDecl *DeducedTemplate = FromInheritedCtor ? FromInheritedCtor->DerivedClassTemplate : AliasTemplate;
+    if (FromInheritedCtor) {
+      TSI = buildInheritedConstructorDeductionGuideType(
+          SemaRef, *FromInheritedCtor, TSI);
+      if (!TSI)
+        return nullptr;
+      ReturnType = TSI->getType().getTypePtr()->getAs<FunctionProtoType>()->getReturnType();
+    }
 
     Expr *IsDeducible =
         buildIsDeducibleConstraint(SemaRef, AliasTemplate, ReturnType,
-                                   FPrimeTemplateParams, DeducingTemplate);
+                                   FPrimeTemplateParams, DeducedTemplate);
     Expr *RequiresClause =
         buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults,
                                    FirstUndeducedParamIdx, IsDeducible);
@@ -1201,7 +1206,7 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
         AliasTemplate->getTemplateParameters()->getRAngleLoc(),
         /*RequiresClause=*/RequiresClause);
     auto *Result = cast<FunctionTemplateDecl>(buildDeductionGuide(
-        SemaRef, DeducingTemplate, FPrimeTemplateParamList,
+        SemaRef, DeducedTemplate, FPrimeTemplateParamList,
         GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(), TSI,
         AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
         AliasTemplate->getEndLoc(), F->isImplicit()));
@@ -1210,7 +1215,7 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     DGuide->setSourceDeductionGuide(
         cast<CXXDeductionGuideDecl>(F->getTemplatedDecl()));
     DGuide->setSourceKind(
-        DerivedClassMapperType
+        FromInheritedCtor
             ? CXXDeductionGuideDecl::SourceKind::InheritedConstructor
             : CXXDeductionGuideDecl::SourceKind::Alias);
     return Result;
@@ -1220,19 +1225,17 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
 void DeclareImplicitDeductionGuidesForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc,
-    TemplateDecl *DeducingTemplate = nullptr,
-    TypeSourceInfo *DerivedClassMapperType = nullptr) {
+    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor = std::nullopt)  {
   if (AliasTemplate->isInvalidDecl())
     return;
-  if (!DeducingTemplate)
-    DeducingTemplate = AliasTemplate;
+  TemplateDecl *DeducedTemplate = FromInheritedCtor ? FromInheritedCtor->DerivedClassTemplate : AliasTemplate;
   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.
   // This check is already performed in the inherited constructor case by
   // DeclareImplicitDeductionGuides
-  if (!DerivedClassMapperType &&
+  if (!FromInheritedCtor &&
       hasDeclaredDeductionGuides(
           Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
           AliasTemplate->getDeclContext()))
@@ -1269,16 +1272,18 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
 
       QualType ReturnType =
           cast<FunctionProtoType>(FunctionType->getType())->getReturnType();
-      if (DerivedClassMapperType)
-        std::tie(FunctionType, ReturnType) =
-            buildInheritedConstructorDeductionGuideType(
-                SemaRef, DerivedClassMapperType, DeducingTemplate,
-                FunctionType);
       if (!FunctionType)
         continue;
+      if (FromInheritedCtor) {
+        FunctionType = buildInheritedConstructorDeductionGuideType(
+            SemaRef, *FromInheritedCtor, FunctionType);
+        if (!FunctionType)
+          continue;
+        ReturnType = FunctionType->getType().getTypePtr()->getAs<FunctionProtoType>()->getReturnType();
+      }
 
       auto *Transformed = cast<CXXDeductionGuideDecl>(buildDeductionGuide(
-          SemaRef, DeducingTemplate, /*TemplateParams=*/nullptr,
+          SemaRef, DeducedTemplate, /*TemplateParams=*/nullptr,
           /*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType,
           AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
           AliasTemplate->getEndLoc(), DG->isImplicit()));
@@ -1288,7 +1293,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
       // function. Per [dcl.decl]p4, the requires-clause shall be present only
       // if the declarator declares a templated function, a bug in standard?
       auto *Constraint = buildIsDeducibleConstraint(
-          SemaRef, AliasTemplate, ReturnType, {}, DeducingTemplate);
+          SemaRef, AliasTemplate, ReturnType, {}, DeducedTemplate);
       if (auto *RC = DG->getTrailingRequiresClause()) {
         auto Conjunction =
             SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{},
@@ -1309,7 +1314,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
       continue;
 
     BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc,
-                                    DeducingTemplate, DerivedClassMapperType);
+                                    FromInheritedCtor);
   }
 }
 
@@ -1327,7 +1332,7 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   if (!BaseTD)
     return;
 
-  // Subsitute any parameters with default arguments not present in the base,
+  // Substitute any parameters with default arguments not present in the base,
   // since partial specializations cannot have default parameters
   TemplateParameterList *TemplateTPL = Pattern->getTemplateParameters();
   auto BaseDeducedTemplateParams =
@@ -1523,8 +1528,9 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   TypeSourceInfo *MapperTSI =
       ReturnTypeTLB.getTypeSourceInfo(Context, MapperReturnType);
 
+  InheritedConstructorDeductionInfo Info{Template, MapperTSI};
   DeclareImplicitDeductionGuidesForTypeAlias(SemaRef, BaseATD, BaseLoc,
-                                             Template, MapperTSI);
+                                             Info);
 }
 
 // Build an aggregate deduction guide for a type alias template.
@@ -1633,6 +1639,8 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   if (!isCompleteType(Loc, Transform.DeducedType))
     return;
 
+  // FIXME: Handle explicit deduction guides from inherited constructors
+  // when the base deduction guides are declared after this has first run
   if (hasDeclaredDeductionGuides(Transform.DeductionGuideName, DC))
     return;
 
@@ -1695,8 +1703,14 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   if (!AddedAny)
     Transform.buildSimpleDeductionGuide(std::nullopt);
 
-  // FIXME: Handle explicit deduction guides from inherited constructors
-  // when the base deduction guides are declared after this has first run
+  //    -- An additional function template derived as above from a hypothetical
+  //    constructor C(C), called the copy deduction candidate.
+  cast<CXXDeductionGuideDecl>(
+      cast<FunctionTemplateDecl>(
+          Transform.buildSimpleDeductionGuide(Transform.DeducedType))
+          ->getTemplatedDecl())
+      ->setDeductionCandidateKind(DeductionCandidate::Copy);
+
   CXXRecordDecl *TemplatedDecl = Pattern->getTemplatedDecl();
   if (getLangOpts().CPlusPlus23 && TemplatedDecl->hasDefinition()) {
     unsigned BaseIdx = 0;
@@ -1722,13 +1736,5 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
     }
   }
 
-  //    -- An additional function template derived as above from a hypothetical
-  //    constructor C(C), called the copy deduction candidate.
-  cast<CXXDeductionGuideDecl>(
-      cast<FunctionTemplateDecl>(
-          Transform.buildSimpleDeductionGuide(Transform.DeducedType))
-          ->getTemplatedDecl())
-      ->setDeductionCandidateKind(DeductionCandidate::Copy);
-
   SavedContext.pop();
 }

>From 18b8161caecfe7cf1ec66e47c6fb66cabf3b1f10 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Sat, 24 Aug 2024 00:08:45 -0400
Subject: [PATCH 13/15] Run clang-format

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 38 ++++++++++++-------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 548c343599b864..dda4182f87125a 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -871,7 +871,7 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
   ASTContext &Context = SemaRef.Context;
   // Constraint AST nodes must use uninstantiated depth.
   assert(!DeducedTemplate || DeducedTemplate->getTemplateDepth() ==
-                                  AliasTemplate->getTemplateDepth());
+                                 AliasTemplate->getTemplateDepth());
   if (auto *PrimaryTemplate =
           AliasTemplate->getInstantiatedFromMemberTemplate();
       PrimaryTemplate && TemplateParams.size() > 0) {
@@ -959,8 +959,7 @@ struct InheritedConstructorDeductionInfo {
 // [over.match.class.deduct]p1.10:
 // ... the set contains the guides of A with the return type R
 // of each guide replaced with `typename CC<R>::type` ...
-TypeSourceInfo *
-buildInheritedConstructorDeductionGuideType(
+TypeSourceInfo *buildInheritedConstructorDeductionGuideType(
     Sema &SemaRef, InheritedConstructorDeductionInfo Info,
     TypeSourceInfo *SourceGuideTSI) {
   auto &Context = SemaRef.Context;
@@ -975,9 +974,9 @@ buildInheritedConstructorDeductionGuideType(
   Args.addOuterTemplateArguments(Info.DerivedClassTemplate,
                                  TemplateArgument(FPT->getReturnType()), false);
   Args.addOuterRetainedLevels(Info.DerivedClassTemplate->getTemplateDepth());
-  TypeSourceInfo *ReturnTypeTSI =
-      SemaRef.SubstType(Info.CCType, Args,
-                        Info.DerivedClassTemplate->getBeginLoc(), DeclarationName());
+  TypeSourceInfo *ReturnTypeTSI = SemaRef.SubstType(
+      Info.CCType, Args, Info.DerivedClassTemplate->getBeginLoc(),
+      DeclarationName());
   if (!ReturnTypeTSI || Trap.hasErrorOccurred())
     return nullptr;
   QualType ReturnType = ReturnTypeTSI->getType();
@@ -1010,7 +1009,8 @@ buildInheritedConstructorDeductionGuideType(
 FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     FunctionTemplateDecl *F, SourceLocation Loc,
-    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor = std::nullopt) {
+    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor =
+        std::nullopt) {
   LocalInstantiationScope Scope(SemaRef);
   Sema::InstantiatingTemplate BuildingDeductionGuides(
       SemaRef, AliasTemplate->getLocation(), F,
@@ -1183,13 +1183,18 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
     TypeSourceInfo *TSI = GG->getTypeSourceInfo();
     QualType ReturnType = FPrime->getReturnType();
-    TemplateDecl *DeducedTemplate = FromInheritedCtor ? FromInheritedCtor->DerivedClassTemplate : AliasTemplate;
+    TemplateDecl *DeducedTemplate =
+        FromInheritedCtor ? FromInheritedCtor->DerivedClassTemplate
+                          : AliasTemplate;
     if (FromInheritedCtor) {
       TSI = buildInheritedConstructorDeductionGuideType(
           SemaRef, *FromInheritedCtor, TSI);
       if (!TSI)
         return nullptr;
-      ReturnType = TSI->getType().getTypePtr()->getAs<FunctionProtoType>()->getReturnType();
+      ReturnType = TSI->getType()
+                       .getTypePtr()
+                       ->getAs<FunctionProtoType>()
+                       ->getReturnType();
     }
 
     Expr *IsDeducible =
@@ -1225,10 +1230,13 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
 void DeclareImplicitDeductionGuidesForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc,
-    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor = std::nullopt)  {
+    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor =
+        std::nullopt) {
   if (AliasTemplate->isInvalidDecl())
     return;
-  TemplateDecl *DeducedTemplate = FromInheritedCtor ? FromInheritedCtor->DerivedClassTemplate : AliasTemplate;
+  TemplateDecl *DeducedTemplate = FromInheritedCtor
+                                      ? FromInheritedCtor->DerivedClassTemplate
+                                      : AliasTemplate;
   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
@@ -1279,7 +1287,10 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
             SemaRef, *FromInheritedCtor, FunctionType);
         if (!FunctionType)
           continue;
-        ReturnType = FunctionType->getType().getTypePtr()->getAs<FunctionProtoType>()->getReturnType();
+        ReturnType = FunctionType->getType()
+                         .getTypePtr()
+                         ->getAs<FunctionProtoType>()
+                         ->getReturnType();
       }
 
       auto *Transformed = cast<CXXDeductionGuideDecl>(buildDeductionGuide(
@@ -1529,8 +1540,7 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
       ReturnTypeTLB.getTypeSourceInfo(Context, MapperReturnType);
 
   InheritedConstructorDeductionInfo Info{Template, MapperTSI};
-  DeclareImplicitDeductionGuidesForTypeAlias(SemaRef, BaseATD, BaseLoc,
-                                             Info);
+  DeclareImplicitDeductionGuidesForTypeAlias(SemaRef, BaseATD, BaseLoc, Info);
 }
 
 // Build an aggregate deduction guide for a type alias template.

>From 471a4212d6234cbdc44980a1aa495009e1569e11 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Tue, 10 Sep 2024 18:44:09 -0400
Subject: [PATCH 14/15] Address nits, check base template deducibility, clone
 TPL for partial spec

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 91 +++++++++++++++----
 .../SemaCXX/cxx23-ctad-inherited-ctors.cpp    | 29 ++++--
 2 files changed, 96 insertions(+), 24 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index dda4182f87125a..4024ca33724ca5 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -951,7 +951,13 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
 }
 
 struct InheritedConstructorDeductionInfo {
+  // Class template for which we are declaring deduction guides
+  // This is `C` in the standard wording
   TemplateDecl *DerivedClassTemplate;
+
+  // `template<typename> CC` in the standard wording
+  // This is the type of template that is substituted in the deduction guide
+  // return type `CC<R>`
   TypeSourceInfo *CCType;
 };
 
@@ -960,7 +966,7 @@ struct InheritedConstructorDeductionInfo {
 // ... the set contains the guides of A with the return type R
 // of each guide replaced with `typename CC<R>::type` ...
 TypeSourceInfo *buildInheritedConstructorDeductionGuideType(
-    Sema &SemaRef, InheritedConstructorDeductionInfo Info,
+    Sema &SemaRef, const InheritedConstructorDeductionInfo &Info,
     TypeSourceInfo *SourceGuideTSI) {
   auto &Context = SemaRef.Context;
   const auto *FPT = SourceGuideTSI->getType()->getAs<FunctionProtoType>();
@@ -1009,8 +1015,8 @@ TypeSourceInfo *buildInheritedConstructorDeductionGuideType(
 FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     FunctionTemplateDecl *F, SourceLocation Loc,
-    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor =
-        std::nullopt) {
+    InheritedConstructorDeductionInfo *FromInheritedCtor =
+        nullptr) {
   LocalInstantiationScope Scope(SemaRef);
   Sema::InstantiatingTemplate BuildingDeductionGuides(
       SemaRef, AliasTemplate->getLocation(), F,
@@ -1230,8 +1236,8 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
 void DeclareImplicitDeductionGuidesForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc,
-    std::optional<InheritedConstructorDeductionInfo> FromInheritedCtor =
-        std::nullopt) {
+    InheritedConstructorDeductionInfo *FromInheritedCtor =
+        nullptr) {
   if (AliasTemplate->isInvalidDecl())
     return;
   TemplateDecl *DeducedTemplate = FromInheritedCtor
@@ -1329,6 +1335,39 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
   }
 }
 
+// Check if a template is deducible as per [dcl.type.simple]p3
+static bool IsDeducibleTemplate(TemplateDecl *TD) {
+  while (TD) {
+    // [dcl.type.simple]p3: A deducible template is either a class template ...
+    if (isa<ClassTemplateDecl>(TD))
+      return true;
+
+    // ... or is an alias template ...
+    auto *Alias = dyn_cast<TypeAliasTemplateDecl>(TD);
+    if (!Alias)
+      return false;
+
+    QualType AliasType = Alias->getTemplatedDecl()->getUnderlyingType().getCanonicalType();
+
+    // ... whose defining-type-id is of the form
+    // [typename] [nested-name-specifier] [template] simple-template-id ...
+    if (const auto *TST = AliasType->getAs<TemplateSpecializationType>()) {
+      // ... and the template-name of the simple-template-id names a deducible template
+      TD = TST->getTemplateName().getAsTemplateDecl();
+      continue;
+    }
+
+    // Handle the case that the RHS of the alias is not dependent
+    // e.g. using AliasFoo = Foo<bool>;
+    if (const auto *RT = AliasType->getAs<RecordType>())
+      return isa<ClassTemplateSpecializationDecl>(RT->getAsCXXRecordDecl());
+
+    return false;
+  }
+
+  return false;
+}
+
 void DeclareImplicitDeductionGuidesFromInheritedConstructors(
     Sema &SemaRef, TemplateDecl *Template, ClassTemplateDecl *Pattern,
     TypeSourceInfo *BaseTSI, unsigned BaseIdx) {
@@ -1340,7 +1379,10 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   SourceLocation BaseLoc = BaseTSI->getTypeLoc().getBeginLoc();
 
   TemplateDecl *BaseTD = BaseTST->getTemplateName().getAsTemplateDecl();
-  if (!BaseTD)
+
+  // The alias template `A` that we build out of the base type must be a deducible template.
+  // `A` will be of the correct form, so it is deducible iff BaseTD is deducible
+  if (!BaseTD || !IsDeducibleTemplate(BaseTD))
     return;
 
   // Substitute any parameters with default arguments not present in the base,
@@ -1349,9 +1391,9 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   auto BaseDeducedTemplateParams =
       TemplateParamsReferencedInTemplateArgumentList(
           TemplateTPL, BaseTST->template_arguments());
-  SmallVector<NamedDecl *, 8> PartialSpecParams;
+  SmallVector<NamedDecl *, 8> AliasTemplateParams;
   SmallVector<TemplateArgument, 8> SubstArgs;
-  PartialSpecParams.reserve(TemplateTPL->size());
+  AliasTemplateParams.reserve(TemplateTPL->size());
   SubstArgs.reserve(TemplateTPL->size());
   LocalInstantiationScope Scope(SemaRef);
   for (unsigned I = 0, N = TemplateTPL->size(); I < N; ++I) {
@@ -1386,12 +1428,12 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
     Args.addOuterRetainedLevels(Template->getTemplateDepth());
 
     NamedDecl *NewParam = transformTemplateParameter(
-        SemaRef, DC, Param, Args, PartialSpecParams.size(),
+        SemaRef, DC, Param, Args, AliasTemplateParams.size(),
         Template->getTemplateDepth());
     if (!NewParam)
       return;
 
-    PartialSpecParams.push_back(NewParam);
+    AliasTemplateParams.push_back(NewParam);
     SubstArgs.push_back(Context.getInjectedTemplateArg(NewParam));
   }
 
@@ -1406,9 +1448,26 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
       return;
     RequiresClause = E.getAs<Expr>();
   }
-  auto *PartialSpecTPL = TemplateParameterList::Create(
+  auto *AliasTPL = TemplateParameterList::Create(
       Context, TemplateTPL->getTemplateLoc(), TemplateTPL->getLAngleLoc(),
-      PartialSpecParams, TemplateTPL->getRAngleLoc(), RequiresClause);
+      AliasTemplateParams, TemplateTPL->getRAngleLoc(), RequiresClause);
+
+  // Clone AliasTPL into a new parameter list for the partial specialization,
+  // but with default arguments removed, using the template instantiator
+  // for heavy lifting.
+  LocalInstantiationScope CloneScope(SemaRef);
+  TemplateDeclInstantiator CloneTDI(SemaRef, DC, /*TemplateArgs=*/{});
+  TemplateParameterList *PartialSpecTPL = CloneTDI.SubstTemplateParams(AliasTPL);
+  CloneScope.Exit();
+  for (NamedDecl *Param : *PartialSpecTPL) {
+    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+      TTP->removeDefaultArgument();
+    } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+      NTTP->removeDefaultArgument();
+    } else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+      TTP->removeDefaultArgument();
+    }
+  }
 
   // [over.match.class.deduct]p1.10
   // Let A be an alias template whose template parameter list is that of
@@ -1419,12 +1478,12 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
       Context, DC, SourceLocation(), BaseLoc,
       TransformedBase->getType().getBaseTypeIdentifier(), TransformedBase);
   std::string AliasDeclName =
-      (Twine("__ctad_alias_") + BaseTD->getName() + "_to_" +
+      (Twine("__ctad_A_") + BaseTD->getName() + "_to_" +
        Template->getName() + "_" + Twine(BaseIdx))
           .str();
   IdentifierInfo *AliasIdentifier = &Context.Idents.get(AliasDeclName);
   auto *BaseATD = TypeAliasTemplateDecl::Create(
-      Context, DC, BaseLoc, DeclarationName(AliasIdentifier), PartialSpecTPL,
+      Context, DC, BaseLoc, DeclarationName(AliasIdentifier), AliasTPL,
       BaseAD);
   BaseAD->setDescribedAliasTemplate(BaseATD);
   BaseAD->setImplicit();
@@ -1443,7 +1502,7 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
       ArrayRef<NamedDecl *>(TParam), SourceLocation(), nullptr);
 
   std::string MapperDeclName =
-      (Twine("__ctad_mapper_") + BaseTD->getName() + "_to_" +
+      (Twine("__ctad_CC_") + BaseTD->getName() + "_to_" +
        Template->getName() + "_" + Twine(BaseIdx))
           .str();
   IdentifierInfo *MapperII = &Context.Idents.get(MapperDeclName);
@@ -1540,7 +1599,7 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
       ReturnTypeTLB.getTypeSourceInfo(Context, MapperReturnType);
 
   InheritedConstructorDeductionInfo Info{Template, MapperTSI};
-  DeclareImplicitDeductionGuidesForTypeAlias(SemaRef, BaseATD, BaseLoc, Info);
+  DeclareImplicitDeductionGuidesForTypeAlias(SemaRef, BaseATD, BaseLoc, &Info);
 }
 
 // Build an aggregate deduction guide for a type alias template.
diff --git a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
index 0adf465ef014b1..507badc00ff6ca 100644
--- a/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
+++ b/clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp
@@ -41,9 +41,9 @@ namespace test1 {
                                                                       // expected-note 2{{implicit deduction guide declared as }}
     using NonTemplateDGuideBase<T>::NonTemplateDGuideBase; // expected-note {{candidate function not viable: no known conversion from 'const char[1]' to 'int' for 1st argument}} \
                                                            // expected-note {{candidate template ignored: could not deduce template arguments for 'NonTemplateDGuideDerived<T>' from 'NonTemplateDGuideBase<T>' [with T = const char *]}} \
-                                                           // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(T) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
+                                                           // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_CC_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(T) -> typename __ctad_CC_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}} \
                                                            // expected-note {{candidate template ignored: could not match 'NonTemplateDGuideBase<T>' against 'const char *'}} \
-                                                           // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<T>) -> typename __ctad_mapper_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}}
+                                                           // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::NonTemplateDGuideDerived, typename __ctad_CC_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type) NonTemplateDGuideDerived(NonTemplateDGuideBase<T>) -> typename __ctad_CC_NonTemplateDGuideBase_to_NonTemplateDGuideDerived_0<NonTemplateDGuideBase<T>>::type'}}
   };
 
   NonTemplateDGuideDerived ntdg(1);
@@ -66,10 +66,10 @@ namespace test1 {
                                                     // expected-note 2{{implicit deduction guide declared as }}
 
     using ExplicitBase<T>::ExplicitBase; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
-                                         // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(V) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
+                                         // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T, typename V> requires __is_deducible(test1::ExplicitDerived, typename __ctad_CC_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(V) -> typename __ctad_CC_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}} \
                                          // expected-note {{candidate template ignored: could not match 'ExplicitBase<T>' against 'const char *'}} \
                                          // expected-note {{candidate template ignored: could not deduce template arguments for 'ExplicitDerived<T>' from 'ExplicitBase<T>' [with T = const char *]}} \
-                                         // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(ExplicitBase<T>) -> typename __ctad_mapper_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}}
+                                         // expected-note {{implicit deduction guide declared as 'template <NoPointers<> T> requires __is_deducible(test1::ExplicitDerived, typename __ctad_CC_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type) ExplicitDerived(ExplicitBase<T>) -> typename __ctad_CC_ExplicitBase_to_ExplicitDerived_0<ExplicitBase<T>>::type'}}
   };
 
   ExplicitDerived ed(10);
@@ -115,9 +115,9 @@ namespace test3 {
                                                                              // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                                                              // expected-note 3{{implicit deduction guide declared as}}
     using Base<T>::Base; // expected-note {{candidate template ignored: could not deduce template arguments for 'NotEnoughParams<T, U>' from 'Base<T>' [with T = int]}} \
-                         // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(T) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
+                         // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_CC_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(T) -> typename __ctad_CC_Base_to_NotEnoughParams_0<Base<T>>::type'}} \
                          // expected-note {{candidate template ignored: could not match 'Base<T>' against 'int'}} \
-                         // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(Base<T>) -> typename __ctad_mapper_Base_to_NotEnoughParams_0<Base<T>>::type'}}
+                         // expected-note {{implicit deduction guide declared as 'template <typename T> requires __is_deducible(test3::NotEnoughParams, typename __ctad_CC_Base_to_NotEnoughParams_0<Base<T>>::type) NotEnoughParams(Base<T>) -> typename __ctad_CC_Base_to_NotEnoughParams_0<Base<T>>::type'}}
   };
 
   NotEnoughParams notEnoughParams(1); // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
@@ -181,9 +181,9 @@ namespace test6 {
                                          // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
                                          // expected-note 3{{implicit deduction guide declared as}}
       using Base<F>::Base; // expected-note {{candidate template ignored: could not deduce template arguments for 'DerivedFalse<F>' from 'Base<T>' [with F = int]}} \
-                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(F) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}} \
+                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_CC_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(F) -> typename __ctad_CC_Base_to_DerivedFalse_0<Base<F>>::type'}} \
                            // expected-note {{candidate template ignored: could not match 'Base<F>' against 'int'}} \
-                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(Base<F>) -> typename __ctad_mapper_Base_to_DerivedFalse_0<Base<F>>::type'}}
+                           // expected-note {{implicit deduction guide declared as 'template <False<> F> requires __is_deducible(test6::DerivedFalse, typename __ctad_CC_Base_to_DerivedFalse_0<Base<F>>::type) DerivedFalse(Base<F>) -> typename __ctad_CC_Base_to_DerivedFalse_0<Base<F>>::type'}}
     };
 
   template<True F>
@@ -269,3 +269,16 @@ namespace test9 {
   C c('1', 2, 3, 4, 5);
   static_assert(__is_same(C<char, int, int, int, int>, decltype(c)));
 }
+
+namespace test10 {
+  // L is not a deducible template
+  template<typename V>
+  using L = decltype([]<class T>(T t) -> int { return 0; });
+
+  template<typename T = int>
+  class Derived : L<T> {
+    using L<T>::L; // expected-error {{using declaration refers into 'L<int>::', which is not a base class of 'Derived<>'}}
+  };
+
+  Derived d; // expected-note {{in instantiation of template class 'test10::Derived<>' requested here}}
+}

>From c7071c8f21969f3ff13bedecd5bc87a0da2a9892 Mon Sep 17 00:00:00 2001
From: antangelo <contact at antangelo.com>
Date: Tue, 10 Sep 2024 18:44:44 -0400
Subject: [PATCH 15/15] clang-format

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 34 +++++++++----------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 4024ca33724ca5..53eb67ba5c77bf 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1015,8 +1015,7 @@ TypeSourceInfo *buildInheritedConstructorDeductionGuideType(
 FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     FunctionTemplateDecl *F, SourceLocation Loc,
-    InheritedConstructorDeductionInfo *FromInheritedCtor =
-        nullptr) {
+    InheritedConstructorDeductionInfo *FromInheritedCtor = nullptr) {
   LocalInstantiationScope Scope(SemaRef);
   Sema::InstantiatingTemplate BuildingDeductionGuides(
       SemaRef, AliasTemplate->getLocation(), F,
@@ -1236,8 +1235,7 @@ FunctionTemplateDecl *BuildDeductionGuideForTypeAlias(
 
 void DeclareImplicitDeductionGuidesForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc,
-    InheritedConstructorDeductionInfo *FromInheritedCtor =
-        nullptr) {
+    InheritedConstructorDeductionInfo *FromInheritedCtor = nullptr) {
   if (AliasTemplate->isInvalidDecl())
     return;
   TemplateDecl *DeducedTemplate = FromInheritedCtor
@@ -1347,12 +1345,14 @@ static bool IsDeducibleTemplate(TemplateDecl *TD) {
     if (!Alias)
       return false;
 
-    QualType AliasType = Alias->getTemplatedDecl()->getUnderlyingType().getCanonicalType();
+    QualType AliasType =
+        Alias->getTemplatedDecl()->getUnderlyingType().getCanonicalType();
 
     // ... whose defining-type-id is of the form
     // [typename] [nested-name-specifier] [template] simple-template-id ...
     if (const auto *TST = AliasType->getAs<TemplateSpecializationType>()) {
-      // ... and the template-name of the simple-template-id names a deducible template
+      // ... and the template-name of the simple-template-id names a deducible
+      // template
       TD = TST->getTemplateName().getAsTemplateDecl();
       continue;
     }
@@ -1380,8 +1380,9 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
 
   TemplateDecl *BaseTD = BaseTST->getTemplateName().getAsTemplateDecl();
 
-  // The alias template `A` that we build out of the base type must be a deducible template.
-  // `A` will be of the correct form, so it is deducible iff BaseTD is deducible
+  // The alias template `A` that we build out of the base type must be a
+  // deducible template. `A` will be of the correct form, so it is deducible iff
+  // BaseTD is deducible
   if (!BaseTD || !IsDeducibleTemplate(BaseTD))
     return;
 
@@ -1457,7 +1458,8 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   // for heavy lifting.
   LocalInstantiationScope CloneScope(SemaRef);
   TemplateDeclInstantiator CloneTDI(SemaRef, DC, /*TemplateArgs=*/{});
-  TemplateParameterList *PartialSpecTPL = CloneTDI.SubstTemplateParams(AliasTPL);
+  TemplateParameterList *PartialSpecTPL =
+      CloneTDI.SubstTemplateParams(AliasTPL);
   CloneScope.Exit();
   for (NamedDecl *Param : *PartialSpecTPL) {
     if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
@@ -1477,14 +1479,12 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
   auto *BaseAD = TypeAliasDecl::Create(
       Context, DC, SourceLocation(), BaseLoc,
       TransformedBase->getType().getBaseTypeIdentifier(), TransformedBase);
-  std::string AliasDeclName =
-      (Twine("__ctad_A_") + BaseTD->getName() + "_to_" +
-       Template->getName() + "_" + Twine(BaseIdx))
-          .str();
+  std::string AliasDeclName = (Twine("__ctad_A_") + BaseTD->getName() + "_to_" +
+                               Template->getName() + "_" + Twine(BaseIdx))
+                                  .str();
   IdentifierInfo *AliasIdentifier = &Context.Idents.get(AliasDeclName);
   auto *BaseATD = TypeAliasTemplateDecl::Create(
-      Context, DC, BaseLoc, DeclarationName(AliasIdentifier), AliasTPL,
-      BaseAD);
+      Context, DC, BaseLoc, DeclarationName(AliasIdentifier), AliasTPL, BaseAD);
   BaseAD->setDescribedAliasTemplate(BaseATD);
   BaseAD->setImplicit();
   BaseATD->setImplicit();
@@ -1502,8 +1502,8 @@ void DeclareImplicitDeductionGuidesFromInheritedConstructors(
       ArrayRef<NamedDecl *>(TParam), SourceLocation(), nullptr);
 
   std::string MapperDeclName =
-      (Twine("__ctad_CC_") + BaseTD->getName() + "_to_" +
-       Template->getName() + "_" + Twine(BaseIdx))
+      (Twine("__ctad_CC_") + BaseTD->getName() + "_to_" + Template->getName() +
+       "_" + Twine(BaseIdx))
           .str();
   IdentifierInfo *MapperII = &Context.Idents.get(MapperDeclName);
   CXXRecordDecl *MapperRD = CXXRecordDecl::Create(



More information about the cfe-commits mailing list