================
@@ -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:
I am surprised we even had to implement anything, I thought this already worked
in all compilers?
So for example, I don't get this change.
Why do we even care about the `SubstTemplateTemplateParm`?
It's basically like a typedef, it doesn't change anything about what it
introduces.
The previous implementation, and now the 'else' branch here, are doing the
right thing, which is to just step over template name sugar and get to the
template declaration that matters, with `getAsTemplateDecl`.
The call to `getAsSubstTemplateTemplateParm` does the opposite, it expects
there to be exactly a top level `SubstTemplateTemplateParm` and returns it,
null otherwise.
So for example, this does nothing if there are two levels of substitution
involved (ie we had to replace two template template parameters to get to the
alias template). I'd expect in that case for it to fall back to the else
branch, and then just work? But then it would also work for the one level case,
so why this branch then though?
https://github.com/llvm/llvm-project/pull/191409
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits