================
@@ -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

Reply via email to