Skip to content

Commit 69a6417

Browse files
committed
[clang] Implement divergence for TypedefType and UsingType
With this patch, TypedefTypes and UsingTypes can have an underlying type which diverges from their corresponding declarations. For the TypedefType case, this can be seen when getting the common sugared type between two redeclarations with different sugar. For both cases, this will become important as resugaring is implemented, as this will allow us to resugar these when they were dependent before instantiation. Signed-off-by: Matheus Izvekov <mizvekov@gmail.com> Differential Revision: https://reviews.llvm.org/D133468
1 parent eda6ff3 commit 69a6417

11 files changed

+164
-42
lines changed

clang/include/clang/AST/ASTContext.h

+1
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
246246
TemplateSpecializationTypes;
247247
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
248248
mutable llvm::FoldingSet<UsingType> UsingTypes;
249+
mutable llvm::FoldingSet<TypedefType> TypedefTypes;
249250
mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes{
250251
GeneralTypesLog2InitSize};
251252
mutable llvm::FoldingSet<DependentNameType> DependentNameTypes;

clang/include/clang/AST/JSONNodeDumper.h

+1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class JSONNodeDumper
209209
void Visit(const APValue &Value, QualType Ty);
210210

211211
void VisitTypedefType(const TypedefType *TT);
212+
void VisitUsingType(const UsingType *TT);
212213
void VisitFunctionType(const FunctionType *T);
213214
void VisitFunctionProtoType(const FunctionProtoType *T);
214215
void VisitRValueReferenceType(const ReferenceType *RT);

clang/include/clang/AST/Type.h

+55-7
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,24 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
18071807
unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
18081808
};
18091809

1810+
class UsingBitfields {
1811+
friend class UsingType;
1812+
1813+
unsigned : NumTypeBits;
1814+
1815+
/// True if the underlying type is different from the declared one.
1816+
unsigned hasTypeDifferentFromDecl : 1;
1817+
};
1818+
1819+
class TypedefBitfields {
1820+
friend class TypedefType;
1821+
1822+
unsigned : NumTypeBits;
1823+
1824+
/// True if the underlying type is different from the declared one.
1825+
unsigned hasTypeDifferentFromDecl : 1;
1826+
};
1827+
18101828
class SubstTemplateTypeParmTypeBitfields {
18111829
friend class SubstTemplateTypeParmType;
18121830

@@ -1897,6 +1915,8 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
18971915
AttributedTypeBitfields AttributedTypeBits;
18981916
AutoTypeBitfields AutoTypeBits;
18991917
TypeOfBitfields TypeOfBits;
1918+
TypedefBitfields TypedefBits;
1919+
UsingBitfields UsingBits;
19001920
BuiltinTypeBitfields BuiltinTypeBits;
19011921
FunctionTypeBitfields FunctionTypeBits;
19021922
ObjCObjectTypeBitfields ObjCObjectTypeBits;
@@ -4476,9 +4496,12 @@ class UnresolvedUsingType : public Type {
44764496
}
44774497
};
44784498

4479-
class UsingType : public Type, public llvm::FoldingSetNode {
4499+
class UsingType final : public Type,
4500+
public llvm::FoldingSetNode,
4501+
private llvm::TrailingObjects<UsingType, QualType> {
44804502
UsingShadowDecl *Found;
44814503
friend class ASTContext; // ASTContext creates these.
4504+
friend TrailingObjects;
44824505

44834506
UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon);
44844507

@@ -4487,21 +4510,31 @@ class UsingType : public Type, public llvm::FoldingSetNode {
44874510
QualType getUnderlyingType() const;
44884511

44894512
bool isSugared() const { return true; }
4513+
4514+
// This always has the 'same' type as declared, but not necessarily identical.
44904515
QualType desugar() const { return getUnderlyingType(); }
44914516

4492-
void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Found); }
4493-
static void Profile(llvm::FoldingSetNodeID &ID,
4494-
const UsingShadowDecl *Found) {
4517+
// Internal helper, for debugging purposes.
4518+
bool typeMatchesDecl() const { return !UsingBits.hasTypeDifferentFromDecl; }
4519+
4520+
void Profile(llvm::FoldingSetNodeID &ID) {
4521+
Profile(ID, Found, typeMatchesDecl() ? QualType() : getUnderlyingType());
4522+
}
4523+
static void Profile(llvm::FoldingSetNodeID &ID, const UsingShadowDecl *Found,
4524+
QualType Underlying) {
44954525
ID.AddPointer(Found);
4526+
if (!Underlying.isNull())
4527+
Underlying.Profile(ID);
44964528
}
44974529
static bool classof(const Type *T) { return T->getTypeClass() == Using; }
44984530
};
44994531

4500-
class TypedefType : public Type {
4532+
class TypedefType final : public Type,
4533+
public llvm::FoldingSetNode,
4534+
private llvm::TrailingObjects<TypedefType, QualType> {
45014535
TypedefNameDecl *Decl;
4502-
4503-
private:
45044536
friend class ASTContext; // ASTContext creates these.
4537+
friend TrailingObjects;
45054538

45064539
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying,
45074540
QualType can);
@@ -4510,8 +4543,23 @@ class TypedefType : public Type {
45104543
TypedefNameDecl *getDecl() const { return Decl; }
45114544

45124545
bool isSugared() const { return true; }
4546+
4547+
// This always has the 'same' type as declared, but not necessarily identical.
45134548
QualType desugar() const;
45144549

4550+
// Internal helper, for debugging purposes.
4551+
bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; }
4552+
4553+
void Profile(llvm::FoldingSetNodeID &ID) {
4554+
Profile(ID, Decl, typeMatchesDecl() ? QualType() : desugar());
4555+
}
4556+
static void Profile(llvm::FoldingSetNodeID &ID, const TypedefNameDecl *Decl,
4557+
QualType Underlying) {
4558+
ID.AddPointer(Decl);
4559+
if (!Underlying.isNull())
4560+
Underlying.Profile(ID);
4561+
}
4562+
45154563
static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
45164564
};
45174565

clang/include/clang/AST/TypeProperties.td

+3-7
Original file line numberDiff line numberDiff line change
@@ -379,16 +379,12 @@ let Class = TypedefType in {
379379
def : Property<"declaration", DeclRef> {
380380
let Read = [{ node->getDecl() }];
381381
}
382-
def : Property<"canonicalType", Optional<QualType>> {
383-
let Read = [{ makeOptionalFromNullable(node->getCanonicalTypeInternal()) }];
382+
def : Property<"underlyingType", QualType> {
383+
let Read = [{ node->desugar() }];
384384
}
385385

386386
def : Creator<[{
387-
QualType finalCanonicalType =
388-
canonicalType ? ctx.getCanonicalType(*canonicalType)
389-
: QualType();
390-
return ctx.getTypedefType(cast<TypedefNameDecl>(declaration),
391-
finalCanonicalType);
387+
return ctx.getTypedefType(cast<TypedefNameDecl>(declaration), underlyingType);
392388
}]>;
393389
}
394390

clang/lib/AST/ASTContext.cpp

+46-20
Original file line numberDiff line numberDiff line change
@@ -2364,12 +2364,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
23642364
return getTypeInfo(cast<UsingType>(T)->desugar().getTypePtr());
23652365

23662366
case Type::Typedef: {
2367-
const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
2368-
TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
2367+
const auto *TT = cast<TypedefType>(T);
2368+
TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr());
23692369
// If the typedef has an aligned attribute on it, it overrides any computed
23702370
// alignment we have. This violates the GCC documentation (which says that
23712371
// attribute(aligned) can only round up) but matches its implementation.
2372-
if (unsigned AttrAlign = Typedef->getMaxAlignment()) {
2372+
if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) {
23732373
Align = AttrAlign;
23742374
AlignRequirement = AlignRequirementKind::RequiredByTypedef;
23752375
} else {
@@ -4638,34 +4638,60 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
46384638
/// specified typedef name decl.
46394639
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
46404640
QualType Underlying) const {
4641-
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
4641+
if (!Decl->TypeForDecl) {
4642+
if (Underlying.isNull())
4643+
Underlying = Decl->getUnderlyingType();
4644+
auto *NewType = new (*this, TypeAlignment) TypedefType(
4645+
Type::Typedef, Decl, QualType(), getCanonicalType(Underlying));
4646+
Decl->TypeForDecl = NewType;
4647+
Types.push_back(NewType);
4648+
return QualType(NewType, 0);
4649+
}
4650+
if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying)
4651+
return QualType(Decl->TypeForDecl, 0);
4652+
assert(hasSameType(Decl->getUnderlyingType(), Underlying));
46424653

4643-
if (Underlying.isNull())
4644-
Underlying = Decl->getUnderlyingType();
4645-
QualType Canonical = getCanonicalType(Underlying);
4646-
auto *newType = new (*this, TypeAlignment)
4647-
TypedefType(Type::Typedef, Decl, Underlying, Canonical);
4648-
Decl->TypeForDecl = newType;
4649-
Types.push_back(newType);
4650-
return QualType(newType, 0);
4654+
llvm::FoldingSetNodeID ID;
4655+
TypedefType::Profile(ID, Decl, Underlying);
4656+
4657+
void *InsertPos = nullptr;
4658+
if (TypedefType *T = TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) {
4659+
assert(!T->typeMatchesDecl() &&
4660+
"non-divergent case should be handled with TypeDecl");
4661+
return QualType(T, 0);
4662+
}
4663+
4664+
void *Mem =
4665+
Allocate(TypedefType::totalSizeToAlloc<QualType>(true), TypeAlignment);
4666+
auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying,
4667+
getCanonicalType(Underlying));
4668+
TypedefTypes.InsertNode(NewType, InsertPos);
4669+
Types.push_back(NewType);
4670+
return QualType(NewType, 0);
46514671
}
46524672

46534673
QualType ASTContext::getUsingType(const UsingShadowDecl *Found,
46544674
QualType Underlying) const {
46554675
llvm::FoldingSetNodeID ID;
4656-
UsingType::Profile(ID, Found);
4676+
UsingType::Profile(ID, Found, Underlying);
46574677

46584678
void *InsertPos = nullptr;
4659-
UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos);
4660-
if (T)
4679+
if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos))
46614680
return QualType(T, 0);
46624681

4663-
assert(!Underlying.hasLocalQualifiers());
4664-
assert(Underlying == getTypeDeclType(cast<TypeDecl>(Found->getTargetDecl())));
4665-
QualType Canon = Underlying.getCanonicalType();
4682+
const Type *TypeForDecl =
4683+
cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl();
46664684

4667-
UsingType *NewType =
4668-
new (*this, TypeAlignment) UsingType(Found, Underlying, Canon);
4685+
assert(!Underlying.hasLocalQualifiers());
4686+
QualType Canon = Underlying->getCanonicalTypeInternal();
4687+
assert(TypeForDecl->getCanonicalTypeInternal() == Canon);
4688+
4689+
if (Underlying.getTypePtr() == TypeForDecl)
4690+
Underlying = QualType();
4691+
void *Mem =
4692+
Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()),
4693+
TypeAlignment);
4694+
UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon);
46694695
Types.push_back(NewType);
46704696
UsingTypes.InsertNode(NewType, InsertPos);
46714697
return QualType(NewType, 0);

clang/lib/AST/ASTImporter.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -1362,8 +1362,12 @@ ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
13621362
Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl());
13631363
if (!ToDeclOrErr)
13641364
return ToDeclOrErr.takeError();
1365+
ExpectedType ToUnderlyingTypeOrErr = import(T->desugar());
1366+
if (!ToUnderlyingTypeOrErr)
1367+
return ToUnderlyingTypeOrErr.takeError();
13651368

1366-
return Importer.getToContext().getTypeDeclType(*ToDeclOrErr);
1369+
return Importer.getToContext().getTypedefType(*ToDeclOrErr,
1370+
*ToUnderlyingTypeOrErr);
13671371
}
13681372

13691373
ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) {

clang/lib/AST/ASTStructuralEquivalence.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -957,11 +957,17 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
957957
if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
958958
cast<UsingType>(T2)->getFoundDecl()))
959959
return false;
960+
if (!IsStructurallyEquivalent(Context,
961+
cast<UsingType>(T1)->getUnderlyingType(),
962+
cast<UsingType>(T2)->getUnderlyingType()))
963+
return false;
960964
break;
961965

962966
case Type::Typedef:
963967
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
964-
cast<TypedefType>(T2)->getDecl()))
968+
cast<TypedefType>(T2)->getDecl()) ||
969+
!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),
970+
cast<TypedefType>(T2)->desugar()))
965971
return false;
966972
break;
967973

clang/lib/AST/JSONNodeDumper.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,14 @@ JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) {
530530

531531
void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
532532
JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
533+
if (!TT->typeMatchesDecl())
534+
JOS.attribute("type", createQualType(TT->desugar()));
535+
}
536+
537+
void JSONNodeDumper::VisitUsingType(const UsingType *TT) {
538+
JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl()));
539+
if (!TT->typeMatchesDecl())
540+
JOS.attribute("type", createQualType(TT->desugar()));
533541
}
534542

535543
void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {

clang/lib/AST/TextNodeDumper.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1543,10 +1543,14 @@ void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
15431543

15441544
void TextNodeDumper::VisitUsingType(const UsingType *T) {
15451545
dumpDeclRef(T->getFoundDecl());
1546+
if (!T->typeMatchesDecl())
1547+
OS << " divergent";
15461548
}
15471549

15481550
void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
15491551
dumpDeclRef(T->getDecl());
1552+
if (!T->typeMatchesDecl())
1553+
OS << " divergent";
15501554
}
15511555

15521556
void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {

clang/lib/AST/Type.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -3434,25 +3434,34 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
34343434
}
34353435

34363436
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
3437-
QualType underlying, QualType can)
3438-
: Type(tc, can, toSemanticDependence(underlying->getDependence())),
3437+
QualType Underlying, QualType can)
3438+
: Type(tc, can, toSemanticDependence(can->getDependence())),
34393439
Decl(const_cast<TypedefNameDecl *>(D)) {
34403440
assert(!isa<TypedefType>(can) && "Invalid canonical type");
3441+
TypedefBits.hasTypeDifferentFromDecl = !Underlying.isNull();
3442+
if (!typeMatchesDecl())
3443+
*getTrailingObjects<QualType>() = Underlying;
34413444
}
34423445

34433446
QualType TypedefType::desugar() const {
3444-
return getDecl()->getUnderlyingType();
3447+
return typeMatchesDecl() ? Decl->getUnderlyingType()
3448+
: *getTrailingObjects<QualType>();
34453449
}
34463450

34473451
UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying,
34483452
QualType Canon)
3449-
: Type(Using, Canon, toSemanticDependence(Underlying->getDependence())),
3453+
: Type(Using, Canon, toSemanticDependence(Canon->getDependence())),
34503454
Found(const_cast<UsingShadowDecl *>(Found)) {
3451-
assert(Underlying == getUnderlyingType());
3455+
UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull();
3456+
if (!typeMatchesDecl())
3457+
*getTrailingObjects<QualType>() = Underlying;
34523458
}
34533459

34543460
QualType UsingType::getUnderlyingType() const {
3455-
return QualType(cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0);
3461+
return typeMatchesDecl()
3462+
? QualType(
3463+
cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0)
3464+
: *getTrailingObjects<QualType>();
34563465
}
34573466

34583467
QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }

clang/test/SemaCXX/sugar-common-types.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,22 @@ C1<X2> auto t26_2 = (::SB1){};
112112
C2<X2> auto t26_3 = (::SB1){};
113113
N t26 = 0 ? t26_1 : t26_2; // expected-error {{from 'SB1' (aka 'SS1')}}
114114
N t27 = 0 ? t26_1 : t26_3; // expected-error {{from 'SB1' (aka 'SS1')}}
115+
116+
using RPB1 = X1*;
117+
using RPX1 = RPB1;
118+
using RPB1 = Y1*; // redeclared
119+
using RPY1 = RPB1;
120+
N t28 = *(RPB1){}; // expected-error {{lvalue of type 'Y1' (aka 'int')}}
121+
auto t29 = 0 ? (RPX1){} : (RPY1){};
122+
N t30 = t29; // expected-error {{lvalue of type 'RPB1' (aka 'int *')}}
123+
N t31 = *t29; // expected-error {{lvalue of type 'B1' (aka 'int')}}
124+
125+
namespace A { using type1 = X1*; };
126+
namespace C { using A::type1; };
127+
using UPX1 = C::type1;
128+
namespace A { using type1 = Y1*; }; // redeclared
129+
namespace C { using A::type1; }; // redeclared
130+
using UPY1 = C::type1;
131+
auto t32 = 0 ? (UPX1){} : (UPY1){};
132+
N t33 = t32; // expected-error {{lvalue of type 'C::type1' (aka 'int *')}}
133+
N t34 = *t32; // expected-error {{lvalue of type 'B1' (aka 'int')}}

0 commit comments

Comments
 (0)