https://github.com/bassiounix updated 
https://github.com/llvm/llvm-project/pull/193056

>From 39b87cfe469336770e1d94e6bea5f50f6fae75d4 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Mon, 20 Apr 2026 20:50:53 +0200
Subject: [PATCH 01/12] [Clang][C++20] Add full support to deduction guides

---
 clang/lib/Frontend/InitPreprocessor.cpp | 3 +--
 clang/test/Lexer/cxx-features.cpp       | 3 +--
 clang/www/cxx_status.html               | 8 +-------
 3 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/clang/lib/Frontend/InitPreprocessor.cpp 
b/clang/lib/Frontend/InitPreprocessor.cpp
index 1ccd74314f373..0a5ab5c21cce6 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -686,7 +686,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const 
LangOptions &LangOpts,
     Builder.defineMacro("__cpp_noexcept_function_type", "201510L");
     Builder.defineMacro("__cpp_capture_star_this", "201603L");
     Builder.defineMacro("__cpp_if_constexpr", "201606L");
-    Builder.defineMacro("__cpp_deduction_guides", "201703L"); // (not latest)
     Builder.defineMacro("__cpp_template_auto", "201606L"); // (old name)
     Builder.defineMacro("__cpp_namespace_attributes", "201411L");
     Builder.defineMacro("__cpp_enumerator_attributes", "201411L");
@@ -708,7 +707,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const 
LangOptions &LangOpts,
   // C++20 features.
   if (LangOpts.CPlusPlus20) {
     Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
-
+    Builder.defineMacro("__cpp_deduction_guides", "201907L");
     Builder.defineMacro("__cpp_concepts", "202002");
     Builder.defineMacro("__cpp_conditional_explicit", "201806L");
     Builder.defineMacro("__cpp_consteval", "202211L");
diff --git a/clang/test/Lexer/cxx-features.cpp 
b/clang/test/Lexer/cxx-features.cpp
index 8eb9ea032879c..f8440ba6c641e 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -193,8 +193,7 @@
 #error "wrong value for __cpp_if_constexpr"
 #endif
 
-#if check(deduction_guides, 0, 0, 0, 201703, 201703, 201703, 201703)
-// FIXME: 201907 in C++20
+#if check(deduction_guides, 0, 0, 0, 201907, 201907, 201907, 201907)
 #error "wrong value for __cpp_deduction_guides"
 #endif
 
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 2c834b07f9a8f..eac8689da39fb 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1030,13 +1030,7 @@ <h2 id="cxx20">C++20 implementation status</h2>
     <tr>
       <td>Class template argument deduction for alias templates</td>
       <td><a href="https://wg21.link/p1814r0";>P1814R0</a></td>
-      <td class="partial" align="center">
-        <details>
-          <summary>Clang 19 (Partial)</summary>
-          This feature has been initially completed, but the feature macro
-          __cpp_deduction_guides has not been updated.
-        </details>
-      </td>
+      <td class="full" align="center">Clang 22</td>
     </tr>
     <tr>
       <td>Permit conversions to arrays of unknown bound</td>

>From d86ad85b0e6a6b9c167fd04b00fe5f291ff30958 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Mon, 20 Apr 2026 22:35:16 +0200
Subject: [PATCH 02/12] fix build

---
 clang/test/Lexer/cxx-features.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/test/Lexer/cxx-features.cpp 
b/clang/test/Lexer/cxx-features.cpp
index f8440ba6c641e..c99b0eca3af22 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -94,6 +94,10 @@
 #error "wrong value for __cpp_aggregate_paren_init"
 #endif
 
+#if check(deduction_guides, 0, 0, 0, 0, 201907, 201907, 201907)
+#error "wrong value for __cpp_deduction_guides"
+#endif
+
 #if defined(CHAR8_T) ? check(char8_t, 202207, 202207, 202207, 202207, 202207, 
202207, 202207) : \
     defined(NO_CHAR8_T) ? check(char8_t, 0, 0, 0, 0, 0, 0, 0) : \
     check(char8_t, 0, 0, 0, 0, 202207, 202207, 202207)
@@ -193,10 +197,6 @@
 #error "wrong value for __cpp_if_constexpr"
 #endif
 
-#if check(deduction_guides, 0, 0, 0, 201907, 201907, 201907, 201907)
-#error "wrong value for __cpp_deduction_guides"
-#endif
-
 #if check(nontype_template_parameter_auto, 0, 0, 0, 201606, 201606, 201606, 
201606)
 #error "wrong value for __cpp_nontype_template_parameter_auto"
 #endif

>From 971ce4bf50a10750dd894cef32c489b037d2e8d6 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Tue, 21 Apr 2026 15:42:00 +0200
Subject: [PATCH 03/12] enable ctad for both c++17 and c++20

---
 clang/lib/Frontend/InitPreprocessor.cpp | 1 +
 clang/test/Lexer/cxx-features.cpp       | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Frontend/InitPreprocessor.cpp 
b/clang/lib/Frontend/InitPreprocessor.cpp
index 0a5ab5c21cce6..0bab87c8a8d1b 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -686,6 +686,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const 
LangOptions &LangOpts,
     Builder.defineMacro("__cpp_noexcept_function_type", "201510L");
     Builder.defineMacro("__cpp_capture_star_this", "201603L");
     Builder.defineMacro("__cpp_if_constexpr", "201606L");
+    Builder.defineMacro("__cpp_deduction_guides", "201703L");
     Builder.defineMacro("__cpp_template_auto", "201606L"); // (old name)
     Builder.defineMacro("__cpp_namespace_attributes", "201411L");
     Builder.defineMacro("__cpp_enumerator_attributes", "201411L");
diff --git a/clang/test/Lexer/cxx-features.cpp 
b/clang/test/Lexer/cxx-features.cpp
index c99b0eca3af22..494b86d024b30 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -94,7 +94,7 @@
 #error "wrong value for __cpp_aggregate_paren_init"
 #endif
 
-#if check(deduction_guides, 0, 0, 0, 0, 201907, 201907, 201907)
+#if check(deduction_guides, 0, 0, 0, 201703, 201907, 201907, 201907)
 #error "wrong value for __cpp_deduction_guides"
 #endif
 

>From df7eb6223031877af5628b9bcc0cd54ba9629b83 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Tue, 21 Apr 2026 15:42:17 +0200
Subject: [PATCH 04/12] increase clang support version

---
 clang/www/cxx_status.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index eac8689da39fb..0581370ea751b 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1030,7 +1030,7 @@ <h2 id="cxx20">C++20 implementation status</h2>
     <tr>
       <td>Class template argument deduction for alias templates</td>
       <td><a href="https://wg21.link/p1814r0";>P1814R0</a></td>
-      <td class="full" align="center">Clang 22</td>
+      <td class="full" align="center">Clang 23</td>
     </tr>
     <tr>
       <td>Permit conversions to arrays of unknown bound</td>

>From e9bfd0893afd468860cee6ae5fddde9bfdff526e Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Wed, 2 Sep 2026 22:22:34 +0300
Subject: [PATCH 05/12] Fix GH125821

---
 clang/docs/ReleaseNotes.md                    |  7 ++++
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 35 ++++++++++++++++---
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  |  4 +--
 3 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index cd7f40aec112d..79386c1c8924f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -470,6 +470,13 @@ features cannot lower the translation-unit ABI level;
 
 - Fixed an issue where `__typeof__` incorrectly rejected cv-qualified function 
types.
 
+- Class template argument deduction through an alias template now works when
+  the right-hand side of the alias names another alias template that cannot
+  have deduction guides of its own, such as an identity alias
+  (`template <class T> using Identity = T;`). The deduction guides are now
+  derived from the first template in the chain that can have them, per the
+  equivalence rule of `[temp.alias]p2`, matching GCC. (#GH125821)
+
 - Fixed a bug where top-level CV qualifiers (such as ``const``) were dropped 
from pointers modified by Microsoft pointer attributes (like ``__ptr32`` and 
``__ptr64``) and WebAssembly's ``__funcref``.
 
 - Fixed an issue where we tried to compare invalid NTTPs for variable 
declarations, which ended up in hitting an assertion with a constrained 
non-plain-auto NTTP, which we don't quite implement yet. (#GH208658)
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 63d6759bc5490..e133ae0b1e9b0 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1177,13 +1177,40 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, 
TypeAliasTemplateDecl *AliasTemplate) {
   auto RhsType = AliasTemplate->getTemplatedDecl()->getUnderlyingType();
   TemplateDecl *Template = nullptr;
   llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
-  if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) {
+  const auto *TST = RhsType->getAs<TemplateSpecializationType>();
+
+  // The RHS of the alias may name another alias template that can never have
+  // deduction guides of its own, because its defining-type-id is not of the
+  // form
+  //   [typename] [nested-name-specifier] [template] simple-template-id
+  // as required by [over.match.class.deduct]p3. e.g.
+  //   template <typename T>
+  //   using Identity = T;
+  //   template <typename T>
+  //   using C = Identity<Foo<T>>;
+  // Per [temp.alias]p2, Identity<Foo<T>> is equivalent to Foo<T>, so step
+  // through such aliases and derive the deduction guides from the first
+  // template that can actually have them (GH125821).
+  while (TST) {
+    auto *RhsAlias = dyn_cast_or_null<TypeAliasTemplateDecl>(
+        TST->getTemplateName().getAsTemplateDecl());
+    if (!RhsAlias || getRHSTemplateDeclAndArgs(SemaRef, RhsAlias).first)
+      break;
+    RhsType = TST->desugar();
+    TST = RhsType->getAs<TemplateSpecializationType>();
+  }
+
+  if (TST) {
     // Cases where the RHS of the alias is dependent. e.g.
     //   template<typename T>
     //   using AliasFoo1 = Foo<T>; // a class/type alias template 
specialization
-    Template = TST->getTemplateName().getAsTemplateDecl();
-    AliasRhsTemplateArgs =
-        TST->getAsNonAliasTemplateSpecializationType()->template_arguments();
+    // The RHS may not desugar to a template specialization at all (e.g. an
+    // alias of the form 'T*' whose specialization ends up being a pointer);
+    // in that case, there is no template to derive the guides from.
+    if (const auto *RhsTST = TST->getAsNonAliasTemplateSpecializationType()) {
+      Template = TST->getTemplateName().getAsTemplateDecl();
+      AliasRhsTemplateArgs = RhsTST->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.
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp 
b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 78911cbaed67b..e0f59be663b2f 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -553,7 +553,6 @@ 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){} };
@@ -564,7 +563,8 @@ using Proxy = T;
 template<typename T>
 using C = Proxy< A<T> >;
 
-C test{ 42 }; // expected-error {{no viable constructor or deduction guide for 
deduction of template arguments}}
+C test{ 42 };
+static_assert(__is_same(decltype(test), A<int>));
 
 } // namespace GH125821
 

>From 83b7daebf896606b9bb518591e94a97160b0626a Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Wed, 2 Sep 2026 22:25:02 +0300
Subject: [PATCH 06/12] pump up clang version

---
 clang/www/cxx_status.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 6c045937add3e..9617a8f833fe1 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1154,7 +1154,7 @@ <h2 id="cxx20">C++20 implementation status</h2>
     <tr>
       <td>Class template argument deduction for alias templates</td>
       <td><a href="https://wg21.link/p1814r0";>P1814R0</a></td>
-      <td class="full" align="center">Clang 23</td>
+      <td class="unreleased" align="center">Clang 24</td>
     </tr>
     <tr>
       <td>Permit conversions to arrays of unknown bound</td>

>From b306f8160976b89f0bd2d8eaf0f42fa6d0b5bd88 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Thu, 3 Sep 2026 06:03:55 +0300
Subject: [PATCH 07/12] Allow default arguments deduction from the return type
 of the underlying deduction guide.

This change ensures that template parameters that cannot be deduced from 
constructor arguments receive appropriate default values.
---
 clang/docs/ReleaseNotes.md                    |  15 +-
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 454 ++++++++++++++++--
 clang/test/AST/ast-dump-ctad-alias.cpp        |  30 ++
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  | 102 ++++
 4 files changed, 560 insertions(+), 41 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 79386c1c8924f..21578b5eb87e1 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -73,7 +73,7 @@ features cannot lower the translation-unit ABI level;
 - On SPARC, a `_Complex` value with an integer element type is now passed and
   returned packed into the one or two integer registers it fits in, matching 
GCC.
   Clang previously passed such a value indirectly and returned it with one part
-  per register. 
+  per register.
   `-fclang-abi-compat=23` restores the previous behavior. (#GH212340)
 
 - On SPARC64, a `_Complex char` or `_Complex short` is now
@@ -119,7 +119,7 @@ features cannot lower the translation-unit ABI level;
 
 - `CompletionString.availability` now returns instances of `AvailabilityKind`.
   As a result, the `__str__` representation of its return values changed.
-  Like other libclang enums, it now follows the 
`CompletionChunkKind.VARIANT_NAME` scheme instead of `VariantName`. 
+  Like other libclang enums, it now follows the 
`CompletionChunkKind.VARIANT_NAME` scheme instead of `VariantName`.
 
 ### OpenCL Potentially Breaking Changes
 
@@ -477,6 +477,13 @@ features cannot lower the translation-unit ABI level;
   derived from the first template in the chain that can have them, per the
   equivalence rule of `[temp.alias]p2`, matching GCC. (#GH125821)
 
+- Class template argument deduction through an alias template now works when
+  a template parameter of the alias only appears in the synthesized deduction
+  guide through default template arguments. Such a template parameter now gets 
a default
+  template argument deduced from the return type of the underlying deduction
+  guide (here `Key` becomes the iterator's value type), instead of being
+  undeducible.
+
 - Fixed a bug where top-level CV qualifiers (such as ``const``) were dropped 
from pointers modified by Microsoft pointer attributes (like ``__ptr32`` and 
``__ptr64``) and WebAssembly's ``__funcref``.
 
 - Fixed an issue where we tried to compare invalid NTTPs for variable 
declarations, which ended up in hitting an assertion with a constrained 
non-plain-auto NTTP, which we don't quite implement yet. (#GH208658)
@@ -491,9 +498,9 @@ features cannot lower the translation-unit ABI level;
   producing a spurious "no matching function" error with no candidate notes.
   (#GH210822)
 
-- Fixed a crash when module directive export module foo not following a 
+- Fixed a crash when module directive export module foo not following a
   semicolon and there are no rest pp-tokens in current module file. (#GH187771)
-  
+
 - Fixed a crash when a lambda parameter pack was given a default argument that
   is a pack expansion referencing an enclosing function's parameter pack (e.g.
   `[](Types... = args...) {}`). Clang now diagnoses the illegal default
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index e133ae0b1e9b0..05b99c9374148 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -956,19 +956,61 @@ llvm::DenseSet<const NamedDecl *> 
getSourceDeductionGuides(DeclarationName Name,
   return Result;
 }
 
+// Marker for a template parameter that doesn't appear in the synthesized
+// deduction guide f' of an alias template.
+constexpr unsigned InvalidFPrimeIndex = -1;
+
+// A template parameter of the synthesized deduction guide f' of an alias
+// template A, before it is created.
+struct FPrimeTemplateParamRef {
+  // Whether this is a template parameter of A, as opposed to a non-deduced
+  // template parameter of the underlying deduction guide f.
+  bool IsAliasParam;
+  // The index of the template parameter in the template parameter list of A or
+  // f, respectively.
+  unsigned Index;
+  // For a non-deduced template parameter of f: the deduced template parameters
+  // of f that it refers to.
+  llvm::SmallBitVector DeducedFParamsUsed;
+};
+
+static bool hasDefaultArgument(const NamedDecl *Param) {
+  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+    return TTP->hasDefaultArgument();
+  if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+    return NTTP->hasDefaultArgument();
+  return cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();
+}
+
+static void setDefaultArgument(ASTContext &Context, NamedDecl *Param,
+                               const TemplateArgumentLoc &DefArg) {
+  if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+    TTP->setDefaultArgument(Context, DefArg);
+  else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+    NTTP->setDefaultArgument(Context, DefArg);
+  else
+    cast<TemplateTemplateParmDecl>(Param)->setDefaultArgument(Context, DefArg);
+}
+
 // 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
 //   associated constraints of g and a constraint that is satisfied if and only
 //   if the arguments of A are deducible (see below) from the return type.
 //
+// AliasParamFPrimeIndex and FParamFPrimeIndex give the index in f' of the
+// template parameters of the alias template and of the non-deduced template
+// parameters of F, respectively (InvalidFPrimeIndex for those not in f').
+//
 // The return result is expected to be the require-clause for the synthesized
 // alias deduction guide.
 Expr *
 buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
                            TypeAliasTemplateDecl *AliasTemplate,
                            ArrayRef<DeducedTemplateArgument> DeduceResults,
-                           unsigned FirstUndeducedParamIdx, Expr *IsDeducible) 
{
+                           ArrayRef<unsigned> AliasParamFPrimeIndex,
+                           ArrayRef<unsigned> FParamFPrimeIndex,
+                           Expr *IsDeducible) {
   Expr *RC = F->getTemplateParameters()->getRequiresClause();
   if (!RC)
     return IsDeducible;
@@ -1002,15 +1044,19 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
   // build template arguments refer to them.
   SmallVector<TemplateArgument> AdjustedAliasTemplateArgs;
 
-  for (auto *TP : *AliasTemplate->getTemplateParameters()) {
+  for (auto [Index, TP] :
+       llvm::enumerate(*AliasTemplate->getTemplateParameters())) {
     // Rebuild any internal references to earlier parameters and reindex
-    // as we go.
+    // as we go. Template parameters of the alias that don't appear in f' are
+    // not referred to by the deduced template arguments; keep their index.
     MultiLevelTemplateArgumentList Args;
     Args.setKind(TemplateSubstitutionKind::Rewrite);
     Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
+    unsigned NewIndex = AliasParamFPrimeIndex[Index] != InvalidFPrimeIndex
+                            ? AliasParamFPrimeIndex[Index]
+                            : Index;
     NamedDecl *NewParam = transformTemplateParameter(
-        SemaRef, AliasTemplate->getDeclContext(), TP, Args,
-        /*NewIndex=*/AdjustedAliasTemplateArgs.size(),
+        SemaRef, AliasTemplate->getDeclContext(), TP, Args, NewIndex,
         getDepthAndIndex(TP).first + AdjustDepth);
 
     TemplateArgument NewTemplateArgument =
@@ -1036,9 +1082,8 @@ buildAssociatedConstraints(Sema &SemaRef, 
FunctionTemplateDecl *F,
       // Rebuild the template parameter with updated depth and index.
       NamedDecl *NewParam =
           transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args,
-                                     /*NewIndex=*/FirstUndeducedParamIdx,
+                                     /*NewIndex=*/FParamFPrimeIndex[Index],
                                      getDepthAndIndex(TP).first + AdjustDepth);
-      FirstUndeducedParamIdx += 1;
       assert(TemplateArgsForBuildingRC[Index].isNull());
       TemplateArgsForBuildingRC[Index] =
           Context.getInjectedTemplateArg(NewParam);
@@ -1237,6 +1282,255 @@ bool IsNonDeducedArgument(const TemplateArgument &TA) {
           llvm::any_of(TA.pack_elements(), IsNonDeducedArgument));
 }
 
+// Synthesize default template arguments for the template parameters of the
+// alias template A that appear in the deduction guide f' without having a
+// default template argument.
+//
+// Such a template parameter cannot be deduced from the function parameters of
+// f' if it only appears in f' through the default template arguments of other
+// template parameters of A, e.g.
+//
+//   template <class Key, class Hash = std::hash<Key>>
+//   using MySet = std::unordered_set<Key, Hash>;
+//
+// with the deduction guide
+//
+//   template <class It, class H = std::hash<iter_value_t<It>>>
+//   unordered_set(It, It, H = H()) -> unordered_set<iter_value_t<It>, H>;
+//
+// Deducing the return type of the guide from the defining-type-id of MySet
+// gives H = Hash, so Hash and, through its default template argument, Key are
+// template parameters of f':
+//
+//   template <class Key, class Hash = std::hash<Key>, class It>
+//   MySet(It, It, Hash) -> unordered_set<iter_value_t<It>, Hash>;
+//
+// and `MySet(first, last)` fails, as Key cannot be deduced. However, Key
+// corresponds to `iter_value_t<It>` in the return type of the guide: deducing
+// the template arguments of A from the return type of f gives
+// Key = iter_value_t<It>, which we use as the default template argument of Key
+// in f' (see orderFPrimeTemplateParameters for the resulting order):
+//
+//   template <class It, class Key = iter_value_t<It>,
+//             class Hash = std::hash<Key>>
+//   MySet(It, It, Hash) -> unordered_set<iter_value_t<It>, Hash>;
+//
+// The result has an entry for each template parameter of A, which is null for
+// those that don't get a synthesized default template argument. The 
synthesized
+// default template arguments refer to the (non-deduced) template parameters of
+// f.
+static SmallVector<TemplateArgument> synthesizeDefaultArgumentsForFPrime(
+    Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
+    FunctionTemplateDecl *F, ArrayRef<TemplateArgument> AliasRhsTemplateArgs,
+    ArrayRef<TemplateArgument> FReturnTemplateArgs,
+    ArrayRef<DeducedTemplateArgument> DeduceResults,
+    ArrayRef<unsigned> AliasParamsInFPrime, SourceLocation Loc) {
+  TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
+  TemplateParameterList *FParams = F->getTemplateParameters();
+  SmallVector<TemplateArgument> Result(AliasParams->size());
+
+  auto NeedsDefaultArgument = [&](unsigned Index) {
+    NamedDecl *Param = AliasParams->getParam(Index);
+    return !Param->isTemplateParameterPack() && !hasDefaultArgument(Param);
+  };
+
+  if (llvm::none_of(AliasParamsInFPrime, NeedsDefaultArgument))
+    return Result;
+
+  // Deduce the template arguments of A from the return type of f, the reverse
+  // of the deduction of the template arguments of f from the defining-type-id
+  // of A.
+  sema::TemplateDeductionInfo Info(Loc, AliasParams->getDepth());
+  SmallVector<DeducedTemplateArgument> Deduced(AliasParams->size());
+  SemaRef.DeduceTemplateArguments(AliasParams, AliasRhsTemplateArgs,
+                                  FReturnTemplateArgs, Info, Deduced,
+                                  /*NumberOfArgumentsMustMatch=*/false);
+
+  for (unsigned Index : AliasParamsInFPrime) {
+    if (!NeedsDefaultArgument(Index))
+      continue;
+    const TemplateArgument &D = Deduced[Index];
+
+    if (D.isNull() || D.isPackExpansion())
+      continue;
+
+    NamedDecl *Param = AliasParams->getParam(Index);
+
+    bool KindMatches = [&] {
+      switch (D.getKind()) {
+      case TemplateArgument::Type:
+        return isa<TemplateTypeParmDecl>(Param);
+      case TemplateArgument::Template:
+        return isa<TemplateTemplateParmDecl>(Param);
+      case TemplateArgument::Expression:
+        return isa<NonTypeTemplateParmDecl>(Param);
+      default:
+        return false;
+      }
+    }();
+
+    if (!KindMatches)
+      continue;
+
+    // The deduced argument may only refer to the non-deduced template
+    // parameters of f. The deduced ones are replaced in f' by the template
+    // parameters of A they were deduced to, whose default template arguments
+    // may in turn refer to this template parameter.
+    llvm::SmallBitVector UsedFParams(FParams->size());
+    SemaRef.MarkUsedTemplateParameters(D, /*OnlyDeduced=*/false,
+                                       FParams->getDepth(), UsedFParams);
+    if (llvm::any_of(UsedFParams.set_bits(), [&](unsigned FIndex) {
+          return !IsNonDeducedArgument(DeduceResults[FIndex]);
+        }))
+      continue;
+    Result[Index] = D;
+  }
+  return Result;
+}
+
+// Determine the order of the template parameters of the deduction guide f' of
+// the alias template A when some of them got a synthesized default template
+// argument (see synthesizeDefaultArgumentsForFPrime).
+//
+// A default template argument can only refer to preceding template parameters.
+// The order given by the standard (the template parameters of A, followed by
+// the non-deduced template parameters of f) doesn't satisfy that for the
+// synthesized default template arguments, which refer to non-deduced template
+// parameters of f. Instead, order the template parameters of f' such that each
+// of them follows the ones its default template argument, its type (for a
+// non-type template parameter) and its type-constraint refer to, staying as
+// close to the standard's order as possible.
+//
+// Returns false if there is no such order.
+static bool orderFPrimeTemplateParameters(
+    Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
+    FunctionTemplateDecl *F, ArrayRef<DeducedTemplateArgument> DeduceResults,
+    ArrayRef<unsigned> AliasParamsInFPrime,
+    ArrayRef<unsigned> NonDeducedFParams,
+    ArrayRef<TemplateArgument> SynthesizedDefaultArgs,
+    SmallVectorImpl<FPrimeTemplateParamRef> &Order) {
+  TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
+  TemplateParameterList *FParams = F->getTemplateParameters();
+
+  // The template parameters of f' in the standard's order, and the position
+  // of each template parameter of A / non-deduced template parameter of f in
+  // that list.
+  SmallVector<FPrimeTemplateParamRef> Params;
+  SmallVector<unsigned> AliasParamPos(AliasParams->size(), InvalidFPrimeIndex);
+  SmallVector<unsigned> FParamPos(FParams->size(), InvalidFPrimeIndex);
+
+  for (unsigned Index : AliasParamsInFPrime) {
+    AliasParamPos[Index] = Params.size();
+    Params.push_back(
+        {/*IsAliasParam=*/true, Index, llvm::SmallBitVector(FParams->size())});
+  }
+
+  for (unsigned Index : NonDeducedFParams) {
+    FParamPos[Index] = Params.size();
+    Params.push_back(
+        {/*IsAliasParam=*/false, Index, 
llvm::SmallBitVector(FParams->size())});
+  }
+
+  unsigned NumParams = Params.size();
+
+  // Mark the template parameters (of the list containing Param, at the given
+  // depth) that the default template argument, the type and the
+  // type-constraint of Param refer to.
+  auto MarkReferencedTemplateParams = [&](NamedDecl *Param, unsigned Depth,
+                                          llvm::SmallBitVector &Used) {
+    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+      if (TTP->hasDefaultArgument())
+        SemaRef.MarkUsedTemplateParameters(
+            TTP->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
+            Depth, Used);
+      if (const TypeConstraint *TC = TTP->getTypeConstraint())
+        if (const Expr *E = TC->getImmediatelyDeclaredConstraint())
+          SemaRef.MarkUsedTemplateParameters(E, /*OnlyDeduced=*/false, Depth,
+                                             Used);
+    } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+      if (NTTP->hasDefaultArgument())
+        SemaRef.MarkUsedTemplateParameters(
+            NTTP->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
+            Depth, Used);
+      SemaRef.MarkUsedTemplateParameters(TemplateArgument(NTTP->getType()),
+                                         /*OnlyDeduced=*/false, Depth, Used);
+    } else {
+      auto *TTP = cast<TemplateTemplateParmDecl>(Param);
+      if (TTP->hasDefaultArgument())
+        SemaRef.MarkUsedTemplateParameters(
+            TTP->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
+            Depth, Used);
+    }
+  };
+
+  // Deps[I] holds the positions of the template parameters that must precede
+  // the I-th template parameter.
+  SmallVector<llvm::SmallBitVector> Deps(NumParams,
+                                         llvm::SmallBitVector(NumParams));
+  for (auto [Pos, P] : llvm::enumerate(Params)) {
+    if (P.IsAliasParam) {
+      llvm::SmallBitVector UsedAliasParams(AliasParams->size());
+      MarkReferencedTemplateParams(AliasParams->getParam(P.Index),
+                                   AliasParams->getDepth(), UsedAliasParams);
+      for (unsigned Index : UsedAliasParams.set_bits())
+        if (Index != P.Index && AliasParamPos[Index] != InvalidFPrimeIndex)
+          Deps[Pos].set(AliasParamPos[Index]);
+      // The synthesized default template argument refers to non-deduced
+      // template parameters of f.
+      if (!SynthesizedDefaultArgs[P.Index].isNull()) {
+        llvm::SmallBitVector UsedFParams(FParams->size());
+        SemaRef.MarkUsedTemplateParameters(SynthesizedDefaultArgs[P.Index],
+                                           /*OnlyDeduced=*/false,
+                                           FParams->getDepth(), UsedFParams);
+        for (unsigned Index : UsedFParams.set_bits()) {
+          assert(FParamPos[Index] != InvalidFPrimeIndex &&
+                 "synthesized default argument refers to a deduced parameter");
+          Deps[Pos].set(FParamPos[Index]);
+        }
+      }
+      continue;
+    }
+
+    llvm::SmallBitVector UsedFParams(FParams->size());
+    MarkReferencedTemplateParams(FParams->getParam(P.Index),
+                                 FParams->getDepth(), UsedFParams);
+    for (unsigned Index : UsedFParams.set_bits()) {
+      if (Index == P.Index)
+        continue;
+      if (FParamPos[Index] != InvalidFPrimeIndex) {
+        Deps[Pos].set(FParamPos[Index]);
+        continue;
+      }
+      // A deduced template parameter of f, which is replaced in f' by the
+      // template parameters of A that its deduced argument refers to.
+      P.DeducedFParamsUsed.set(Index);
+      const TemplateArgument &DeducedArg = DeduceResults[Index];
+      llvm::SmallBitVector UsedAliasParams(AliasParams->size());
+      SemaRef.MarkUsedTemplateParameters(DeducedArg, /*OnlyDeduced=*/false,
+                                         AliasParams->getDepth(),
+                                         UsedAliasParams);
+      for (unsigned AliasIndex : UsedAliasParams.set_bits())
+        if (AliasParamPos[AliasIndex] != InvalidFPrimeIndex)
+          Deps[Pos].set(AliasParamPos[AliasIndex]);
+    }
+  }
+
+  // Repeatedly pick the first template parameter all of whose dependencies
+  // have been placed.
+  llvm::SmallBitVector Placed(NumParams);
+  while (Order.size() < NumParams) {
+    unsigned Next = NumParams;
+    for (unsigned Pos = 0; Pos != NumParams && Next == NumParams; ++Pos)
+      if (!Placed[Pos] && !Deps[Pos].test(Placed))
+        Next = Pos;
+    if (Next == NumParams) // The dependencies are circular.
+      return false;
+    Placed.set(Next);
+    Order.push_back(std::move(Params[Next]));
+  }
+  return true;
+}
+
 // Build deduction guides for a type alias template from the given underlying
 // source deduction guide.
 CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
@@ -1349,26 +1643,59 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
       F->getTemplateParameters()->size());
 
+  TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
+  TemplateParameterList *FParams = F->getTemplateParameters();
+
   // Create a template parameter list for the synthesized deduction guide f'.
   //
   // C++ [over.match.class.deduct]p3.2:
   //   If f is a function template, f' is a function template whose template
   //   parameter list consists of all the template parameters of A
   //   (including their default template arguments) that appear in the above
-  //   deductions or (recursively) in their default template arguments
+  //   deductions or (recursively) in their default template arguments,
+  //   followed by the template parameters of f that were not deduced
+  //   (including their default template arguments)
   SmallVector<NamedDecl *> FPrimeTemplateParams;
   // Store template arguments that refer to the newly-created template
   // parameters, used for building `TemplateArgsForBuildingFPrime`.
   SmallVector<TemplateArgument, 16> TransformedDeducedAliasArgs(
-      AliasTemplate->getTemplateParameters()->size());
+      AliasParams->size());
+  // The index in f' of the template parameters of A, and of the non-deduced
+  // template parameters of f, that appear in f'.
+  SmallVector<unsigned> AliasParamFPrimeIndex(AliasParams->size(),
+                                              InvalidFPrimeIndex);
+  SmallVector<unsigned> FParamFPrimeIndex(FParams->size(), InvalidFPrimeIndex);
+
+  // Template parameters of A that appear in f' without a default template
+  // argument, and that cannot be deduced from the function parameters of f',
+  // get a default template argument synthesized from the return type of f.
+  SmallVector<TemplateArgument> SynthesizedDefaultArgs =
+      synthesizeDefaultArgumentsForFPrime(
+          SemaRef, AliasTemplate, F, AliasRhsTemplateArgs, FReturnTemplateArgs,
+          DeduceResults, DeducedAliasTemplateParams, Loc);
+  // Those refer to template parameters of f, which the standard's order places
+  // after the template parameters of A; reorder the template parameters of f'
+  // so that default template arguments only refer to preceding template
+  // parameters. If that is not possible, don't synthesize any.
+  SmallVector<FPrimeTemplateParamRef> FPrimeParamOrder;
+  if (llvm::any_of(SynthesizedDefaultArgs,
+                   [](const TemplateArgument &TA) { return !TA.isNull(); }) &&
+      !orderFPrimeTemplateParameters(
+          SemaRef, AliasTemplate, F, DeduceResults, DeducedAliasTemplateParams,
+          NonDeducedTemplateParamsInFIndex, SynthesizedDefaultArgs,
+          FPrimeParamOrder)) {
+    llvm::fill(SynthesizedDefaultArgs, TemplateArgument());
+    FPrimeParamOrder.clear();
+  }
+
   // We might be already within a pack expansion, but rewriting template
   // parameters is independent of that. (We may or may not expand new packs
   // when rewriting. So clear the state)
   Sema::ArgPackSubstIndexRAII PackSubstReset(SemaRef, std::nullopt);
 
-  for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams) {
-    auto *TP =
-        
AliasTemplate->getTemplateParameters()->getParam(AliasTemplateParamIdx);
+  // Add the template parameter of A at the given index to f'.
+  auto AddAliasTemplateParam = [&](unsigned AliasTemplateParamIdx) -> bool {
+    auto *TP = AliasParams->getParam(AliasTemplateParamIdx);
     // Rebuild any internal references to earlier parameters and reindex as
     // we go.
     MultiLevelTemplateArgumentList Args;
@@ -1377,13 +1704,31 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
     NamedDecl *NewParam = transformTemplateParameter(
         SemaRef, AliasTemplate->getDeclContext(), TP, Args,
         /*NewIndex=*/FPrimeTemplateParams.size(), getDepthAndIndex(TP).first);
+    if (const TemplateArgument &Default =
+            SynthesizedDefaultArgs[AliasTemplateParamIdx];
+        !Default.isNull()) {
+      // The synthesized default template argument refers to template
+      // parameters of f; rewrite it in terms of the corresponding
+      // (already created) template parameters of f'.
+      QualType NTTPType;
+      if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(NewParam))
+        NTTPType = NTTP->getType();
+      MultiLevelTemplateArgumentList FArgs;
+      FArgs.setKind(TemplateSubstitutionKind::Rewrite);
+      FArgs.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
+      TemplateArgumentLoc Output;
+      if (SemaRef.SubstTemplateArgument(
+              SemaRef.getTrivialTemplateArgumentLoc(Default, NTTPType, Loc),
+              FArgs, Output, Loc, NewParam->getDeclName()))
+        return false;
+      setDefaultArgument(Context, NewParam, Output);
+    }
+    AliasParamFPrimeIndex[AliasTemplateParamIdx] = FPrimeTemplateParams.size();
     FPrimeTemplateParams.push_back(NewParam);
-
-    TemplateArgument NewTemplateArgument =
+    TransformedDeducedAliasArgs[AliasTemplateParamIdx] =
         Context.getInjectedTemplateArg(NewParam);
-    TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
-  }
-  unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
+    return true;
+  };
 
   // To form a deduction guide f' from f, we leverage clang's instantiation
   // mechanism, we construct a template argument list where the template
@@ -1400,21 +1745,21 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   //
   // Note: the non-deduced template arguments of `f` might refer to arguments
   // deduced in 1), as in a type constraint.
-  MultiLevelTemplateArgumentList Args;
-  Args.setKind(TemplateSubstitutionKind::Rewrite);
-  Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
-  for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
+  //
+  // Substitute the template parameters of f' into the deduced template
+  // argument for the template parameter of f at the given index (1). The
+  // template parameters of A it refers to must have been added to f' already.
+  auto SubstDeducedTemplateArg = [&](unsigned Index) -> bool {
     const auto &D = DeduceResults[Index];
-    auto *TP = F->getTemplateParameters()->getParam(Index);
-    if (IsNonDeducedArgument(D)) {
-      // 2): Non-deduced template parameters would be substituted later.
-      continue;
-    }
+    auto *TP = FParams->getParam(Index);
+    MultiLevelTemplateArgumentList Args;
+    Args.setKind(TemplateSubstitutionKind::Rewrite);
+    Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
     TemplateArgumentLoc Input =
         SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
     TemplateArgumentListInfo Output;
     if (SemaRef.SubstTemplateArguments(Input, Args, Output))
-      return nullptr;
+      return false;
     assert(TemplateArgsForBuildingFPrime[Index].isNull() &&
            "InstantiatedArgs must be null before setting");
     // CheckTemplateArgument is necessary for NTTP initializations.
@@ -1428,7 +1773,7 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
               TP, TA, F, F->getLocation(), F->getLocation(),
               /*ArgumentPackIndex=*/-1, CTAI,
               Sema::CheckTemplateArgumentKind::CTAK_Specified))
-        return nullptr;
+        return false;
     if (Input.getArgument().getKind() == TemplateArgument::Pack) {
       // We will substitute the non-deduced template arguments with these
       // transformed (unpacked at this point) arguments, where that 
substitution
@@ -1439,13 +1784,12 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
       assert(Output.arguments().size() == 1);
       TemplateArgsForBuildingFPrime[Index] = CTAI.SugaredConverted[0];
     }
-  }
+    return true;
+  };
 
-  // Case 2)
-  //   ...followed by the template parameters of f that were not deduced
-  //   (including their default template arguments)
-  for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
-    auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
+  // Add the non-deduced template parameter of f at the given index to f' (2).
+  auto AddFTemplateParam = [&](unsigned FTemplateParamIdx) {
+    auto *TP = FParams->getParam(FTemplateParamIdx);
     MultiLevelTemplateArgumentList Args;
     Args.setKind(TemplateSubstitutionKind::Rewrite);
     // We take a shortcut here, it is ok to reuse the
@@ -1454,12 +1798,48 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
     NamedDecl *NewParam = transformTemplateParameter(
         SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
         getDepthAndIndex(TP).first);
+    FParamFPrimeIndex[FTemplateParamIdx] = FPrimeTemplateParams.size();
     FPrimeTemplateParams.push_back(NewParam);
 
     assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
            "The argument must be null before setting");
     TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
         Context.getInjectedTemplateArg(NewParam);
+  };
+
+  if (FPrimeParamOrder.empty()) {
+    // The standard's order: the template parameters of A that appear in the
+    // deductions, followed by the non-deduced template parameters of f.
+    for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams)
+      if (!AddAliasTemplateParam(AliasTemplateParamIdx))
+        return nullptr;
+    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index)
+      if (!IsNonDeducedArgument(DeduceResults[Index]) &&
+          !SubstDeducedTemplateArg(Index))
+        return nullptr;
+    for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex)
+      AddFTemplateParam(FTemplateParamIdx);
+  } else {
+    for (const FPrimeTemplateParamRef &P : FPrimeParamOrder) {
+      if (P.IsAliasParam) {
+        if (!AddAliasTemplateParam(P.Index))
+          return nullptr;
+        continue;
+      }
+      // The template parameters of A that the deduced template arguments
+      // referred to by this template parameter of f refer to have been added
+      // already, so we can substitute them now.
+      for (unsigned Index : P.DeducedFParamsUsed.set_bits())
+        if (TemplateArgsForBuildingFPrime[Index].isNull() &&
+            !SubstDeducedTemplateArg(Index))
+          return nullptr;
+      AddFTemplateParam(P.Index);
+    }
+    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index)
+      if (!IsNonDeducedArgument(DeduceResults[Index]) &&
+          TemplateArgsForBuildingFPrime[Index].isNull() &&
+          !SubstDeducedTemplateArg(Index))
+        return nullptr;
   }
 
   auto *TemplateArgListForBuildingFPrime =
@@ -1472,9 +1852,9 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
 
     Expr *IsDeducible = buildIsDeducibleConstraint(
         SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
-    Expr *RequiresClause =
-        buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults,
-                                   FirstUndeducedParamIdx, IsDeducible);
+    Expr *RequiresClause = buildAssociatedConstraints(
+        SemaRef, F, AliasTemplate, DeduceResults, AliasParamFPrimeIndex,
+        FParamFPrimeIndex, IsDeducible);
 
     TemplateParameterList *FPrimeTemplateParamList = nullptr;
     if (!FPrimeTemplateParams.empty())
diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp 
b/clang/test/AST/ast-dump-ctad-alias.cpp
index 4ca84dc2d1828..2704bab0910bc 100644
--- a/clang/test/AST/ast-dump-ctad-alias.cpp
+++ b/clang/test/AST/ast-dump-ctad-alias.cpp
@@ -202,3 +202,33 @@ void foo() {
 // CHECK-NEXT: | | | |   `-TemplateTypeParm {{.*}} 'U'
 
 } // namespace GH124715
+
+// A template parameter of the alias template that cannot be deduced from the
+// constructor arguments gets a default template argument deduced from the
+// return type of the underlying deduction guide ('Key' below), and the 
template
+// parameters of the synthesized guide are ordered so that default template
+// arguments only refer to preceding ones ('It' comes first).
+namespace synthesized_default_args {
+template <class T> struct hash {};
+template <class It> struct iter_traits { using value_type = typename 
It::value_type; };
+struct Iter { using value_type = int; };
+template <class Key, class Hash = hash<Key>> struct Set { template <class It> 
Set(It, It); };
+template <class It, class Hash = hash<typename iter_traits<It>::value_type>>
+Set(It, It, Hash = Hash()) -> Set<typename iter_traits<It>::value_type, Hash>;
+template <class Key, class Hash = hash<Key>> using MySet = Set<Key, Hash>;
+void f(Iter b, Iter e) { MySet s(b, e); }
+
+// CHECK:      <deduction guide for MySet> 'auto 
(synthesized_default_args::Set<Key, Hash>) -> 
synthesized_default_args::Set<Key, Hash>'
+// CHECK:      `-FunctionTemplateDecl {{.*}} <deduction guide for MySet>
+// CHECK-NEXT:   |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 It
+// CHECK-NEXT:   |-TemplateTypeParmDecl {{.*}} class depth 0 index 1 Key
+// CHECK-NEXT:   | `-TemplateArgument type 'typename 
iter_traits<It>::value_type':'synthesized_default_args::iter_traits<type-parameter-0-0>::value_type'
+// CHECK-NEXT:   |   `-DependentNameType {{.*}} 'typename 
iter_traits<It>::value_type' dependent
+// CHECK-NEXT:   |-TemplateTypeParmDecl {{.*}} class depth 0 index 2 Hash
+// CHECK-NEXT:   | `-TemplateArgument type 
'hash<Key>':'synthesized_default_args::hash<type-parameter-0-1>'
+// CHECK:        |-CXXDeductionGuideDecl {{.*}} <deduction guide for MySet> 
'auto (It, It, Hash) -> Set<typename iter_traits<It>::value_type, Hash>'
+// CHECK-NEXT:   | |-ParmVarDecl {{.*}} 'It'
+// CHECK-NEXT:   | |-ParmVarDecl {{.*}} 'It'
+// CHECK-NEXT:   | `-ParmVarDecl {{.*}} 'Hash'
+// CHECK-NEXT:   `-CXXDeductionGuideDecl {{.*}} used <deduction guide for 
MySet> 'auto (synthesized_default_args::Iter, synthesized_default_args::Iter, 
synthesized_default_args::hash<int>) -> Set<typename 
iter_traits<synthesized_default_args::Iter>::value_type, 
synthesized_default_args::hash<int>>' implicit_instantiation
+} // namespace synthesized_default_args
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp 
b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index e0f59be663b2f..fe7012e1a87ab 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -629,3 +629,105 @@ template <typename T> using S3 = S2<T>; // expected-note 
{{candidate function no
                                         // expected-note {{cannot deduce 
template arguments for 'GH190517::S3' from 'GH190517::S1<char>'}}
 S3 foo(42); // expected-error {{no viable constructor or deduction guide for 
deduction of template arguments of 'S3'}}
 }
+
+// Template parameters of the alias template that appear in a synthesized
+// deduction guide only through the default template arguments of other
+// template parameters cannot be deduced from the constructor arguments. They
+// get a default template argument deduced from the return type of the
+// underlying deduction guide instead, and the template parameters of the
+// synthesized guide are ordered so that default template arguments only refer
+// to preceding ones.
+namespace synthesized_default_args {
+template <class T> struct hash {};
+template <class T> struct alloc {};
+template <class It> struct iter_traits { using value_type = typename 
It::value_type; };
+struct Iter { using value_type = int; };
+
+template <class Key, class Hash = hash<Key>, class Alloc = alloc<Key>>
+struct Set {
+  Set();
+  template <class It> Set(It, It);
+  template <class It> Set(It, It, Hash);
+};
+template <class It,
+          class Hash = hash<typename iter_traits<It>::value_type>,
+          class Alloc = alloc<typename iter_traits<It>::value_type>>
+Set(It, It, Hash = Hash(), Alloc = Alloc())
+    -> Set<typename iter_traits<It>::value_type, Hash, Alloc>;
+
+// Like std::unordered_set: the alias merely renames the class template.
+template <class Key, class Hash = hash<Key>, class Alloc = alloc<Key>>
+using MySet = Set<Key, Hash, Alloc>;
+// The alias has fewer template parameters than the class template.
+template <class Key, class Hash = hash<Key>>
+using MySet2 = Set<Key, Hash>;
+// The alias has a different default template argument, which wins.
+template <class Key, class Hash = hash<Key*>, class Alloc = alloc<Key>>
+using MySet3 = Set<Key, Hash, Alloc>; // #MySet3
+
+void f(Iter b, Iter e) {
+  MySet s1(b, e);
+  static_assert(__is_same(decltype(s1), Set<int, hash<int>, alloc<int>>));
+  MySet s2(b, e, hash<long>());
+  static_assert(__is_same(decltype(s2), Set<int, hash<long>, alloc<int>>));
+  MySet2 s3(b, e);
+  static_assert(__is_same(decltype(s3), Set<int, hash<int>, alloc<int>>));
+  MySet3 s4(b, e);
+  static_assert(__is_same(decltype(s4), Set<int, hash<int*>, alloc<int>>));
+  MySet s5 = s1;
+  static_assert(__is_same(decltype(s5), decltype(s1)));
+
+  // The non-deduced template parameter 'It' of the underlying guide now comes
+  // first, followed by 'Key' with its synthesized default template argument.
+  MySet3 s6(b, e, 1, 2, 3); // expected-error {{no viable constructor or 
deduction guide for deduction of template arguments of 'MySet3'}}
+  // expected-note@#MySet3 {{implicit deduction guide declared as 'template 
<class It, class Key = typename iter_traits<It>::value_type, class Hash = 
hash<Key *>, class Alloc = alloc<Key>> requires 
__is_deducible(synthesized_default_args::MySet3, Set<typename 
iter_traits<It>::value_type, Hash, Alloc>) MySet3(It, It, Hash, Alloc) -> 
Set<typename iter_traits<It>::value_type, Hash, Alloc>'}}
+  // expected-note@#MySet3 4 {{implicit deduction guide declared as}}
+  // expected-note@#MySet3 {{requires at most 4 arguments, but 5 were 
provided}}
+  // expected-note@#MySet3 {{requires 3 arguments, but 5 were provided}}
+  // expected-note@#MySet3 {{requires 2 arguments, but 5 were provided}}
+  // expected-note@#MySet3 {{requires 1 argument, but 5 were provided}}
+  // expected-note@#MySet3 {{requires 0 arguments, but 5 were provided}}
+}
+
+// A template parameter of the alias that is deducible from some constructor
+// arguments only.
+template <class T, class A = alloc<T>> struct Vec {
+  template <class It> Vec(It, It);
+  template <class It> Vec(It, It, A);
+};
+template <class It, class A = alloc<typename iter_traits<It>::value_type>>
+Vec(It, It, A = A()) -> Vec<typename iter_traits<It>::value_type, A>;
+template <class T> using MyVec = Vec<T, hash<T>>;
+
+void g(Iter b, Iter e) {
+  MyVec v1(b, e);
+  static_assert(__is_same(decltype(v1), Vec<int, hash<int>>));
+  MyVec v2(b, e, hash<int>());
+  static_assert(__is_same(decltype(v2), Vec<int, hash<int>>));
+}
+
+// The underlying guide is constrained, and the alias is a member of a class
+// template.
+template <class T> concept Any = true;
+template <class Key, class Hash = hash<Key>> struct CSet {
+  CSet();
+  template <class It> CSet(It, It);
+};
+template <class It, class Hash = hash<typename iter_traits<It>::value_type>>
+  requires Any<It> && Any<Hash>
+CSet(It, It, Hash = Hash()) -> CSet<typename iter_traits<It>::value_type, 
Hash>;
+
+template <class U> struct Outer {
+  template <class Key, class Hash = hash<Key>> using MyCSet = CSet<Key, Hash>;
+};
+
+void h(Iter b, Iter e) {
+  Outer<long>::MyCSet s1(b, e);
+  static_assert(__is_same(decltype(s1), CSet<int, hash<int>>));
+}
+template <class U> void h2(Iter b, Iter e) {
+  typename Outer<U>::MyCSet s(b, e);
+  static_assert(__is_same(decltype(s), CSet<int, hash<int>>));
+}
+template void h2<char>(Iter, Iter);
+} // namespace synthesized_default_args

>From 4273ef2625e800180ff9a722b7b4b96fc9f7e904 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Thu, 3 Sep 2026 22:36:41 +0300
Subject: [PATCH 08/12] chore: unwanted format

---
 clang/docs/ReleaseNotes.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 21578b5eb87e1..6cded152a827b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -73,7 +73,7 @@ features cannot lower the translation-unit ABI level;
 - On SPARC, a `_Complex` value with an integer element type is now passed and
   returned packed into the one or two integer registers it fits in, matching 
GCC.
   Clang previously passed such a value indirectly and returned it with one part
-  per register.
+  per register. 
   `-fclang-abi-compat=23` restores the previous behavior. (#GH212340)
 
 - On SPARC64, a `_Complex char` or `_Complex short` is now
@@ -119,7 +119,7 @@ features cannot lower the translation-unit ABI level;
 
 - `CompletionString.availability` now returns instances of `AvailabilityKind`.
   As a result, the `__str__` representation of its return values changed.
-  Like other libclang enums, it now follows the 
`CompletionChunkKind.VARIANT_NAME` scheme instead of `VariantName`.
+  Like other libclang enums, it now follows the 
`CompletionChunkKind.VARIANT_NAME` scheme instead of `VariantName`. 
 
 ### OpenCL Potentially Breaking Changes
 
@@ -498,9 +498,9 @@ features cannot lower the translation-unit ABI level;
   producing a spurious "no matching function" error with no candidate notes.
   (#GH210822)
 
-- Fixed a crash when module directive export module foo not following a
+- Fixed a crash when module directive export module foo not following a 
   semicolon and there are no rest pp-tokens in current module file. (#GH187771)
-
+  
 - Fixed a crash when a lambda parameter pack was given a default argument that
   is a pack expansion referencing an enclosing function's parameter pack (e.g.
   `[](Types... = args...) {}`). Clang now diagnoses the illegal default

>From 3d8a41a80165f87b7e7a0e8dfea3386d7a06e233 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Fri, 4 Sep 2026 03:21:15 +0300
Subject: [PATCH 09/12] Fix crash in class template argument deduction with
 alias templates

---
 clang/docs/ReleaseNotes.md                    |  8 +++
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 57 +++++++++++++++----
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  | 47 +++++++++++++++
 3 files changed, 101 insertions(+), 11 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 6cded152a827b..26cb86cc7dc92 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -484,6 +484,14 @@ features cannot lower the translation-unit ABI level;
   guide (here `Key` becomes the iterator's value type), instead of being
   undeducible.
 
+- Fixed a crash in class template argument deduction through an alias template
+  when the alias fixes a non-type template parameter of the underlying template
+  to a constant (e.g. `template <class T> using A = S<T, false>;`) and a
+  non-deduced template parameter of a constructor or deduction guide refers to
+  it in its type, such as `std::enable_if_t<!B, int> = 0`. If that type becomes
+  invalid with the constant substituted, the deduction guide is now silently
+  not synthesized for the alias instead of crashing, matching GCC.
+
 - Fixed a bug where top-level CV qualifiers (such as ``const``) were dropped 
from pointers modified by Microsoft pointer attributes (like ``__ptr32`` and 
``__ptr64``) and WebAssembly's ``__funcref``.
 
 - Fixed an issue where we tried to compare invalid NTTPs for variable 
declarations, which ended up in hitting an assertion with a constrained 
non-plain-auto NTTP, which we don't quite implement yet. (#GH208658)
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 05b99c9374148..d85c84562a082 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -337,6 +337,8 @@ transformTemplateParam(Sema &SemaRef, DeclContext *DC,
   return NewTTP;
 }
 
+// Transform a given non-type template parameter `TTP`. Returns null if its 
type
+// becomes invalid after substitution.
 NonTypeTemplateParmDecl *
 transformTemplateParam(Sema &SemaRef, DeclContext *DC,
                        NonTypeTemplateParmDecl *TTP, unsigned NewDepth,
@@ -351,11 +353,13 @@ transformTemplateParam(Sema &SemaRef, DeclContext *DC,
       TypeSourceInfo *NewTSI =
           SemaRef.SubstType(TTP->getExpansionTypeSourceInfo(I), Args,
                             TTP->getLocation(), TTP->getDeclName());
-      assert(NewTSI);
+      if (!NewTSI)
+        return nullptr;
 
       QualType NewT =
           SemaRef.CheckNonTypeTemplateParameterType(NewTSI, 
TTP->getLocation());
-      assert(!NewT.isNull());
+      if (NewT.isNull())
+        return nullptr;
 
       ExpandedTypeSourceInfos[I] = NewTSI;
       ExpandedTypes[I] = NewT;
@@ -367,11 +371,13 @@ transformTemplateParam(Sema &SemaRef, DeclContext *DC,
   } else {
     TypeSourceInfo *NewTSI = SemaRef.SubstType(
         TTP->getTypeSourceInfo(), Args, TTP->getLocation(), 
TTP->getDeclName());
-    assert(NewTSI);
+    if (!NewTSI)
+      return nullptr;
 
     QualType NewT =
         SemaRef.CheckNonTypeTemplateParameterType(NewTSI, TTP->getLocation());
-    assert(!NewT.isNull());
+    if (NewT.isNull())
+      return nullptr;
 
     NewTTP = NonTypeTemplateParmDecl::Create(
         SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(), NewDepth,
@@ -1642,6 +1648,16 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   // All template arguments null by default.
   SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
       F->getTemplateParameters()->size());
+  // The same template arguments, but with the deduced non-type template
+  // arguments as (not yet converted) expressions, for rewriting the template
+  // parameters of f in terms of those of f'. The rewrite requires expressions,
+  // while instantiating f requires converted template arguments, e.g. a
+  // template parameter `bool B` of f deduced as `false` from the alias must be
+  // rewritten as the expression `false` in the type of a template parameter
+  // `std::enable_if_t<!B, int> = 0` of f, but instantiated as the integral
+  // value.
+  SmallVector<TemplateArgument> TemplateArgsForRewritingFPrime(
+      F->getTemplateParameters()->size());
 
   TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
   TemplateParameterList *FParams = F->getTemplateParameters();
@@ -1704,6 +1720,8 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
     NamedDecl *NewParam = transformTemplateParameter(
         SemaRef, AliasTemplate->getDeclContext(), TP, Args,
         /*NewIndex=*/FPrimeTemplateParams.size(), getDepthAndIndex(TP).first);
+    if (!NewParam)
+      return false;
     if (const TemplateArgument &Default =
             SynthesizedDefaultArgs[AliasTemplateParamIdx];
         !Default.isNull()) {
@@ -1715,7 +1733,7 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
         NTTPType = NTTP->getType();
       MultiLevelTemplateArgumentList FArgs;
       FArgs.setKind(TemplateSubstitutionKind::Rewrite);
-      FArgs.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
+      FArgs.addOuterTemplateArguments(TemplateArgsForRewritingFPrime);
       TemplateArgumentLoc Output;
       if (SemaRef.SubstTemplateArgument(
               SemaRef.getTrivialTemplateArgumentLoc(Default, NTTPType, Loc),
@@ -1774,30 +1792,42 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
               /*ArgumentPackIndex=*/-1, CTAI,
               Sema::CheckTemplateArgumentKind::CTAK_Specified))
         return false;
+    SmallVector<TemplateArgument> OutputArgs;
+    for (const TemplateArgumentLoc &TA : Output.arguments())
+      OutputArgs.push_back(TA.getArgument());
     if (Input.getArgument().getKind() == TemplateArgument::Pack) {
       // We will substitute the non-deduced template arguments with these
       // transformed (unpacked at this point) arguments, where that 
substitution
       // requires a pack for the corresponding parameter packs.
       TemplateArgsForBuildingFPrime[Index] =
           TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted);
+      TemplateArgsForRewritingFPrime[Index] =
+          TemplateArgument::CreatePackCopy(Context, OutputArgs);
     } else {
       assert(Output.arguments().size() == 1);
       TemplateArgsForBuildingFPrime[Index] = CTAI.SugaredConverted[0];
+      TemplateArgsForRewritingFPrime[Index] = OutputArgs[0];
     }
     return true;
   };
 
   // Add the non-deduced template parameter of f at the given index to f' (2).
-  auto AddFTemplateParam = [&](unsigned FTemplateParamIdx) {
+  auto AddFTemplateParam = [&](unsigned FTemplateParamIdx) -> bool {
     auto *TP = FParams->getParam(FTemplateParamIdx);
     MultiLevelTemplateArgumentList Args;
     Args.setKind(TemplateSubstitutionKind::Rewrite);
-    // We take a shortcut here, it is ok to reuse the
-    // TemplateArgsForBuildingFPrime.
-    Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
+    Args.addOuterTemplateArguments(TemplateArgsForRewritingFPrime);
+    // Substituting the deduced template arguments into the template parameter
+    // may fail, e.g. for a template parameter `std::enable_if_t<!B, int> = 0`
+    // of f whose template parameter B was deduced as `true` from the alias.
+    // Then f' can't be formed; it is not viable, but forming it is not an
+    // error either. Don't diagnose the failure and don't form f'.
+    Sema::SFINAETrap Trap(SemaRef);
     NamedDecl *NewParam = transformTemplateParameter(
         SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
         getDepthAndIndex(TP).first);
+    if (!NewParam || Trap.hasErrorOccurred())
+      return false;
     FParamFPrimeIndex[FTemplateParamIdx] = FPrimeTemplateParams.size();
     FPrimeTemplateParams.push_back(NewParam);
 
@@ -1805,6 +1835,9 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
            "The argument must be null before setting");
     TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
         Context.getInjectedTemplateArg(NewParam);
+    TemplateArgsForRewritingFPrime[FTemplateParamIdx] =
+        TemplateArgsForBuildingFPrime[FTemplateParamIdx];
+    return true;
   };
 
   if (FPrimeParamOrder.empty()) {
@@ -1818,7 +1851,8 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
           !SubstDeducedTemplateArg(Index))
         return nullptr;
     for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex)
-      AddFTemplateParam(FTemplateParamIdx);
+      if (!AddFTemplateParam(FTemplateParamIdx))
+        return nullptr;
   } else {
     for (const FPrimeTemplateParamRef &P : FPrimeParamOrder) {
       if (P.IsAliasParam) {
@@ -1833,7 +1867,8 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
         if (TemplateArgsForBuildingFPrime[Index].isNull() &&
             !SubstDeducedTemplateArg(Index))
           return nullptr;
-      AddFTemplateParam(P.Index);
+      if (!AddFTemplateParam(P.Index))
+        return nullptr;
     }
     for (unsigned Index = 0; Index < DeduceResults.size(); ++Index)
       if (!IsNonDeducedArgument(DeduceResults[Index]) &&
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp 
b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index fe7012e1a87ab..f9d190f97abec 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -731,3 +731,50 @@ template <class U> void h2(Iter b, Iter e) {
 }
 template void h2<char>(Iter, Iter);
 } // namespace synthesized_default_args
+
+namespace nttp_deduced_from_alias_in_nondeduced_param_type {
+// The template parameter B of the deduction guide of basic_fn is deduced as
+// the constant `false` from the alias fn_ref, while the type of the
+// non-deduced template parameter `enable_if_t<!bool_constant<B>::value, int>`
+// refers to it; this used to crash when rewriting that type for the deduction
+// guide of fn_ref.
+template <bool B> struct bool_constant { static constexpr bool value = B; };
+using false_type = bool_constant<false>;
+using true_type = bool_constant<true>;
+template <bool, class T = void> struct enable_if {};
+template <class T> struct enable_if<true, T> { using type = T; };
+template <bool B, class T = void> using enable_if_t = typename enable_if<B, 
T>::type;
+
+template <class T, class C> struct function {
+  template <class U, enable_if_t<!C::value, int> = 0>
+  function(U) noexcept {}
+};
+
+template <class T> function(T) -> function<T, false_type>;
+
+template <class T, bool B> using basic_fn = function<T, bool_constant<B>>;
+
+template <class T> using fn_ref = basic_fn<T, false>;
+template <class T> using fn_disabled = basic_fn<T, true>;
+// expected-note@-1 {{candidate template ignored: could not match 
'nttp_deduced_from_alias_in_nondeduced_param_type::function<T, 
bool_constant<true>>' against 'int'}}
+// expected-note@-2 {{implicit deduction guide declared as 'template <class T> 
requires 
__is_deducible(nttp_deduced_from_alias_in_nondeduced_param_type::basic_fn, 
nttp_deduced_from_alias_in_nondeduced_param_type::function<T, 
bool_constant<true>>) && 
__is_deducible(nttp_deduced_from_alias_in_nondeduced_param_type::fn_disabled, 
nttp_deduced_from_alias_in_nondeduced_param_type::function<T, 
bool_constant<true>>) 
fn_disabled(nttp_deduced_from_alias_in_nondeduced_param_type::function<T, 
bool_constant<true>>) -> 
nttp_deduced_from_alias_in_nondeduced_param_type::function<T, 
bool_constant<true>>'}}
+// expected-note@-3 {{candidate template ignored: constraints not satisfied 
[with T = int]}}
+// expected-note@-4 {{cannot deduce template arguments for 
'nttp_deduced_from_alias_in_nondeduced_param_type::fn_disabled' from 
'function<int, false_type>' (aka 'function<int, bool_constant<false>>')}}
+// expected-note@-5 {{implicit deduction guide declared as 'template <class T> 
requires 
__is_deducible(nttp_deduced_from_alias_in_nondeduced_param_type::basic_fn, 
function<T, false_type>) && 
__is_deducible(nttp_deduced_from_alias_in_nondeduced_param_type::fn_disabled, 
function<T, false_type>) fn_disabled(T) -> function<T, false_type>'}}
+
+fn_ref f = 0;
+static_assert(__is_same(decltype(f), function<int, false_type>));
+
+// The deduction guide derived from the constructor is not formed, as
+// substituting B = true into `enable_if_t<!bool_constant<B>::value, int>` 
fails.
+fn_disabled g = 0; // expected-error {{no viable constructor or deduction 
guide for deduction of template arguments of 'fn_disabled'}}
+
+template <class T, int N> struct Arr {
+  template <class U, int M = N, enable_if_t<(M > 0), int> = 0>
+  Arr(T (&)[M], U = {}) {}
+};
+template <class T> using Arr3 = Arr<T, 3>;
+int arr3[3];
+Arr3 a3(arr3, 0);
+static_assert(__is_same(decltype(a3), Arr<int, 3>));
+} // namespace nttp_deduced_from_alias_in_nondeduced_param_type

>From fe7155caedb1d870842dc89324e5294c309b1080 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Fri, 4 Sep 2026 03:29:58 +0300
Subject: [PATCH 10/12] chore: fix style

---
 clang/test/AST/ast-dump-ctad-alias.cpp | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp 
b/clang/test/AST/ast-dump-ctad-alias.cpp
index 2704bab0910bc..4454ed0e15ff7 100644
--- a/clang/test/AST/ast-dump-ctad-alias.cpp
+++ b/clang/test/AST/ast-dump-ctad-alias.cpp
@@ -209,12 +209,22 @@ void foo() {
 // parameters of the synthesized guide are ordered so that default template
 // arguments only refer to preceding ones ('It' comes first).
 namespace synthesized_default_args {
+
 template <class T> struct hash {};
-template <class It> struct iter_traits { using value_type = typename 
It::value_type; };
+
+template <class It> struct iter_traits {
+  using value_type = typename It::value_type;
+};
+
 struct Iter { using value_type = int; };
-template <class Key, class Hash = hash<Key>> struct Set { template <class It> 
Set(It, It); };
+
+template <class Key, class Hash = hash<Key>> struct Set {
+  template <class It> Set(It, It);
+};
+
 template <class It, class Hash = hash<typename iter_traits<It>::value_type>>
 Set(It, It, Hash = Hash()) -> Set<typename iter_traits<It>::value_type, Hash>;
+
 template <class Key, class Hash = hash<Key>> using MySet = Set<Key, Hash>;
 void f(Iter b, Iter e) { MySet s(b, e); }
 

>From edb7c7053536168574efb702658ddab12b39d990 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Fri, 4 Sep 2026 04:33:39 +0300
Subject: [PATCH 11/12] Fix crash in class template argument deduction with
 lambda closure types in deduction guides

---
 clang/docs/ReleaseNotes.md                    |  7 ++++
 clang/lib/Sema/SemaLambda.cpp                 |  8 +++++
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 10 ++++++
 clang/test/AST/ByteCode/cxx2a.cpp             | 10 ++++--
 .../cxx20-ctad-lambda-in-deduction-guide.cpp  | 35 +++++++++++++++++++
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  | 29 +++++++++++++++
 6 files changed, 97 insertions(+), 2 deletions(-)
 create mode 100644 
clang/test/CodeGenCXX/cxx20-ctad-lambda-in-deduction-guide.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 26cb86cc7dc92..febbe7353c2f0 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -492,6 +492,13 @@ features cannot lower the translation-unit ABI level;
   invalid with the constant substituted, the deduction guide is now silently
   not synthesized for the alias instead of crashing, matching GCC.
 
+- Fixed a crash in class template argument deduction when the deduced type
+  contains the closure type of a lambda from the right-hand side of an alias
+  template (`template <class T> using A = S<T, decltype([](T) {})>;`) or from
+  the return type of a user-written deduction guide. The lambda is now
+  instantiated along with the deduction guide, and its closure type is created
+  in the scope enclosing the guide so that it can be mangled, matching GCC.
+
 - Fixed a bug where top-level CV qualifiers (such as ``const``) were dropped 
from pointers modified by Microsoft pointer attributes (like ``__ptr32`` and 
``__ptr64``) and WebAssembly's ``__funcref``.
 
 - Fixed an issue where we tried to compare invalid NTTPs for variable 
declarations, which ended up in hitting an assertion with a constrained 
non-plain-auto NTTP, which we don't quite implement yet. (#GH208658)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0acfd14265904..1f8be1e3cc495 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -246,6 +246,14 @@ Sema::createLambdaClosureType(SourceRange IntroducerRange, 
TypeSourceInfo *Info,
                               unsigned LambdaDependencyKind,
                               LambdaCaptureDefault CaptureDefault) {
   DeclContext *DC = CurContext->getEnclosingNonExpansionStatementContext();
+  // A deduction guide is never called or mangled, so a closure type in its
+  // signature, e.g. of the lambda in `-> A<T, decltype([](T) {})>`, must not
+  // be a local class of the guide: it becomes a template argument of the
+  // deduced class type, whose name is mangled. Create it in the context
+  // enclosing the guide instead, which is where the closure type of a lambda
+  // written in a deduction guide is created when the guide is parsed.
+  if (isa<CXXDeductionGuideDecl>(DC))
+    DC = DC->getParent();
 
   bool IsGenericLambda =
       Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 21781f7474e56..8c3c6fc92f178 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1778,6 +1778,16 @@ namespace {
                          [](const auto &TA) { return TA.isDependent(); }))
           return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
       }
+      // Substituting dependent template arguments yields another templated
+      // entity, so a lambda in it is dependent, like any lambda written in a
+      // template. TransformLambdaExpr cannot tell that from the DeclContext
+      // alone, e.g. when the template parameters of a deduction guide are
+      // rewritten in terms of those of the guide synthesized for an alias
+      // template, the lambda in the return type `A<T, decltype([](T) {})>` is
+      // substituted in an unevaluated, file-scope context and would otherwise
+      // become never-dependent although it still refers to T.
+      if (TemplateArgs.isAnyArgInstantiationDependent())
+        return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
       return inherited::ComputeLambdaDependency(LSI);
     }
 
diff --git a/clang/test/AST/ByteCode/cxx2a.cpp 
b/clang/test/AST/ByteCode/cxx2a.cpp
index e2cf74aa4ec57..0d067d99b5d66 100644
--- a/clang/test/AST/ByteCode/cxx2a.cpp
+++ b/clang/test/AST/ByteCode/cxx2a.cpp
@@ -276,7 +276,7 @@ namespace GH150705 {
 
 namespace DependentRequiresExpr {
   template <class T,
-            bool = []() -> bool { // both-error {{not a constant expression}}
+            bool = []() -> bool {
               if (requires { T::type; })
                 return true;
               return false;
@@ -285,7 +285,13 @@ namespace DependentRequiresExpr {
     using type = void;
   };
 
-  template <class T> using P = p<T>::type; // both-note {{while checking a 
default template argument}}
+  // The lambda is substituted with the dependent T of the alias, so it stays
+  // dependent, and the default template argument is not evaluated until the
+  // alias is used.
+  template <class T> using P = p<T>::type;
+  struct S { using type = int; };
+  static_assert(__is_same(P<int>, void));
+  static_assert(__is_same(P<S>, void));
 }
 
 namespace PseudoDtorOnGlobal {
diff --git a/clang/test/CodeGenCXX/cxx20-ctad-lambda-in-deduction-guide.cpp 
b/clang/test/CodeGenCXX/cxx20-ctad-lambda-in-deduction-guide.cpp
new file mode 100644
index 0000000000000..5d41cc5b59c21
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx20-ctad-lambda-in-deduction-guide.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -emit-llvm -o - %s | 
FileCheck %s
+
+// The closure type of a lambda in the return type of a deduction guide becomes
+// a template argument of the deduced class type. A deduction guide has no
+// mangled name, so the closure type must be one of the scope enclosing the
+// guide, and its call operator must have been instantiated along with the
+// guide (`operator()(int)`, not `operator()(T)`).
+
+namespace alias_rhs {
+
+template <class T, class F> struct A {
+  A(T, F f = {}) { f({}); }
+};
+
+template <class T> using AA = A<T, decltype([](T) {})>;
+
+AA a{0};
+// CHECK-LABEL: define {{.*}} @_ZN9alias_rhs1AIiNS_UliE{{[0-9]*}}_EEC2EiS1_(
+// CHECK: call void @_ZNK9alias_rhsUliE{{[0-9]*}}_clEi(
+// CHECK-LABEL: define {{.*}} @_ZNK9alias_rhsUliE{{[0-9]*}}_clEi(
+} // namespace alias_rhs
+
+namespace user_guide {
+
+template <class T, class F> struct A {
+  A(T, F f = {}) { f({}); }
+};
+
+template <class T> A(T) -> A<T, decltype([](T) {})>;
+
+A a{0};
+// CHECK-LABEL: define {{.*}} @_ZN10user_guide1AIiNS_UliE{{[0-9]*}}_EEC2EiS1_(
+// CHECK: call void @_ZNK10user_guideUliE{{[0-9]*}}_clEi(
+// CHECK-LABEL: define {{.*}} @_ZNK10user_guideUliE{{[0-9]*}}_clEi(
+} // namespace user_guide
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp 
b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index f9d190f97abec..ccc0185790eb9 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -778,3 +778,32 @@ int arr3[3];
 Arr3 a3(arr3, 0);
 static_assert(__is_same(decltype(a3), Arr<int, 3>));
 } // namespace nttp_deduced_from_alias_in_nondeduced_param_type
+
+namespace lambda_in_alias_rhs {
+// The lambda in the RHS of the alias is rewritten in terms of the template
+// parameters of the synthesized deduction guide, and must remain dependent
+// there, so that it is instantiated along with the guide. Otherwise, the call
+// operator of the closure type in the deduced type would keep the parameter
+// type T.
+template <class T, class F> struct A {
+  constexpr A(T t, F f = {}) : v(f(t)) {}
+  int v;
+};
+
+template <class T> using AA = A<T, decltype([](T x) { return x + 1; })>;
+constexpr AA a{41};
+static_assert(a.v == 42);
+
+// The lambda comes from the RHS of the alias that AAA is equivalent to.
+template <class T> using AAA = AA<T>;
+constexpr AAA aa{1};
+static_assert(aa.v == 2);
+
+template <class T, class F> struct B {
+  B(T, F f = {}) { f({}); }
+};
+
+template <class T> using BB = B<T, decltype([](T) {})>;
+BB b{0};
+
+} // namespace lambda_in_alias_rhs

>From f1ec263c3e8dcd98a5a7424d2c0356532fa3b79e Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Fri, 4 Sep 2026 07:13:08 +0300
Subject: [PATCH 12/12] Make Younan Zhang happy and  enhance deduction guide
 for type aliases to support template template parameters and reorder
 synthesized parameters accordingly

---
 clang/docs/ReleaseNotes.md                    |  10 +-
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 313 +++++++++---------
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  |  24 ++
 3 files changed, 181 insertions(+), 166 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index febbe7353c2f0..8e080f370f8f4 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -479,10 +479,12 @@ features cannot lower the translation-unit ABI level;
 
 - Class template argument deduction through an alias template now works when
   a template parameter of the alias only appears in the synthesized deduction
-  guide through default template arguments. Such a template parameter now gets 
a default
-  template argument deduced from the return type of the underlying deduction
-  guide (here `Key` becomes the iterator's value type), instead of being
-  undeducible.
+  guide through default template arguments, such as `Key` in
+  `template <class Key, class Hash = std::hash<Key>> using MySet = 
std::unordered_set<Key, Hash>;`
+  when deducing `MySet s(first, last);`. Such a template parameter now gets a
+  default template argument deduced from the return type of the underlying
+  deduction guide (here `Key` becomes the iterator's value type), instead of
+  being undeducible.
 
 - Fixed a crash in class template argument deduction through an alias template
   when the alias fixes a non-type template parameter of the underlying template
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index d85c84562a082..3ddf61b81a066 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -888,6 +888,19 @@ struct ConvertConstructorToDeductionGuideTransform {
   }
 };
 
+// Returns the default template argument of the given template parameter, or
+// null if it doesn't have one.
+static const TemplateArgumentLoc *getDefaultArgument(const NamedDecl *Param) {
+  auto Get = [](const auto *P) -> const TemplateArgumentLoc * {
+    return P->hasDefaultArgument() ? &P->getDefaultArgument() : nullptr;
+  };
+  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+    return Get(TTP);
+  if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+    return Get(NTTP);
+  return Get(cast<TemplateTemplateParmDecl>(Param));
+}
+
 // Find all template parameters that appear in the given DeducedArgs.
 // Return the indices of the template parameters in the TemplateParams.
 SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
@@ -899,24 +912,14 @@ SmallVector<unsigned> 
TemplateParamsReferencedInTemplateArgumentList(
                                      TemplateParamsList->getDepth(),
                                      ReferencedTemplateParams);
 
-  auto MarkDefaultArgs = [&](auto *Param) {
-    if (!Param->hasDefaultArgument())
-      return;
-    SemaRef.MarkUsedTemplateParameters(
-        Param->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
-        TemplateParamsList->getDepth(), ReferencedTemplateParams);
-  };
-
   for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
     if (!ReferencedTemplateParams[Index])
       continue;
-    auto *Param = TemplateParamsList->getParam(Index);
-    if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Param))
-      MarkDefaultArgs(TTPD);
-    else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param))
-      MarkDefaultArgs(NTTPD);
-    else
-      MarkDefaultArgs(cast<TemplateTemplateParmDecl>(Param));
+    if (const TemplateArgumentLoc *Default =
+            getDefaultArgument(TemplateParamsList->getParam(Index)))
+      SemaRef.MarkUsedTemplateParameters(
+          Default->getArgument(), /*OnlyDeduced=*/false,
+          TemplateParamsList->getDepth(), ReferencedTemplateParams);
   }
 
   SmallVector<unsigned> Results;
@@ -975,19 +978,8 @@ struct FPrimeTemplateParamRef {
   // The index of the template parameter in the template parameter list of A or
   // f, respectively.
   unsigned Index;
-  // For a non-deduced template parameter of f: the deduced template parameters
-  // of f that it refers to.
-  llvm::SmallBitVector DeducedFParamsUsed;
 };
 
-static bool hasDefaultArgument(const NamedDecl *Param) {
-  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
-    return TTP->hasDefaultArgument();
-  if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
-    return NTTP->hasDefaultArgument();
-  return cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();
-}
-
 static void setDefaultArgument(ASTContext &Context, NamedDecl *Param,
                                const TemplateArgumentLoc &DefArg) {
   if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
@@ -1337,7 +1329,7 @@ static SmallVector<TemplateArgument> 
synthesizeDefaultArgumentsForFPrime(
 
   auto NeedsDefaultArgument = [&](unsigned Index) {
     NamedDecl *Param = AliasParams->getParam(Index);
-    return !Param->isTemplateParameterPack() && !hasDefaultArgument(Param);
+    return !Param->isTemplateParameterPack() && !getDefaultArgument(Param);
   };
 
   if (llvm::none_of(AliasParamsInFPrime, NeedsDefaultArgument))
@@ -1394,81 +1386,75 @@ static SmallVector<TemplateArgument> 
synthesizeDefaultArgumentsForFPrime(
   return Result;
 }
 
-// Determine the order of the template parameters of the deduction guide f' of
-// the alias template A when some of them got a synthesized default template
-// argument (see synthesizeDefaultArgumentsForFPrime).
+// Mark the template parameters at the given depth that the given template
+// parameter refers to: through its default template argument, its type (for a
+// non-type template parameter), its type-constraint (for a type template
+// parameter) or its template parameter list (for a template template
+// parameter).
+static void markReferencedTemplateParams(Sema &SemaRef, const NamedDecl *Param,
+                                         unsigned Depth,
+                                         llvm::SmallBitVector &Used) {
+  if (const TemplateArgumentLoc *Default = getDefaultArgument(Param))
+    SemaRef.MarkUsedTemplateParameters(Default->getArgument(),
+                                       /*OnlyDeduced=*/false, Depth, Used);
+  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+    if (const TypeConstraint *TC = TTP->getTypeConstraint())
+      if (const Expr *E = TC->getImmediatelyDeclaredConstraint())
+        SemaRef.MarkUsedTemplateParameters(E, /*OnlyDeduced=*/false, Depth,
+                                           Used);
+  } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+    SemaRef.MarkUsedTemplateParameters(TemplateArgument(NTTP->getType()),
+                                       /*OnlyDeduced=*/false, Depth, Used);
+  } else {
+    TemplateParameterList *TPL =
+        cast<TemplateTemplateParmDecl>(Param)->getTemplateParameters();
+    for (const NamedDecl *P : *TPL)
+      markReferencedTemplateParams(SemaRef, P, Depth, Used);
+    if (const Expr *RC = TPL->getRequiresClause())
+      SemaRef.MarkUsedTemplateParameters(RC, /*OnlyDeduced=*/false, Depth,
+                                         Used);
+  }
+}
+
+// Reorder the template parameters of the deduction guide f' of the alias
+// template A, given in the standard's order (the template parameters of A,
+// followed by the non-deduced template parameters of f), when some of them got
+// a synthesized default template argument (see
+// synthesizeDefaultArgumentsForFPrime).
 //
 // A default template argument can only refer to preceding template parameters.
-// The order given by the standard (the template parameters of A, followed by
-// the non-deduced template parameters of f) doesn't satisfy that for the
-// synthesized default template arguments, which refer to non-deduced template
-// parameters of f. Instead, order the template parameters of f' such that each
-// of them follows the ones its default template argument, its type (for a
-// non-type template parameter) and its type-constraint refer to, staying as
-// close to the standard's order as possible.
+// The standard's order doesn't satisfy that for the synthesized default
+// template arguments, which refer to non-deduced template parameters of f.
+// Instead, order the template parameters of f' such that each of them follows
+// the ones its default template argument, its type (for a non-type template
+// parameter) and its type-constraint refer to, staying as close to the
+// standard's order as possible.
+//
+// AliasParamsUsedByDeducedArg[I] holds the template parameters of A that the
+// deduced template argument for the I-th template parameter of f refers to.
 //
-// Returns false if there is no such order.
-static bool orderFPrimeTemplateParameters(
+// Returns false, leaving Params unchanged, if there is no such order.
+static bool reorderFPrimeTemplateParameters(
     Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
-    FunctionTemplateDecl *F, ArrayRef<DeducedTemplateArgument> DeduceResults,
-    ArrayRef<unsigned> AliasParamsInFPrime,
-    ArrayRef<unsigned> NonDeducedFParams,
+    FunctionTemplateDecl *F,
+    ArrayRef<llvm::SmallBitVector> AliasParamsUsedByDeducedArg,
     ArrayRef<TemplateArgument> SynthesizedDefaultArgs,
-    SmallVectorImpl<FPrimeTemplateParamRef> &Order) {
+    SmallVectorImpl<FPrimeTemplateParamRef> &Params) {
   TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
   TemplateParameterList *FParams = F->getTemplateParameters();
+  unsigned NumParams = Params.size();
 
-  // The template parameters of f' in the standard's order, and the position
-  // of each template parameter of A / non-deduced template parameter of f in
-  // that list.
-  SmallVector<FPrimeTemplateParamRef> Params;
+  // The position in Params of each template parameter of A / non-deduced
+  // template parameter of f.
   SmallVector<unsigned> AliasParamPos(AliasParams->size(), InvalidFPrimeIndex);
   SmallVector<unsigned> FParamPos(FParams->size(), InvalidFPrimeIndex);
-
-  for (unsigned Index : AliasParamsInFPrime) {
-    AliasParamPos[Index] = Params.size();
-    Params.push_back(
-        {/*IsAliasParam=*/true, Index, llvm::SmallBitVector(FParams->size())});
-  }
-
-  for (unsigned Index : NonDeducedFParams) {
-    FParamPos[Index] = Params.size();
-    Params.push_back(
-        {/*IsAliasParam=*/false, Index, 
llvm::SmallBitVector(FParams->size())});
+  for (auto [Pos, P] : llvm::enumerate(Params)) {
+    if (P.IsAliasParam)
+      AliasParamPos[P.Index] = Pos;
+    else
+      FParamPos[P.Index] = Pos;
   }
 
-  unsigned NumParams = Params.size();
-
-  // Mark the template parameters (of the list containing Param, at the given
-  // depth) that the default template argument, the type and the
-  // type-constraint of Param refer to.
-  auto MarkReferencedTemplateParams = [&](NamedDecl *Param, unsigned Depth,
-                                          llvm::SmallBitVector &Used) {
-    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
-      if (TTP->hasDefaultArgument())
-        SemaRef.MarkUsedTemplateParameters(
-            TTP->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
-            Depth, Used);
-      if (const TypeConstraint *TC = TTP->getTypeConstraint())
-        if (const Expr *E = TC->getImmediatelyDeclaredConstraint())
-          SemaRef.MarkUsedTemplateParameters(E, /*OnlyDeduced=*/false, Depth,
-                                             Used);
-    } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-      if (NTTP->hasDefaultArgument())
-        SemaRef.MarkUsedTemplateParameters(
-            NTTP->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
-            Depth, Used);
-      SemaRef.MarkUsedTemplateParameters(TemplateArgument(NTTP->getType()),
-                                         /*OnlyDeduced=*/false, Depth, Used);
-    } else {
-      auto *TTP = cast<TemplateTemplateParmDecl>(Param);
-      if (TTP->hasDefaultArgument())
-        SemaRef.MarkUsedTemplateParameters(
-            TTP->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
-            Depth, Used);
-    }
-  };
-
   // Deps[I] holds the positions of the template parameters that must precede
   // the I-th template parameter.
   SmallVector<llvm::SmallBitVector> Deps(NumParams,
@@ -1476,7 +1462,7 @@ static bool orderFPrimeTemplateParameters(
   for (auto [Pos, P] : llvm::enumerate(Params)) {
     if (P.IsAliasParam) {
       llvm::SmallBitVector UsedAliasParams(AliasParams->size());
-      MarkReferencedTemplateParams(AliasParams->getParam(P.Index),
+      markReferencedTemplateParams(SemaRef, AliasParams->getParam(P.Index),
                                    AliasParams->getDepth(), UsedAliasParams);
       for (unsigned Index : UsedAliasParams.set_bits())
         if (Index != P.Index && AliasParamPos[Index] != InvalidFPrimeIndex)
@@ -1498,7 +1484,7 @@ static bool orderFPrimeTemplateParameters(
     }
 
     llvm::SmallBitVector UsedFParams(FParams->size());
-    MarkReferencedTemplateParams(FParams->getParam(P.Index),
+    markReferencedTemplateParams(SemaRef, FParams->getParam(P.Index),
                                  FParams->getDepth(), UsedFParams);
     for (unsigned Index : UsedFParams.set_bits()) {
       if (Index == P.Index)
@@ -1509,13 +1495,7 @@ static bool orderFPrimeTemplateParameters(
       }
       // A deduced template parameter of f, which is replaced in f' by the
       // template parameters of A that its deduced argument refers to.
-      P.DeducedFParamsUsed.set(Index);
-      const TemplateArgument &DeducedArg = DeduceResults[Index];
-      llvm::SmallBitVector UsedAliasParams(AliasParams->size());
-      SemaRef.MarkUsedTemplateParameters(DeducedArg, /*OnlyDeduced=*/false,
-                                         AliasParams->getDepth(),
-                                         UsedAliasParams);
-      for (unsigned AliasIndex : UsedAliasParams.set_bits())
+      for (unsigned AliasIndex : AliasParamsUsedByDeducedArg[Index].set_bits())
         if (AliasParamPos[AliasIndex] != InvalidFPrimeIndex)
           Deps[Pos].set(AliasParamPos[AliasIndex]);
     }
@@ -1523,6 +1503,7 @@ static bool orderFPrimeTemplateParameters(
 
   // Repeatedly pick the first template parameter all of whose dependencies
   // have been placed.
+  SmallVector<FPrimeTemplateParamRef> Order;
   llvm::SmallBitVector Placed(NumParams);
   while (Order.size() < NumParams) {
     unsigned Next = NumParams;
@@ -1532,8 +1513,9 @@ static bool orderFPrimeTemplateParameters(
     if (Next == NumParams) // The dependencies are circular.
       return false;
     Placed.set(Next);
-    Order.push_back(std::move(Params[Next]));
+    Order.push_back(Params[Next]);
   }
+  Params = std::move(Order);
   return true;
 }
 
@@ -1545,6 +1527,8 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   FunctionTemplateDecl *F =
       SourceDeductionGuide->getDescribedFunctionTemplate();
   assert(F && "deduction guide for alias template must be a function 
template");
+  TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
+  TemplateParameterList *FParams = F->getTemplateParameters();
 
   LocalInstantiationScope Scope(SemaRef);
   Sema::NonSFINAEContext _1(SemaRef);
@@ -1618,36 +1602,42 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   // the return type of the deduction guide from it: Y->int, X->U
   sema::TemplateDeductionInfo TDeduceInfo(Loc);
   // Must initialize n elements, this is required by DeduceTemplateArguments.
-  SmallVector<DeducedTemplateArgument> DeduceResults(
-      F->getTemplateParameters()->size());
+  SmallVector<DeducedTemplateArgument> DeduceResults(FParams->size());
 
   // FIXME: DeduceTemplateArguments stops immediately at the first
   // non-deducible template argument. However, this doesn't seem to cause
   // issues for practice cases, we probably need to extend it to continue
   // performing deduction for rest of arguments to align with the C++
   // standard.
-  SemaRef.DeduceTemplateArguments(
-      F->getTemplateParameters(), FReturnTemplateArgs,
-      AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
-      /*NumberOfArgumentsMustMatch=*/false);
+  SemaRef.DeduceTemplateArguments(FParams, FReturnTemplateArgs,
+                                  AliasRhsTemplateArgs, TDeduceInfo,
+                                  DeduceResults,
+                                  /*NumberOfArgumentsMustMatch=*/false);
 
   SmallVector<TemplateArgument> DeducedArgs;
   SmallVector<unsigned> NonDeducedTemplateParamsInFIndex;
+  // The template parameters of A that the deduced template argument for each
+  // template parameter of f refers to (none for the non-deduced ones).
+  SmallVector<llvm::SmallBitVector> AliasParamsUsedByDeducedArg(
+      FParams->size(), llvm::SmallBitVector(AliasParams->size()));
   // !!NOTE: DeduceResults respects the sequence of template parameters of
   // the deduction guide f.
   for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
-    const auto &D = DeduceResults[Index];
-    if (!IsNonDeducedArgument(D))
-      DeducedArgs.push_back(D);
-    else
+    const TemplateArgument &D = DeduceResults[Index];
+    if (IsNonDeducedArgument(D)) {
       NonDeducedTemplateParamsInFIndex.push_back(Index);
+      continue;
+    }
+    DeducedArgs.push_back(D);
+    SemaRef.MarkUsedTemplateParameters(D, /*OnlyDeduced=*/false,
+                                       AliasParams->getDepth(),
+                                       AliasParamsUsedByDeducedArg[Index]);
   }
   auto DeducedAliasTemplateParams =
-      TemplateParamsReferencedInTemplateArgumentList(
-          SemaRef, AliasTemplate->getTemplateParameters(), DeducedArgs);
+      TemplateParamsReferencedInTemplateArgumentList(SemaRef, AliasParams,
+                                                     DeducedArgs);
   // All template arguments null by default.
-  SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
-      F->getTemplateParameters()->size());
+  SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(FParams->size());
   // The same template arguments, but with the deduced non-type template
   // arguments as (not yet converted) expressions, for rewriting the template
   // parameters of f in terms of those of f'. The rewrite requires expressions,
@@ -1656,11 +1646,7 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   // rewritten as the expression `false` in the type of a template parameter
   // `std::enable_if_t<!B, int> = 0` of f, but instantiated as the integral
   // value.
-  SmallVector<TemplateArgument> TemplateArgsForRewritingFPrime(
-      F->getTemplateParameters()->size());
-
-  TemplateParameterList *AliasParams = AliasTemplate->getTemplateParameters();
-  TemplateParameterList *FParams = F->getTemplateParameters();
+  SmallVector<TemplateArgument> 
TemplateArgsForRewritingFPrime(FParams->size());
 
   // Create a template parameter list for the synthesized deduction guide f'.
   //
@@ -1682,6 +1668,15 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
                                               InvalidFPrimeIndex);
   SmallVector<unsigned> FParamFPrimeIndex(FParams->size(), InvalidFPrimeIndex);
 
+  // The template parameters of f', in the standard's order: the template
+  // parameters of A that appear in the deductions, followed by the non-deduced
+  // template parameters of f.
+  SmallVector<FPrimeTemplateParamRef> FPrimeParamOrder;
+  for (unsigned Index : DeducedAliasTemplateParams)
+    FPrimeParamOrder.push_back({/*IsAliasParam=*/true, Index});
+  for (unsigned Index : NonDeducedTemplateParamsInFIndex)
+    FPrimeParamOrder.push_back({/*IsAliasParam=*/false, Index});
+
   // Template parameters of A that appear in f' without a default template
   // argument, and that cannot be deduced from the function parameters of f',
   // get a default template argument synthesized from the return type of f.
@@ -1693,16 +1688,12 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
   // after the template parameters of A; reorder the template parameters of f'
   // so that default template arguments only refer to preceding template
   // parameters. If that is not possible, don't synthesize any.
-  SmallVector<FPrimeTemplateParamRef> FPrimeParamOrder;
   if (llvm::any_of(SynthesizedDefaultArgs,
                    [](const TemplateArgument &TA) { return !TA.isNull(); }) &&
-      !orderFPrimeTemplateParameters(
-          SemaRef, AliasTemplate, F, DeduceResults, DeducedAliasTemplateParams,
-          NonDeducedTemplateParamsInFIndex, SynthesizedDefaultArgs,
-          FPrimeParamOrder)) {
+      !reorderFPrimeTemplateParameters(
+          SemaRef, AliasTemplate, F, AliasParamsUsedByDeducedArg,
+          SynthesizedDefaultArgs, FPrimeParamOrder))
     llvm::fill(SynthesizedDefaultArgs, TemplateArgument());
-    FPrimeParamOrder.clear();
-  }
 
   // We might be already within a pack expansion, but rewriting template
   // parameters is independent of that. (We may or may not expand new packs
@@ -1840,42 +1831,42 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
     return true;
   };
 
-  if (FPrimeParamOrder.empty()) {
-    // The standard's order: the template parameters of A that appear in the
-    // deductions, followed by the non-deduced template parameters of f.
-    for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams)
-      if (!AddAliasTemplateParam(AliasTemplateParamIdx))
-        return nullptr;
-    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index)
-      if (!IsNonDeducedArgument(DeduceResults[Index]) &&
-          !SubstDeducedTemplateArg(Index))
-        return nullptr;
-    for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex)
-      if (!AddFTemplateParam(FTemplateParamIdx))
-        return nullptr;
-  } else {
-    for (const FPrimeTemplateParamRef &P : FPrimeParamOrder) {
-      if (P.IsAliasParam) {
-        if (!AddAliasTemplateParam(P.Index))
-          return nullptr;
+  // Substitute the deduced template arguments (1) that haven't been 
substituted
+  // yet and whose template parameters of A have all been added to f' already.
+  auto SubstDeducedTemplateArgs = [&]() -> bool {
+    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
+      if (IsNonDeducedArgument(DeduceResults[Index]) ||
+          !TemplateArgsForBuildingFPrime[Index].isNull())
         continue;
-      }
-      // The template parameters of A that the deduced template arguments
-      // referred to by this template parameter of f refer to have been added
-      // already, so we can substitute them now.
-      for (unsigned Index : P.DeducedFParamsUsed.set_bits())
-        if (TemplateArgsForBuildingFPrime[Index].isNull() &&
-            !SubstDeducedTemplateArg(Index))
-          return nullptr;
-      if (!AddFTemplateParam(P.Index))
-        return nullptr;
+      if (llvm::any_of(AliasParamsUsedByDeducedArg[Index].set_bits(),
+                       [&](unsigned AliasIndex) {
+                         return AliasParamFPrimeIndex[AliasIndex] ==
+                                InvalidFPrimeIndex;
+                       }))
+        continue;
+      if (!SubstDeducedTemplateArg(Index))
+        return false;
     }
-    for (unsigned Index = 0; Index < DeduceResults.size(); ++Index)
-      if (!IsNonDeducedArgument(DeduceResults[Index]) &&
-          TemplateArgsForBuildingFPrime[Index].isNull() &&
-          !SubstDeducedTemplateArg(Index))
+    return true;
+  };
+
+  for (const FPrimeTemplateParamRef &P : FPrimeParamOrder) {
+    if (P.IsAliasParam) {
+      if (!AddAliasTemplateParam(P.Index))
         return nullptr;
+      continue;
+    }
+    // A non-deduced template parameter of f may refer to deduced template
+    // parameters of f, whose deduced template arguments must have been
+    // substituted by then. In the standard's order, all of them can be, as all
+    // the template parameters of A precede the template parameters of f.
+    if (!SubstDeducedTemplateArgs() || !AddFTemplateParam(P.Index))
+      return nullptr;
   }
+  // Substitute the deduced template arguments that no template parameter of f'
+  // needed.
+  if (!SubstDeducedTemplateArgs())
+    return nullptr;
 
   auto *TemplateArgListForBuildingFPrime =
       TemplateArgumentList::CreateCopy(Context, TemplateArgsForBuildingFPrime);
@@ -1894,10 +1885,8 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias(
     TemplateParameterList *FPrimeTemplateParamList = nullptr;
     if (!FPrimeTemplateParams.empty())
       FPrimeTemplateParamList = TemplateParameterList::Create(
-          Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
-          AliasTemplate->getTemplateParameters()->getLAngleLoc(),
-          FPrimeTemplateParams,
-          AliasTemplate->getTemplateParameters()->getRAngleLoc(),
+          Context, AliasParams->getTemplateLoc(), AliasParams->getLAngleLoc(),
+          FPrimeTemplateParams, AliasParams->getRAngleLoc(),
           /*RequiresClause=*/RequiresClause);
 
     auto *DGuide = buildDeductionGuide(
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp 
b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index ccc0185790eb9..867ee36ee7f63 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -730,6 +730,30 @@ template <class U> void h2(Iter b, Iter e) {
   static_assert(__is_same(decltype(s), CSet<int, hash<int>>));
 }
 template void h2<char>(Iter, Iter);
+
+// A template template parameter of the alias refers to another template
+// parameter of the alias in its own template parameter list, so it must follow
+// that one when the template parameters of the synthesized guide are 
reordered.
+template <auto> struct Def {};
+template <class Key, class Cmp = hash<Key>, template <Cmp> class TT = Def>
+struct TSet {
+  template <class It> TSet(It, It, Cmp);
+};
+template <class It, class Cmp, template <Cmp> class TT = Def>
+TSet(It, It, Cmp) -> TSet<typename iter_traits<It>::value_type, Cmp, TT>;
+template <class Key, class Cmp = hash<Key>, template <Cmp> class TT = Def>
+using MyTSet = TSet<Key, Cmp, TT>; // #MyTSet
+
+void t(Iter b, Iter e) {
+  MyTSet s1(b, e, hash<int>());
+  static_assert(__is_same(decltype(s1), TSet<int, hash<int>, Def>));
+
+  MyTSet s2(b, e, 1, 2); // expected-error {{no viable constructor or 
deduction guide for deduction of template arguments of 'MyTSet'}}
+  // expected-note@#MyTSet {{implicit deduction guide declared as 'template 
<class It, class Key = typename iter_traits<It>::value_type, class Cmp = 
hash<Key>, template <Cmp> class TT = Def> requires 
__is_deducible(synthesized_default_args::MyTSet, TSet<typename 
iter_traits<It>::value_type, Cmp, TT>) MyTSet(It, It, Cmp) -> TSet<typename 
iter_traits<It>::value_type, Cmp, TT>'}}
+  // expected-note@#MyTSet 2 {{implicit deduction guide declared as}}
+  // expected-note@#MyTSet 2 {{requires 3 arguments, but 4 were provided}}
+  // expected-note@#MyTSet {{requires 1 argument, but 4 were provided}}
+}
 } // namespace synthesized_default_args
 
 namespace nttp_deduced_from_alias_in_nondeduced_param_type {

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

Reply via email to