[clang-tools-extra] 88438ba - [clang] AST: fix getAs canonicalization of leaf types (#155028)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 27 02:20:18 PDT 2025
Author: Matheus Izvekov
Date: 2025-08-27T06:20:14-03:00
New Revision: 88438ba1f37fa4e0c2db203cd5556e52c9c34c08
URL: https://github.com/llvm/llvm-project/commit/88438ba1f37fa4e0c2db203cd5556e52c9c34c08
DIFF: https://github.com/llvm/llvm-project/commit/88438ba1f37fa4e0c2db203cd5556e52c9c34c08.diff
LOG: [clang] AST: fix getAs canonicalization of leaf types (#155028)
Added:
Modified:
clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
clang/include/clang/AST/Type.h
clang/include/clang/Basic/TypeNodes.td
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Pointer.cpp
clang/lib/AST/CXXInheritance.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclCXX.cpp
clang/lib/AST/DeclarationName.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/AST/InheritViz.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/RecordLayoutBuilder.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/AST/Type.cpp
clang/lib/AST/TypePrinter.cpp
clang/lib/CodeGen/ABIInfoImpl.cpp
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGExprAgg.cpp
clang/lib/CodeGen/CGExprCXX.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/CodeGen/CGNonTrivialStruct.cpp
clang/lib/CodeGen/CGObjCMac.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenTBAA.cpp
clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
clang/lib/CodeGen/SwiftCallingConv.cpp
clang/lib/CodeGen/Targets/AArch64.cpp
clang/lib/CodeGen/Targets/ARC.cpp
clang/lib/CodeGen/Targets/ARM.cpp
clang/lib/CodeGen/Targets/DirectX.cpp
clang/lib/CodeGen/Targets/Lanai.cpp
clang/lib/CodeGen/Targets/LoongArch.cpp
clang/lib/CodeGen/Targets/Mips.cpp
clang/lib/CodeGen/Targets/RISCV.cpp
clang/lib/CodeGen/Targets/SPIR.cpp
clang/lib/CodeGen/Targets/X86.cpp
clang/lib/CodeGen/Targets/XCore.cpp
clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
clang/lib/Index/USRGeneration.cpp
clang/lib/Sema/SemaBPF.cpp
clang/lib/Sema/SemaCast.cpp
clang/lib/Sema/SemaChecking.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaExprObjC.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaObjC.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaStmt.cpp
clang/lib/Sema/SemaStmtAsm.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateDeductionGuide.cpp
clang/lib/Sema/SemaTypeTraits.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/CXX/drs/cwg0xx.cpp
clang/test/CXX/drs/cwg3xx.cpp
clang/test/ExtractAPI/class_template_param_inheritance.cpp
clang/utils/TableGen/ASTTableGen.h
clang/utils/TableGen/ClangTypeNodesEmitter.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
index 7f1eeef8ea0fd..3c718f1ddbe95 100644
--- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp
@@ -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.
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
index 82d1cf13440bc..75da6de9b5f13 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
index 40607597297b5..e6e79f0f0342a 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -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;
}
diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
index 8211a0ec6a5e1..49432073ce1d7 100644
--- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
@@ -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());
}
};
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index 5310f2fd25381..c74db0ed861b4 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -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);
diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
index 447c2437666cf..a80637dee18f4 100644
--- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
index 7e616968c6046..2c9841762b869 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
@@ -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.
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 187e54f5cb54b..8236a14a2daef 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -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.
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
@@ -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
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index c8d45dec78816..fb6862b90987f 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -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>;
@@ -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;
@@ -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;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 3d652bcc874f2..dca05b41aee77 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2615,10 +2615,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 {
@@ -3553,8 +3553,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
@@ -9278,8 +9277,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())
@@ -9322,8 +9321,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);
@@ -9380,7 +9379,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:
@@ -9447,7 +9446,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")) {
@@ -11819,10 +11818,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.
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 0079d937e885b..6e64fc0a2a7ad 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -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) {
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index c3c67227d0236..9fc5b5183f5f6 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -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");
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index 94f01c86a16ca..7a3e7ea4e5b8f 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -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 {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index c44bf739dca2d..343673069e15e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -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()
@@ -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();
}
@@ -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;
@@ -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();
@@ -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;
}
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 51d2fd21f0ba5..aa1f5a1146599 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2314,7 +2314,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;
}
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp
index 6c7b995d57567..74f2eec69461a 100644
--- a/clang/lib/AST/DeclarationName.cpp
+++ b/clang/lib/AST/DeclarationName.cpp
@@ -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;
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index c93a2186a93e1..0b1637af240cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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 ||
@@ -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
@@ -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;
diff --git a/clang/lib/AST/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp
index c03492c64b161..3c4a5a8e2c4a6 100644
--- a/clang/lib/AST/InheritViz.cpp
+++ b/clang/lib/AST/InheritViz.cpp
@@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
Out << " \"];\n";
// Display the base classes.
- const auto *Decl = static_cast<const CXXRecordDecl *>(
- Type->castAs<RecordType>()->getOriginalDecl());
+ const auto *Decl = cast<CXXRecordDecl>(
+ Type->castAsCanonical<RecordType>()->getOriginalDecl());
for (const auto &Base : Decl->bases()) {
QualType CanonBaseType = Context.getCanonicalType(Base.getType());
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 1ba224b74a606..ffadfce67d631 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4726,7 +4726,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
// Ignore member expressions involving anonymous unions.
- while (const auto *RT = Base->getType()->getAs<RecordType>()) {
+ while (const auto *RT = Base->getType()->getAsCanonical<RecordType>()) {
if (!RT->getOriginalDecl()->isAnonymousStructOrUnion())
break;
const auto *ME = dyn_cast<MemberExpr>(Base);
@@ -7031,7 +7031,7 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name,
if (S.isNull())
return false;
- const RecordType *RT = S->getAs<RecordType>();
+ const RecordType *RT = S->getAsCanonical<RecordType>();
if (!RT)
return false;
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index b3f12a1cce2ec..ca8e2af284c2b 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -396,7 +396,7 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) {
const CXXBaseSpecifier *Base = *I;
const auto *RD = cast<CXXRecordDecl>(
- Base->getType()->castAs<RecordType>()->getOriginalDecl());
+ Base->getType()->castAsCanonical<RecordType>()->getOriginalDecl());
llvm::json::Object Val{{"name", RD->getName()}};
if (Base->isVirtual())
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index e6729f8fbba70..4b312c559bf2a 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2007,7 +2007,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
CTy->getElementType()->castAs<BuiltinType>());
} else if (const BuiltinType *BTy = BaseTy->getAs<BuiltinType>()) {
performBuiltinTypeAlignmentUpgrade(BTy);
- } else if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ } else if (const RecordType *RT = BaseTy->getAsCanonical<RecordType>()) {
const RecordDecl *RD = RT->getOriginalDecl();
const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
PreferredAlign = FieldRecord.getPreferredAlignment();
@@ -2707,8 +2707,9 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
// alignment when it is applied to bitfields.
Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
else {
- if (auto RT =
- FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
+ if (const auto *RT = FD->getType()
+ ->getBaseElementTypeUnsafe()
+ ->getAsCanonical<RecordType>()) {
auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl());
EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject();
FieldRequiredAlignment = std::max(FieldRequiredAlignment,
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 085616049373e..9dca5cf088a85 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1401,7 +1401,7 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
OS << " -> ";
const auto *RD = cast<CXXRecordDecl>(
- Base->getType()->castAs<RecordType>()->getOriginalDecl());
+ Base->getType()->castAsCanonical<RecordType>()->getOriginalDecl());
if (Base->isVirtual())
OS << "virtual ";
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c6896fc70a169..e6113128a3e04 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -670,19 +670,19 @@ const Type *Type::getUnqualifiedDesugaredType() const {
}
bool Type::isClassType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isClass();
return false;
}
bool Type::isStructureType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isStruct();
return false;
}
bool Type::isStructureTypeWithFlexibleArrayMember() const {
- const auto *RT = getAs<RecordType>();
+ const auto *RT = getAsCanonical<RecordType>();
if (!RT)
return false;
const auto *Decl = RT->getOriginalDecl();
@@ -698,33 +698,31 @@ bool Type::isObjCBoxableRecordType() const {
}
bool Type::isInterfaceType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isInterface();
return false;
}
bool Type::isStructureOrClassType() const {
- if (const auto *RT = getAs<RecordType>()) {
- RecordDecl *RD = RT->getOriginalDecl();
- return RD->isStruct() || RD->isClass() || RD->isInterface();
- }
+ if (const auto *RT = getAsCanonical<RecordType>())
+ return RT->getOriginalDecl()->isStructureOrClass();
return false;
}
bool Type::isVoidPointerType() const {
- if (const auto *PT = getAs<PointerType>())
+ if (const auto *PT = getAsCanonical<PointerType>())
return PT->getPointeeType()->isVoidType();
return false;
}
bool Type::isUnionType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isUnion();
return false;
}
bool Type::isComplexType() const {
- if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
+ if (const auto *CT = getAsCanonical<ComplexType>())
return CT->getElementType()->isFloatingType();
return false;
}
@@ -735,7 +733,7 @@ bool Type::isComplexIntegerType() const {
}
bool Type::isScopedEnumeralType() const {
- if (const auto *ET = getAs<EnumType>())
+ if (const auto *ET = getAsCanonical<EnumType>())
return ET->getOriginalDecl()->isScoped();
return false;
}
@@ -1910,9 +1908,9 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
QualType PointeeType;
- if (const auto *PT = getAs<PointerType>())
+ if (const auto *PT = getAsCanonical<PointerType>())
PointeeType = PT->getPointeeType();
- else if (const auto *RT = getAs<ReferenceType>())
+ else if (const auto *RT = getAsCanonical<ReferenceType>())
PointeeType = RT->getPointeeType();
else
return nullptr;
@@ -3233,7 +3231,7 @@ bool Type::isNothrowT() const {
}
bool Type::isAlignValT() const {
- if (const auto *ET = getAs<EnumType>()) {
+ if (const auto *ET = getAsCanonical<EnumType>()) {
const auto *ED = ET->getOriginalDecl();
IdentifierInfo *II = ED->getIdentifier();
if (II && II->isStr("align_val_t") && ED->isInStdNamespace())
@@ -3243,7 +3241,7 @@ bool Type::isAlignValT() const {
}
bool Type::isStdByteType() const {
- if (const auto *ET = getAs<EnumType>()) {
+ if (const auto *ET = getAsCanonical<EnumType>()) {
const auto *ED = ET->getOriginalDecl();
IdentifierInfo *II = ED->getIdentifier();
if (II && II->isStr("byte") && ED->isInStdNamespace())
@@ -4414,7 +4412,7 @@ bool RecordType::hasConstFields() const {
if (FieldTy.isConstQualified())
return true;
FieldTy = FieldTy.getCanonicalType();
- if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) {
+ if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) {
if (!llvm::is_contained(RecordTypeList, FieldRecTy))
RecordTypeList.push_back(FieldRecTy);
}
@@ -5418,7 +5416,7 @@ bool Type::isObjCARCBridgableType() const {
/// Determine whether the given type T is a "bridgeable" C type.
bool Type::isCARCBridgableType() const {
- const auto *Pointer = getAs<PointerType>();
+ const auto *Pointer = getAsCanonical<PointerType>();
if (!Pointer)
return false;
@@ -5428,7 +5426,7 @@ bool Type::isCARCBridgableType() const {
/// Check if the specified type is the CUDA device builtin surface type.
bool Type::isCUDADeviceBuiltinSurfaceType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()
->getMostRecentDecl()
->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>();
@@ -5437,7 +5435,7 @@ bool Type::isCUDADeviceBuiltinSurfaceType() const {
/// Check if the specified type is the CUDA device builtin texture type.
bool Type::isCUDADeviceBuiltinTextureType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()
->getMostRecentDecl()
->hasAttr<CUDADeviceBuiltinTextureTypeAttr>();
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 52ff0d5b5771b..54ca42d2035ad 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2382,7 +2382,7 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
return true;
// A type parameter matches its argument.
- if (auto *TTPT = Pattern->getAs<TemplateTypeParmType>()) {
+ if (auto *TTPT = Pattern->getAsCanonical<TemplateTypeParmType>()) {
if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() &&
Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) {
QualType SubstArg = Ctx.getQualifiedType(
diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp
index 72d359e4862b9..13c837a0fb680 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.cpp
+++ b/clang/lib/CodeGen/ABIInfoImpl.cpp
@@ -114,7 +114,7 @@ CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT,
}
CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) {
- const RecordType *RT = T->getAs<RecordType>();
+ const RecordType *RT = T->getAsCanonical<RecordType>();
if (!RT)
return CGCXXABI::RAA_Default;
return getRecordArgABI(RT, CXXABI);
@@ -260,7 +260,7 @@ bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,
WasArray = true;
}
- const RecordType *RT = FT->getAs<RecordType>();
+ const RecordType *RT = FT->getAsCanonical<RecordType>();
if (!RT)
return false;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index f61d3d987b3c9..5b0dd235b58da 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1896,7 +1896,7 @@ bool CodeGenModule::MayDropFunctionReturn(const ASTContext &Context,
// We can't just discard the return value for a record type with a
// complex destructor or a non-trivially copyable type.
if (const RecordType *RT =
- ReturnType.getCanonicalType()->getAs<RecordType>()) {
+ ReturnType.getCanonicalType()->getAsCanonical<RecordType>()) {
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()))
return ClassDecl->hasTrivialDestructor();
}
@@ -3886,7 +3886,7 @@ static void setUsedBits(CodeGenModule &CGM, const ConstantArrayType *ATy,
// the type `QTy`.
static void setUsedBits(CodeGenModule &CGM, QualType QTy, int Offset,
SmallVectorImpl<uint64_t> &Bits) {
- if (const auto *RTy = QTy->getAs<RecordType>())
+ if (const auto *RTy = QTy->getAsCanonical<RecordType>())
return setUsedBits(CGM, RTy, Offset, Bits);
ASTContext &Context = CGM.getContext();
@@ -3930,7 +3930,7 @@ llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src,
const llvm::DataLayout &DataLayout = CGM.getDataLayout();
int Size = DataLayout.getTypeStoreSize(ITy);
SmallVector<uint64_t, 4> Bits(Size);
- setUsedBits(CGM, QTy->castAs<RecordType>(), 0, Bits);
+ setUsedBits(CGM, QTy->castAsCanonical<RecordType>(), 0, Bits);
int CharWidth = CGM.getContext().getCharWidth();
uint64_t Mask =
@@ -3947,7 +3947,7 @@ llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src,
const llvm::DataLayout &DataLayout = CGM.getDataLayout();
int Size = DataLayout.getTypeStoreSize(ATy);
SmallVector<uint64_t, 16> Bits(Size);
- setUsedBits(CGM, QTy->castAs<RecordType>(), 0, Bits);
+ setUsedBits(CGM, QTy->castAsCanonical<RecordType>(), 0, Bits);
// Clear each element of the LLVM array.
int CharWidth = CGM.getContext().getCharWidth();
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 560749f8ab308..0385dbdac869b 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2359,7 +2359,7 @@ void CGDebugInfo::CollectCXXBasesAux(
for (const auto &BI : Bases) {
const auto *Base =
cast<CXXRecordDecl>(
- BI.getType()->castAs<RecordType>()->getOriginalDecl())
+ BI.getType()->castAsCanonical<RecordType>()->getOriginalDecl())
->getDefinition();
if (!SeenTypes.insert(Base).second)
continue;
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 50575362d304b..b8150a24d45fc 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -2114,7 +2114,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// InitListExprs for structs have to be handled carefully. If there are
// reference members, we need to consider the size of the reference, not the
// referencee. InitListExprs for unions and arrays can't have references.
- if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
+ if (const RecordType *RT = E->getType()->getAsCanonical<RecordType>()) {
if (!RT->isUnionType()) {
RecordDecl *SD = RT->getOriginalDecl()->getDefinitionOrSelf();
CharUnits NumNonZeroBytes = CharUnits::Zero();
@@ -2167,7 +2167,8 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
// C++ objects with a user-declared constructor don't need zero'ing.
if (CGF.getLangOpts().CPlusPlus)
if (const RecordType *RT = CGF.getContext()
- .getBaseElementType(E->getType())->getAs<RecordType>()) {
+ .getBaseElementType(E->getType())
+ ->getAsCanonical<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getOriginalDecl());
if (RD->hasUserDeclaredConstructor())
return;
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 810a2ab8c1fcd..1e4c72a210f9a 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1234,9 +1234,10 @@ void CodeGenFunction::EmitNewArrayInitializer(
// If we have a struct whose every field is value-initialized, we can
// usually use memset.
if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
- const RecordDecl *RD = RType->getOriginalDecl()->getDefinitionOrSelf();
- if (RD->isStruct()) {
+ if (const RecordType *RType =
+ ILE->getType()->getAsCanonical<RecordType>()) {
+ if (RType->getOriginalDecl()->isStruct()) {
+ const RecordDecl *RD = RType->getOriginalDecl()->getDefinitionOrSelf();
unsigned NumElements = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
NumElements = CXXRD->getNumBases();
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 43d295599c4c8..2338cbd74f002 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3549,7 +3549,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
}
const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(
- CurrentType->castAs<RecordType>()->getOriginalDecl());
+ CurrentType->castAsCanonical<RecordType>()->getOriginalDecl());
// Save the element type.
CurrentType = ON.getBase()->getType();
diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp
index b78d89fd1e348..2d70e4c2e0394 100644
--- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp
+++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp
@@ -673,7 +673,8 @@ struct GenDefaultInitialize
CharUnits Size = Ctx.getTypeSizeInChars(QualType(AT, 0));
QualType EltTy = Ctx.getBaseElementType(QualType(AT, 0));
- if (Size < CharUnits::fromQuantity(16) || EltTy->getAs<RecordType>()) {
+ if (Size < CharUnits::fromQuantity(16) ||
+ EltTy->getAsCanonical<RecordType>()) {
GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStructOffset, Addrs);
return;
}
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index d1fb05d594058..60f30a1334d6d 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -2315,7 +2315,7 @@ void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) {
}
assert(!type->isArrayType() && "array variable should not be caught");
- if (const RecordType *record = type->getAs<RecordType>()) {
+ if (const RecordType *record = type->getAsCanonical<RecordType>()) {
visitRecord(record, fieldOffset);
continue;
}
@@ -2409,7 +2409,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
if (FQT->isUnionType())
HasUnion = true;
- BuildRCBlockVarRecordLayout(FQT->castAs<RecordType>(),
+ BuildRCBlockVarRecordLayout(FQT->castAsCanonical<RecordType>(),
BytePos + FieldOffset, HasUnion);
continue;
}
@@ -2426,7 +2426,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
}
if (FQT->isRecordType() && ElCount) {
int OldIndex = RunSkipBlockVars.size() - 1;
- auto *RT = FQT->castAs<RecordType>();
+ auto *RT = FQT->castAsCanonical<RecordType>();
BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset, HasUnion);
// Replicate layout information for each array element. Note that
@@ -2831,7 +2831,7 @@ void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM,
assert(!type->isArrayType() && "array variable should not be caught");
if (!CI.isByRef())
- if (const RecordType *record = type->getAs<RecordType>()) {
+ if (const auto *record = type->getAsCanonical<RecordType>()) {
BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
continue;
}
@@ -2865,7 +2865,7 @@ llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
CharUnits fieldOffset;
RunSkipBlockVars.clear();
bool hasUnion = false;
- if (const RecordType *record = T->getAs<RecordType>()) {
+ if (const auto *record = T->getAsCanonical<RecordType>()) {
BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion,
true /*ByrefLayout */);
llvm::Constant *Result = getBitmapBlockLayout(true);
@@ -5246,7 +5246,7 @@ void IvarLayoutBuilder::visitField(const FieldDecl *field,
return;
// Recurse if the base element type is a record type.
- if (auto recType = fieldType->getAs<RecordType>()) {
+ if (const auto *recType = fieldType->getAsCanonical<RecordType>()) {
size_t oldEnd = IvarsInfo.size();
visitRecord(recType, fieldOffset);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 7064421fe0613..323823c964a79 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4195,7 +4195,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// Check if T is a class type with a destructor that's not dllimport.
static bool HasNonDllImportDtor(QualType T) {
- if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
+ if (const auto *RT =
+ T->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>())
if (auto *RD = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) {
RD = RD->getDefinitionOrSelf();
if (RD->getDestructor() && !RD->getDestructor()->hasAttr<DLLImportAttr>())
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index 8cb8024960176..f8c7d64cc1aa2 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -295,7 +295,7 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
// Be conservative if the type isn't a RecordType. We are specifically
// required to do this for member pointers until we implement the
// similar-types rule.
- const auto *RT = Ty->getAs<RecordType>();
+ const auto *RT = Ty->getAsCanonical<RecordType>();
if (!RT)
return getAnyPtr(PtrDepth);
@@ -424,7 +424,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
bool MayAlias) {
/* Things not handled yet include: C++ base classes, bitfields, */
- if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ if (const auto *TTy = QTy->getAsCanonical<RecordType>()) {
if (TTy->isUnionType()) {
uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity();
llvm::MDNode *TBAAType = getChar();
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
index 4e25e887c4133..a21feaa1120c6 100644
--- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
@@ -201,8 +201,8 @@ bool HLSLBufferLayoutBuilder::layoutField(const FieldDecl *FD,
// For array of structures, create a new array with a layout type
// instead of the structure type.
if (Ty->isStructureOrClassType()) {
- llvm::Type *NewTy =
- cast<llvm::TargetExtType>(createLayoutType(Ty->getAs<RecordType>()));
+ llvm::Type *NewTy = cast<llvm::TargetExtType>(
+ createLayoutType(Ty->getAsCanonical<RecordType>()));
if (!NewTy)
return false;
assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
@@ -220,8 +220,8 @@ bool HLSLBufferLayoutBuilder::layoutField(const FieldDecl *FD,
} else if (FieldTy->isStructureOrClassType()) {
// Create a layout type for the structure
- ElemLayoutTy =
- createLayoutType(cast<RecordType>(FieldTy->getAs<RecordType>()));
+ ElemLayoutTy = createLayoutType(
+ cast<RecordType>(FieldTy->getAsCanonical<RecordType>()));
if (!ElemLayoutTy)
return false;
assert(isa<llvm::TargetExtType>(ElemLayoutTy) && "expected target type");
diff --git a/clang/lib/CodeGen/SwiftCallingConv.cpp b/clang/lib/CodeGen/SwiftCallingConv.cpp
index de58e0d95a866..4d894fd99db05 100644
--- a/clang/lib/CodeGen/SwiftCallingConv.cpp
+++ b/clang/lib/CodeGen/SwiftCallingConv.cpp
@@ -65,7 +65,7 @@ void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) {
// Deal with various aggregate types as special cases:
// Record types.
- if (auto recType = type->getAs<RecordType>()) {
+ if (auto recType = type->getAsCanonical<RecordType>()) {
addTypedData(recType->getOriginalDecl(), begin);
// Array types.
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 6bdfdbcf0e89a..d7deece232a9f 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -736,7 +736,7 @@ bool AArch64ABIInfo::passAsPureScalableType(
return true;
}
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (const RecordType *RT = Ty->getAsCanonical<RecordType>()) {
// If the record cannot be passed in registers, then it's not a PST.
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
RAA != CGCXXABI::RAA_Default)
diff --git a/clang/lib/CodeGen/Targets/ARC.cpp b/clang/lib/CodeGen/Targets/ARC.cpp
index 56bbae0eace94..67275877cbd9e 100644
--- a/clang/lib/CodeGen/Targets/ARC.cpp
+++ b/clang/lib/CodeGen/Targets/ARC.cpp
@@ -94,7 +94,7 @@ RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty,
uint8_t FreeRegs) const {
// Handle the generic C++ ABI.
- const RecordType *RT = Ty->getAs<RecordType>();
+ const RecordType *RT = Ty->getAsCanonical<RecordType>();
if (RT) {
CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
if (RAA == CGCXXABI::RAA_Indirect)
diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp
index d5c86e19fd358..c84c9f2f643ee 100644
--- a/clang/lib/CodeGen/Targets/ARM.cpp
+++ b/clang/lib/CodeGen/Targets/ARM.cpp
@@ -512,7 +512,7 @@ static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
// above, but they are not.
// Otherwise, it must be a record type.
- const RecordType *RT = Ty->getAs<RecordType>();
+ const RecordType *RT = Ty->getAsCanonical<RecordType>();
if (!RT) return false;
// Ignore records with flexible arrays.
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 96a1284661394..b4cebb9a32aca 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -77,7 +77,8 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
llvm::Type *BufferLayoutTy =
HLSLBufferLayoutBuilder(CGM, "dx.Layout")
- .createLayoutType(ContainedTy->getAsStructureType(), Packoffsets);
+ .createLayoutType(ContainedTy->castAsCanonical<RecordType>(),
+ Packoffsets);
if (!BufferLayoutTy)
return nullptr;
diff --git a/clang/lib/CodeGen/Targets/Lanai.cpp b/clang/lib/CodeGen/Targets/Lanai.cpp
index 675009f0e5748..e76431a484e70 100644
--- a/clang/lib/CodeGen/Targets/Lanai.cpp
+++ b/clang/lib/CodeGen/Targets/Lanai.cpp
@@ -88,7 +88,7 @@ ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal,
ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty,
CCState &State) const {
// Check with the C++ ABI first.
- const RecordType *RT = Ty->getAs<RecordType>();
+ const RecordType *RT = Ty->getAsCanonical<RecordType>();
if (RT) {
CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
if (RAA == CGCXXABI::RAA_Indirect) {
diff --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp
index 0ea08ff533916..1f344d6582510 100644
--- a/clang/lib/CodeGen/Targets/LoongArch.cpp
+++ b/clang/lib/CodeGen/Targets/LoongArch.cpp
@@ -149,7 +149,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
QualType EltTy = ATy->getElementType();
// Non-zero-length arrays of empty records make the struct ineligible to be
// passed via FARs in C++.
- if (const auto *RTy = EltTy->getAs<RecordType>()) {
+ if (const auto *RTy = EltTy->getAsCanonical<RecordType>()) {
if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getOriginalDecl()) &&
isEmptyRecord(getContext(), EltTy, true, true))
return false;
@@ -164,7 +164,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
return true;
}
- if (const auto *RTy = Ty->getAs<RecordType>()) {
+ if (const auto *RTy = Ty->getAsCanonical<RecordType>()) {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are not eligible for the FP calling convention.
if (getRecordArgABI(Ty, CGT.getCXXABI()))
diff --git a/clang/lib/CodeGen/Targets/Mips.cpp b/clang/lib/CodeGen/Targets/Mips.cpp
index 9c3016fa1f5a5..f26ab974d699e 100644
--- a/clang/lib/CodeGen/Targets/Mips.cpp
+++ b/clang/lib/CodeGen/Targets/Mips.cpp
@@ -153,7 +153,7 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
if (Ty->isComplexType())
return CGT.ConvertType(Ty);
- const RecordType *RT = Ty->getAs<RecordType>();
+ const RecordType *RT = Ty->getAsCanonical<RecordType>();
// Unions/vectors are passed in integer registers.
if (!RT || !RT->isStructureOrClassType()) {
@@ -261,7 +261,7 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
llvm::Type*
MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const {
- const RecordType *RT = RetTy->getAs<RecordType>();
+ const RecordType *RT = RetTy->getAsCanonical<RecordType>();
SmallVector<llvm::Type*, 8> RTList;
if (RT && RT->isStructureOrClassType()) {
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index 049f61bb86b1e..0ef39b68eb6e3 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -233,7 +233,7 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
QualType EltTy = ATy->getElementType();
// Non-zero-length arrays of empty records make the struct ineligible for
// the FP calling convention in C++.
- if (const auto *RTy = EltTy->getAs<RecordType>()) {
+ if (const auto *RTy = EltTy->getAsCanonical<RecordType>()) {
if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getOriginalDecl()) &&
isEmptyRecord(getContext(), EltTy, true, true))
return false;
@@ -249,7 +249,7 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
return true;
}
- if (const auto *RTy = Ty->getAs<RecordType>()) {
+ if (const auto *RTy = Ty->getAsCanonical<RecordType>()) {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are not eligible for the FP calling convention.
if (getRecordArgABI(Ty, CGT.getCXXABI()))
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index ababb25736203..4f0c4d0d906b1 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -500,7 +500,8 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
llvm::Type *BufferLayoutTy =
HLSLBufferLayoutBuilder(CGM, "spirv.Layout")
- .createLayoutType(ContainedTy->getAsStructureType(), Packoffsets);
+ .createLayoutType(ContainedTy->castAsCanonical<RecordType>(),
+ Packoffsets);
uint32_t StorageClass = /* Uniform storage class */ 2;
return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {BufferLayoutTy},
{StorageClass, false});
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 386772a96c7ff..71db63bb89645 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -752,7 +752,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State,
TypeInfo TI = getContext().getTypeInfo(Ty);
// Check with the C++ ABI first.
- const RecordType *RT = Ty->getAs<RecordType>();
+ const RecordType *RT = Ty->getAsCanonical<RecordType>();
if (RT) {
CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
if (RAA == CGCXXABI::RAA_Indirect) {
@@ -2039,7 +2039,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
return;
}
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (const RecordType *RT = Ty->getAsCanonical<RecordType>()) {
uint64_t Size = getContext().getTypeSize(Ty);
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
@@ -3309,14 +3309,14 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
if (Ty->isVoidType())
return ABIArgInfo::getIgnore();
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = Ty->getAsEnumDecl())
+ Ty = ED->getIntegerType();
TypeInfo Info = getContext().getTypeInfo(Ty);
uint64_t Width = Info.Width;
CharUnits Align = getContext().toCharUnitsFromBits(Info.Align);
- const RecordType *RT = Ty->getAs<RecordType>();
+ const RecordType *RT = Ty->getAsCanonical<RecordType>();
if (RT) {
if (!IsReturnType) {
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
diff --git a/clang/lib/CodeGen/Targets/XCore.cpp b/clang/lib/CodeGen/Targets/XCore.cpp
index d65af5f82b7f8..ab0115467e521 100644
--- a/clang/lib/CodeGen/Targets/XCore.cpp
+++ b/clang/lib/CodeGen/Targets/XCore.cpp
@@ -615,13 +615,10 @@ static bool appendType(SmallStringEnc &Enc, QualType QType,
if (const PointerType *PT = QT->getAs<PointerType>())
return appendPointerType(Enc, PT, CGM, TSC);
- if (const EnumType *ET = QT->getAs<EnumType>())
+ if (const EnumType *ET = QT->getAsCanonical<EnumType>())
return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier());
- if (const RecordType *RT = QT->getAsStructureType())
- return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
-
- if (const RecordType *RT = QT->getAsUnionType())
+ if (const RecordType *RT = QT->getAsCanonical<RecordType>())
return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
if (const FunctionType *FT = QT->getAs<FunctionType>())
diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index ad8916f817486..42f2d6591b213 100644
--- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -852,7 +852,7 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!IvarT->getAs<TypedefType>() && IvarT->isRecordType()) {
- RecordDecl *RD = IvarT->castAs<RecordType>()->getOriginalDecl();
+ RecordDecl *RD = IvarT->castAsCanonical<RecordType>()->getOriginalDecl();
RD = RD->getDefinition();
if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
// decltype(((Foo_IMPL*)0)->bar) *
@@ -7453,7 +7453,8 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!IvarT->getAs<TypedefType>() && IvarT->isRecordType()) {
- RecordDecl *RD = IvarT->castAs<RecordType>()->getOriginalDecl();
+ RecordDecl *RD =
+ IvarT->castAsCanonical<RecordType>()->getOriginalDecl();
RD = RD->getDefinition();
if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
// decltype(((Foo_IMPL*)0)->bar) *
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index 6bdddcc6967c9..c78d66f9502dd 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -931,7 +931,8 @@ void USRGenerator::VisitType(QualType T) {
VisitObjCProtocolDecl(Prot);
return;
}
- if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) {
+ if (const TemplateTypeParmType *TTP =
+ T->getAsCanonical<TemplateTypeParmType>()) {
Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
return;
}
diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp
index c5e97484dab78..be890ab7fa75f 100644
--- a/clang/lib/Sema/SemaBPF.cpp
+++ b/clang/lib/Sema/SemaBPF.cpp
@@ -56,14 +56,9 @@ static bool isValidPreserveTypeInfoArg(Expr *Arg) {
return true;
// Record type or Enum type.
- const Type *Ty = ArgType->getUnqualifiedDesugaredType();
- if (const auto *RT = Ty->getAs<RecordType>()) {
+ if (const auto *RT = ArgType->getAsCanonical<TagType>())
if (!RT->getOriginalDecl()->getDeclName().isEmpty())
return true;
- } else if (const auto *ET = Ty->getAs<EnumType>()) {
- if (!ET->getOriginalDecl()->getDeclName().isEmpty())
- return true;
- }
return false;
}
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index de22419ee35de..8ee3e0c7105b9 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -863,7 +863,7 @@ void CastOperation::CheckDynamicCast() {
return;
}
- const RecordType *DestRecord = DestPointee->getAs<RecordType>();
+ const auto *DestRecord = DestPointee->getAsCanonical<RecordType>();
if (DestPointee->isVoidType()) {
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
@@ -910,7 +910,7 @@ void CastOperation::CheckDynamicCast() {
SrcPointee = SrcType;
}
- const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
+ const auto *SrcRecord = SrcPointee->getAsCanonical<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
diag::err_bad_cast_incomplete,
@@ -3094,7 +3094,8 @@ void CastOperation::CheckCStyleCast() {
if (!DestType->isScalarType() && !DestType->isVectorType() &&
!DestType->isMatrixType()) {
- if (const RecordType *DestRecordTy = DestType->getAs<RecordType>()) {
+ if (const RecordType *DestRecordTy =
+ DestType->getAsCanonical<RecordType>()) {
if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
// GCC struct/union extension: allow cast to self.
Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1a30793f8ca44..4e475e56af85c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -12692,8 +12692,8 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
// type, to give us better diagnostics.
Source = Context.getCanonicalType(SourceType).getTypePtr();
- if (const EnumType *SourceEnum = Source->getAs<EnumType>())
- if (const EnumType *TargetEnum = Target->getAs<EnumType>())
+ if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>())
+ if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>())
if (SourceEnum->getOriginalDecl()->hasNameForLinkage() &&
TargetEnum->getOriginalDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c3a61741cc874..3ded60cd8b073 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -233,7 +233,7 @@ static const RecordDecl *getRecordDecl(QualType QT) {
return RD;
// Now check if we point to a record.
- if (const auto *PT = QT->getAs<PointerType>())
+ if (const auto *PT = QT->getAsCanonical<PointerType>())
return PT->getPointeeType()->getAsRecordDecl();
return nullptr;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5dc0a7eb4c29d..4b0dead182543 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -5472,7 +5472,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
CXXCtorInitializer *Member = Initializers[i];
if (Member->isBaseInitializer())
- Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+ Info.AllBaseFields[Member->getBaseClass()->getAsCanonical<RecordType>()] =
+ Member;
else {
Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member;
@@ -5500,8 +5501,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// Push virtual bases before others.
for (auto &VBase : ClassDecl->vbases()) {
- if (CXXCtorInitializer *Value
- = Info.AllBaseFields.lookup(VBase.getType()->getAs<RecordType>())) {
+ if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(
+ VBase.getType()->getAsCanonical<RecordType>())) {
// [class.base.init]p7, per DR257:
// A mem-initializer where the mem-initializer-id names a virtual base
// class is ignored during execution of a constructor of any class that
@@ -5539,8 +5540,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
if (Base.isVirtual())
continue;
- if (CXXCtorInitializer *Value
- = Info.AllBaseFields.lookup(Base.getType()->getAs<RecordType>())) {
+ if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(
+ Base.getType()->getAsCanonical<RecordType>())) {
Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
CXXCtorInitializer *CXXBaseInit;
@@ -5628,7 +5629,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
}
static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*> &IdealInits) {
- if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (const RecordType *RT = Field->getType()->getAsCanonical<RecordType>()) {
const RecordDecl *RD = RT->getOriginalDecl();
if (RD->isAnonymousStructOrUnion()) {
for (auto *Field : RD->getDefinitionOrSelf()->fields())
@@ -7628,7 +7629,7 @@ static bool defaultedSpecialMemberIsConstexpr(
F->hasInClassInitializer())
continue;
QualType BaseType = S.Context.getBaseElementType(F->getType());
- if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
+ if (const RecordType *RecordTy = BaseType->getAsCanonical<RecordType>()) {
CXXRecordDecl *FieldRecDecl =
cast<CXXRecordDecl>(RecordTy->getOriginalDecl())
->getDefinitionOrSelf();
@@ -10623,7 +10624,8 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) {
return;
}
- if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>())
+ if (const auto *RT =
+ FT->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>())
if (!RT->isDependentType() &&
!cast<CXXRecordDecl>(RT->getOriginalDecl()->getDefinitionOrSelf())
->canPassInRegisters()) {
@@ -16961,9 +16963,9 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
// first template parameter as its type.
if (PmType && PmArgs && !PmType->isTemplateParameterPack() &&
PmArgs->isTemplateParameterPack()) {
- const TemplateTypeParmType *TArgs =
- PmArgs->getType()->getAs<TemplateTypeParmType>();
- if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
+ if (const auto *TArgs =
+ PmArgs->getType()->getAsCanonical<TemplateTypeParmType>();
+ TArgs && TArgs->getDepth() == PmType->getDepth() &&
TArgs->getIndex() == PmType->getIndex()) {
if (!SemaRef.inTemplateInstantiation())
SemaRef.Diag(TpDecl->getLocation(),
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 29f825b49104e..d383544e54329 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1529,8 +1529,12 @@ void Sema::checkEnumArithmeticConversions(Expr *LHS, Expr *RHS,
// are ill-formed.
if (getLangOpts().CPlusPlus26)
DiagID = diag::warn_conv_mixed_enum_types_cxx26;
- else if (!L->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage() ||
- !R->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage()) {
+ else if (!L->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->hasNameForLinkage() ||
+ !R->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->hasNameForLinkage()) {
// If either enumeration type is unnamed, it's less likely that the
// user cares about this, but this situation is still deprecated in
// C++2a. Use a
diff erent warning group.
@@ -11495,7 +11499,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
}
static bool isScopedEnumerationType(QualType T) {
- if (const EnumType *ET = T->getAs<EnumType>())
+ if (const EnumType *ET = T->getAsCanonical<EnumType>())
return ET->getOriginalDecl()->isScoped();
return false;
}
@@ -13819,7 +13823,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD,
// Then we append it to the list to check next in order.
FieldTy = FieldTy.getCanonicalType();
- if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) {
+ if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) {
if (!llvm::is_contained(RecordTypeList, FieldRecTy))
RecordTypeList.push_back(FieldRecTy);
}
@@ -13835,7 +13839,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E,
QualType Ty = E->getType();
assert(Ty->isRecordType() && "lvalue was not record?");
SourceRange Range = E->getSourceRange();
- const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>();
+ const auto *RTy = Ty->getAsCanonical<RecordType>();
bool DiagEmitted = false;
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 763fc0747eb82..5a9279d928465 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1973,8 +1973,8 @@ static UsualDeallocFnInfo resolveDeallocationOverload(
static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
TypeAwareAllocationMode PassType,
QualType allocType) {
- const RecordType *record =
- allocType->getBaseElementTypeUnsafe()->getAs<RecordType>();
+ const auto *record =
+ allocType->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>();
if (!record) return false;
// Try to find an operator delete[] in class scope.
@@ -5519,8 +5519,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// the same or one is a base class of the other:
QualType FTy = From->getType();
QualType TTy = To->getType();
- const RecordType *FRec = FTy->getAs<RecordType>();
- const RecordType *TRec = TTy->getAs<RecordType>();
+ const RecordType *FRec = FTy->getAsCanonical<RecordType>();
+ const RecordType *TRec = TTy->getAsCanonical<RecordType>();
bool FDerivedFromT = FRec && TRec && FRec != TRec &&
Self.IsDerivedFrom(QuestionLoc, FTy, TTy);
if (FRec && TRec && (FRec == TRec || FDerivedFromT ||
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index 5684e53a6bcaa..331f6e585555b 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -3845,7 +3845,7 @@ static inline T *getObjCBridgeAttr(const TypedefType *TD) {
QualType QT = TDNDecl->getUnderlyingType();
if (QT->isPointerType()) {
QT = QT->getPointeeType();
- if (const RecordType *RT = QT->getAs<RecordType>()) {
+ if (const RecordType *RT = QT->getAsCanonical<RecordType>()) {
for (auto *Redecl :
RT->getOriginalDecl()->getMostRecentDecl()->redecls()) {
if (auto *attr = Redecl->getAttr<T>())
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 4dfeebdea7919..c97129336736b 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -774,7 +774,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
= InitializedEntity::InitializeMember(Field, &ParentEntity);
if (Init >= NumInits || !ILE->getInit(Init)) {
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
+ if (const RecordType *RType = ILE->getType()->getAsCanonical<RecordType>())
if (!RType->getOriginalDecl()->isUnion())
assert((Init < NumInits || VerifyOnly) &&
"This ILE should have been expanded");
diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp
index 8d8d5e87afe73..4f9470a361d2d 100644
--- a/clang/lib/Sema/SemaObjC.cpp
+++ b/clang/lib/Sema/SemaObjC.cpp
@@ -1380,7 +1380,7 @@ SemaObjC::ObjCSubscriptKind SemaObjC::CheckSubscriptingKind(Expr *FromE) {
// If we don't have a class type in C++, there's no way we can get an
// expression of integral or enumeration type.
- const RecordType *RecordTy = T->getAs<RecordType>();
+ const RecordType *RecordTy = T->getAsCanonical<RecordType>();
if (!RecordTy && (T->isObjCObjectPointerType() || T->isVoidPointerType()))
// All other scalar cases are assumed to be dictionary indexing which
// caller handles, with diagnostics if needed.
@@ -1507,7 +1507,7 @@ bool SemaObjC::isCFStringType(QualType T) {
if (!PT)
return false;
- const auto *RT = PT->getPointeeType()->getAs<RecordType>();
+ const auto *RT = PT->getPointeeType()->getAsCanonical<RecordType>();
if (!RT)
return false;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d24550060893b..14fa8478fe317 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -3966,7 +3966,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// If the type we are conversion to is a class type, enumerate its
// constructors.
- if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
+ if (const RecordType *ToRecordType = ToType->getAsCanonical<RecordType>()) {
// C++ [over.match.ctor]p1:
// When objects of class type are direct-initialized (8.5), or
// copy-initialized from an expression of the same or a
@@ -4056,7 +4056,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
} else if (!S.isCompleteType(From->getBeginLoc(), From->getType())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType =
- From->getType()->getAs<RecordType>()) {
+ From->getType()->getAsCanonical<RecordType>()) {
if (auto *FromRecordDecl =
dyn_cast<CXXRecordDecl>(FromRecordType->getOriginalDecl())) {
FromRecordDecl = FromRecordDecl->getDefinitionOrSelf();
@@ -6813,7 +6813,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
// We can only perform contextual implicit conversions on objects of class
// type.
- const RecordType *RecordTy = T->getAs<RecordType>();
+ const RecordType *RecordTy = T->getAsCanonical<RecordType>();
if (!RecordTy || !getLangOpts().CPlusPlus) {
if (!Converter.Suppress)
Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange();
@@ -10195,7 +10195,9 @@ class BuiltinOperatorOverloadBuilder {
if (S.getLangOpts().CPlusPlus11) {
for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) {
- if (!EnumTy->castAs<EnumType>()->getOriginalDecl()->isScoped())
+ if (!EnumTy->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->isScoped())
continue;
if (!AddedTypes.insert(S.Context.getCanonicalType(EnumTy)).second)
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index dda4e00119212..5625fb359807a 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1271,8 +1271,8 @@ static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond,
QualType CondType = Cond->getType();
QualType CaseType = Case->getType();
- const EnumType *CondEnumType = CondType->getAs<EnumType>();
- const EnumType *CaseEnumType = CaseType->getAs<EnumType>();
+ const EnumType *CondEnumType = CondType->getAsCanonical<EnumType>();
+ const EnumType *CaseEnumType = CaseType->getAsCanonical<EnumType>();
if (!CondEnumType || !CaseEnumType)
return;
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index f797756450298..0438af752a69e 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -885,18 +885,19 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
for (StringRef NextMember : Members) {
const RecordType *RT = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
- RT = VD->getType()->getAs<RecordType>();
+ RT = VD->getType()->getAsCanonical<RecordType>();
else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
// MS InlineAsm often uses struct pointer aliases as a base
QualType QT = TD->getUnderlyingType();
if (const auto *PT = QT->getAs<PointerType>())
QT = PT->getPointeeType();
- RT = QT->getAs<RecordType>();
+ RT = QT->getAsCanonical<RecordType>();
} else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
- RT = Context.getTypeDeclType(TD)->getAs<RecordType>();
+ RT = QualType(Context.getCanonicalTypeDeclType(TD))
+ ->getAsCanonical<RecordType>();
else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl))
- RT = TD->getType()->getAs<RecordType>();
+ RT = TD->getType()->getAsCanonical<RecordType>();
if (!RT)
return true;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index e7d981a3210d1..3d8416ac7dc1b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2859,14 +2859,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
}
// Retrieve the parent of an enumeration type.
- if (const EnumType *EnumT = T->getAs<EnumType>()) {
+ if (const EnumType *EnumT = T->getAsCanonical<EnumType>()) {
// FIXME: Forward-declared enums require a TSK_ExplicitSpecialization
// check here.
EnumDecl *Enum = EnumT->getOriginalDecl();
// Get to the parent type.
if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent()))
- T = Context.getTypeDeclType(Parent);
+ T = Context.getCanonicalTypeDeclType(Parent);
else
T = QualType();
continue;
@@ -3313,7 +3313,7 @@ static bool isInVkNamespace(const RecordType *RT) {
static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef,
QualType OperandArg,
SourceLocation Loc) {
- if (auto *RT = OperandArg->getAs<RecordType>()) {
+ if (auto *RT = OperandArg->getAsCanonical<RecordType>()) {
bool Literal = false;
SourceLocation LiteralLoc;
if (isInVkNamespace(RT) && RT->getOriginalDecl()->getName() == "Literal") {
@@ -3323,7 +3323,7 @@ static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef,
const TemplateArgumentList &LiteralArgs = SpecDecl->getTemplateArgs();
QualType ConstantType = LiteralArgs[0].getAsType();
- RT = ConstantType->getAs<RecordType>();
+ RT = ConstantType->getAsCanonical<RecordType>();
Literal = true;
LiteralLoc = SpecDecl->getSourceRange().getBegin();
}
@@ -4132,7 +4132,7 @@ static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg,
case TemplateArgument::Type: {
QualType Type = Arg.getAsType();
const TemplateTypeParmType *TPT =
- Arg.getAsType()->getAs<TemplateTypeParmType>();
+ Arg.getAsType()->getAsCanonical<TemplateTypeParmType>();
return TPT && !Type.hasQualifiers() &&
TPT->getDepth() == Depth && TPT->getIndex() == Index;
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f481a009edab8..cce40c0c91f95 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -698,9 +698,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
TNP = TP->getTemplateName();
// FIXME: To preserve sugar, the TST needs to carry sugared resolved
// arguments.
- PResolved = TP->getCanonicalTypeInternal()
- ->castAs<TemplateSpecializationType>()
- ->template_arguments();
+ PResolved =
+ TP->castAsCanonical<TemplateSpecializationType>()->template_arguments();
} else {
const auto *TT = P->castAs<InjectedClassNameType>();
TNP = TT->getTemplateName(S.Context);
@@ -1437,7 +1436,8 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
if (auto *ParamRef = Param->getAs<RValueReferenceType>()) {
if (ParamRef->getPointeeType().getQualifiers())
return false;
- auto *TypeParm = ParamRef->getPointeeType()->getAs<TemplateTypeParmType>();
+ auto *TypeParm =
+ ParamRef->getPointeeType()->getAsCanonical<TemplateTypeParmType>();
return TypeParm && TypeParm->getIndex() >= FirstInnerIndex;
}
return false;
@@ -1702,7 +1702,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
//
// T
// cv-list T
- if (const auto *TTP = P->getAs<TemplateTypeParmType>()) {
+ if (const auto *TTP = P->getAsCanonical<TemplateTypeParmType>()) {
// Just skip any attempts to deduce from a placeholder type or a parameter
// at a
diff erent depth.
if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth())
@@ -5596,7 +5596,7 @@ static TemplateDeductionResult CheckDeductionConsistency(
// so let it transform their specializations instead.
bool IsDeductionGuide = isa<CXXDeductionGuideDecl>(FTD->getTemplatedDecl());
if (IsDeductionGuide) {
- if (auto *Injected = P->getAs<InjectedClassNameType>())
+ if (auto *Injected = P->getAsCanonical<InjectedClassNameType>())
P = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType(
S.Context);
}
@@ -5617,10 +5617,10 @@ static TemplateDeductionResult CheckDeductionConsistency(
auto T1 = S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType());
auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType());
if (IsDeductionGuide) {
- if (auto *Injected = T1->getAs<InjectedClassNameType>())
+ if (auto *Injected = T1->getAsCanonical<InjectedClassNameType>())
T1 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType(
S.Context);
- if (auto *Injected = T2->getAs<InjectedClassNameType>())
+ if (auto *Injected = T2->getAsCanonical<InjectedClassNameType>())
T2 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType(
S.Context);
}
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 7a7aca8a52d68..3d54d1eb4373a 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1056,7 +1056,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
// The (trailing) return type of the deduction guide.
const TemplateSpecializationType *FReturnType =
RType->getAs<TemplateSpecializationType>();
- if (const auto *ICNT = RType->getAs<InjectedClassNameType>())
+ if (const auto *ICNT = RType->getAsCanonical<InjectedClassNameType>())
// implicitly-generated deduction guide.
FReturnType = cast<TemplateSpecializationType>(
ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType(
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index da372340fc60d..37552331478f1 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1583,8 +1583,8 @@ bool Sema::BuiltinIsBaseOf(SourceLocation RhsTLoc, QualType LhsT,
// Base and Derived are not unions and name the same class type without
// regard to cv-qualifiers.
- const RecordType *lhsRecord = LhsT->getAs<RecordType>();
- const RecordType *rhsRecord = RhsT->getAs<RecordType>();
+ const RecordType *lhsRecord = LhsT->getAsCanonical<RecordType>();
+ const RecordType *rhsRecord = RhsT->getAsCanonical<RecordType>();
if (!rhsRecord || !lhsRecord) {
const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>();
const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>();
@@ -1643,8 +1643,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
return Self.BuiltinIsBaseOf(Rhs->getTypeLoc().getBeginLoc(), LhsT, RhsT);
case BTT_IsVirtualBaseOf: {
- const RecordType *BaseRecord = LhsT->getAs<RecordType>();
- const RecordType *DerivedRecord = RhsT->getAs<RecordType>();
+ const RecordType *BaseRecord = LhsT->getAsCanonical<RecordType>();
+ const RecordType *DerivedRecord = RhsT->getAsCanonical<RecordType>();
if (!BaseRecord || !DerivedRecord) {
DiagnoseVLAInCXXTypeTrait(Self, Lhs,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 79aca11839802..b089745bf5e03 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17631,12 +17631,13 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destroyed) {
- QualType BaseType = Base->getType();
+ QualType CanonicalBaseType = Base->getType().getCanonicalType();
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
- (!isArrow && !BaseType->getAs<RecordType>()) ||
- (isArrow && BaseType->getAs<PointerType>() &&
- !BaseType->castAs<PointerType>()->getPointeeType()
- ->template getAs<RecordType>())){
+ (!isArrow && !isa<RecordType>(CanonicalBaseType)) ||
+ (isArrow && isa<PointerType>(CanonicalBaseType) &&
+ !cast<PointerType>(CanonicalBaseType)
+ ->getPointeeType()
+ ->getAsCanonical<RecordType>())) {
// This pseudo-destructor expression is still a pseudo-destructor.
return SemaRef.BuildPseudoDestructorExpr(
Base, OperatorLoc, isArrow ? tok::arrow : tok::period, SS, ScopeType,
diff --git a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 91faefde43b00..c0727ae5dc8ba 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -27,7 +27,7 @@ using namespace ento;
//===----------------------------------------------------------------------===//
static bool IsLLVMStringRef(QualType T) {
- const RecordType *RT = T->getAs<RecordType>();
+ const RecordType *RT = T->getAsCanonical<RecordType>();
if (!RT)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 36c12582a5787..884dbe90e7b12 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -241,7 +241,7 @@ void RetainTypeChecker::visitTypedef(const TypedefDecl *TD) {
return;
auto PointeeQT = QT->getPointeeType();
- const RecordType *RT = PointeeQT->getAs<RecordType>();
+ const RecordType *RT = PointeeQT->getAsCanonical<RecordType>();
if (!RT) {
if (TD->hasAttr<ObjCBridgeAttr>() || TD->hasAttr<ObjCBridgeMutableAttr>()) {
RecordlessTypes.insert(TD->getASTContext()
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 6a82aa7ba3936..8f18533af68b9 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2454,7 +2454,7 @@ NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
SVal RegionStoreManager::getBindingForStruct(RegionBindingsConstRef B,
const TypedValueRegion *R) {
const RecordDecl *RD =
- R->getValueType()->castAs<RecordType>()->getOriginalDecl();
+ R->getValueType()->castAsCanonical<RecordType>()->getOriginalDecl();
if (!RD->getDefinition())
return UnknownVal();
diff --git a/clang/test/CXX/drs/cwg0xx.cpp b/clang/test/CXX/drs/cwg0xx.cpp
index 9aeee7a76903d..805be67f2dc1a 100644
--- a/clang/test/CXX/drs/cwg0xx.cpp
+++ b/clang/test/CXX/drs/cwg0xx.cpp
@@ -244,7 +244,7 @@ namespace cwg16 { // cwg16: 2.8
// expected-error@#cwg16-A-f-call {{'A' is a private member of 'cwg16::A'}}
// expected-note@#cwg16-B {{constrained by implicitly private inheritance here}}
// expected-note@#cwg16-A {{member is declared here}}
- // expected-error@#cwg16-A-f-call {{cannot cast 'cwg16::C' to its private base class 'cwg16::A'}}
+ // expected-error@#cwg16-A-f-call {{cannot cast 'cwg16::C' to its private base class 'A'}}
// expected-note@#cwg16-B {{implicitly declared private here}}
}
};
@@ -838,7 +838,7 @@ namespace cwg52 { // cwg52: 2.8
// expected-error@#cwg52-k {{'A' is a private member of 'cwg52::A'}}
// expected-note@#cwg52-B {{constrained by private inheritance here}}
// expected-note@#cwg52-A {{member is declared here}}
- // expected-error@#cwg52-k {{cannot cast 'struct B' to its private base class 'cwg52::A'}}
+ // expected-error@#cwg52-k {{cannot cast 'struct B' to its private base class 'A'}}
// expected-note@#cwg52-B {{declared private here}}
} // namespace cwg52
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index 5d09697a3cf6b..bbd87c060801a 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -1321,7 +1321,7 @@ namespace cwg381 { // cwg381: 2.7
void f() {
E e;
e.B::a = 0;
- /* expected-error at -1 {{ambiguous conversion from derived class 'E' to base class 'cwg381::B':
+ /* expected-error at -1 {{ambiguous conversion from derived class 'E' to base class 'B':
struct cwg381::E -> C -> B
struct cwg381::E -> D -> B}} */
F f;
diff --git a/clang/test/ExtractAPI/class_template_param_inheritance.cpp b/clang/test/ExtractAPI/class_template_param_inheritance.cpp
index 53b331e0b460b..5f0056456c730 100644
--- a/clang/test/ExtractAPI/class_template_param_inheritance.cpp
+++ b/clang/test/ExtractAPI/class_template_param_inheritance.cpp
@@ -44,7 +44,7 @@ template<typename T> class Foo : public T {};
{
"kind": "inheritsFrom",
"source": "c:@ST>1#T at Foo",
- "target": "",
+ "target": "c:input.h at 9",
"targetFallback": "T"
}
],
diff --git a/clang/utils/TableGen/ASTTableGen.h b/clang/utils/TableGen/ASTTableGen.h
index 02b97636cf5f2..e9a86f3d5edd3 100644
--- a/clang/utils/TableGen/ASTTableGen.h
+++ b/clang/utils/TableGen/ASTTableGen.h
@@ -38,7 +38,7 @@
#define AlwaysDependentClassName "AlwaysDependent"
#define NeverCanonicalClassName "NeverCanonical"
#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
-#define LeafTypeClassName "LeafType"
+#define AlwaysCanonicalTypeClassName "AlwaysCanonical"
// Cases of various non-ASTNode structured types like DeclarationName.
#define TypeKindClassName "PropertyTypeKind"
diff --git a/clang/utils/TableGen/ClangTypeNodesEmitter.cpp b/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
index 37039361cfc22..2e1eaef6c1823 100644
--- a/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
+++ b/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
@@ -40,8 +40,9 @@
// There is a sixth macro, independent of the others. Most clients
// will not need to use it.
//
-// LEAF_TYPE(Class) - A type that never has inner types. Clients
-// which can operate on such types more efficiently may wish to do so.
+// ALWAYS_CANONICAL_TYPE(Class) - A type which is always identical to its
+// canonical type. Clients which can operate on such types more efficiently
+// may wish to do so.
//
//===----------------------------------------------------------------------===//
@@ -66,7 +67,7 @@ using namespace clang::tblgen;
#define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE"
#define TypeMacroArgs "(Class, Base)"
#define LastTypeMacroName "LAST_TYPE"
-#define LeafTypeMacroName "LEAF_TYPE"
+#define AlwaysCanonicalTypeMacroName "ALWAYS_CANONICAL_TYPE"
#define TypeClassName "Type"
@@ -90,7 +91,7 @@ class TypeNodeEmitter {
void emitNodeInvocations();
void emitLastNodeInvocation(TypeNode lastType);
- void emitLeafNodeInvocations();
+ void emitAlwaysCanonicalNodeInvocations();
void addMacroToUndef(StringRef macroName);
void emitUndefs();
@@ -109,12 +110,12 @@ void TypeNodeEmitter::emit() {
emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs);
emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs);
emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs);
- emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName,
+ emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName,
TypeMacroArgs);
// Invocations.
emitNodeInvocations();
- emitLeafNodeInvocations();
+ emitAlwaysCanonicalNodeInvocations();
// Postmatter
emitUndefs();
@@ -178,15 +179,16 @@ void TypeNodeEmitter::emitLastNodeInvocation(TypeNode type) {
"#endif\n";
}
-void TypeNodeEmitter::emitLeafNodeInvocations() {
- Out << "#ifdef " LeafTypeMacroName "\n";
+void TypeNodeEmitter::emitAlwaysCanonicalNodeInvocations() {
+ Out << "#ifdef " AlwaysCanonicalTypeMacroName "\n";
for (TypeNode type : Types) {
- if (!type.isSubClassOf(LeafTypeClassName)) continue;
- Out << LeafTypeMacroName "(" << type.getId() << ")\n";
+ if (!type.isSubClassOf(AlwaysCanonicalTypeClassName))
+ continue;
+ Out << AlwaysCanonicalTypeMacroName "(" << type.getId() << ")\n";
}
- Out << "#undef " LeafTypeMacroName "\n"
+ Out << "#undef " AlwaysCanonicalTypeMacroName "\n"
"#endif\n";
}
More information about the cfe-commits
mailing list