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

via cfe-commits cfe-commits at lists.llvm.org
Sat Jul 13 19:40:15 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-modules

Author: None (antangelo)

<details>
<summary>Changes</summary>

There are two known issues with this initial implementation:
1. Deduction guides are not generated for explicit guides of the base defined after the initial usage of the derived class. This is a caused by a similar issue in the alias template deduction guide implementation.
2. It is currently unable to detect bases whose constructors are inherited by a using declaration with a dependent name, such as `using Derived::Base::Base;`. These using declarations in general are unresolved, so it is difficult to look them up and match them to the corresponding base before instantiation.

I intend to target clang 20 for merging this patch.

Closes #<!-- -->92606

---

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


13 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+2) 
- (modified) clang/include/clang/AST/DeclCXX.h (+33-3) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4) 
- (modified) clang/lib/AST/ASTImporter.cpp (+5-3) 
- (modified) clang/lib/AST/DeclCXX.cpp (+6-4) 
- (modified) clang/lib/Sema/SemaOverload.cpp (+67) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+359-30) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+2-1) 
- (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+2) 
- (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+2) 
- (added) clang/test/SemaCXX/cxx23-ctad-inherited-ctors.cpp (+260) 
- (modified) clang/unittests/AST/ASTImporterTest.cpp (+43) 
- (modified) clang/www/cxx_status.html (+1-1) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5dc0f8b7e0bbb..b6924f61814fb 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 fb52ac804849d..c8e74f32b2ccb 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 0ea3677355169..da144704957ca 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 9bb035c07b8ae..e4c6ef256872a 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 d5c140fd34389..91877a49dcf5e 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 d4a48858ec419..df2b00edaf940 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 9296cc66d6918..ec939a2fb718d 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(), AliasTemp...
[truncated]

``````````

</details>


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


More information about the cfe-commits mailing list