[llvm-branch-commits] [clang] [clang] Template Specialization Resugaring - Template Type Alias (PR #132442)

Matheus Izvekov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Apr 2 18:53:36 PDT 2025


https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/132442

>From 9d5d42820a4998e0e3eb74f7301aa34dca55b890 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Mon, 30 May 2022 01:46:31 +0200
Subject: [PATCH] [clang] Template Specialization Resugaring - Template Type
 Alias

This implements an additional user of the resugaring transform:
the pattern of template type aliases.

For more details and discussion see:
https://discourse.llvm.org/t/rfc-improving-diagnostics-with-template-specialization-resugaring/64294

Differential Revision: https://reviews.llvm.org/D137199
---
 clang/include/clang/Sema/Sema.h               |  3 +-
 clang/lib/Sema/SemaCXXScopeSpec.cpp           |  3 +-
 clang/lib/Sema/SemaCoroutine.cpp              |  4 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |  6 ++-
 clang/lib/Sema/SemaTemplate.cpp               | 43 +++++++++++--------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  3 +-
 clang/lib/Sema/TreeTransform.h                |  3 +-
 clang/test/AST/ast-dump-template-decls.cpp    |  4 +-
 clang/test/Sema/Resugar/resugar-types.cpp     |  6 +--
 9 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 945ff5e2c2ca6..42a7bf75c3bfc 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11509,7 +11509,8 @@ class Sema final : public SemaBase {
 
   void NoteAllFoundTemplates(TemplateName Name);
 
-  QualType CheckTemplateIdType(TemplateName Template,
+  QualType CheckTemplateIdType(const NestedNameSpecifier *NNS,
+                               TemplateName Template,
                                SourceLocation TemplateLoc,
                                TemplateArgumentListInfo &TemplateArgs);
 
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 1085639dcb355..1c7dff35bb8af 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -907,7 +907,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
 
   // We were able to resolve the template name to an actual template.
   // Build an appropriate nested-name-specifier.
-  QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
+  QualType T = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateNameLoc,
+                                   TemplateArgs);
   if (T.isNull())
     return true;
 
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 75364a3b2c8b5..8dffbca7463dd 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -90,7 +90,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
 
   // Build the template-id.
   QualType CoroTrait =
-      S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args);
+      S.CheckTemplateIdType(nullptr, TemplateName(CoroTraits), KwLoc, Args);
   if (CoroTrait.isNull())
     return QualType();
   if (S.RequireCompleteType(KwLoc, CoroTrait,
@@ -169,7 +169,7 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
 
   // Build the template-id.
   QualType CoroHandleType =
-      S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args);
+      S.CheckTemplateIdType(nullptr, TemplateName(CoroHandle), Loc, Args);
   if (CoroHandleType.isNull())
     return QualType();
   if (S.RequireCompleteType(Loc, CoroHandleType,
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 928bf47285490..8a9ad3271ec26 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1140,7 +1140,8 @@ static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup,
   }
 
   // Build the template-id.
-  QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args);
+  QualType TraitTy =
+      S.CheckTemplateIdType(nullptr, TemplateName(TraitTD), Loc, Args);
   if (TraitTy.isNull())
     return true;
   if (!S.isCompleteType(Loc, TraitTy)) {
@@ -12163,7 +12164,8 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
                                        Context.getTrivialTypeSourceInfo(Element,
                                                                         Loc)));
 
-  QualType T = CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args);
+  QualType T =
+      CheckTemplateIdType(nullptr, TemplateName(StdInitializerList), Loc, Args);
   if (T.isNull())
     return QualType();
 
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 5652b4548895a..673551bd97f3e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3827,7 +3827,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
   }
 }
 
-static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
+static QualType builtinCommonTypeImpl(Sema &S, const NestedNameSpecifier *NNS,
+                                      TemplateName BaseTemplate,
                                       SourceLocation TemplateLoc,
                                       ArrayRef<TemplateArgument> Ts) {
   auto lookUpCommonType = [&](TemplateArgument T1,
@@ -3835,7 +3836,7 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
     // Don't bother looking for other specializations if both types are
     // builtins - users aren't allowed to specialize for them
     if (T1.getAsType()->isBuiltinType() && T2.getAsType()->isBuiltinType())
-      return builtinCommonTypeImpl(S, BaseTemplate, TemplateLoc, {T1, T2});
+      return builtinCommonTypeImpl(S, NNS, BaseTemplate, TemplateLoc, {T1, T2});
 
     TemplateArgumentListInfo Args;
     Args.addArgument(TemplateArgumentLoc(
@@ -3849,7 +3850,7 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
     Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
 
     QualType BaseTemplateInst =
-        S.CheckTemplateIdType(BaseTemplate, TemplateLoc, Args);
+        S.CheckTemplateIdType(NNS, BaseTemplate, TemplateLoc, Args);
 
     if (SFINAE.hasErrorOccurred())
       return QualType();
@@ -3962,8 +3963,8 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
 }
 
 static QualType checkBuiltinTemplateIdType(
-    Sema &SemaRef, TemplateName Name, BuiltinTemplateDecl *BTD,
-    ArrayRef<TemplateArgument> SugaredConverted,
+    Sema &SemaRef, const NestedNameSpecifier *NNS, TemplateName Name,
+    BuiltinTemplateDecl *BTD, ArrayRef<TemplateArgument> SugaredConverted,
     ArrayRef<TemplateArgument> CanonicalConverted, SourceLocation TemplateLoc,
     TemplateArgumentListInfo &TemplateArgs) {
   ASTContext &Context = SemaRef.getASTContext();
@@ -4015,7 +4016,7 @@ static QualType checkBuiltinTemplateIdType(
     // The first template argument will be reused as the template decl that
     // our synthetic template arguments will be applied to.
     QualType Result =
-        SemaRef.CheckTemplateIdType(SugaredConverted[0].getAsTemplate(),
+        SemaRef.CheckTemplateIdType(NNS, SugaredConverted[0].getAsTemplate(),
                                     TemplateLoc, SyntheticTemplateArgs);
     return SemaRef.Context.getTemplateSpecializationType(
         Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted,
@@ -4065,14 +4066,16 @@ static QualType checkBuiltinTemplateIdType(
     QualType HasNoTypeMember = SugaredConverted[2].getAsType();
     ArrayRef<TemplateArgument> Ts = SugaredConverted[3].getPackAsArray();
     QualType Result = HasNoTypeMember;
-    if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts);
+    if (auto CT =
+            builtinCommonTypeImpl(SemaRef, NNS, BaseTemplate, TemplateLoc, Ts);
         !CT.isNull()) {
       TemplateArgumentListInfo TAs;
       TAs.addArgument(TemplateArgumentLoc(
           TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo(
                                     CT, TemplateArgs[1].getLocation())));
 
-      Result = SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs);
+      Result =
+          SemaRef.CheckTemplateIdType(NNS, HasTypeMember, TemplateLoc, TAs);
     }
     return SemaRef.Context.getTemplateSpecializationType(
         Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted,
@@ -4220,7 +4223,8 @@ Sema::findFailedBooleanCondition(Expr *Cond) {
   return { FailedCond, Description };
 }
 
-QualType Sema::CheckTemplateIdType(TemplateName Name,
+QualType Sema::CheckTemplateIdType(const NestedNameSpecifier *NNS,
+                                   TemplateName Name,
                                    SourceLocation TemplateLoc,
                                    TemplateArgumentListInfo &TemplateArgs) {
   // FIXME: 'getUnderlying' loses SubstTemplateTemplateParm nodes from alias
@@ -4299,9 +4303,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
     if (!AliasTemplate->getDeclContext()->isFileContext())
       SavedContext.emplace(*this, AliasTemplate->getDeclContext());
 
-    CanonType =
-        SubstType(Pattern->getUnderlyingType(), TemplateArgLists,
-                  AliasTemplate->getLocation(), AliasTemplate->getDeclName());
+    QualType T = resugar(NNS, Pattern->getUnderlyingType());
+    CanonType = SubstType(T, TemplateArgLists, AliasTemplate->getLocation(),
+                          AliasTemplate->getDeclName());
     if (CanonType.isNull()) {
       // If this was enable_if and we failed to find the nested type
       // within enable_if in a SFINAE context, dig out the specific
@@ -4338,9 +4342,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
       return QualType();
     }
   } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
-    return checkBuiltinTemplateIdType(*this, Name, BTD, CTAI.SugaredConverted,
-                                      CTAI.CanonicalConverted, TemplateLoc,
-                                      TemplateArgs);
+    return checkBuiltinTemplateIdType(
+        *this, NNS, Name, BTD, CTAI.SugaredConverted, CTAI.CanonicalConverted,
+        TemplateLoc, TemplateArgs);
   } else if (Name.isDependent() ||
              TemplateSpecializationType::anyDependentTemplateArguments(
                  TemplateArgs, CTAI.CanonicalConverted)) {
@@ -4583,7 +4587,8 @@ TypeResult Sema::ActOnTemplateIdType(
     return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
   }
 
-  QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
+  QualType SpecTy = CheckTemplateIdType(SS.getScopeRep(), Template,
+                                        TemplateIILoc, TemplateArgs);
   if (SpecTy.isNull())
     return true;
 
@@ -4664,7 +4669,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
     Diag(TAT->getLocation(), diag::note_declared_at);
   }
 
-  QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
+  QualType Result = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateLoc,
+                                        TemplateArgs);
   if (Result.isNull())
     return TypeResult(true);
 
@@ -11446,7 +11452,8 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
     return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
   }
 
-  QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
+  QualType T = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateIILoc,
+                                   TemplateArgs);
   if (T.isNull())
     return true;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9c1eb3f4c88b5..5846b19a5c57b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6816,7 +6816,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
               Args.addArgument(
                   getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc));
           }
-          QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
+          QualType T =
+              CheckTemplateIdType(/*NNS=*/nullptr, TemplateName(TD), Loc, Args);
           // We may get a non-null type with errors, in which case
           // `getAsCXXRecordDecl` will return `nullptr`. For instance, this
           // happens when one of the template arguments is an invalid
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 8250d700d0ac7..94e675383100e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17347,7 +17347,8 @@ QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
                                                       TemplateName Template,
                                              SourceLocation TemplateNameLoc,
                                      TemplateArgumentListInfo &TemplateArgs) {
-  return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
+  return SemaRef.CheckTemplateIdType(nullptr, Template, TemplateNameLoc,
+                                     TemplateArgs);
 }
 
 template<typename Derived>
diff --git a/clang/test/AST/ast-dump-template-decls.cpp b/clang/test/AST/ast-dump-template-decls.cpp
index d5228d4667304..c9e66d18bc454 100644
--- a/clang/test/AST/ast-dump-template-decls.cpp
+++ b/clang/test/AST/ast-dump-template-decls.cpp
@@ -126,7 +126,7 @@ using type2 = typename C<int>::type1<void>;
 // CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'void' sugar class depth 0 index 0 U final
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'type1'
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void'
-// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 0 T
+// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 0 T final
 // CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'C'
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'int'
 } // namespace PR55886
@@ -138,7 +138,7 @@ template <typename... T> struct D {
   };
 };
 template struct D<float, char>::bind<int, short>;
-// CHECK:      TypeAliasDecl 0x{{[^ ]*}} <line:{{[1-9]+}}:5, col:45> col:11 bound_type 'int (int (*)(float, int), int (*)(char, short))'
+// CHECK:      TypeAliasDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:5, col:45> col:11 bound_type 'int (int (*)(float, int), int (*)(char, short))'
 // CHECK:      FunctionProtoType 0x{{[^ ]*}} 'int (int (*)(float, int), int (*)(char, short))' cdecl
 // CHECK:      FunctionProtoType 0x{{[^ ]*}} 'int (float, int)' cdecl
 // CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... T pack_index 1{{$}}
diff --git a/clang/test/Sema/Resugar/resugar-types.cpp b/clang/test/Sema/Resugar/resugar-types.cpp
index baa3b4ed65f20..296a79a05b6be 100644
--- a/clang/test/Sema/Resugar/resugar-types.cpp
+++ b/clang/test/Sema/Resugar/resugar-types.cpp
@@ -88,7 +88,7 @@ template <class E> struct foo {
 };
 using T1 = foo<Bar>::apply<char>;
 TEST_NOT(T1::type1);
-TEST_NOT(T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases.
+TEST(T1::type2);
 
 using T2 = foo<int>::apply<Bar>;
 TEST(T2::type1);
@@ -106,7 +106,7 @@ template <typename... Cs> struct foo {
 };
 using T1 = foo<Bar>::bind<char>;
 TEST_NOT(T1::type1);
-TEST_NOT(T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases.
+TEST(T1::type2);
 
 using T2 = foo<int>::bind<Bar>;
 TEST(T2::type1);
@@ -148,7 +148,7 @@ template <typename... Ts> using Z = Y<Ts...>;
 
 using T1 = typename foo<Z, Bar>::template bind<int>;
 TEST_NOT(typename T1::type1);
-TEST_NOT(typename T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases.
+TEST(typename T1::type2);
 
 using T2 = typename foo<Z, int>::template bind<Bar>;
 TEST(typename T2::type1);



More information about the llvm-branch-commits mailing list