[clang] AST: SubstTemplateTypeParmType support for non-canonical underlying type

This change allows us to represent in the AST some specific
circumstances where we substitute a template parameter type
which is part of the underlying type of a previous substitution.

This presently happens in some circumstances dealing with
substitution of defaulted parameters of template template
parameters, and in some other cases during concepts substitution.

The main motivation for this change is for the future use in the
implementation of template specialization resugaring, as this will
allow us to represent a substitution with sugared types.

Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>

Differential Revision: https://reviews.llvm.org/D132816
This commit is contained in:
Matheus Izvekov 2022-08-28 22:26:01 +02:00
parent 54d81e49e3
commit ef4bbfe338
No known key found for this signature in database
GPG Key ID: 22C080C6DC4E70F8
8 changed files with 46 additions and 18 deletions

View File

@ -1798,6 +1798,8 @@ protected:
unsigned : NumTypeBits;
unsigned HasNonCanonicalUnderlyingType : 1;
/// Represents the index within a pack if this represents a substitution
/// from a pack expansion. This index starts at the end of the pack and
/// increments towards the beginning.
@ -4985,8 +4987,12 @@ public:
/// been replaced with these. They are used solely to record that a
/// type was originally written as a template type parameter;
/// therefore they are never canonical.
class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
class SubstTemplateTypeParmType final
: public Type,
public llvm::FoldingSetNode,
private llvm::TrailingObjects<SubstTemplateTypeParmType, QualType> {
friend class ASTContext;
friend class llvm::TrailingObjects<SubstTemplateTypeParmType, QualType>;
// The original type parameter.
const TemplateTypeParmType *Replaced;
@ -5003,7 +5009,9 @@ public:
/// Gets the type that was substituted for the template
/// parameter.
QualType getReplacementType() const {
return getCanonicalTypeInternal();
return SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType
? *getTrailingObjects<QualType>()
: getCanonicalTypeInternal();
}
Optional<unsigned> getPackIndex() const {
@ -5023,7 +5031,7 @@ public:
const TemplateTypeParmType *Replaced,
QualType Replacement, Optional<unsigned> PackIndex) {
ID.AddPointer(Replaced);
ID.AddPointer(Replacement.getAsOpaquePtr());
Replacement.Profile(ID);
ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
}

View File

@ -739,10 +739,9 @@ let Class = SubstTemplateTypeParmType in {
}
def : Creator<[{
// The call to getCanonicalType here existed in ASTReader.cpp, too.
return ctx.getSubstTemplateTypeParmType(
cast<TemplateTypeParmType>(replacedParameter),
ctx.getCanonicalType(replacementType), PackIndex);
replacementType, PackIndex);
}]>;
}

View File

@ -4764,9 +4764,6 @@ QualType
ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
QualType Replacement,
Optional<unsigned> PackIndex) const {
assert(Replacement.isCanonical()
&& "replacement types must always be canonical");
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmType::Profile(ID, Parm, Replacement, PackIndex);
void *InsertPos = nullptr;
@ -4774,8 +4771,11 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
= SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!SubstParm) {
SubstParm = new (*this, TypeAlignment)
SubstTemplateTypeParmType(Parm, Replacement, PackIndex);
void *Mem = Allocate(SubstTemplateTypeParmType::totalSizeToAlloc<QualType>(
!Replacement.isCanonical()),
TypeAlignment);
SubstParm =
new (Mem) SubstTemplateTypeParmType(Parm, Replacement, PackIndex);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
}

View File

@ -1530,8 +1530,7 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
return ToReplacementTypeOrErr.takeError();
return Importer.getToContext().getSubstTemplateTypeParmType(
*ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType(),
T->getPackIndex());
*ReplacedOrErr, *ToReplacementTypeOrErr, T->getPackIndex());
}
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(

View File

@ -3650,10 +3650,16 @@ IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
}
SubstTemplateTypeParmType::SubstTemplateTypeParmType(
const TemplateTypeParmType *Param, QualType Canon,
const TemplateTypeParmType *Param, QualType Replacement,
Optional<unsigned> PackIndex)
: Type(SubstTemplateTypeParm, Canon, Canon->getDependence()),
: Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
Replacement->getDependence()),
Replaced(Param) {
SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType =
Replacement != getCanonicalTypeInternal();
if (SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType)
*getTrailingObjects<QualType>() = Replacement;
SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
}

View File

@ -3513,8 +3513,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
0, IndexReplaced, false,
cast<TemplateTypeParmDecl>(TPL->getParam(IndexReplaced)));
return SemaRef.Context.getSubstTemplateTypeParmType(
cast<TemplateTypeParmType>(TTP), Replacement.getCanonicalType(),
PackIndexReplaced);
cast<TemplateTypeParmType>(TTP), Replacement, PackIndexReplaced);
};
switch (BTD->getBuiltinTemplateKind()) {

View File

@ -6408,8 +6408,6 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
if (Replacement.isNull())
return QualType();
// Always canonicalize the replacement type.
Replacement = SemaRef.Context.getCanonicalType(Replacement);
QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
T->getReplacedParameter(), Replacement, T->getPackIndex());

View File

@ -162,3 +162,22 @@ using t2 = D<float, char>::B<int, short>;
// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 0
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
} // namespace PR56099
namespace subst_default_argument {
template<class A1> class A {};
template<template<class C1, class C2 = A<C1>> class D1, class D2> using D = D1<D2>;
template<class E1, class E2> class E {};
using test1 = D<E, int>;
// CHECK: TypeAliasDecl 0x{{[^ ]*}} <line:{{[1-9]+}}:1, col:23> col:7 test1 'D<subst_default_argument::E, int>':'subst_default_argument::E<int, subst_default_argument::A<int>>'
// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'A<int>' sugar A
// CHECK-NEXT: |-TemplateArgument type 'int':'int'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar
// CHECK-NEXT: | |-TemplateTypeParmType 0x{{[^ ]*}} 'C1' dependent depth 1 index 0
// CHECK-NEXT: | | `-TemplateTypeParm 0x{{[^ ]*}} 'C1'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar
// CHECK-NEXT: | |-TemplateTypeParmType 0x{{[^ ]*}} 'type-parameter-0-1' dependent depth 0 index 1
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'int'
// CHECK-NEXT: `-RecordType 0x{{[^ ]*}} 'subst_default_argument::A<int>'
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[^ ]*}} 'A'
} // namespace subst_default_argument