https://github.com/zyn0217 updated 
https://github.com/llvm/llvm-project/pull/223340

>From f7ae9a62e7d82a71be4f2c1c8f153a85b0d2f2a7 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Mon, 14 Sep 2026 17:31:25 +0800
Subject: [PATCH 1/3] [Clang] Fix synthesizing of alias CTAD constraints

buildAssociatedConstraints reconstructs a template parameter list relative
to its primary template. However it didn't match the construction of
the CTAD guide very precisely.
---
 clang/docs/ReleaseNotes.md                    |  2 ++
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 29 ++++++++++++-------
 clang/test/SemaCXX/ctad.cpp                   | 29 +++++++++++++++++++
 3 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 043a0ddae2a6c..be67a1b3779d8 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -579,6 +579,8 @@ features cannot lower the translation-unit ABI level;
 - Fixed a crash when a using-declaration naming an unresolvable member of a
   dependent base was shadowed by an invalid using-declaration. (#GH209427)
 
+- Fixed a CTAD bug when combining with concepts. (#GH124715)
+
 - Fixed a regression where an internal-linkage function (e.g. a `static` or
   anonymous-namespace helper) declared in the global module fragment of the
   current translation unit was removed from the overload set when the calling
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 1a488ece55d25..e1000372985fc 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -998,11 +998,19 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
           AliasTemplate->getInstantiatedFromMemberTemplate())
     AdjustDepth = PrimaryTemplate->getTemplateDepth();
 
+  // FIXME: We're rebuilding the synthesized template parameter list again
+  // Consider reuse the template parameter from its caller.
+
   // We rebuild all template parameters with the uninstantiated depth, and
   // build template arguments refer to them.
-  SmallVector<TemplateArgument> AdjustedAliasTemplateArgs;
+  SmallVector<TemplateArgument> AdjustedAliasTemplateArgs(
+      AliasTemplate->getTemplateParameters()->size());
 
-  for (auto *TP : *AliasTemplate->getTemplateParameters()) {
+  unsigned N = 0;
+  for (unsigned Index = 0; Index != AdjustedAliasTemplateArgs.size(); ++Index) 
{
+    if (DeduceResults[Index].isNull())
+      continue;
+    auto *TP = AliasTemplate->getTemplateParameters()->getParam(Index);
     // Rebuild any internal references to earlier parameters and reindex
     // as we go.
     MultiLevelTemplateArgumentList Args;
@@ -1010,21 +1018,22 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
     Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
     NamedDecl *NewParam = transformTemplateParameter(
         SemaRef, AliasTemplate->getDeclContext(), TP, Args,
-        /*NewIndex=*/AdjustedAliasTemplateArgs.size(),
-        getDepthAndIndex(TP).first + AdjustDepth);
+        /*NewIndex=*/N++, getDepthAndIndex(TP).first + AdjustDepth);
 
     TemplateArgument NewTemplateArgument =
         Context.getInjectedTemplateArg(NewParam);
-    AdjustedAliasTemplateArgs.push_back(NewTemplateArgument);
+    AdjustedAliasTemplateArgs[Index] = NewTemplateArgument;
   }
+  assert(FirstUndeducedParamIdx == N);
+
   // Template arguments used to transform the template arguments in
   // DeducedResults.
   SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
       F->getTemplateParameters()->size());
   // Transform the transformed template args
-  MultiLevelTemplateArgumentList Args;
-  Args.setKind(TemplateSubstitutionKind::Rewrite);
-  Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
+  MultiLevelTemplateArgumentList ArgsForDeducedParams;
+  ArgsForDeducedParams.setKind(TemplateSubstitutionKind::Rewrite);
+  ArgsForDeducedParams.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
 
   for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
     const auto &D = DeduceResults[Index];
@@ -1047,7 +1056,7 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
     TemplateArgumentLoc Input =
         SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
     TemplateArgumentLoc Output;
-    if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
+    if (!SemaRef.SubstTemplateArgument(Input, ArgsForDeducedParams, Output)) {
       assert(TemplateArgsForBuildingRC[Index].isNull() &&
              "InstantiatedArgs must be null before setting");
       TemplateArgsForBuildingRC[Index] = Output.getArgument();
@@ -1119,7 +1128,7 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
 Expr *buildIsDeducibleConstraint(Sema &SemaRef,
                                  TypeAliasTemplateDecl *AliasTemplate,
                                  QualType ReturnType,
-                                 SmallVector<NamedDecl *> TemplateParams) {
+                                 ArrayRef<NamedDecl *> TemplateParams) {
   ASTContext &Context = SemaRef.Context;
   // Constraint AST nodes must use uninstantiated depth.
   if (auto *PrimaryTemplate =
diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp
index 2a4e1c571ac5c..6517e88a8a831 100644
--- a/clang/test/SemaCXX/ctad.cpp
+++ b/clang/test/SemaCXX/ctad.cpp
@@ -197,3 +197,32 @@ namespace GH131342 {
   template <class T> using AA = A<T, val<T>>;
   AA a{0};
 } // namespace GH131342
+
+namespace GH124715_2 {
+
+template <class F, class... Args>
+using invoke_result_t = decltype(F()(Args()...));
+
+template <class F, class... Args>
+invoke_result_t<F, Args...> invoke(F f, Args... args);
+
+template <class F, class... Args>
+concept invocable = requires(F f, Args... args) {
+    invoke(f, args...);
+};
+
+template <class Ret, class... Args>
+struct A {
+    A(auto&&...) {}
+};
+
+template <class Lambda, class... Args>
+    requires invocable<Lambda, Args...>
+A(Lambda, Args...) -> A<invoke_result_t<Lambda, Args...>, Args...>;
+
+template <class T, class... Ts>
+using AliasName = A<T, Ts...>;
+
+AliasName aa([](int){}, 0);
+
+}

>From dec9c601da34631af5d8989bcfaed628d7cd2030 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Tue, 15 Sep 2026 16:39:52 +0800
Subject: [PATCH 2/3] Remove FIXME

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

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index e1000372985fc..5f656c01083d2 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -998,9 +998,6 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
           AliasTemplate->getInstantiatedFromMemberTemplate())
     AdjustDepth = PrimaryTemplate->getTemplateDepth();
 
-  // FIXME: We're rebuilding the synthesized template parameter list again
-  // Consider reuse the template parameter from its caller.
-
   // We rebuild all template parameters with the uninstantiated depth, and
   // build template arguments refer to them.
   SmallVector<TemplateArgument> AdjustedAliasTemplateArgs(

>From 8d6208ad2b3d9ff161161b476d8b5b8e8faf1812 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Tue, 15 Sep 2026 16:58:27 +0800
Subject: [PATCH 3/3] Really match how BuildDeductionGuideForTypeAlias works

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 51 +++++++++----------
 1 file changed, 23 insertions(+), 28 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 5f656c01083d2..fa0918ae30282 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -956,6 +956,19 @@ llvm::DenseSet<const NamedDecl *> 
getSourceDeductionGuides(DeclarationName Name,
   return Result;
 }
 
+bool IsNonDeducedArgument(const TemplateArgument &TA) {
+  // The following cases indicate the template argument is non-deducible:
+  //   1. The result is null. E.g. When it comes from a default template
+  //   argument that doesn't appear in the alias declaration.
+  //   2. The template parameter is a pack and that cannot be deduced from
+  //   the arguments within the alias declaration.
+  // Non-deducible template parameters will persist in the transformed
+  // deduction guide.
+  return TA.isNull() ||
+         (TA.getKind() == TemplateArgument::Pack &&
+          llvm::any_of(TA.pack_elements(), IsNonDeducedArgument));
+}
+
 // Build the associated constraints for the alias deduction guides.
 // C++ [over.match.class.deduct]p3.3:
 //   The associated constraints ([temp.constr.decl]) are the conjunction of the
@@ -968,7 +981,8 @@ Expr *
 buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
                            TypeAliasTemplateDecl *AliasTemplate,
                            ArrayRef<DeducedTemplateArgument> DeduceResults,
-                           unsigned FirstUndeducedParamIdx, Expr *IsDeducible) 
{
+                           ArrayRef<unsigned> DeducedAliasTemplateParams,
+                           Expr *IsDeducible) {
   Expr *RC = F->getTemplateParameters()->getRequiresClause();
   if (!RC)
     return IsDeducible;
@@ -1004,9 +1018,7 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
       AliasTemplate->getTemplateParameters()->size());
 
   unsigned N = 0;
-  for (unsigned Index = 0; Index != AdjustedAliasTemplateArgs.size(); ++Index) 
{
-    if (DeduceResults[Index].isNull())
-      continue;
+  for (unsigned Index : DeducedAliasTemplateParams) {
     auto *TP = AliasTemplate->getTemplateParameters()->getParam(Index);
     // Rebuild any internal references to earlier parameters and reindex
     // as we go.
@@ -1021,7 +1033,6 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
         Context.getInjectedTemplateArg(NewParam);
     AdjustedAliasTemplateArgs[Index] = NewTemplateArgument;
   }
-  assert(FirstUndeducedParamIdx == N);
 
   // Template arguments used to transform the template arguments in
   // DeducedResults.
@@ -1034,17 +1045,15 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
 
   for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
     const auto &D = DeduceResults[Index];
-    if (D.isNull()) { // non-deduced template parameters of f
+    if (IsNonDeducedArgument(D)) { // non-deduced template parameters of f
       NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
       MultiLevelTemplateArgumentList Args;
       Args.setKind(TemplateSubstitutionKind::Rewrite);
       Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
       // Rebuild the template parameter with updated depth and index.
-      NamedDecl *NewParam =
-          transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args,
-                                     /*NewIndex=*/FirstUndeducedParamIdx,
-                                     getDepthAndIndex(TP).first + AdjustDepth);
-      FirstUndeducedParamIdx += 1;
+      NamedDecl *NewParam = transformTemplateParameter(
+          SemaRef, F->getDeclContext(), TP, Args,
+          /*NewIndex=*/N++, getDepthAndIndex(TP).first + AdjustDepth);
       assert(TemplateArgsForBuildingRC[Index].isNull());
       TemplateArgsForBuildingRC[Index] =
           Context.getInjectedTemplateArg(NewParam);
@@ -1203,19 +1212,6 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, 
TypeAliasTemplateDecl *AliasTemplate) {
   return {Template, AliasRhsTemplateArgs};
 }
 
-bool IsNonDeducedArgument(const TemplateArgument &TA) {
-  // The following cases indicate the template argument is non-deducible:
-  //   1. The result is null. E.g. When it comes from a default template
-  //   argument that doesn't appear in the alias declaration.
-  //   2. The template parameter is a pack and that cannot be deduced from
-  //   the arguments within the alias declaration.
-  // Non-deducible template parameters will persist in the transformed
-  // deduction guide.
-  return TA.isNull() ||
-         (TA.getKind() == TemplateArgument::Pack &&
-          llvm::any_of(TA.pack_elements(), IsNonDeducedArgument));
-}
-
 // Build deduction guides for a type alias template from the given underlying
 // source deduction guide.
 CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
@@ -1362,7 +1358,6 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
         Context.getInjectedTemplateArg(NewParam);
     TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
   }
-  unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
 
   // To form a deduction guide f' from f, we leverage clang's instantiation
   // mechanism, we construct a template argument list where the template
@@ -1453,7 +1448,7 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
         SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
     Expr *RequiresClause =
         buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults,
-                                   FirstUndeducedParamIdx, IsDeducible);
+                                   DeducedAliasTemplateParams, IsDeducible);
 
     TemplateParameterList *FPrimeTemplateParamList = nullptr;
     if (!FPrimeTemplateParams.empty())
@@ -1519,11 +1514,11 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
         NewParam->setScopeInfo(0, I);
         FPTL.setParam(I, NewParam);
       }
-      auto *Transformed = cast<CXXDeductionGuideDecl>(buildDeductionGuide(
+      auto *Transformed = buildDeductionGuide(
           SemaRef, AliasTemplate, /*TemplateParams=*/nullptr,
           /*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType,
           AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
-          AliasTemplate->getEndLoc(), DG->isImplicit()));
+          AliasTemplate->getEndLoc(), DG->isImplicit());
       Transformed->setSourceDeductionGuide(DG);
       Transformed->setSourceDeductionGuideKind(
           CXXDeductionGuideDecl::SourceDeductionGuideKind::Alias);

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to