Skip to content

Commit b046fbd

Browse files
mizvekovvar-const
authored andcommitted
[clang] Improved canonicalization for template specialization types (llvm#135119)
This changes the TemplateArgument representation to hold a flag indicating whether a template argument of expression type is supposed to be canonical or not. This gets one step closer to solving llvm#92292 This still doesn't try to unique as-written TSTs. While this would increase the amount of memory savings and make code dealing with the AST more well-behaved, profiling template argument lists is still too expensive for this to be worthwhile, at least for now. Without this uniquing, this patch stands neutral in terms of performance impact. This also fixes the context creation of TSTs, so that they don't in some cases get incorrectly flagged as sugar over their own canonical form. This is captured in the test expectation change of some AST dumps. This fixes some places which were unnecessarily canonicalizing these TSTs.
1 parent 3ca7a1a commit b046fbd

28 files changed

+448
-422
lines changed

clang-tools-extra/clangd/AST.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,8 @@ QualType declaredType(const TypeDecl *D) {
439439
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
440440
if (const auto *Args = CTSD->getTemplateArgsAsWritten())
441441
return Context.getTemplateSpecializationType(
442-
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments());
442+
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
443+
/*CanonicalArgs=*/std::nullopt);
443444
return Context.getTypeDeclType(D);
444445
}
445446

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ Improvements to Clang's diagnostics
292292
- Clang now better preserves the sugared types of pointers to member.
293293
- Clang now better preserves the presence of the template keyword with dependent
294294
prefixes.
295+
- Clang now in more cases avoids printing 'type-parameter-X-X' instead of the name of
296+
the template parameter.
295297
- Clang now respects the current language mode when printing expressions in
296298
diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
297299
a bunch of HLSL types being printed as their C++ equivalents.

clang/include/clang/AST/ASTContext.h

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
364364
const ASTContext&>
365365
CanonTemplateTemplateParms;
366366

367-
TemplateTemplateParmDecl *
368-
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
369-
370367
/// The typedef for the __int128_t type.
371368
mutable TypedefDecl *Int128Decl = nullptr;
372369

@@ -1808,22 +1805,26 @@ class ASTContext : public RefCountedBase<ASTContext> {
18081805
bool ParameterPack,
18091806
TemplateTypeParmDecl *ParmDecl = nullptr) const;
18101807

1811-
QualType getTemplateSpecializationType(TemplateName T,
1812-
ArrayRef<TemplateArgument> Args,
1813-
QualType Canon = QualType()) const;
1808+
QualType getCanonicalTemplateSpecializationType(
1809+
TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;
18141810

18151811
QualType
1816-
getCanonicalTemplateSpecializationType(TemplateName T,
1817-
ArrayRef<TemplateArgument> Args) const;
1812+
getTemplateSpecializationType(TemplateName T,
1813+
ArrayRef<TemplateArgument> SpecifiedArgs,
1814+
ArrayRef<TemplateArgument> CanonicalArgs,
1815+
QualType Underlying = QualType()) const;
18181816

1819-
QualType getTemplateSpecializationType(TemplateName T,
1820-
ArrayRef<TemplateArgumentLoc> Args,
1821-
QualType Canon = QualType()) const;
1817+
QualType
1818+
getTemplateSpecializationType(TemplateName T,
1819+
ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
1820+
ArrayRef<TemplateArgument> CanonicalArgs,
1821+
QualType Canon = QualType()) const;
18221822

1823-
TypeSourceInfo *
1824-
getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,
1825-
const TemplateArgumentListInfo &Args,
1826-
QualType Canon = QualType()) const;
1823+
TypeSourceInfo *getTemplateSpecializationTypeInfo(
1824+
TemplateName T, SourceLocation TLoc,
1825+
const TemplateArgumentListInfo &SpecifiedArgs,
1826+
ArrayRef<TemplateArgument> CanonicalArgs,
1827+
QualType Canon = QualType()) const;
18271828

18281829
QualType getParenType(QualType NamedType) const;
18291830

@@ -2939,6 +2940,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
29392940
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg)
29402941
const;
29412942

2943+
/// Canonicalize the given template argument list.
2944+
///
2945+
/// Returns true if any arguments were non-canonical, false otherwise.
2946+
bool
2947+
canonicalizeTemplateArguments(MutableArrayRef<TemplateArgument> Args) const;
2948+
2949+
/// Canonicalize the given TemplateTemplateParmDecl.
2950+
TemplateTemplateParmDecl *
2951+
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
2952+
2953+
TemplateTemplateParmDecl *findCanonicalTemplateTemplateParmDeclInternal(
2954+
TemplateTemplateParmDecl *TTP) const;
2955+
TemplateTemplateParmDecl *insertCanonicalTemplateTemplateParmDeclInternal(
2956+
TemplateTemplateParmDecl *CanonTTP) const;
2957+
29422958
/// Type Query functions. If the type is an instance of the specified class,
29432959
/// return the Type pointer for the underlying maximally pretty type. This
29442960
/// is a member of ASTContext because this may need to do some amount of

clang/include/clang/AST/PropertiesBase.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,11 +877,14 @@ let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
877877
def : Property<"expression", ExprRef> {
878878
let Read = [{ node.getAsExpr() }];
879879
}
880+
def : Property<"IsCanonical", Bool> {
881+
let Read = [{ node.isCanonicalExpr() }];
882+
}
880883
def : Property<"isDefaulted", Bool> {
881884
let Read = [{ node.getIsDefaulted() }];
882885
}
883886
def : Creator<[{
884-
return TemplateArgument(expression, isDefaulted);
887+
return TemplateArgument(expression, IsCanonical, isDefaulted);
885888
}]>;
886889
}
887890
let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {

clang/include/clang/AST/TemplateBase.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class TemplateArgument {
167167
unsigned Kind : 31;
168168
LLVM_PREFERRED_TYPE(bool)
169169
unsigned IsDefaulted : 1;
170+
LLVM_PREFERRED_TYPE(bool)
171+
unsigned IsCanonicalExpr : 1;
170172
uintptr_t V;
171173
};
172174
union {
@@ -187,7 +189,8 @@ class TemplateArgument {
187189

188190
public:
189191
/// Construct an empty, invalid template argument.
190-
constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
192+
constexpr TemplateArgument()
193+
: TypeOrValue{Null, /*IsDefaulted=*/0, /*IsCanonicalExpr=*/0, /*V=*/0} {}
191194

192195
/// Construct a template type argument.
193196
TemplateArgument(QualType T, bool isNullPtr = false,
@@ -262,9 +265,10 @@ class TemplateArgument {
262265
/// This form of template argument only occurs in template argument
263266
/// lists used for dependent types and for expression; it will not
264267
/// occur in a non-dependent, canonical template argument list.
265-
explicit TemplateArgument(Expr *E, bool IsDefaulted = false) {
268+
TemplateArgument(Expr *E, bool IsCanonical, bool IsDefaulted = false) {
266269
TypeOrValue.Kind = Expression;
267270
TypeOrValue.IsDefaulted = IsDefaulted;
271+
TypeOrValue.IsCanonicalExpr = IsCanonical;
268272
TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
269273
}
270274

@@ -407,6 +411,11 @@ class TemplateArgument {
407411
return reinterpret_cast<Expr *>(TypeOrValue.V);
408412
}
409413

414+
bool isCanonicalExpr() const {
415+
assert(getKind() == Expression && "Unexpected kind");
416+
return TypeOrValue.IsCanonicalExpr;
417+
}
418+
410419
/// Iterator that traverses the elements of a template argument pack.
411420
using pack_iterator = const TemplateArgument *;
412421

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6676,10 +6676,9 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
66766676
/// replacement must, recursively, be one of these).
66776677
TemplateName Template;
66786678

6679-
TemplateSpecializationType(TemplateName T,
6679+
TemplateSpecializationType(TemplateName T, bool IsAlias,
66806680
ArrayRef<TemplateArgument> Args,
6681-
QualType Canon,
6682-
QualType Aliased);
6681+
QualType Underlying);
66836682

66846683
public:
66856684
/// Determine whether any of the given template arguments are dependent.
@@ -6747,7 +6746,7 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
67476746

67486747
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
67496748
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
6750-
ArrayRef<TemplateArgument> Args,
6749+
ArrayRef<TemplateArgument> Args, QualType Underlying,
67516750
const ASTContext &Context);
67526751

67536752
static bool classof(const Type *T) {

clang/include/clang/AST/TypeProperties.td

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -737,39 +737,19 @@ let Class = DependentAddressSpaceType in {
737737
}
738738

739739
let Class = TemplateSpecializationType in {
740-
def : Property<"dependent", Bool> {
741-
let Read = [{ node->isDependentType() }];
742-
}
743740
def : Property<"templateName", TemplateName> {
744741
let Read = [{ node->getTemplateName() }];
745742
}
746-
def : Property<"templateArguments", Array<TemplateArgument>> {
743+
def : Property<"args", Array<TemplateArgument>> {
747744
let Read = [{ node->template_arguments() }];
748745
}
749-
def : Property<"underlyingType", Optional<QualType>> {
750-
let Read = [{
751-
node->isTypeAlias()
752-
? std::optional<QualType>(node->getAliasedType())
753-
: node->isCanonicalUnqualified()
754-
? std::nullopt
755-
: std::optional<QualType>(node->getCanonicalTypeInternal())
756-
}];
746+
def : Property<"UnderlyingType", QualType> {
747+
let Read = [{ node->isCanonicalUnqualified() ? QualType() :
748+
node->desugar() }];
757749
}
758750

759751
def : Creator<[{
760-
QualType result;
761-
if (!underlyingType) {
762-
result = ctx.getCanonicalTemplateSpecializationType(templateName,
763-
templateArguments);
764-
} else {
765-
result = ctx.getTemplateSpecializationType(templateName,
766-
templateArguments,
767-
*underlyingType);
768-
}
769-
if (dependent)
770-
const_cast<Type *>(result.getTypePtr())
771-
->addDependence(TypeDependence::DependentInstantiation);
772-
return result;
752+
return ctx.getTemplateSpecializationType(templateName, args, std::nullopt, UnderlyingType);
773753
}]>;
774754
}
775755

0 commit comments

Comments
 (0)