Skip to content

[clang] Template Specialization Resugaring - Template Type Alias #132442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: users/mizvekov/clang-resugar-typedecl
Choose a base branch
from

Conversation

mizvekov
Copy link
Contributor

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

@mizvekov mizvekov self-assigned this Mar 21, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" coroutines C++20 coroutines labels Mar 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2025

@llvm/pr-subscribers-coroutines

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/132442.diff

9 Files Affected:

  • (modified) clang/include/clang/Sema/Sema.h (+2-1)
  • (modified) clang/lib/Sema/SemaCXXScopeSpec.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaCoroutine.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaDeclCXX.cpp (+4-2)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+25-18)
  • (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+2-1)
  • (modified) clang/lib/Sema/TreeTransform.h (+2-1)
  • (modified) clang/test/AST/ast-dump-template-decls.cpp (+1-3)
  • (modified) clang/test/Sema/Resugar/resugar-types.cpp (+3-3)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 047ba88511dac..d45fc14e7b3c4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11508,7 +11508,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 e8fe1cdd7336a..fe39696a6c6b6 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -910,7 +910,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 88d849b27db07..8cca65edc84e3 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,
@@ -170,7 +170,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 330afbfa2d19d..26a3f86a718c4 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1142,7 +1142,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)) {
@@ -12185,7 +12186,8 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
   return Context.getElaboratedType(
       ElaboratedTypeKeyword::None,
       NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()),
-      CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
+      CheckTemplateIdType(nullptr, TemplateName(StdInitializerList), Loc,
+                          Args));
 }
 
 bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0b26f79ea3bfc..63a4dab9a41f3 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3817,7 +3817,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,
@@ -3825,7 +3826,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(
@@ -3839,7 +3840,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();
@@ -3952,8 +3953,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();
@@ -4005,7 +4006,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,
@@ -4055,14 +4056,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,
@@ -4210,7 +4213,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) {
   DependentTemplateName *DTN =
@@ -4294,9 +4298,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
@@ -4333,9 +4337,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)) {
@@ -4579,7 +4583,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;
 
@@ -4661,7 +4666,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);
 
@@ -11451,7 +11457,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 4ee943ea5597e..ffe944fc53558 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17330,7 +17330,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 9f578e5afe561..8ffcaeb879ee9 100644
--- a/clang/test/AST/ast-dump-template-decls.cpp
+++ b/clang/test/AST/ast-dump-template-decls.cpp
@@ -124,8 +124,6 @@ using type2 = typename C<int>::type1<void>;
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void'
 // CHECK-NEXT: FunctionProtoType 0x{{[^ ]*}} 'void (int)' cdecl
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void'
-// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 0 T
-// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'C'
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'int'
 } // namespace PR55886
 
@@ -136,7 +134,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);

@mizvekov mizvekov force-pushed the users/mizvekov/clang-resugar-typedecl branch from e621da3 to 4571fad Compare March 21, 2025 18:43
@mizvekov mizvekov requested a review from JDevlieghere as a code owner March 21, 2025 18:43
@mizvekov mizvekov force-pushed the users/mizvekov/clang-resugar-temp-type-alias branch from 3022927 to 67a0981 Compare March 21, 2025 18:43
@mizvekov mizvekov force-pushed the users/mizvekov/clang-resugar-temp-type-alias branch from 67a0981 to 9d5d428 Compare April 3, 2025 01:53
@mizvekov mizvekov force-pushed the users/mizvekov/clang-resugar-typedecl branch from 4571fad to 0793555 Compare April 3, 2025 01:53
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
@mizvekov mizvekov force-pushed the users/mizvekov/clang-resugar-typedecl branch from 0793555 to a010f37 Compare April 3, 2025 18:14
@mizvekov mizvekov force-pushed the users/mizvekov/clang-resugar-temp-type-alias branch from 9d5d428 to 900a26a Compare April 3, 2025 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category coroutines C++20 coroutines
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants