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

>From f8b1894ad39560edb5bb0c14194a3a2d54a911ff Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7...@gmail.com>
Date: Wed, 9 Jul 2025 16:29:45 +0800
Subject: [PATCH 1/2] [Clang] Consider default template arguments when
 synthesizing CTAD guides

We copy arguments from different template parameter lists depending on
the deducibility of the template parameters. In particular, we may lose
the default template argument from the original alias declaration, and
this patch helps preserve that.
---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 34 +++++++++---
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  | 52 ++++++++++++++++---
 2 files changed, 74 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index bdc46a0115a45..3951813dc66dd 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -949,7 +949,7 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
     ReturnType = SemaRef.SubstType(
         ReturnType, Args, AliasTemplate->getLocation(),
         Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate));
-  };
+  }
 
   SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = {
       Context.getTrivialTypeSourceInfo(
@@ -969,11 +969,14 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
 }
 
 std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>>
-getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) 
{
+getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
+                          bool Desugar) {
   // Unwrap the sugared ElaboratedType.
   auto RhsType = AliasTemplate->getTemplatedDecl()
                      ->getUnderlyingType()
                      .getSingleStepDesugaredType(SemaRef.Context);
+  if (Desugar)
+    RhsType = RhsType.getDesugaredType(SemaRef.Context);
   TemplateDecl *Template = nullptr;
   llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
   if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
@@ -1023,8 +1026,26 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
 
   auto &Context = SemaRef.Context;
   auto [Template, AliasRhsTemplateArgs] =
-      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
+      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate, /*Desugar=*/true);
 
+  // We need both types desugared, before we continue to perform type 
deduction.
+  // The intent is to get the template argument list 'matched', e.g. in the
+  // following case:
+  //
+  //
+  //  template <class T>
+  //  struct A {};
+  //  template <class T>
+  //  using Foo = A<A<T>>;
+  //  template <class U = int>
+  //  using Bar = Foo<U>;
+  //
+  // In terms of Bar, we want U (which has the default argument) to appear in
+  // the synthesized deduction guide, but U would remain undeduced if we 
deduced
+  // A<A<T>> using Foo<U> directly.
+  //
+  // Instead, we need to canonicalize both against A, i.e. A<A<T>> and A<A<U>>,
+  // such that T can be deduced as U.
   auto RType = F->getTemplatedDecl()->getReturnType();
   // The (trailing) return type of the deduction guide.
   const TemplateSpecializationType *FReturnType =
@@ -1034,7 +1055,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
     FReturnType = InjectedCNT->getInjectedTST();
   else if (const auto *ET = RType->getAs<ElaboratedType>())
     // explicit deduction guide.
-    FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
+    FReturnType = 
ET->getNamedType()->getAsNonAliasTemplateSpecializationType();
   assert(FReturnType && "expected to see a return type");
   // Deduce template arguments of the deduction guide f from the RHS of
   // the alias.
@@ -1223,7 +1244,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
     return;
   auto &Context = SemaRef.Context;
   auto [Template, AliasRhsTemplateArgs] =
-      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
+      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate, /*Desugar=*/false);
   if (!Template)
     return;
   auto SourceDeductionGuides = getSourceDeductionGuides(
@@ -1303,7 +1324,8 @@ FunctionTemplateDecl 
*DeclareAggregateDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     MutableArrayRef<QualType> ParamTypes, SourceLocation Loc) {
   TemplateDecl *RHSTemplate =
-      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate).first;
+      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate, /*Desugar=*/false)
+          .first;
   if (!RHSTemplate)
     return nullptr;
 
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp 
b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index aeb02c9e4898e..34bfa020f5baa 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -207,13 +207,14 @@ namespace test15 {
 template <class T> struct Foo { Foo(T); };
 
 template<class V> using AFoo = Foo<V *>;
-template<typename> concept False = false;
+template<typename> concept False = false; // #test15_False
 template<False W>
-using BFoo = AFoo<W>; // expected-note {{candidate template ignored: 
constraints not satisfied [with V = int]}} \
-                      // expected-note {{cannot deduce template arguments for 
'BFoo' from 'Foo<int *>'}} \
-                      // expected-note {{implicit deduction guide declared as 
'template <class V> requires __is_deducible(AFoo, Foo<V *>) && 
__is_deducible(test15::BFoo, Foo<V *>) BFoo(V *) -> Foo<V *>}} \
-                      // expected-note {{candidate template ignored: could not 
match 'Foo<V *>' against 'int *'}} \
-                      // expected-note {{template <class V> requires 
__is_deducible(AFoo, Foo<V *>) && __is_deducible(test15::BFoo, Foo<V *>) 
BFoo(Foo<V *>) -> Foo<V *>}}
+using BFoo = AFoo<W>; // expected-note {{candidate template ignored: 
constraints not satisfied [with W = int]}} \
+                      // expected-note@-1 {{because 'int' does not satisfy 
'False'}} \
+                      // expected-note@#test15_False {{because 'false' 
evaluated to false}} \
+                      // expected-note {{implicit deduction guide declared as 
'template <False<> W> requires __is_deducible(AFoo, Foo<W *>) && 
__is_deducible(test15::BFoo, Foo<W *>) BFoo(W *) -> Foo<W *>}} \
+                      // expected-note {{candidate template ignored: could not 
match 'Foo<W *>' against 'int *'}} \
+                      // expected-note {{template <False<> W> requires 
__is_deducible(AFoo, Foo<W *>) && __is_deducible(test15::BFoo, Foo<W *>) 
BFoo(Foo<W *>) -> Foo<W *>}}
 int i = 0;
 AFoo a1(&i); // OK, deduce Foo<int *>
 
@@ -441,6 +442,25 @@ ACase4 case4{0, 1};
 
 } // namespace test24
 
+namespace test25 {
+
+template<typename T, typename...Us>
+struct A{
+  template<typename V> requires __is_same(V, int)
+  A(V);
+};
+
+template<typename...TS>
+using AA = A<int, TS...>;
+
+template<typename...US>
+using BB = AA<US...>;
+
+BB a{0};
+static_assert(__is_same(decltype(a), A<int>));
+
+}
+
 namespace GH92212 {
 template<typename T, typename...Us>
 struct A{
@@ -526,6 +546,7 @@ void foo() { test<{1, 2, 3}>(); }
 
 } // namespace GH113518
 
+// FIXME: This is accepted by GCC: https://gcc.godbolt.org/z/f3rMfbacz
 namespace GH125821 {
 template<typename T>
 struct A { A(T){} };
@@ -539,3 +560,22 @@ using C = Proxy< A<T> >;
 C test{ 42 }; // expected-error {{no viable constructor or deduction guide for 
deduction of template arguments}}
 
 } // namespace GH125821
+
+namespace GH133132 {
+
+template <class T>
+struct A {};
+
+template <class T>
+using Foo = A<A<T>>;
+
+template <class T>
+using Bar = Foo<T>;
+
+template <class T = int>
+using Baz = Bar<T>;
+
+Baz a{};
+static_assert(__is_same(decltype(a), A<A<int>>));
+
+} // namespace GH133132

>From 7450653f60791c5de9c59f0c7dcc92a6dd40999c Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7...@gmail.com>
Date: Fri, 11 Jul 2025 16:26:28 +0800
Subject: [PATCH 2/2] Simplify more

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

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 3951813dc66dd..9be1c9c356cb2 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -969,14 +969,11 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
 }
 
 std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>>
-getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
-                          bool Desugar) {
+getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) 
{
   // Unwrap the sugared ElaboratedType.
   auto RhsType = AliasTemplate->getTemplatedDecl()
                      ->getUnderlyingType()
                      .getSingleStepDesugaredType(SemaRef.Context);
-  if (Desugar)
-    RhsType = RhsType.getDesugaredType(SemaRef.Context);
   TemplateDecl *Template = nullptr;
   llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
   if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
@@ -984,7 +981,8 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, 
TypeAliasTemplateDecl *AliasTemplate,
     //   template<typename T>
     //   using AliasFoo1 = Foo<T>; // a class/type alias template 
specialization
     Template = TST->getTemplateName().getAsTemplateDecl();
-    AliasRhsTemplateArgs = TST->template_arguments();
+    AliasRhsTemplateArgs =
+        TST->getAsNonAliasTemplateSpecializationType()->template_arguments();
   } else if (const auto *RT = RhsType->getAs<RecordType>()) {
     // Cases where template arguments in the RHS of the alias are not
     // dependent. e.g.
@@ -1026,7 +1024,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
 
   auto &Context = SemaRef.Context;
   auto [Template, AliasRhsTemplateArgs] =
-      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate, /*Desugar=*/true);
+      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
 
   // We need both types desugared, before we continue to perform type 
deduction.
   // The intent is to get the template argument list 'matched', e.g. in the
@@ -1244,7 +1242,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
     return;
   auto &Context = SemaRef.Context;
   auto [Template, AliasRhsTemplateArgs] =
-      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate, /*Desugar=*/false);
+      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
   if (!Template)
     return;
   auto SourceDeductionGuides = getSourceDeductionGuides(
@@ -1324,8 +1322,7 @@ FunctionTemplateDecl 
*DeclareAggregateDeductionGuideForTypeAlias(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
     MutableArrayRef<QualType> ParamTypes, SourceLocation Loc) {
   TemplateDecl *RHSTemplate =
-      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate, /*Desugar=*/false)
-          .first;
+      getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate).first;
   if (!RHSTemplate)
     return nullptr;
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to