https://github.com/bassiounix created
https://github.com/llvm/llvm-project/pull/222215
Fix edge case of CTAD alias template
```cpp
template<typename T>
struct A { A(T){} };
template<typename T>
using Proxy = T;
template<typename T>
using C = Proxy<A<T>>;
C test{ 42 };
```
>From 6930b7f5fc60aad7ed9dc666998fec878246d623 Mon Sep 17 00:00:00 2001
From: bassiounix <[email protected]>
Date: Wed, 9 Sep 2026 04:42:51 +0300
Subject: [PATCH] [Clang][CTAD] Implement deduction guides for alias templates
with nested aliases
---
clang/docs/ReleaseNotes.md | 5 +++
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 35 ++++++++++++++++---
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 4 +--
3 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 0fb6dcf59d4c9f..66a3456d78eb71 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -551,6 +551,11 @@ 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. The deduction guides are now
+ derived from the first template in the chain that can have them. (#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 a bug where we accepted ``__super`` being qualified by a scope
specifier, causing codegen to assertion fail elsewhere. (#GH212988)
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 1a488ece55d258..7edf07b129cf93 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 78911cbaed67be..e0f59be663b2fa 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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits