Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
WorkType = QualType{ToBuiltin, FastQualifiersToApply};
}

const auto *FromEnum = WorkType->getAs<EnumType>();
const auto *FromEnum = WorkType->getAsCanonical<EnumType>();
const auto *ToEnum = To->getAs<EnumType>();
if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
// Unscoped enumerations (or enumerations in C) convert to numerics.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ AST_MATCHER(ParmVarDecl, isTemplateTypeParameter) {

QualType ParamType =
Node.getType().getNonPackExpansionType()->getPointeeType();
const auto *TemplateType = ParamType->getAs<TemplateTypeParmType>();
const auto *TemplateType = ParamType->getAsCanonical<TemplateTypeParmType>();
if (!TemplateType)
return false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ struct InitializerInsertion {

// Convenience utility to get a RecordDecl from a QualType.
const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
if (const auto *RT = Type->getAsCanonical<RecordType>())
return RT->getOriginalDecl();
return nullptr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
return;
}
if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
if (const auto *ET = ECD->getType()->getAs<EnumType>())
if (const auto *ET = ECD->getType()->getAsCanonical<EnumType>())
removeFromFoundDecls(ET->getOriginalDecl());
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static bool isLockGuardDecl(const NamedDecl *Decl) {
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,11 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,

// Arithmetic types are interconvertible, except scoped enums.
if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) {
if ((ParamType->isEnumeralType() &&
ParamType->castAs<EnumType>()->getOriginalDecl()->isScoped()) ||
if ((ParamType->isEnumeralType() && ParamType->castAsCanonical<EnumType>()
->getOriginalDecl()
->isScoped()) ||
(ArgType->isEnumeralType() &&
ArgType->castAs<EnumType>()->getOriginalDecl()->isScoped()))
ArgType->castAsCanonical<EnumType>()->getOriginalDecl()->isScoped()))
return false;

return true;
Expand Down
6 changes: 3 additions & 3 deletions clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ bool PopulateSwitch::prepare(const Selection &Sel) {
// Ignore implicit casts, since enums implicitly cast to integer types.
Cond = Cond->IgnoreParenImpCasts();
// Get the canonical type to handle typedefs.
EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>();
EnumT = Cond->getType()->getAsCanonical<EnumType>();
if (!EnumT)
return false;
EnumD = EnumT->getOriginalDecl();
if (!EnumD || EnumD->isDependentType())
EnumD = EnumT->getOriginalDecl()->getDefinitionOrSelf();
if (EnumD->isDependentType())
return false;

// Finally, check which cases exist and which are covered.
Expand Down
41 changes: 32 additions & 9 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2929,8 +2929,31 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
///
/// There are some specializations of this member template listed
/// immediately following this class.
///
/// If you are interested only in the canonical properties of this type,
/// consider using getAsCanonical instead, as that is much faster.
Comment on lines +2932 to +2934
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we're replacing some uses with getAsXXXX, so maybe we want to update the comment to avoid confusing:

///  ... This scheme will eventually replace the specific getAsXXXX methods above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is talking specifically about the getAsFooType methods, which have direct equivalents with getAs<FooType>. I am not sure we have really any left, this comment can probably be removed.

template <typename T> const T *getAs() const;

/// If this type is canonically the specified type, return its canonical type
/// cast to that specified type, otherwise returns null.
template <typename T> const T *getAsCanonical() const {
return dyn_cast<T>(CanonicalType);
}

/// Return this type's canonical type cast to the specified type.
/// If the type is not canonically that specified type, the behaviour is
/// undefined.
template <typename T> const T *castAsCanonical() const {
return cast<T>(CanonicalType);
}

// It is not helpful to use these on types which are never canonical
#define TYPE(Class, Base)
#define NEVER_CANONICAL_TYPE(Class) \
template <> inline const Class##Type *Type::getAsCanonical() const = delete; \
template <> inline const Class##Type *Type::castAsCanonical() const = delete;
#include "clang/AST/TypeNodes.inc"

/// Look through sugar for an instance of TemplateSpecializationType which
/// is not a type alias, or null if there is no such type.
/// This is used when you want as-written template arguments or the template
Expand Down Expand Up @@ -3142,16 +3165,16 @@ template <> const BoundsAttributedType *Type::getAs() const;
/// sugar until it reaches an CountAttributedType or a non-sugared type.
template <> const CountAttributedType *Type::getAs() const;

// We can do canonical leaf types faster, because we don't have to
// worry about preserving child type decoration.
// We can do always canonical types faster, because we don't have to
// worry about preserving decoration.
#define TYPE(Class, Base)
#define LEAF_TYPE(Class) \
template <> inline const Class##Type *Type::getAs() const { \
return dyn_cast<Class##Type>(CanonicalType); \
} \
template <> inline const Class##Type *Type::castAs() const { \
return cast<Class##Type>(CanonicalType); \
}
#define ALWAYS_CANONICAL_TYPE(Class) \
template <> inline const Class##Type *Type::getAs() const { \
return dyn_cast<Class##Type>(CanonicalType); \
} \
template <> inline const Class##Type *Type::castAs() const { \
return cast<Class##Type>(CanonicalType); \
}
#include "clang/AST/TypeNodes.inc"

/// This class is used for builtin types like 'int'. Builtin
Expand Down
27 changes: 9 additions & 18 deletions clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,12 @@ class NeverCanonical {}
/// canonical types can ignore these nodes.
class NeverCanonicalUnlessDependent {}

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

def Type : TypeNode<?, 1>;
def BuiltinType : TypeNode<Type>, LeafType;
def BuiltinType : TypeNode<Type>, AlwaysCanonical;
def ComplexType : TypeNode<Type>;
def PointerType : TypeNode<Type>;
def BlockPointerType : TypeNode<Type>;
Expand Down Expand Up @@ -88,14 +79,14 @@ def TypeOfType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def DecltypeType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def UnaryTransformType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def TagType : TypeNode<Type, 1>;
def RecordType : TypeNode<TagType>, LeafType;
def EnumType : TypeNode<TagType>, LeafType;
def InjectedClassNameType : TypeNode<TagType>, AlwaysDependent, LeafType;
def RecordType : TypeNode<TagType>;
def EnumType : TypeNode<TagType>;
def InjectedClassNameType : TypeNode<TagType>, AlwaysDependent;
def AttributedType : TypeNode<Type>, NeverCanonical;
def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
def HLSLAttributedResourceType : TypeNode<Type>;
def HLSLInlineSpirvType : TypeNode<Type>;
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent;
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
def SubstPackType : TypeNode<Type, 1>;
def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
Expand All @@ -110,7 +101,7 @@ def PackExpansionType : TypeNode<Type>, AlwaysDependent;
def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def ObjCTypeParamType : TypeNode<Type>, NeverCanonical;
def ObjCObjectType : TypeNode<Type>;
def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;
def ObjCInterfaceType : TypeNode<ObjCObjectType>, AlwaysCanonical;
def ObjCObjectPointerType : TypeNode<Type>;
def BoundsAttributedType : TypeNode<Type, 1>;
def CountAttributedType : TypeNode<BoundsAttributedType>, NeverCanonical;
Expand Down
23 changes: 11 additions & 12 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2614,10 +2614,10 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const {
return I->second;

unsigned UnadjustedAlign;
if (const auto *RT = T->getAs<RecordType>()) {
if (const auto *RT = T->getAsCanonical<RecordType>()) {
const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl());
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
} else if (const auto *ObjCI = T->getAs<ObjCInterfaceType>()) {
} else if (const auto *ObjCI = T->getAsCanonical<ObjCInterfaceType>()) {
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
} else {
Expand Down Expand Up @@ -3552,8 +3552,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
llvm_unreachable("should never get here");
}
case Type::Record: {
const RecordDecl *RD =
T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
const RecordDecl *RD = T->castAsCanonical<RecordType>()->getOriginalDecl();
const IdentifierInfo *II = RD->getIdentifier();

// In C++, an immediate typedef of an anonymous struct or union
Expand Down Expand Up @@ -9277,8 +9276,8 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C,
llvm_unreachable("invalid BuiltinType::Kind value");
}

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

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

S += llvm::utostr(Offset);

if (const auto *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
if (const auto *ET = T->getAsCanonical<EnumType>())
S += ObjCEncodingForEnumDecl(Ctx, ET->getOriginalDecl());
else {
const auto *BT = T->castAs<BuiltinType>();
S += getObjCEncodingForPrimitiveType(Ctx, BT);
Expand Down Expand Up @@ -9379,7 +9378,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
if (const auto *BT = dyn_cast<BuiltinType>(CT))
S += getObjCEncodingForPrimitiveType(this, BT);
else
S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
S += ObjCEncodingForEnumDecl(this, cast<EnumType>(CT)->getOriginalDecl());
return;

case Type::Complex:
Expand Down Expand Up @@ -9446,7 +9445,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
S += '*';
return;
}
} else if (const auto *RTy = PointeeTy->getAs<RecordType>()) {
} else if (const auto *RTy = PointeeTy->getAsCanonical<RecordType>()) {
const IdentifierInfo *II = RTy->getOriginalDecl()->getIdentifier();
// GCC binary compat: Need to convert "struct objc_class *" to "#".
if (II == &Idents.get("objc_class")) {
Expand Down Expand Up @@ -11818,10 +11817,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
if (LHSClass != RHSClass) {
// Note that we only have special rules for turning block enum
// returns into block int returns, not vice-versa.
if (const auto *ETy = LHS->getAs<EnumType>()) {
if (const auto *ETy = LHS->getAsCanonical<EnumType>()) {
return mergeEnumWithInteger(*this, ETy, RHS, false);
}
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
if (const EnumType *ETy = RHS->getAsCanonical<EnumType>()) {
return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
}
// allow block pointer type to match an 'id' type.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4609,8 +4609,8 @@ UnsignedOrNone Compiler<Emitter>::allocateTemporary(const Expr *E) {
template <class Emitter>
const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) {
if (const PointerType *PT = dyn_cast<PointerType>(Ty))
return PT->getPointeeType()->getAs<RecordType>();
return Ty->getAs<RecordType>();
return PT->getPointeeType()->getAsCanonical<RecordType>();
return Ty->getAsCanonical<RecordType>();
}

template <class Emitter> Record *Compiler<Emitter>::getRecord(QualType Ty) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
return true;
}

if (const auto *RT = Ty->getAs<RecordType>()) {
if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
const auto *Record = Ptr.getRecord();
assert(Record && "Missing record descriptor");

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/CXXInheritance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
if (isDetectingVirtual() && DetectedVirtual == nullptr) {
// If this is the first virtual we find, remember it. If it turns out
// there is no base path here, we'll reset it later.
DetectedVirtual = BaseType->getAs<RecordType>();
DetectedVirtual = BaseType->getAsCanonical<RecordType>();
SetVirtual = true;
}
} else {
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2988,7 +2988,7 @@ bool ParmVarDecl::isDestroyedInCallee() const {

// FIXME: isParamDestroyedInCallee() should probably imply
// isDestructedType()
const auto *RT = getType()->getAs<RecordType>();
const auto *RT = getType()->getAsCanonical<RecordType>();
if (RT &&
RT->getOriginalDecl()
->getDefinitionOrSelf()
Expand Down Expand Up @@ -3503,7 +3503,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation(
while (const auto *TD = T->getAs<TypedefType>())
T = TD->getDecl()->getUnderlyingType();
const IdentifierInfo *II =
T->castAs<EnumType>()->getOriginalDecl()->getIdentifier();
T->castAsCanonical<EnumType>()->getOriginalDecl()->getIdentifier();
if (II && II->isStr("__hot_cold_t"))
Consume();
}
Expand Down Expand Up @@ -4653,7 +4653,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
if (!isImplicit() || getDeclName())
return false;

if (const auto *Record = getType()->getAs<RecordType>())
if (const auto *Record = getType()->getAsCanonical<RecordType>())
return Record->getOriginalDecl()->isAnonymousStructOrUnion();

return false;
Expand Down Expand Up @@ -4711,7 +4711,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const {
return false;

// -- is not of class type, or
const auto *RT = getType()->getAs<RecordType>();
const auto *RT = getType()->getAsCanonical<RecordType>();
if (!RT)
return false;
const RecordDecl *RD = RT->getOriginalDecl()->getDefinition();
Expand Down Expand Up @@ -5138,7 +5138,7 @@ bool RecordDecl::isOrContainsUnion() const {

if (const RecordDecl *Def = getDefinition()) {
for (const FieldDecl *FD : Def->fields()) {
const RecordType *RT = FD->getType()->getAs<RecordType>();
const RecordType *RT = FD->getType()->getAsCanonical<RecordType>();
if (RT && RT->getOriginalDecl()->isOrContainsUnion())
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2307,7 +2307,7 @@ bool CXXRecordDecl::mayBeAbstract() const {

for (const auto &B : bases()) {
const auto *BaseDecl = cast<CXXRecordDecl>(
B.getType()->castAs<RecordType>()->getOriginalDecl());
B.getType()->castAsCanonical<RecordType>()->getOriginalDecl());
if (BaseDecl->isAbstract())
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/DeclarationName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ static void printCXXConstructorDestructorName(QualType ClassType,
// We know we're printing C++ here. Ensure we print types properly.
Policy.adjustForCPlusPlus();

if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) {
if (const RecordType *ClassRec = ClassType->getAsCanonical<RecordType>()) {
ClassRec->getOriginalDecl()->printName(OS, Policy);
return;
}
if (Policy.SuppressTemplateArgsInCXXConstructors) {
if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) {
if (auto *InjTy = ClassType->getAsCanonical<InjectedClassNameType>()) {
InjTy->getOriginalDecl()->printName(OS, Policy);
return;
}
Expand Down
17 changes: 8 additions & 9 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4100,7 +4100,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}

// Next subobject is a class, struct or union field.
RecordDecl *RD = ObjType->castAs<RecordType>()->getOriginalDecl();
RecordDecl *RD =
ObjType->castAsCanonical<RecordType>()->getOriginalDecl();
if (RD->isUnion()) {
const FieldDecl *UnionField = O->getUnionField();
if (!UnionField ||
Expand Down Expand Up @@ -8581,10 +8582,9 @@ class ExprEvaluatorBase
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
assert(
BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() &&
"record / field mismatch");
assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() ==
FD->getParent()->getCanonicalDecl() &&
"record / field mismatch");

// Note: there is no lvalue base here. But this case should only ever
// happen in C or in C++98, where we cannot be evaluating a constexpr
Expand Down Expand Up @@ -8811,10 +8811,9 @@ class LValueExprEvaluatorBase

const ValueDecl *MD = E->getMemberDecl();
if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
assert(
BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() &&
"record / field mismatch");
assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() ==
FD->getParent()->getCanonicalDecl() &&
"record / field mismatch");
(void)BaseTy;
if (!HandleLValueMember(this->Info, E, Result, FD))
return false;
Expand Down
Loading
Loading