================
@@ -10140,32 +10140,60 @@ QualType
Sema::DeduceTemplateSpecializationFromInitializer(
if (TemplateName.isDependent())
return SubstAutoTypeSourceInfoDependent(TSInfo)->getType();
- // We can only perform deduction for class templates or alias templates.
- auto *Template =
- dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
- TemplateDecl *LookupTemplateDecl = Template;
- if (!Template) {
- if (auto *AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
- TemplateName.getAsTemplateDecl())) {
- DiagCompat(Kind.getLocation(), diag_compat::ctad_for_alias_templates);
- LookupTemplateDecl = AliasTemplate;
- auto UnderlyingType = AliasTemplate->getTemplatedDecl()
- ->getUnderlyingType()
- .getCanonicalType();
- // C++ [over.match.class.deduct#3]: ..., the defining-type-id of A must
be
- // of the form
- // [typename] [nested-name-specifier] [template] simple-template-id
- if (const auto *TST =
- UnderlyingType->getAs<TemplateSpecializationType>()) {
- Template = dyn_cast_or_null<ClassTemplateDecl>(
- TST->getTemplateName().getAsTemplateDecl());
- } else if (const auto *RT = UnderlyingType->getAs<RecordType>()) {
- // Cases where template arguments in the RHS of the alias are not
- // dependent. e.g.
- // using AliasFoo = Foo<bool>;
- if (const auto *CTSD =
- llvm::dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
- Template = CTSD->getSpecializedTemplate();
+ TemplateDecl *LookupTemplateDecl = nullptr;
+ ClassTemplateDecl *Template = nullptr;
+
+ // [C++26] [over.match.class.deduct]p3
+ // When resolving a placeholder for a deduced class type where the
+ // template-name designates a type template template parameter P.
+ //
+ // This is applied as a DR to C++20 (Aliases templates are technically a
C++20
+ // feature)
+ if (const SubstTemplateTemplateParmStorage *SubstitutedTTP =
+ TemplateName.getAsSubstTemplateTemplateParm();
+ SubstitutedTTP && getLangOpts().CPlusPlus20) {
+
+ TypeAliasTemplateDecl *Alias = BuildAliasForCTADFromTypeTemplateParameter(
+ SubstitutedTTP->getParameter(), SubstitutedTTP->getReplacement(),
+ Kind.getLocation());
+ if (!Alias)
+ return QualType();
+
+ LookupTemplateDecl = Alias;
+ auto UnderlyingType =
+ Alias->getTemplatedDecl()->getUnderlyingType().getCanonicalType();
+ const auto *TST = UnderlyingType->getAs<TemplateSpecializationType>();
+ Template = dyn_cast_or_null<ClassTemplateDecl>(
+ TST->getTemplateName().getAsTemplateDecl());
+ } else {
----------------
mizvekov wrote:
Another example involving multiple levels:
```C++
template<template<typename ... Ts> class X>
using Z = decltype([]{
X x0{}; // Fail, should succeeed
X x1{1}; // OK, deduces Y<int>
X x2{1, 2}; // Succeed, should fail
}());
template<template<typename T = char> class X>
void g() {
using R = Z<X>;
};
template<typename ... Ts> struct Y {
Y();
Y(Ts ...);
};
template void g<Y>();
```
This should produce a TemplateName with two SubstTemplateTemplate nodes in
sequence, because alias template specialization is eager and sugar preserving.
https://github.com/llvm/llvm-project/pull/191409
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits