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 1/7] [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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 7/7] 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

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

Reply via email to