Skip to content

Commit 88438ba

Browse files
authored
[clang] AST: fix getAs canonicalization of leaf types (#155028)
1 parent f6d2fcc commit 88438ba

File tree

75 files changed

+267
-242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+267
-242
lines changed

clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
997997
WorkType = QualType{ToBuiltin, FastQualifiersToApply};
998998
}
999999

1000-
const auto *FromEnum = WorkType->getAs<EnumType>();
1000+
const auto *FromEnum = WorkType->getAsCanonical<EnumType>();
10011001
const auto *ToEnum = To->getAs<EnumType>();
10021002
if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
10031003
// Unscoped enumerations (or enumerations in C) convert to numerics.

clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ AST_MATCHER(ParmVarDecl, isTemplateTypeParameter) {
4545

4646
QualType ParamType =
4747
Node.getType().getNonPackExpansionType()->getPointeeType();
48-
const auto *TemplateType = ParamType->getAs<TemplateTypeParmType>();
48+
const auto *TemplateType = ParamType->getAsCanonical<TemplateTypeParmType>();
4949
if (!TemplateType)
5050
return false;
5151

clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ struct InitializerInsertion {
189189

190190
// Convenience utility to get a RecordDecl from a QualType.
191191
const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
192-
if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
192+
if (const auto *RT = Type->getAsCanonical<RecordType>())
193193
return RT->getOriginalDecl();
194194
return nullptr;
195195
}

clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
131131
return;
132132
}
133133
if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
134-
if (const auto *ET = ECD->getType()->getAs<EnumType>())
134+
if (const auto *ET = ECD->getType()->getAsCanonical<EnumType>())
135135
removeFromFoundDecls(ET->getOriginalDecl());
136136
}
137137
};

clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static bool isLockGuardDecl(const NamedDecl *Decl) {
2828
}
2929

3030
static bool isLockGuard(const QualType &Type) {
31-
if (const auto *Record = Type->getAs<RecordType>())
31+
if (const auto *Record = Type->getAsCanonical<RecordType>())
3232
if (const RecordDecl *Decl = Record->getOriginalDecl())
3333
return isLockGuardDecl(Decl);
3434

clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,11 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
413413

414414
// Arithmetic types are interconvertible, except scoped enums.
415415
if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) {
416-
if ((ParamType->isEnumeralType() &&
417-
ParamType->castAs<EnumType>()->getOriginalDecl()->isScoped()) ||
416+
if ((ParamType->isEnumeralType() && ParamType->castAsCanonical<EnumType>()
417+
->getOriginalDecl()
418+
->isScoped()) ||
418419
(ArgType->isEnumeralType() &&
419-
ArgType->castAs<EnumType>()->getOriginalDecl()->isScoped()))
420+
ArgType->castAsCanonical<EnumType>()->getOriginalDecl()->isScoped()))
420421
return false;
421422

422423
return true;

clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ bool PopulateSwitch::prepare(const Selection &Sel) {
113113
// Ignore implicit casts, since enums implicitly cast to integer types.
114114
Cond = Cond->IgnoreParenImpCasts();
115115
// Get the canonical type to handle typedefs.
116-
EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>();
116+
EnumT = Cond->getType()->getAsCanonical<EnumType>();
117117
if (!EnumT)
118118
return false;
119-
EnumD = EnumT->getOriginalDecl();
120-
if (!EnumD || EnumD->isDependentType())
119+
EnumD = EnumT->getOriginalDecl()->getDefinitionOrSelf();
120+
if (EnumD->isDependentType())
121121
return false;
122122

123123
// Finally, check which cases exist and which are covered.

clang/include/clang/AST/Type.h

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2929,8 +2929,31 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
29292929
///
29302930
/// There are some specializations of this member template listed
29312931
/// immediately following this class.
2932+
///
2933+
/// If you are interested only in the canonical properties of this type,
2934+
/// consider using getAsCanonical instead, as that is much faster.
29322935
template <typename T> const T *getAs() const;
29332936

2937+
/// If this type is canonically the specified type, return its canonical type
2938+
/// cast to that specified type, otherwise returns null.
2939+
template <typename T> const T *getAsCanonical() const {
2940+
return dyn_cast<T>(CanonicalType);
2941+
}
2942+
2943+
/// Return this type's canonical type cast to the specified type.
2944+
/// If the type is not canonically that specified type, the behaviour is
2945+
/// undefined.
2946+
template <typename T> const T *castAsCanonical() const {
2947+
return cast<T>(CanonicalType);
2948+
}
2949+
2950+
// It is not helpful to use these on types which are never canonical
2951+
#define TYPE(Class, Base)
2952+
#define NEVER_CANONICAL_TYPE(Class) \
2953+
template <> inline const Class##Type *Type::getAsCanonical() const = delete; \
2954+
template <> inline const Class##Type *Type::castAsCanonical() const = delete;
2955+
#include "clang/AST/TypeNodes.inc"
2956+
29342957
/// Look through sugar for an instance of TemplateSpecializationType which
29352958
/// is not a type alias, or null if there is no such type.
29362959
/// This is used when you want as-written template arguments or the template
@@ -3142,16 +3165,16 @@ template <> const BoundsAttributedType *Type::getAs() const;
31423165
/// sugar until it reaches an CountAttributedType or a non-sugared type.
31433166
template <> const CountAttributedType *Type::getAs() const;
31443167

3145-
// We can do canonical leaf types faster, because we don't have to
3146-
// worry about preserving child type decoration.
3168+
// We can do always canonical types faster, because we don't have to
3169+
// worry about preserving decoration.
31473170
#define TYPE(Class, Base)
3148-
#define LEAF_TYPE(Class) \
3149-
template <> inline const Class##Type *Type::getAs() const { \
3150-
return dyn_cast<Class##Type>(CanonicalType); \
3151-
} \
3152-
template <> inline const Class##Type *Type::castAs() const { \
3153-
return cast<Class##Type>(CanonicalType); \
3154-
}
3171+
#define ALWAYS_CANONICAL_TYPE(Class) \
3172+
template <> inline const Class##Type *Type::getAs() const { \
3173+
return dyn_cast<Class##Type>(CanonicalType); \
3174+
} \
3175+
template <> inline const Class##Type *Type::castAs() const { \
3176+
return cast<Class##Type>(CanonicalType); \
3177+
}
31553178
#include "clang/AST/TypeNodes.inc"
31563179

31573180
/// This class is used for builtin types like 'int'. Builtin

clang/include/clang/Basic/TypeNodes.td

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,12 @@ class NeverCanonical {}
3737
/// canonical types can ignore these nodes.
3838
class NeverCanonicalUnlessDependent {}
3939

40-
/// A type node which never has component type structure. Some code may be
41-
/// able to operate on leaf types faster than they can on non-leaf types.
42-
///
43-
/// For example, the function type `void (int)` is not a leaf type because it
44-
/// is structurally composed of component types (`void` and `int`).
45-
///
46-
/// A struct type is a leaf type because its field types are not part of its
47-
/// type-expression.
48-
///
49-
/// Nodes like `TypedefType` which are syntactically leaves but can desugar
50-
/// to types that may not be leaves should not declare this.
51-
class LeafType {}
40+
/// A type node which is always a canonical type, that is, types for which
41+
/// `T.getCanonicalType() == T` always holds.
42+
class AlwaysCanonical {}
5243

5344
def Type : TypeNode<?, 1>;
54-
def BuiltinType : TypeNode<Type>, LeafType;
45+
def BuiltinType : TypeNode<Type>, AlwaysCanonical;
5546
def ComplexType : TypeNode<Type>;
5647
def PointerType : TypeNode<Type>;
5748
def BlockPointerType : TypeNode<Type>;
@@ -88,14 +79,14 @@ def TypeOfType : TypeNode<Type>, NeverCanonicalUnlessDependent;
8879
def DecltypeType : TypeNode<Type>, NeverCanonicalUnlessDependent;
8980
def UnaryTransformType : TypeNode<Type>, NeverCanonicalUnlessDependent;
9081
def TagType : TypeNode<Type, 1>;
91-
def RecordType : TypeNode<TagType>, LeafType;
92-
def EnumType : TypeNode<TagType>, LeafType;
93-
def InjectedClassNameType : TypeNode<TagType>, AlwaysDependent, LeafType;
82+
def RecordType : TypeNode<TagType>;
83+
def EnumType : TypeNode<TagType>;
84+
def InjectedClassNameType : TypeNode<TagType>, AlwaysDependent;
9485
def AttributedType : TypeNode<Type>, NeverCanonical;
9586
def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
9687
def HLSLAttributedResourceType : TypeNode<Type>;
9788
def HLSLInlineSpirvType : TypeNode<Type>;
98-
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
89+
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent;
9990
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
10091
def SubstPackType : TypeNode<Type, 1>;
10192
def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
@@ -110,7 +101,7 @@ def PackExpansionType : TypeNode<Type>, AlwaysDependent;
110101
def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent;
111102
def ObjCTypeParamType : TypeNode<Type>, NeverCanonical;
112103
def ObjCObjectType : TypeNode<Type>;
113-
def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;
104+
def ObjCInterfaceType : TypeNode<ObjCObjectType>, AlwaysCanonical;
114105
def ObjCObjectPointerType : TypeNode<Type>;
115106
def BoundsAttributedType : TypeNode<Type, 1>;
116107
def CountAttributedType : TypeNode<BoundsAttributedType>, NeverCanonical;

clang/lib/AST/ASTContext.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2615,10 +2615,10 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const {
26152615
return I->second;
26162616

26172617
unsigned UnadjustedAlign;
2618-
if (const auto *RT = T->getAs<RecordType>()) {
2618+
if (const auto *RT = T->getAsCanonical<RecordType>()) {
26192619
const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl());
26202620
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
2621-
} else if (const auto *ObjCI = T->getAs<ObjCInterfaceType>()) {
2621+
} else if (const auto *ObjCI = T->getAsCanonical<ObjCInterfaceType>()) {
26222622
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
26232623
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
26242624
} else {
@@ -3553,8 +3553,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
35533553
llvm_unreachable("should never get here");
35543554
}
35553555
case Type::Record: {
3556-
const RecordDecl *RD =
3557-
T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
3556+
const RecordDecl *RD = T->castAsCanonical<RecordType>()->getOriginalDecl();
35583557
const IdentifierInfo *II = RD->getIdentifier();
35593558

35603559
// In C++, an immediate typedef of an anonymous struct or union
@@ -9278,8 +9277,8 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C,
92789277
llvm_unreachable("invalid BuiltinType::Kind value");
92799278
}
92809279

9281-
static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
9282-
EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf();
9280+
static char ObjCEncodingForEnumDecl(const ASTContext *C, const EnumDecl *ED) {
9281+
EnumDecl *Enum = ED->getDefinitionOrSelf();
92839282

92849283
// The encoding of an non-fixed enum type is always 'i', regardless of size.
92859284
if (!Enum->isFixed())
@@ -9322,8 +9321,8 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
93229321

93239322
S += llvm::utostr(Offset);
93249323

9325-
if (const auto *ET = T->getAs<EnumType>())
9326-
S += ObjCEncodingForEnumType(Ctx, ET);
9324+
if (const auto *ET = T->getAsCanonical<EnumType>())
9325+
S += ObjCEncodingForEnumDecl(Ctx, ET->getOriginalDecl());
93279326
else {
93289327
const auto *BT = T->castAs<BuiltinType>();
93299328
S += getObjCEncodingForPrimitiveType(Ctx, BT);
@@ -9380,7 +9379,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
93809379
if (const auto *BT = dyn_cast<BuiltinType>(CT))
93819380
S += getObjCEncodingForPrimitiveType(this, BT);
93829381
else
9383-
S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
9382+
S += ObjCEncodingForEnumDecl(this, cast<EnumType>(CT)->getOriginalDecl());
93849383
return;
93859384

93869385
case Type::Complex:
@@ -9447,7 +9446,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
94479446
S += '*';
94489447
return;
94499448
}
9450-
} else if (const auto *RTy = PointeeTy->getAs<RecordType>()) {
9449+
} else if (const auto *RTy = PointeeTy->getAsCanonical<RecordType>()) {
94519450
const IdentifierInfo *II = RTy->getOriginalDecl()->getIdentifier();
94529451
// GCC binary compat: Need to convert "struct objc_class *" to "#".
94539452
if (II == &Idents.get("objc_class")) {
@@ -11819,10 +11818,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1181911818
if (LHSClass != RHSClass) {
1182011819
// Note that we only have special rules for turning block enum
1182111820
// returns into block int returns, not vice-versa.
11822-
if (const auto *ETy = LHS->getAs<EnumType>()) {
11821+
if (const auto *ETy = LHS->getAsCanonical<EnumType>()) {
1182311822
return mergeEnumWithInteger(*this, ETy, RHS, false);
1182411823
}
11825-
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
11824+
if (const EnumType *ETy = RHS->getAsCanonical<EnumType>()) {
1182611825
return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
1182711826
}
1182811827
// allow block pointer type to match an 'id' type.

0 commit comments

Comments
 (0)