Skip to content

Commit 761787d

Browse files
authored
Reland: [clang] Improved canonicalization for template specialization types (#135414)
This relands #135119, after fixing crashes seen in LLDB CI reported here: #135119 (comment) Fixes #135119 This changes the TemplateArgument representation to hold a flag indicating whether a tempalte argument of expression type is supposed to be canonical or not. This gets one step closer to solving #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. 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 009971a commit 761787d

29 files changed

+511
-497
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
@@ -303,6 +303,8 @@ Improvements to Clang's diagnostics
303303
- Clang now better preserves the sugared types of pointers to member.
304304
- Clang now better preserves the presence of the template keyword with dependent
305305
prefixes.
306+
- Clang now in more cases avoids printing 'type-parameter-X-X' instead of the name of
307+
the template parameter.
306308
- Clang now respects the current language mode when printing expressions in
307309
diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
308310
a bunch of HLSL types being printed as their C++ equivalents.

clang/include/clang/AST/ASTContext.h

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
243243
mutable llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
244244
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
245245
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
246-
mutable llvm::FoldingSet<DependentUnaryTransformType>
247-
DependentUnaryTransformTypes;
246+
mutable llvm::FoldingSet<UnaryTransformType> UnaryTransformTypes;
248247
// An AutoType can have a dependency on another AutoType via its template
249248
// arguments. Since both dependent and dependency are on the same set,
250249
// we can end up in an infinite recursion when looking for a node if we used
@@ -367,9 +366,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
367366
const ASTContext&>
368367
CanonTemplateTemplateParms;
369368

370-
TemplateTemplateParmDecl *
371-
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
372-
373369
/// The typedef for the __int128_t type.
374370
mutable TypedefDecl *Int128Decl = nullptr;
375371

@@ -1811,22 +1807,26 @@ class ASTContext : public RefCountedBase<ASTContext> {
18111807
bool ParameterPack,
18121808
TemplateTypeParmDecl *ParmDecl = nullptr) const;
18131809

1814-
QualType getTemplateSpecializationType(TemplateName T,
1815-
ArrayRef<TemplateArgument> Args,
1816-
QualType Canon = QualType()) const;
1810+
QualType getCanonicalTemplateSpecializationType(
1811+
TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;
18171812

18181813
QualType
1819-
getCanonicalTemplateSpecializationType(TemplateName T,
1820-
ArrayRef<TemplateArgument> Args) const;
1814+
getTemplateSpecializationType(TemplateName T,
1815+
ArrayRef<TemplateArgument> SpecifiedArgs,
1816+
ArrayRef<TemplateArgument> CanonicalArgs,
1817+
QualType Underlying = QualType()) const;
18211818

1822-
QualType getTemplateSpecializationType(TemplateName T,
1823-
ArrayRef<TemplateArgumentLoc> Args,
1824-
QualType Canon = QualType()) const;
1819+
QualType
1820+
getTemplateSpecializationType(TemplateName T,
1821+
ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
1822+
ArrayRef<TemplateArgument> CanonicalArgs,
1823+
QualType Canon = QualType()) const;
18251824

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

18311831
QualType getParenType(QualType NamedType) const;
18321832

@@ -2942,6 +2942,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
29422942
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg)
29432943
const;
29442944

2945+
/// Canonicalize the given template argument list.
2946+
///
2947+
/// Returns true if any arguments were non-canonical, false otherwise.
2948+
bool
2949+
canonicalizeTemplateArguments(MutableArrayRef<TemplateArgument> Args) const;
2950+
2951+
/// Canonicalize the given TemplateTemplateParmDecl.
2952+
TemplateTemplateParmDecl *
2953+
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
2954+
2955+
TemplateTemplateParmDecl *findCanonicalTemplateTemplateParmDeclInternal(
2956+
TemplateTemplateParmDecl *TTP) const;
2957+
TemplateTemplateParmDecl *insertCanonicalTemplateTemplateParmDeclInternal(
2958+
TemplateTemplateParmDecl *CanonTTP) const;
2959+
29452960
/// Type Query functions. If the type is an instance of the specified class,
29462961
/// return the Type pointer for the underlying maximally pretty type. This
29472962
/// 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: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5918,7 +5918,7 @@ class DecltypeType : public Type {
59185918
/// of this class via DecltypeType nodes.
59195919
class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
59205920
public:
5921-
DependentDecltypeType(Expr *E, QualType UnderlyingTpe);
5921+
DependentDecltypeType(Expr *E);
59225922

59235923
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
59245924
Profile(ID, Context, getUnderlyingExpr());
@@ -6003,7 +6003,7 @@ class PackIndexingType final
60036003
};
60046004

60056005
/// A unary type transform, which is a type constructed from another.
6006-
class UnaryTransformType : public Type {
6006+
class UnaryTransformType : public Type, public llvm::FoldingSetNode {
60076007
public:
60086008
enum UTTKind {
60096009
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
@@ -6037,28 +6037,16 @@ class UnaryTransformType : public Type {
60376037
static bool classof(const Type *T) {
60386038
return T->getTypeClass() == UnaryTransform;
60396039
}
6040-
};
6041-
6042-
/// Internal representation of canonical, dependent
6043-
/// __underlying_type(type) types.
6044-
///
6045-
/// This class is used internally by the ASTContext to manage
6046-
/// canonical, dependent types, only. Clients will only see instances
6047-
/// of this class via UnaryTransformType nodes.
6048-
class DependentUnaryTransformType : public UnaryTransformType,
6049-
public llvm::FoldingSetNode {
6050-
public:
6051-
DependentUnaryTransformType(const ASTContext &C, QualType BaseType,
6052-
UTTKind UKind);
60536040

60546041
void Profile(llvm::FoldingSetNodeID &ID) {
6055-
Profile(ID, getBaseType(), getUTTKind());
6042+
Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind());
60566043
}
60576044

60586045
static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
6059-
UTTKind UKind) {
6060-
ID.AddPointer(BaseType.getAsOpaquePtr());
6061-
ID.AddInteger((unsigned)UKind);
6046+
QualType UnderlyingType, UTTKind UKind) {
6047+
BaseType.Profile(ID);
6048+
UnderlyingType.Profile(ID);
6049+
ID.AddInteger(UKind);
60626050
}
60636051
};
60646052

@@ -6676,10 +6664,9 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
66766664
/// replacement must, recursively, be one of these).
66776665
TemplateName Template;
66786666

6679-
TemplateSpecializationType(TemplateName T,
6667+
TemplateSpecializationType(TemplateName T, bool IsAlias,
66806668
ArrayRef<TemplateArgument> Args,
6681-
QualType Canon,
6682-
QualType Aliased);
6669+
QualType Underlying);
66836670

66846671
public:
66856672
/// Determine whether any of the given template arguments are dependent.
@@ -6747,7 +6734,7 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
67476734

67486735
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
67496736
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
6750-
ArrayRef<TemplateArgument> Args,
6737+
ArrayRef<TemplateArgument> Args, QualType Underlying,
67516738
const ASTContext &Context);
67526739

67536740
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)