[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
Thu Apr 3 11:14:27 PDT 2025
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/132442
>From 900a26a5e2a64a8c12c7cd593e957eb9148091b1 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 9399e333223a9..069fe077cc74c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11512,7 +11512,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 f8772f4ea86ad..ed3b867aae1a0 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)) {
@@ -12162,7 +12163,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 c0e33deae7e66..0b78f3d9e02bb 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3826,7 +3826,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,
@@ -3834,7 +3835,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(
@@ -3848,7 +3849,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();
@@ -3961,8 +3962,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();
@@ -4014,7 +4015,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,
@@ -4064,14 +4065,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,
@@ -4219,7 +4222,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
@@ -4298,9 +4302,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
@@ -4337,9 +4341,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)) {
@@ -4582,7 +4586,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;
@@ -4663,7 +4668,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);
@@ -11444,7 +11450,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 4d8d43fa3723b..c17d015f82ff7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6817,7 +6817,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 96cef87fcf346..67677669b08d8 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17349,7 +17349,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