[clang] eb00182 - [Clang] prevent errors for deduction guides using deduced type aliases (#117450)

via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 27 01:51:43 PST 2024


Author: Oleksandr T.
Date: 2024-11-27T11:51:34+02:00
New Revision: eb001820b47176fc3e7bc643525c6352b76dcd1d

URL: https://github.com/llvm/llvm-project/commit/eb001820b47176fc3e7bc643525c6352b76dcd1d
DIFF: https://github.com/llvm/llvm-project/commit/eb001820b47176fc3e7bc643525c6352b76dcd1d.diff

LOG: [Clang] prevent errors for deduction guides using deduced type aliases (#117450)

Fixes #54909

--- 

Clang incorrectly produces diagnostics for alias templates in deduction
guides, treating them as separate from their underlying types. This
issue arises because Clang doesn't properly handle
`TypeAliasTemplateDecl` when comparing template names for equality in
the context of deduction guides, resulting in diagnostics that don't
align with the C++ standard. As the C++ standard specifies - _an alias
template is considered a synonym for its underlying type_

With this change, Clang now correctly resolves alias templates to their
underlying types in deduction guides, ensuring compliance with the C++
standard.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/CXX/temp/temp.deduct.guide/p3.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6c40e48e2f49b3..356b091c13af4f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -590,6 +590,9 @@ Improvements to Clang's diagnostics
 
 - Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961).
 
+- Clang now supports using alias templates in deduction guides, aligning with the C++ standard,
+  which treats alias templates as synonyms for their underlying types (#GH54909).
+
 Improvements to Clang's time-trace
 ----------------------------------
 

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 26041e53de5061..3ff365649c93d2 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11451,23 +11451,29 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
     bool MightInstantiateToSpecialization = false;
     if (auto RetTST =
             TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
-      TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
-      bool TemplateMatches = Context.hasSameTemplateName(
-          SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);
-
-      const QualifiedTemplateName *Qualifiers =
-          SpecifiedName.getAsQualifiedTemplateName();
-      assert(Qualifiers && "expected QualifiedTemplate");
-      bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
-                           Qualifiers->getQualifier() == nullptr;
-      if (SimplyWritten && TemplateMatches)
-        AcceptableReturnType = true;
-      else {
-        // This could still instantiate to the right type, unless we know it
-        // names the wrong class template.
-        auto *TD = SpecifiedName.getAsTemplateDecl();
-        MightInstantiateToSpecialization = !(TD && isa<ClassTemplateDecl>(TD) &&
-                                             !TemplateMatches);
+      const TemplateSpecializationType *TST = RetTST.getTypePtr();
+      while (TST && TST->isTypeAlias())
+        TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
+
+      if (TST) {
+        TemplateName SpecifiedName = TST->getTemplateName();
+        bool TemplateMatches = Context.hasSameTemplateName(
+            SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);
+
+        const QualifiedTemplateName *Qualifiers =
+            SpecifiedName.getAsQualifiedTemplateName();
+        assert(Qualifiers && "expected QualifiedTemplate");
+        bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
+                             Qualifiers->getQualifier() == nullptr;
+        if (SimplyWritten && TemplateMatches)
+          AcceptableReturnType = true;
+        else {
+          // This could still instantiate to the right type, unless we know it
+          // names the wrong class template.
+          auto *TD = SpecifiedName.getAsTemplateDecl();
+          MightInstantiateToSpecialization =
+              !(TD && isa<ClassTemplateDecl>(TD) && !TemplateMatches);
+        }
       }
     } else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) {
       MightInstantiateToSpecialization = true;

diff  --git a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp
index c5404847beb066..195ba2831439d0 100644
--- a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp
+++ b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp
@@ -33,7 +33,7 @@ template<template<typename> typename TT> struct E { // expected-note 2{{template
 };
 
 A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}}
-template <typename T> A(T)->B<T>;         // expected-error {{deduced type 'B<T>' (aka 'A<T>') of deduction guide is not written as a specialization of template 'A'}}
+template <typename T> A(T)->B<T>;
 template<typename T> A(T*) -> const A<T>; // expected-error {{deduced type 'const A<T>' of deduction guide is not a specialization of template 'A'}}
 
 // A deduction-guide shall be declared in the same scope as the corresponding
@@ -71,3 +71,11 @@ namespace WrongScope {
     Local(int) -> Local<int>; // expected-error {{expected}}
   }
 }
+
+namespace GH54909 {
+template <class T> struct A {};
+struct B {};
+
+template <typename T> using C = B;
+template <typename T> A() -> C<T>; // expected-error {{deduced type 'C<T>' (aka 'GH54909::B') of deduction guide is not a specialization of template 'A'}}
+}


        


More information about the cfe-commits mailing list