diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index bcab4f1b8a729..506cc0a3b0e8f 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -901,9 +901,8 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, if (!D->isThisDeclarationADefinition()) return; for (const CXXBaseSpecifier &B : D->bases()) { - if (const RecordType *Ty = B.getType()->getAs()) { - if (const CXXRecordDecl *Base = cast_or_null( - Ty->getOriginalDecl()->getDefinition())) { + if (const auto *Base = B.getType()->getAsCXXRecordDecl()) { + if (Base->isCompleteDefinition()) { // Initialized without USR and name, this will be set in the following // if-else stmt. BaseRecordInfo BI( 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(); + const auto *FromEnum = WorkType->getAsCanonical(); const auto *ToEnum = To->getAs(); if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) { // Unscoped enumerations (or enumerations in C) convert to numerics. diff --git a/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp index ddbb14e3ac62b..02f4421efdbf4 100644 --- a/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp @@ -169,15 +169,8 @@ void TaggedUnionMemberCountCheck::check( if (!Root || !UnionField || !TagField) return; - const auto *UnionDef = - UnionField->getType().getCanonicalType().getTypePtr()->getAsRecordDecl(); - const auto *EnumDef = llvm::dyn_cast( - TagField->getType().getCanonicalType().getTypePtr()->getAsTagDecl()); - - assert(UnionDef && "UnionDef is missing!"); - assert(EnumDef && "EnumDef is missing!"); - if (!UnionDef || !EnumDef) - return; + const auto *UnionDef = UnionField->getType()->castAsRecordDecl(); + const auto *EnumDef = TagField->getType()->castAsEnumDecl(); const std::size_t UnionMemberCount = llvm::range_size(UnionDef->fields()); auto [TagCount, CountingEnumConstantDecl] = getNumberOfEnumValues(EnumDef); diff --git a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp index 2a0d0ada42b28..2c2248afb69e7 100644 --- a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp +++ b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp @@ -31,7 +31,7 @@ void DefaultOperatorNewAlignmentCheck::check( return; const TagDecl *D = T->getAsTagDecl(); // Alignment can not be obtained for undefined type. - if (!D || !D->getDefinition() || !D->isCompleteDefinition()) + if (!D || !D->isCompleteDefinition()) return; ASTContext &Context = D->getASTContext(); 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(); + const auto *TemplateType = ParamType->getAsCanonical(); 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()) + if (const auto *RT = Type->getAsCanonical()) return RT->getOriginalDecl(); return nullptr; } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp index 40fd15c08f0a1..6508bfd5ca808 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp @@ -90,9 +90,8 @@ void SlicingCheck::diagnoseSlicedOverriddenMethods( } // Recursively process bases. for (const auto &Base : DerivedDecl.bases()) { - if (const auto *BaseRecordType = Base.getType()->getAs()) { - if (const auto *BaseRecord = cast_or_null( - BaseRecordType->getOriginalDecl()->getDefinition())) + if (const auto *BaseRecord = Base.getType()->getAsCXXRecordDecl()) { + if (BaseRecord->isCompleteDefinition()) diagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl); } } diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp index 0302a5ad4957c..36b6007b58a51 100644 --- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp +++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp @@ -71,13 +71,10 @@ bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) { for (const auto &I : Node->bases()) { if (I.isVirtual()) continue; - const auto *Ty = I.getType()->getAs(); - if (!Ty) + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) continue; - const RecordDecl *D = Ty->getOriginalDecl()->getDefinition(); - if (!D) - continue; - const auto *Base = cast(D); + assert(Base->isCompleteDefinition()); if (!isInterface(Base)) { addNodeToInterfaceMap(Node, false); return false; @@ -103,11 +100,10 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) { for (const auto &I : D->bases()) { if (I.isVirtual()) continue; - const auto *Ty = I.getType()->getAs(); - if (!Ty) + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) continue; - const auto *Base = - cast(Ty->getOriginalDecl()->getDefinition()); + assert(Base->isCompleteDefinition()); if (!isInterface(Base)) NumConcrete++; } @@ -115,11 +111,10 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) { // Check virtual bases to see if there is more than one concrete // non-virtual base. for (const auto &V : D->vbases()) { - const auto *Ty = V.getType()->getAs(); - if (!Ty) + const auto *Base = V.getType()->getAsCXXRecordDecl(); + if (!Base) continue; - const auto *Base = - cast(Ty->getOriginalDecl()->getDefinition()); + assert(Base->isCompleteDefinition()); if (!isInterface(Base)) NumConcrete++; } 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(Used)) { - if (const auto *ET = ECD->getType()->getAs()) + if (const auto *ET = ECD->getType()->getAsCanonical()) 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()) + if (const auto *Record = Type->getAsCanonical()) 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()->getOriginalDecl()->isScoped()) || + if ((ParamType->isEnumeralType() && ParamType->castAsCanonical() + ->getOriginalDecl() + ->isScoped()) || (ArgType->isEnumeralType() && - ArgType->castAs()->getOriginalDecl()->isScoped())) + ArgType->castAsCanonical()->getOriginalDecl()->isScoped())) return false; return true; diff --git a/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp index 6914ec2beb2fb..d43716e901e84 100644 --- a/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp +++ b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp @@ -13,6 +13,7 @@ #include "DesignatedInitializers.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/ScopeExit.h" diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp index aa6aefcf0c493..4693c656a6602 100644 --- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp @@ -9,6 +9,7 @@ #include "ExceptionSpecAnalyzer.h" #include "clang/AST/Expr.h" +#include "clang/AST/Type.h" namespace clang::tidy::utils { @@ -66,10 +67,7 @@ ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base, if (!RecType) return State::Unknown; - const auto *BaseClass = - cast(RecType->getOriginalDecl())->getDefinitionOrSelf(); - - return analyzeRecord(BaseClass, Kind); + return analyzeRecord(RecType->getAsCXXRecordDecl(), Kind); } ExceptionSpecAnalyzer::State diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index 0df8e913100fc..0d0834dc38fc6 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -460,10 +460,9 @@ bool FormatStringConverter::emitIntegerArgument( // be passed as its underlying type. However, printf will have forced // the signedness based on the format string, so we need to do the // same. - if (const auto *ET = ArgType->getAs()) { - if (const std::optional MaybeCastType = castTypeForArgument( - ArgKind, - ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType())) + if (const auto *ED = ArgType->getAsEnumDecl()) { + if (const std::optional MaybeCastType = + castTypeForArgument(ArgKind, ED->getIntegerType())) ArgFixes.emplace_back( ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str()); else diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp index 5518afd32e7f0..f944306171135 100644 --- a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp +++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp @@ -119,9 +119,8 @@ bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; - if (const auto *RT = CanonicalType->getAs()) { - return recordIsTriviallyDefaultConstructible( - *RT->getOriginalDecl()->getDefinitionOrSelf(), Context); + if (const auto *RD = CanonicalType->getAsRecordDecl()) { + return recordIsTriviallyDefaultConstructible(*RD, Context); } // No other types can match. diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index a7cf45c632827..6e45c9ae4f8bf 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -454,8 +454,7 @@ std::optional printExprValue(const Expr *E, Constant.Val.getInt().getSignificantBits() <= 64) { // Compare to int64_t to avoid bit-width match requirements. int64_t Val = Constant.Val.getInt().getExtValue(); - for (const EnumConstantDecl *ECD : - T->castAs()->getOriginalDecl()->enumerators()) + for (const EnumConstantDecl *ECD : T->castAsEnumDecl()->enumerators()) if (ECD->getInitVal() == Val) return llvm::formatv("{0} ({1})", ECD->getNameAsString(), printHex(Constant.Val.getInt())) @@ -832,7 +831,7 @@ std::optional getThisExprHoverContents(const CXXThisExpr *CTE, ASTContext &ASTCtx, const PrintingPolicy &PP) { QualType OriginThisType = CTE->getType()->getPointeeType(); - QualType ClassType = declaredType(OriginThisType->getAsTagDecl()); + QualType ClassType = declaredType(OriginThisType->castAsTagDecl()); // For partial specialization class, origin `this` pointee type will be // parsed as `InjectedClassNameType`, which will ouput template arguments // like "type-parameter-0-0". So we retrieve user written class type in this 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(); + EnumT = Cond->getType()->getAsCanonical(); 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/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index 26052b8086cf7..0d187eb49d6ca 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -193,7 +193,7 @@ class DataStreamBasicReader : public BasicReaderBase { auto elemTy = origTy; unsigned pathLength = asImpl().readUInt32(); for (unsigned i = 0; i < pathLength; ++i) { - if (elemTy->template getAs()) { + if (elemTy->isRecordType()) { unsigned int_ = asImpl().readUInt32(); Decl *decl = asImpl().template readDeclAs(); if (auto *recordDecl = dyn_cast(decl)) diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index d41e655986ef9..8ea0c29cf5070 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -176,7 +176,7 @@ class DataStreamBasicWriter : public BasicWriterBase { asImpl().writeUInt32(path.size()); auto &ctx = ((BasicWriterBase *)this)->getASTContext(); for (auto elem : path) { - if (elemTy->getAs()) { + if (elemTy->isRecordType()) { asImpl().writeUInt32(elem.getAsBaseOrMember().getInt()); const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer(); if (const auto *recordDecl = dyn_cast(baseOrMember)) { diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index bebbde3661a33..7c9245d8298a2 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -22,7 +22,7 @@ #include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/Redeclarable.h" -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -3915,6 +3915,10 @@ class TagDecl : public TypeDecl, bool isUnion() const { return getTagKind() == TagTypeKind::Union; } bool isEnum() const { return getTagKind() == TagTypeKind::Enum; } + bool isStructureOrClass() const { + return isStruct() || isClass() || isInterface(); + } + /// Is this tag type named, either directly or via being defined in /// a typedef of this type? /// diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 1d2ef0f4f2319..00d8f724671f1 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -22,10 +22,10 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LambdaCapture.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/Stmt.h" -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/LLVM.h" @@ -3825,7 +3825,9 @@ class UsingEnumDecl : public BaseUsingDecl, public Mergeable { void setEnumType(TypeSourceInfo *TSI) { EnumType = TSI; } public: - EnumDecl *getEnumDecl() const { return cast(EnumType->getType()->getAsTagDecl()); } + EnumDecl *getEnumDecl() const { + return cast(EnumType->getType())->getOriginalDecl(); + } static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation UsingL, SourceLocation EnumL, diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 284228dc0ee47..a7185f5bce04b 100644 --- a/clang/include/clang/AST/DeclarationName.h +++ b/clang/include/clang/AST/DeclarationName.h @@ -13,7 +13,7 @@ #ifndef LLVM_CLANG_AST_DECLARATIONNAME_H #define LLVM_CLANG_AST_DECLARATIONNAME_H -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/OperatorKinds.h" diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 77d0912d1f41b..aeb1aba03ee49 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -23,7 +23,7 @@ #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SyncScope.h" diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index 69481e85d87fa..de248ac3cf703 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -17,7 +17,7 @@ #include "clang/AST/DependenceFlags.h" #include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateName.h" -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/APInt.h" diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index adf5cb0462154..48575c1b19395 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -9,9261 +9,87 @@ /// \file /// C Language Family Type Representation /// -/// This file defines the clang::Type interface and subclasses, used to -/// represent types for languages in the C family. +/// This file defines some inline methods for clang::Type which depend on +/// Decl.h, avoiding a circular dependency. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TYPE_H #define LLVM_CLANG_AST_TYPE_H -#include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifierBase.h" -#include "clang/AST/TemplateName.h" -#include "clang/Basic/AddressSpaces.h" -#include "clang/Basic/AttrKinds.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/ExceptionSpecificationType.h" -#include "clang/Basic/LLVM.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/Linkage.h" -#include "clang/Basic/PartialDiagnostic.h" -#include "clang/Basic/PointerAuthOptions.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/Specifiers.h" -#include "clang/Basic/Visibility.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/STLForwardCompat.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DXILABI.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/PointerLikeTypeTraits.h" -#include "llvm/Support/TrailingObjects.h" -#include "llvm/Support/type_traits.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/TypeBase.h" namespace clang { -class BTFTypeTagAttr; -class ExtQuals; -class QualType; -class ConceptDecl; -class ValueDecl; -class TagDecl; -class TemplateParameterList; -class Type; -class Attr; - -enum { - TypeAlignmentInBits = 4, - TypeAlignment = 1 << TypeAlignmentInBits -}; - -namespace serialization { - template class AbstractTypeReader; - template class AbstractTypeWriter; -} - -} // namespace clang - -namespace llvm { - - template - struct PointerLikeTypeTraits; - template<> - struct PointerLikeTypeTraits< ::clang::Type*> { - static inline void *getAsVoidPointer(::clang::Type *P) { return P; } - - static inline ::clang::Type *getFromVoidPointer(void *P) { - return static_cast< ::clang::Type*>(P); - } - - static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits; - }; - - template<> - struct PointerLikeTypeTraits< ::clang::ExtQuals*> { - static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } - - static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { - return static_cast< ::clang::ExtQuals*>(P); - } - - static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits; - }; - -} // namespace llvm - -namespace clang { - -class ASTContext; -template class CanQual; -class CXXRecordDecl; -class DeclContext; -class EnumDecl; -class Expr; -class ExtQualsTypeCommonBase; -class FunctionDecl; -class FunctionEffectsRef; -class FunctionEffectKindSet; -class FunctionEffectSet; -class IdentifierInfo; -class NamedDecl; -class ObjCInterfaceDecl; -class ObjCProtocolDecl; -class ObjCTypeParamDecl; -struct PrintingPolicy; -class RecordDecl; -class Stmt; -class TagDecl; -class ClassTemplateDecl; -class TemplateArgument; -class TemplateArgumentListInfo; -class TemplateArgumentLoc; -class TemplateTypeParmDecl; -class TypedefNameDecl; -class UnresolvedUsingTypenameDecl; -class UsingShadowDecl; - -using CanQualType = CanQual; - -// Provide forward declarations for all of the *Type classes. -#define TYPE(Class, Base) class Class##Type; -#include "clang/AST/TypeNodes.inc" - -/// Pointer-authentication qualifiers. -class PointerAuthQualifier { - enum : uint32_t { - EnabledShift = 0, - EnabledBits = 1, - EnabledMask = 1 << EnabledShift, - AddressDiscriminatedShift = EnabledShift + EnabledBits, - AddressDiscriminatedBits = 1, - AddressDiscriminatedMask = 1 << AddressDiscriminatedShift, - AuthenticationModeShift = - AddressDiscriminatedShift + AddressDiscriminatedBits, - AuthenticationModeBits = 2, - AuthenticationModeMask = ((1 << AuthenticationModeBits) - 1) - << AuthenticationModeShift, - IsaPointerShift = AuthenticationModeShift + AuthenticationModeBits, - IsaPointerBits = 1, - IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift, - AuthenticatesNullValuesShift = IsaPointerShift + IsaPointerBits, - AuthenticatesNullValuesBits = 1, - AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1) - << AuthenticatesNullValuesShift, - KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits, - KeyBits = 10, - KeyMask = ((1 << KeyBits) - 1) << KeyShift, - DiscriminatorShift = KeyShift + KeyBits, - DiscriminatorBits = 16, - DiscriminatorMask = ((1u << DiscriminatorBits) - 1) << DiscriminatorShift, - }; - - // bits: |0 |1 |2..3 |4 | - // |Enabled|Address|AuthenticationMode|ISA pointer| - // bits: |5 |6..15| 16...31 | - // |AuthenticatesNull|Key |Discriminator| - uint32_t Data = 0; - - // The following static assertions check that each of the 32 bits is present - // exactly in one of the constants. - static_assert((EnabledBits + AddressDiscriminatedBits + - AuthenticationModeBits + IsaPointerBits + - AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) == - 32, - "PointerAuthQualifier should be exactly 32 bits"); - static_assert((EnabledMask + AddressDiscriminatedMask + - AuthenticationModeMask + IsaPointerMask + - AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) == - 0xFFFFFFFF, - "All masks should cover the entire bits"); - static_assert((EnabledMask ^ AddressDiscriminatedMask ^ - AuthenticationModeMask ^ IsaPointerMask ^ - AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) == - 0xFFFFFFFF, - "All masks should cover the entire bits"); - - PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated, - unsigned ExtraDiscriminator, - PointerAuthenticationMode AuthenticationMode, - bool IsIsaPointer, bool AuthenticatesNullValues) - : Data(EnabledMask | - (IsAddressDiscriminated - ? llvm::to_underlying(AddressDiscriminatedMask) - : 0) | - (Key << KeyShift) | - (llvm::to_underlying(AuthenticationMode) - << AuthenticationModeShift) | - (ExtraDiscriminator << DiscriminatorShift) | - (IsIsaPointer << IsaPointerShift) | - (AuthenticatesNullValues << AuthenticatesNullValuesShift)) { - assert(Key <= KeyNoneInternal); - assert(ExtraDiscriminator <= MaxDiscriminator); - assert((Data == 0) == - (getAuthenticationMode() == PointerAuthenticationMode::None)); - } - -public: - enum { - KeyNoneInternal = (1u << KeyBits) - 1, - - /// The maximum supported pointer-authentication key. - MaxKey = KeyNoneInternal - 1, - - /// The maximum supported pointer-authentication discriminator. - MaxDiscriminator = (1u << DiscriminatorBits) - 1 - }; - -public: - PointerAuthQualifier() = default; - - static PointerAuthQualifier - Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator, - PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer, - bool AuthenticatesNullValues) { - if (Key == PointerAuthKeyNone) - Key = KeyNoneInternal; - assert(Key <= KeyNoneInternal && "out-of-range key value"); - return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator, - AuthenticationMode, IsIsaPointer, - AuthenticatesNullValues); - } - - bool isPresent() const { - assert((Data == 0) == - (getAuthenticationMode() == PointerAuthenticationMode::None)); - return Data != 0; - } - - explicit operator bool() const { return isPresent(); } - - unsigned getKey() const { - assert(isPresent()); - return (Data & KeyMask) >> KeyShift; - } - - bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; } - - bool isAddressDiscriminated() const { - assert(isPresent()); - return (Data & AddressDiscriminatedMask) >> AddressDiscriminatedShift; - } - - unsigned getExtraDiscriminator() const { - assert(isPresent()); - return (Data >> DiscriminatorShift); - } - - PointerAuthenticationMode getAuthenticationMode() const { - return PointerAuthenticationMode((Data & AuthenticationModeMask) >> - AuthenticationModeShift); - } - - bool isIsaPointer() const { - assert(isPresent()); - return (Data & IsaPointerMask) >> IsaPointerShift; - } - - bool authenticatesNullValues() const { - assert(isPresent()); - return (Data & AuthenticatesNullValuesMask) >> AuthenticatesNullValuesShift; - } - - PointerAuthQualifier withoutKeyNone() const { - return hasKeyNone() ? PointerAuthQualifier() : *this; - } - - friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) { - return Lhs.Data == Rhs.Data; - } - friend bool operator!=(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) { - return Lhs.Data != Rhs.Data; - } - - bool isEquivalent(PointerAuthQualifier Other) const { - return withoutKeyNone() == Other.withoutKeyNone(); - } - - uint32_t getAsOpaqueValue() const { return Data; } - - // Deserialize pointer-auth qualifiers from an opaque representation. - static PointerAuthQualifier fromOpaqueValue(uint32_t Opaque) { - PointerAuthQualifier Result; - Result.Data = Opaque; - assert((Result.Data == 0) == - (Result.getAuthenticationMode() == PointerAuthenticationMode::None)); - return Result; - } - - std::string getAsString() const; - std::string getAsString(const PrintingPolicy &Policy) const; - - bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; - void print(raw_ostream &OS, const PrintingPolicy &Policy) const; - - void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); } -}; - -/// The collection of all-type qualifiers we support. -/// Clang supports five independent qualifiers: -/// * C99: const, volatile, and restrict -/// * MS: __unaligned -/// * Embedded C (TR18037): address spaces -/// * Objective C: the GC attributes (none, weak, or strong) -class Qualifiers { -public: - Qualifiers() = default; - enum TQ : uint64_t { - // NOTE: These flags must be kept in sync with DeclSpec::TQ. - Const = 0x1, - Restrict = 0x2, - Volatile = 0x4, - CVRMask = Const | Volatile | Restrict - }; - - enum GC { - GCNone = 0, - Weak, - Strong - }; - - enum ObjCLifetime { - /// There is no lifetime qualification on this type. - OCL_None, - - /// This object can be modified without requiring retains or - /// releases. - OCL_ExplicitNone, - - /// Assigning into this object requires the old value to be - /// released and the new value to be retained. The timing of the - /// release of the old value is inexact: it may be moved to - /// immediately after the last known point where the value is - /// live. - OCL_Strong, - - /// Reading or writing from this object requires a barrier call. - OCL_Weak, - - /// Assigning into this object requires a lifetime extension. - OCL_Autoreleasing - }; - - enum : uint64_t { - /// The maximum supported address space number. - /// 23 bits should be enough for anyone. - MaxAddressSpace = 0x7fffffu, - - /// The width of the "fast" qualifier mask. - FastWidth = 3, - - /// The fast qualifier mask. - FastMask = (1 << FastWidth) - 1 - }; - - /// Returns the common set of qualifiers while removing them from - /// the given sets. - static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { - Qualifiers Q; - PointerAuthQualifier LPtrAuth = L.getPointerAuth(); - if (LPtrAuth.isPresent() && - LPtrAuth.getKey() != PointerAuthQualifier::KeyNoneInternal && - LPtrAuth == R.getPointerAuth()) { - Q.setPointerAuth(LPtrAuth); - PointerAuthQualifier Empty; - L.setPointerAuth(Empty); - R.setPointerAuth(Empty); - } - - // If both are only CVR-qualified, bit operations are sufficient. - if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { - Q.Mask = L.Mask & R.Mask; - L.Mask &= ~Q.Mask; - R.Mask &= ~Q.Mask; - return Q; - } - - unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); - Q.addCVRQualifiers(CommonCRV); - L.removeCVRQualifiers(CommonCRV); - R.removeCVRQualifiers(CommonCRV); - - if (L.getObjCGCAttr() == R.getObjCGCAttr()) { - Q.setObjCGCAttr(L.getObjCGCAttr()); - L.removeObjCGCAttr(); - R.removeObjCGCAttr(); - } - - if (L.getObjCLifetime() == R.getObjCLifetime()) { - Q.setObjCLifetime(L.getObjCLifetime()); - L.removeObjCLifetime(); - R.removeObjCLifetime(); - } - - if (L.getAddressSpace() == R.getAddressSpace()) { - Q.setAddressSpace(L.getAddressSpace()); - L.removeAddressSpace(); - R.removeAddressSpace(); - } - return Q; - } - - static Qualifiers fromFastMask(unsigned Mask) { - Qualifiers Qs; - Qs.addFastQualifiers(Mask); - return Qs; - } - - static Qualifiers fromCVRMask(unsigned CVR) { - Qualifiers Qs; - Qs.addCVRQualifiers(CVR); - return Qs; - } - - static Qualifiers fromCVRUMask(unsigned CVRU) { - Qualifiers Qs; - Qs.addCVRUQualifiers(CVRU); - return Qs; - } - - // Deserialize qualifiers from an opaque representation. - static Qualifiers fromOpaqueValue(uint64_t opaque) { - Qualifiers Qs; - Qs.Mask = opaque; - return Qs; - } - - // Serialize these qualifiers into an opaque representation. - uint64_t getAsOpaqueValue() const { return Mask; } - - bool hasConst() const { return Mask & Const; } - bool hasOnlyConst() const { return Mask == Const; } - void removeConst() { Mask &= ~Const; } - void addConst() { Mask |= Const; } - Qualifiers withConst() const { - Qualifiers Qs = *this; - Qs.addConst(); - return Qs; - } - - bool hasVolatile() const { return Mask & Volatile; } - bool hasOnlyVolatile() const { return Mask == Volatile; } - void removeVolatile() { Mask &= ~Volatile; } - void addVolatile() { Mask |= Volatile; } - Qualifiers withVolatile() const { - Qualifiers Qs = *this; - Qs.addVolatile(); - return Qs; - } - - bool hasRestrict() const { return Mask & Restrict; } - bool hasOnlyRestrict() const { return Mask == Restrict; } - void removeRestrict() { Mask &= ~Restrict; } - void addRestrict() { Mask |= Restrict; } - Qualifiers withRestrict() const { - Qualifiers Qs = *this; - Qs.addRestrict(); - return Qs; - } - - bool hasCVRQualifiers() const { return getCVRQualifiers(); } - unsigned getCVRQualifiers() const { return Mask & CVRMask; } - unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); } - - void setCVRQualifiers(unsigned mask) { - assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); - Mask = (Mask & ~CVRMask) | mask; - } - void removeCVRQualifiers(unsigned mask) { - assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); - Mask &= ~static_cast(mask); - } - void removeCVRQualifiers() { - removeCVRQualifiers(CVRMask); - } - void addCVRQualifiers(unsigned mask) { - assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); - Mask |= mask; - } - void addCVRUQualifiers(unsigned mask) { - assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits"); - Mask |= mask; - } - - bool hasUnaligned() const { return Mask & UMask; } - void setUnaligned(bool flag) { - Mask = (Mask & ~UMask) | (flag ? UMask : 0); - } - void removeUnaligned() { Mask &= ~UMask; } - void addUnaligned() { Mask |= UMask; } - - bool hasObjCGCAttr() const { return Mask & GCAttrMask; } - GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } - void setObjCGCAttr(GC type) { - Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); - } - void removeObjCGCAttr() { setObjCGCAttr(GCNone); } - void addObjCGCAttr(GC type) { - assert(type); - setObjCGCAttr(type); - } - Qualifiers withoutObjCGCAttr() const { - Qualifiers qs = *this; - qs.removeObjCGCAttr(); - return qs; - } - Qualifiers withoutObjCLifetime() const { - Qualifiers qs = *this; - qs.removeObjCLifetime(); - return qs; - } - Qualifiers withoutAddressSpace() const { - Qualifiers qs = *this; - qs.removeAddressSpace(); - return qs; - } - - bool hasObjCLifetime() const { return Mask & LifetimeMask; } - ObjCLifetime getObjCLifetime() const { - return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); - } - void setObjCLifetime(ObjCLifetime type) { - Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); - } - void removeObjCLifetime() { setObjCLifetime(OCL_None); } - void addObjCLifetime(ObjCLifetime type) { - assert(type); - assert(!hasObjCLifetime()); - Mask |= (type << LifetimeShift); - } - - /// True if the lifetime is neither None or ExplicitNone. - bool hasNonTrivialObjCLifetime() const { - ObjCLifetime lifetime = getObjCLifetime(); - return (lifetime > OCL_ExplicitNone); - } - - /// True if the lifetime is either strong or weak. - bool hasStrongOrWeakObjCLifetime() const { - ObjCLifetime lifetime = getObjCLifetime(); - return (lifetime == OCL_Strong || lifetime == OCL_Weak); - } - - bool hasAddressSpace() const { return Mask & AddressSpaceMask; } - LangAS getAddressSpace() const { - return static_cast((Mask & AddressSpaceMask) >> AddressSpaceShift); - } - bool hasTargetSpecificAddressSpace() const { - return isTargetAddressSpace(getAddressSpace()); - } - /// Get the address space attribute value to be printed by diagnostics. - unsigned getAddressSpaceAttributePrintValue() const { - auto Addr = getAddressSpace(); - // This function is not supposed to be used with language specific - // address spaces. If that happens, the diagnostic message should consider - // printing the QualType instead of the address space value. - assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); - if (Addr != LangAS::Default) - return toTargetAddressSpace(Addr); - // TODO: The diagnostic messages where Addr may be 0 should be fixed - // since it cannot differentiate the situation where 0 denotes the default - // address space or user specified __attribute__((address_space(0))). - return 0; - } - void setAddressSpace(LangAS space) { - assert((unsigned)space <= MaxAddressSpace); - Mask = (Mask & ~AddressSpaceMask) - | (((uint32_t) space) << AddressSpaceShift); - } - void removeAddressSpace() { setAddressSpace(LangAS::Default); } - void addAddressSpace(LangAS space) { - assert(space != LangAS::Default); - setAddressSpace(space); - } - - bool hasPointerAuth() const { return Mask & PtrAuthMask; } - PointerAuthQualifier getPointerAuth() const { - return PointerAuthQualifier::fromOpaqueValue(Mask >> PtrAuthShift); - } - void setPointerAuth(PointerAuthQualifier Q) { - Mask = (Mask & ~PtrAuthMask) | - (uint64_t(Q.getAsOpaqueValue()) << PtrAuthShift); - } - void removePointerAuth() { Mask &= ~PtrAuthMask; } - void addPointerAuth(PointerAuthQualifier Q) { - assert(Q.isPresent()); - setPointerAuth(Q); - } - - // Fast qualifiers are those that can be allocated directly - // on a QualType object. - bool hasFastQualifiers() const { return getFastQualifiers(); } - unsigned getFastQualifiers() const { return Mask & FastMask; } - void setFastQualifiers(unsigned mask) { - assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); - Mask = (Mask & ~FastMask) | mask; - } - void removeFastQualifiers(unsigned mask) { - assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); - Mask &= ~static_cast(mask); - } - void removeFastQualifiers() { - removeFastQualifiers(FastMask); - } - void addFastQualifiers(unsigned mask) { - assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); - Mask |= mask; - } - - /// Return true if the set contains any qualifiers which require an ExtQuals - /// node to be allocated. - bool hasNonFastQualifiers() const { return Mask & ~FastMask; } - Qualifiers getNonFastQualifiers() const { - Qualifiers Quals = *this; - Quals.setFastQualifiers(0); - return Quals; - } - - /// Return true if the set contains any qualifiers. - bool hasQualifiers() const { return Mask; } - bool empty() const { return !Mask; } - - /// Add the qualifiers from the given set to this set. - void addQualifiers(Qualifiers Q) { - // If the other set doesn't have any non-boolean qualifiers, just - // bit-or it in. - if (!(Q.Mask & ~CVRMask)) - Mask |= Q.Mask; - else { - Mask |= (Q.Mask & CVRMask); - if (Q.hasAddressSpace()) - addAddressSpace(Q.getAddressSpace()); - if (Q.hasObjCGCAttr()) - addObjCGCAttr(Q.getObjCGCAttr()); - if (Q.hasObjCLifetime()) - addObjCLifetime(Q.getObjCLifetime()); - if (Q.hasPointerAuth()) - addPointerAuth(Q.getPointerAuth()); - } - } - - /// Remove the qualifiers from the given set from this set. - void removeQualifiers(Qualifiers Q) { - // If the other set doesn't have any non-boolean qualifiers, just - // bit-and the inverse in. - if (!(Q.Mask & ~CVRMask)) - Mask &= ~Q.Mask; - else { - Mask &= ~(Q.Mask & CVRMask); - if (getObjCGCAttr() == Q.getObjCGCAttr()) - removeObjCGCAttr(); - if (getObjCLifetime() == Q.getObjCLifetime()) - removeObjCLifetime(); - if (getAddressSpace() == Q.getAddressSpace()) - removeAddressSpace(); - if (getPointerAuth() == Q.getPointerAuth()) - removePointerAuth(); - } - } - - /// Add the qualifiers from the given set to this set, given that - /// they don't conflict. - void addConsistentQualifiers(Qualifiers qs) { - assert(getAddressSpace() == qs.getAddressSpace() || - !hasAddressSpace() || !qs.hasAddressSpace()); - assert(getObjCGCAttr() == qs.getObjCGCAttr() || - !hasObjCGCAttr() || !qs.hasObjCGCAttr()); - assert(getObjCLifetime() == qs.getObjCLifetime() || - !hasObjCLifetime() || !qs.hasObjCLifetime()); - assert(!hasPointerAuth() || !qs.hasPointerAuth() || - getPointerAuth() == qs.getPointerAuth()); - Mask |= qs.Mask; - } - - /// Returns true if address space A is equal to or a superset of B. - /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of - /// overlapping address spaces. - /// CL1.1 or CL1.2: - /// every address space is a superset of itself. - /// CL2.0 adds: - /// __generic is a superset of any address space except for __constant. - static bool isAddressSpaceSupersetOf(LangAS A, LangAS B, - const ASTContext &Ctx) { - // Address spaces must match exactly. - return A == B || isTargetAddressSpaceSupersetOf(A, B, Ctx); - } - - static bool isTargetAddressSpaceSupersetOf(LangAS A, LangAS B, - const ASTContext &Ctx); - - /// Returns true if the address space in these qualifiers is equal to or - /// a superset of the address space in the argument qualifiers. - bool isAddressSpaceSupersetOf(Qualifiers other, const ASTContext &Ctx) const { - return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(), - Ctx); - } - - /// Determines if these qualifiers compatibly include another set. - /// Generally this answers the question of whether an object with the other - /// qualifiers can be safely used as an object with these qualifiers. - bool compatiblyIncludes(Qualifiers other, const ASTContext &Ctx) const { - return isAddressSpaceSupersetOf(other, Ctx) && - // ObjC GC qualifiers can match, be added, or be removed, but can't - // be changed. - (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || - !other.hasObjCGCAttr()) && - // Pointer-auth qualifiers must match exactly. - getPointerAuth() == other.getPointerAuth() && - // ObjC lifetime qualifiers must match exactly. - getObjCLifetime() == other.getObjCLifetime() && - // CVR qualifiers may subset. - (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) && - // U qualifier may superset. - (!other.hasUnaligned() || hasUnaligned()); - } - - /// Determines if these qualifiers compatibly include another set of - /// qualifiers from the narrow perspective of Objective-C ARC lifetime. - /// - /// One set of Objective-C lifetime qualifiers compatibly includes the other - /// if the lifetime qualifiers match, or if both are non-__weak and the - /// including set also contains the 'const' qualifier, or both are non-__weak - /// and one is None (which can only happen in non-ARC modes). - bool compatiblyIncludesObjCLifetime(Qualifiers other) const { - if (getObjCLifetime() == other.getObjCLifetime()) - return true; - - if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) - return false; - - if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None) - return true; - - return hasConst(); - } - - /// Determine whether this set of qualifiers is a strict superset of - /// another set of qualifiers, not considering qualifier compatibility. - bool isStrictSupersetOf(Qualifiers Other) const; - - bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } - bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } - - explicit operator bool() const { return hasQualifiers(); } - - Qualifiers &operator+=(Qualifiers R) { - addQualifiers(R); - return *this; - } - - // Union two qualifier sets. If an enumerated qualifier appears - // in both sets, use the one from the right. - friend Qualifiers operator+(Qualifiers L, Qualifiers R) { - L += R; - return L; - } - - Qualifiers &operator-=(Qualifiers R) { - removeQualifiers(R); - return *this; - } - - /// Compute the difference between two qualifier sets. - friend Qualifiers operator-(Qualifiers L, Qualifiers R) { - L -= R; - return L; - } - - std::string getAsString() const; - std::string getAsString(const PrintingPolicy &Policy) const; - - static std::string getAddrSpaceAsString(LangAS AS); - - bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; - void print(raw_ostream &OS, const PrintingPolicy &Policy, - bool appendSpaceIfNonEmpty = false) const; - - void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } - -private: - // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|32 ... 63| - // |C R V|U|GCAttr|Lifetime|AddressSpace| PtrAuth | - uint64_t Mask = 0; - static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t), - "PointerAuthQualifier must be 32 bits"); - - static constexpr uint64_t PtrAuthShift = 32; - static constexpr uint64_t PtrAuthMask = UINT64_C(0xffffffff) << PtrAuthShift; - - static constexpr uint64_t UMask = 0x8; - static constexpr uint64_t UShift = 3; - static constexpr uint64_t GCAttrMask = 0x30; - static constexpr uint64_t GCAttrShift = 4; - static constexpr uint64_t LifetimeMask = 0x1C0; - static constexpr uint64_t LifetimeShift = 6; - static constexpr uint64_t AddressSpaceMask = - ~(CVRMask | UMask | GCAttrMask | LifetimeMask | PtrAuthMask); - static constexpr uint64_t AddressSpaceShift = 9; -}; - -class QualifiersAndAtomic { - Qualifiers Quals; - bool HasAtomic; - -public: - QualifiersAndAtomic() : HasAtomic(false) {} - QualifiersAndAtomic(Qualifiers Quals, bool HasAtomic) - : Quals(Quals), HasAtomic(HasAtomic) {} - - operator Qualifiers() const { return Quals; } - - bool hasVolatile() const { return Quals.hasVolatile(); } - bool hasConst() const { return Quals.hasConst(); } - bool hasRestrict() const { return Quals.hasRestrict(); } - bool hasAtomic() const { return HasAtomic; } - - void addVolatile() { Quals.addVolatile(); } - void addConst() { Quals.addConst(); } - void addRestrict() { Quals.addRestrict(); } - void addAtomic() { HasAtomic = true; } - - void removeVolatile() { Quals.removeVolatile(); } - void removeConst() { Quals.removeConst(); } - void removeRestrict() { Quals.removeRestrict(); } - void removeAtomic() { HasAtomic = false; } - - QualifiersAndAtomic withVolatile() { - return {Quals.withVolatile(), HasAtomic}; - } - QualifiersAndAtomic withConst() { return {Quals.withConst(), HasAtomic}; } - QualifiersAndAtomic withRestrict() { - return {Quals.withRestrict(), HasAtomic}; - } - QualifiersAndAtomic withAtomic() { return {Quals, true}; } - - QualifiersAndAtomic &operator+=(Qualifiers RHS) { - Quals += RHS; - return *this; - } -}; - -/// A std::pair-like structure for storing a qualified type split -/// into its local qualifiers and its locally-unqualified type. -struct SplitQualType { - /// The locally-unqualified type. - const Type *Ty = nullptr; - - /// The local qualifiers. - Qualifiers Quals; - - SplitQualType() = default; - SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} - - SplitQualType getSingleStepDesugaredType() const; // end of this file - - // Make std::tie work. - std::pair asPair() const { - return std::pair(Ty, Quals); - } - - friend bool operator==(SplitQualType a, SplitQualType b) { - return a.Ty == b.Ty && a.Quals == b.Quals; - } - friend bool operator!=(SplitQualType a, SplitQualType b) { - return a.Ty != b.Ty || a.Quals != b.Quals; - } -}; - -/// The kind of type we are substituting Objective-C type arguments into. -/// -/// The kind of substitution affects the replacement of type parameters when -/// no concrete type information is provided, e.g., when dealing with an -/// unspecialized type. -enum class ObjCSubstitutionContext { - /// An ordinary type. - Ordinary, - - /// The result type of a method or function. - Result, - - /// The parameter type of a method or function. - Parameter, - - /// The type of a property. - Property, - - /// The superclass of a type. - Superclass, -}; - -/// The kind of 'typeof' expression we're after. -enum class TypeOfKind : uint8_t { - Qualified, - Unqualified, -}; - -/// A (possibly-)qualified type. -/// -/// For efficiency, we don't store CV-qualified types as nodes on their -/// own: instead each reference to a type stores the qualifiers. This -/// greatly reduces the number of nodes we need to allocate for types (for -/// example we only need one for 'int', 'const int', 'volatile int', -/// 'const volatile int', etc). -/// -/// As an added efficiency bonus, instead of making this a pair, we -/// just store the two bits we care about in the low bits of the -/// pointer. To handle the packing/unpacking, we make QualType be a -/// simple wrapper class that acts like a smart pointer. A third bit -/// indicates whether there are extended qualifiers present, in which -/// case the pointer points to a special structure. -class QualType { - friend class QualifierCollector; - - // Thankfully, these are efficiently composable. - llvm::PointerIntPair, - Qualifiers::FastWidth> Value; - - const ExtQuals *getExtQualsUnsafe() const { - return cast(Value.getPointer()); - } - - const Type *getTypePtrUnsafe() const { - return cast(Value.getPointer()); - } - - const ExtQualsTypeCommonBase *getCommonPtr() const { - assert(!isNull() && "Cannot retrieve a NULL type pointer"); - auto CommonPtrVal = reinterpret_cast(Value.getOpaqueValue()); - CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); - return reinterpret_cast(CommonPtrVal); - } - -public: - QualType() = default; - QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} - QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {} - - unsigned getLocalFastQualifiers() const { return Value.getInt(); } - void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } - - bool UseExcessPrecision(const ASTContext &Ctx); - - /// Retrieves a pointer to the underlying (unqualified) type. - /// - /// This function requires that the type not be NULL. If the type might be - /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). - const Type *getTypePtr() const; - - const Type *getTypePtrOrNull() const; - - /// Retrieves a pointer to the name of the base type. - const IdentifierInfo *getBaseTypeIdentifier() const; - - /// Divides a QualType into its unqualified type and a set of local - /// qualifiers. - SplitQualType split() const; - - void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } - - static QualType getFromOpaquePtr(const void *Ptr) { - QualType T; - T.Value.setFromOpaqueValue(const_cast(Ptr)); - return T; - } - - const Type &operator*() const { - return *getTypePtr(); - } - - const Type *operator->() const { - return getTypePtr(); - } - - bool isCanonical() const; - bool isCanonicalAsParam() const; - - /// Return true if this QualType doesn't point to a type yet. - bool isNull() const { - return Value.getPointer().isNull(); - } - - // Determines if a type can form `T&`. - bool isReferenceable() const; - - /// Determine whether this particular QualType instance has the - /// "const" qualifier set, without looking through typedefs that may have - /// added "const" at a different level. - bool isLocalConstQualified() const { - return (getLocalFastQualifiers() & Qualifiers::Const); - } - - /// Determine whether this type is const-qualified. - bool isConstQualified() const; - - enum class NonConstantStorageReason { - MutableField, - NonConstNonReferenceType, - NonTrivialCtor, - NonTrivialDtor, - }; - /// Determine whether instances of this type can be placed in immutable - /// storage. - /// If ExcludeCtor is true, the duration when the object's constructor runs - /// will not be considered. The caller will need to verify that the object is - /// not written to during its construction. ExcludeDtor works similarly. - std::optional - isNonConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, - bool ExcludeDtor); - - bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, - bool ExcludeDtor) { - return !isNonConstantStorage(Ctx, ExcludeCtor, ExcludeDtor); - } - - /// Determine whether this particular QualType instance has the - /// "restrict" qualifier set, without looking through typedefs that may have - /// added "restrict" at a different level. - bool isLocalRestrictQualified() const { - return (getLocalFastQualifiers() & Qualifiers::Restrict); - } - - /// Determine whether this type is restrict-qualified. - bool isRestrictQualified() const; - - /// Determine whether this particular QualType instance has the - /// "volatile" qualifier set, without looking through typedefs that may have - /// added "volatile" at a different level. - bool isLocalVolatileQualified() const { - return (getLocalFastQualifiers() & Qualifiers::Volatile); - } - - /// Determine whether this type is volatile-qualified. - bool isVolatileQualified() const; - - /// Determine whether this particular QualType instance has any - /// qualifiers, without looking through any typedefs that might add - /// qualifiers at a different level. - bool hasLocalQualifiers() const { - return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); - } - - /// Determine whether this type has any qualifiers. - bool hasQualifiers() const; - - /// Determine whether this particular QualType instance has any - /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType - /// instance. - bool hasLocalNonFastQualifiers() const { - return isa(Value.getPointer()); - } - - /// Retrieve the set of qualifiers local to this particular QualType - /// instance, not including any qualifiers acquired through typedefs or - /// other sugar. - Qualifiers getLocalQualifiers() const; - - /// Retrieve the set of qualifiers applied to this type. - Qualifiers getQualifiers() const; - - /// Retrieve the set of CVR (const-volatile-restrict) qualifiers - /// local to this particular QualType instance, not including any qualifiers - /// acquired through typedefs or other sugar. - unsigned getLocalCVRQualifiers() const { - return getLocalFastQualifiers(); - } - - /// Retrieve the set of CVR (const-volatile-restrict) qualifiers - /// applied to this type. - unsigned getCVRQualifiers() const; - - bool isConstant(const ASTContext& Ctx) const { - return QualType::isConstant(*this, Ctx); - } - - /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). - bool isPODType(const ASTContext &Context) const; - - /// Return true if this is a POD type according to the rules of the C++98 - /// standard, regardless of the current compilation's language. - bool isCXX98PODType(const ASTContext &Context) const; - - /// Return true if this is a POD type according to the more relaxed rules - /// of the C++11 standard, regardless of the current compilation's language. - /// (C++0x [basic.types]p9). Note that, unlike - /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account. - bool isCXX11PODType(const ASTContext &Context) const; - - /// Return true if this is a trivial type per (C++0x [basic.types]p9) - bool isTrivialType(const ASTContext &Context) const; - - /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) - bool isTriviallyCopyableType(const ASTContext &Context) const; - - /// Return true if the type is safe to bitwise copy using memcpy/memmove. - /// - /// This is an extension in clang: bitwise cloneable types act as trivially - /// copyable types, meaning their underlying bytes can be safely copied by - /// memcpy or memmove. After the copy, the destination object has the same - /// object representation. - /// - /// However, there are cases where it is not safe to copy: - /// - When sanitizers, such as AddressSanitizer, add padding with poison, - /// which can cause issues if those poisoned padding bits are accessed. - /// - Types with Objective-C lifetimes, where specific runtime - /// semantics may not be preserved during a bitwise copy. - bool isBitwiseCloneableType(const ASTContext &Context) const; - - /// Return true if this is a trivially copyable type - bool isTriviallyCopyConstructibleType(const ASTContext &Context) const; - - /// Returns true if it is a class and it might be dynamic. - bool mayBeDynamicClass() const; - - /// Returns true if it is not a class or if the class might not be dynamic. - bool mayBeNotDynamicClass() const; - - /// Returns true if it is a WebAssembly Reference Type. - bool isWebAssemblyReferenceType() const; - - /// Returns true if it is a WebAssembly Externref Type. - bool isWebAssemblyExternrefType() const; - - /// Returns true if it is a WebAssembly Funcref Type. - bool isWebAssemblyFuncrefType() const; - - // Don't promise in the API that anything besides 'const' can be - // easily added. - - /// Add the `const` type qualifier to this QualType. - void addConst() { - addFastQualifiers(Qualifiers::Const); - } - QualType withConst() const { - return withFastQualifiers(Qualifiers::Const); - } - - /// Add the `volatile` type qualifier to this QualType. - void addVolatile() { - addFastQualifiers(Qualifiers::Volatile); - } - QualType withVolatile() const { - return withFastQualifiers(Qualifiers::Volatile); - } - - /// Add the `restrict` qualifier to this QualType. - void addRestrict() { - addFastQualifiers(Qualifiers::Restrict); - } - QualType withRestrict() const { - return withFastQualifiers(Qualifiers::Restrict); - } - - QualType withCVRQualifiers(unsigned CVR) const { - return withFastQualifiers(CVR); - } - - void addFastQualifiers(unsigned TQs) { - assert(!(TQs & ~Qualifiers::FastMask) - && "non-fast qualifier bits set in mask!"); - Value.setInt(Value.getInt() | TQs); - } - - void removeLocalConst(); - void removeLocalVolatile(); - void removeLocalRestrict(); - - void removeLocalFastQualifiers() { Value.setInt(0); } - void removeLocalFastQualifiers(unsigned Mask) { - assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); - Value.setInt(Value.getInt() & ~Mask); - } - - // Creates a type with the given qualifiers in addition to any - // qualifiers already on this type. - QualType withFastQualifiers(unsigned TQs) const { - QualType T = *this; - T.addFastQualifiers(TQs); - return T; - } - - // Creates a type with exactly the given fast qualifiers, removing - // any existing fast qualifiers. - QualType withExactLocalFastQualifiers(unsigned TQs) const { - return withoutLocalFastQualifiers().withFastQualifiers(TQs); - } - - // Removes fast qualifiers, but leaves any extended qualifiers in place. - QualType withoutLocalFastQualifiers() const { - QualType T = *this; - T.removeLocalFastQualifiers(); - return T; - } - - QualType getCanonicalType() const; - - /// Return this type with all of the instance-specific qualifiers - /// removed, but without removing any qualifiers that may have been applied - /// through typedefs. - QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } - - /// Retrieve the unqualified variant of the given type, - /// removing as little sugar as possible. - /// - /// This routine looks through various kinds of sugar to find the - /// least-desugared type that is unqualified. For example, given: - /// - /// \code - /// typedef int Integer; - /// typedef const Integer CInteger; - /// typedef CInteger DifferenceType; - /// \endcode - /// - /// Executing \c getUnqualifiedType() on the type \c DifferenceType will - /// desugar until we hit the type \c Integer, which has no qualifiers on it. - /// - /// The resulting type might still be qualified if it's sugar for an array - /// type. To strip qualifiers even from within a sugared array type, use - /// ASTContext::getUnqualifiedArrayType. - /// - /// Note: In C, the _Atomic qualifier is special (see C23 6.2.5p32 for - /// details), and it is not stripped by this function. Use - /// getAtomicUnqualifiedType() to strip qualifiers including _Atomic. - inline QualType getUnqualifiedType() const; - - /// Retrieve the unqualified variant of the given type, removing as little - /// sugar as possible. - /// - /// Like getUnqualifiedType(), but also returns the set of - /// qualifiers that were built up. - /// - /// The resulting type might still be qualified if it's sugar for an array - /// type. To strip qualifiers even from within a sugared array type, use - /// ASTContext::getUnqualifiedArrayType. - inline SplitQualType getSplitUnqualifiedType() const; - - /// Determine whether this type is more qualified than the other - /// given type, requiring exact equality for non-CVR qualifiers. - bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const; - - /// Determine whether this type is at least as qualified as the other - /// given type, requiring exact equality for non-CVR qualifiers. - bool isAtLeastAsQualifiedAs(QualType Other, const ASTContext &Ctx) const; - - QualType getNonReferenceType() const; - - /// Determine the type of a (typically non-lvalue) expression with the - /// specified result type. - /// - /// This routine should be used for expressions for which the return type is - /// explicitly specified (e.g., in a cast or call) and isn't necessarily - /// an lvalue. It removes a top-level reference (since there are no - /// expressions of reference type) and deletes top-level cvr-qualifiers - /// from non-class types (in C++) or all types (in C). - QualType getNonLValueExprType(const ASTContext &Context) const; - - /// Remove an outer pack expansion type (if any) from this type. Used as part - /// of converting the type of a declaration to the type of an expression that - /// references that expression. It's meaningless for an expression to have a - /// pack expansion type. - QualType getNonPackExpansionType() const; - - /// Return the specified type with any "sugar" removed from - /// the type. This takes off typedefs, typeof's etc. If the outer level of - /// the type is already concrete, it returns it unmodified. This is similar - /// to getting the canonical type, but it doesn't remove *all* typedefs. For - /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is - /// concrete. - /// - /// Qualifiers are left in place. - QualType getDesugaredType(const ASTContext &Context) const { - return getDesugaredType(*this, Context); - } - - SplitQualType getSplitDesugaredType() const { - return getSplitDesugaredType(*this); - } - - /// Return the specified type with one level of "sugar" removed from - /// the type. - /// - /// This routine takes off the first typedef, typeof, etc. If the outer level - /// of the type is already concrete, it returns it unmodified. - QualType getSingleStepDesugaredType(const ASTContext &Context) const { - return getSingleStepDesugaredTypeImpl(*this, Context); - } - - /// Returns the specified type after dropping any - /// outer-level parentheses. - QualType IgnoreParens() const { - if (isa(*this)) - return QualType::IgnoreParens(*this); - return *this; - } - - /// Indicate whether the specified types and qualifiers are identical. - friend bool operator==(const QualType &LHS, const QualType &RHS) { - return LHS.Value == RHS.Value; - } - friend bool operator!=(const QualType &LHS, const QualType &RHS) { - return LHS.Value != RHS.Value; - } - friend bool operator<(const QualType &LHS, const QualType &RHS) { - return LHS.Value < RHS.Value; - } - - static std::string getAsString(SplitQualType split, - const PrintingPolicy &Policy) { - return getAsString(split.Ty, split.Quals, Policy); - } - static std::string getAsString(const Type *ty, Qualifiers qs, - const PrintingPolicy &Policy); - - std::string getAsString() const; - std::string getAsString(const PrintingPolicy &Policy) const; - - void print(raw_ostream &OS, const PrintingPolicy &Policy, - const Twine &PlaceHolder = Twine(), - unsigned Indentation = 0) const; - - static void print(SplitQualType split, raw_ostream &OS, - const PrintingPolicy &policy, const Twine &PlaceHolder, - unsigned Indentation = 0) { - return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); - } - - static void print(const Type *ty, Qualifiers qs, - raw_ostream &OS, const PrintingPolicy &policy, - const Twine &PlaceHolder, - unsigned Indentation = 0); - - void getAsStringInternal(std::string &Str, - const PrintingPolicy &Policy) const; - - static void getAsStringInternal(SplitQualType split, std::string &out, - const PrintingPolicy &policy) { - return getAsStringInternal(split.Ty, split.Quals, out, policy); - } - - static void getAsStringInternal(const Type *ty, Qualifiers qs, - std::string &out, - const PrintingPolicy &policy); - - class StreamedQualTypeHelper { - const QualType &T; - const PrintingPolicy &Policy; - const Twine &PlaceHolder; - unsigned Indentation; - - public: - StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, - const Twine &PlaceHolder, unsigned Indentation) - : T(T), Policy(Policy), PlaceHolder(PlaceHolder), - Indentation(Indentation) {} - - friend raw_ostream &operator<<(raw_ostream &OS, - const StreamedQualTypeHelper &SQT) { - SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation); - return OS; - } - }; - - StreamedQualTypeHelper stream(const PrintingPolicy &Policy, - const Twine &PlaceHolder = Twine(), - unsigned Indentation = 0) const { - return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation); - } - - void dump(const char *s) const; - void dump() const; - void dump(llvm::raw_ostream &OS, const ASTContext &Context) const; - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(getAsOpaquePtr()); - } - - /// Check if this type has any address space qualifier. - inline bool hasAddressSpace() const; - - /// Return the address space of this type. - inline LangAS getAddressSpace() const; - - /// Returns true if address space qualifiers overlap with T address space - /// qualifiers. - /// OpenCL C defines conversion rules for pointers to different address spaces - /// and notion of overlapping address spaces. - /// CL1.1 or CL1.2: - /// address spaces overlap iff they are they same. - /// OpenCL C v2.0 s6.5.5 adds: - /// __generic overlaps with any address space except for __constant. - bool isAddressSpaceOverlapping(QualType T, const ASTContext &Ctx) const { - Qualifiers Q = getQualifiers(); - Qualifiers TQ = T.getQualifiers(); - // Address spaces overlap if at least one of them is a superset of another - return Q.isAddressSpaceSupersetOf(TQ, Ctx) || - TQ.isAddressSpaceSupersetOf(Q, Ctx); - } - - /// Returns gc attribute of this type. - inline Qualifiers::GC getObjCGCAttr() const; - - /// true when Type is objc's weak. - bool isObjCGCWeak() const { - return getObjCGCAttr() == Qualifiers::Weak; - } - - /// true when Type is objc's strong. - bool isObjCGCStrong() const { - return getObjCGCAttr() == Qualifiers::Strong; - } - - /// Returns lifetime attribute of this type. - Qualifiers::ObjCLifetime getObjCLifetime() const { - return getQualifiers().getObjCLifetime(); - } - - bool hasNonTrivialObjCLifetime() const { - return getQualifiers().hasNonTrivialObjCLifetime(); - } - - bool hasStrongOrWeakObjCLifetime() const { - return getQualifiers().hasStrongOrWeakObjCLifetime(); - } - - // true when Type is objc's weak and weak is enabled but ARC isn't. - bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; - - PointerAuthQualifier getPointerAuth() const { - return getQualifiers().getPointerAuth(); - } - - bool hasAddressDiscriminatedPointerAuth() const { - if (PointerAuthQualifier PtrAuth = getPointerAuth()) - return PtrAuth.isAddressDiscriminated(); - return false; - } - - enum PrimitiveDefaultInitializeKind { - /// The type does not fall into any of the following categories. Note that - /// this case is zero-valued so that values of this enum can be used as a - /// boolean condition for non-triviality. - PDIK_Trivial, - - /// The type is an Objective-C retainable pointer type that is qualified - /// with the ARC __strong qualifier. - PDIK_ARCStrong, - - /// The type is an Objective-C retainable pointer type that is qualified - /// with the ARC __weak qualifier. - PDIK_ARCWeak, - - /// The type is a struct containing a field whose type is not PCK_Trivial. - PDIK_Struct - }; - - /// Functions to query basic properties of non-trivial C struct types. - - /// Check if this is a non-trivial type that would cause a C struct - /// transitively containing this type to be non-trivial to default initialize - /// and return the kind. - PrimitiveDefaultInitializeKind - isNonTrivialToPrimitiveDefaultInitialize() const; - - enum PrimitiveCopyKind { - /// The type does not fall into any of the following categories. Note that - /// this case is zero-valued so that values of this enum can be used as a - /// boolean condition for non-triviality. - PCK_Trivial, - - /// The type would be trivial except that it is volatile-qualified. Types - /// that fall into one of the other non-trivial cases may additionally be - /// volatile-qualified. - PCK_VolatileTrivial, - - /// The type is an Objective-C retainable pointer type that is qualified - /// with the ARC __strong qualifier. - PCK_ARCStrong, - - /// The type is an Objective-C retainable pointer type that is qualified - /// with the ARC __weak qualifier. - PCK_ARCWeak, - - /// The type is an address-discriminated signed pointer type. - PCK_PtrAuth, - - /// The type is a struct containing a field whose type is neither - /// PCK_Trivial nor PCK_VolatileTrivial. - /// Note that a C++ struct type does not necessarily match this; C++ copying - /// semantics are too complex to express here, in part because they depend - /// on the exact constructor or assignment operator that is chosen by - /// overload resolution to do the copy. - PCK_Struct - }; - - /// Check if this is a non-trivial type that would cause a C struct - /// transitively containing this type to be non-trivial to copy and return the - /// kind. - PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const; - - /// Check if this is a non-trivial type that would cause a C struct - /// transitively containing this type to be non-trivial to destructively - /// move and return the kind. Destructive move in this context is a C++-style - /// move in which the source object is placed in a valid but unspecified state - /// after it is moved, as opposed to a truly destructive move in which the - /// source object is placed in an uninitialized state. - PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const; - - enum DestructionKind { - DK_none, - DK_cxx_destructor, - DK_objc_strong_lifetime, - DK_objc_weak_lifetime, - DK_nontrivial_c_struct - }; - - /// Returns a nonzero value if objects of this type require - /// non-trivial work to clean up after. Non-zero because it's - /// conceivable that qualifiers (objc_gc(weak)?) could make - /// something require destruction. - DestructionKind isDestructedType() const { - return isDestructedTypeImpl(*this); - } - - /// Check if this is or contains a C union that is non-trivial to - /// default-initialize, which is a union that has a member that is non-trivial - /// to default-initialize. If this returns true, - /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct. - bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const; - - /// Check if this is or contains a C union that is non-trivial to destruct, - /// which is a union that has a member that is non-trivial to destruct. If - /// this returns true, isDestructedType returns DK_nontrivial_c_struct. - bool hasNonTrivialToPrimitiveDestructCUnion() const; - - /// Check if this is or contains a C union that is non-trivial to copy, which - /// is a union that has a member that is non-trivial to copy. If this returns - /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct. - bool hasNonTrivialToPrimitiveCopyCUnion() const; - - /// Determine whether expressions of the given type are forbidden - /// from being lvalues in C. - /// - /// The expression types that are forbidden to be lvalues are: - /// - 'void', but not qualified void - /// - function types - /// - /// The exact rule here is C99 6.3.2.1: - /// An lvalue is an expression with an object type or an incomplete - /// type other than void. - bool isCForbiddenLValueType() const; - - /// Substitute type arguments for the Objective-C type parameters used in the - /// subject type. - /// - /// \param ctx ASTContext in which the type exists. - /// - /// \param typeArgs The type arguments that will be substituted for the - /// Objective-C type parameters in the subject type, which are generally - /// computed via \c Type::getObjCSubstitutions. If empty, the type - /// parameters will be replaced with their bounds or id/Class, as appropriate - /// for the context. - /// - /// \param context The context in which the subject type was written. - /// - /// \returns the resulting type. - QualType substObjCTypeArgs(ASTContext &ctx, - ArrayRef typeArgs, - ObjCSubstitutionContext context) const; - - /// Substitute type arguments from an object type for the Objective-C type - /// parameters used in the subject type. - /// - /// This operation combines the computation of type arguments for - /// substitution (\c Type::getObjCSubstitutions) with the actual process of - /// substitution (\c QualType::substObjCTypeArgs) for the convenience of - /// callers that need to perform a single substitution in isolation. - /// - /// \param objectType The type of the object whose member type we're - /// substituting into. For example, this might be the receiver of a message - /// or the base of a property access. - /// - /// \param dc The declaration context from which the subject type was - /// retrieved, which indicates (for example) which type parameters should - /// be substituted. - /// - /// \param context The context in which the subject type was written. - /// - /// \returns the subject type after replacing all of the Objective-C type - /// parameters with their corresponding arguments. - QualType substObjCMemberType(QualType objectType, - const DeclContext *dc, - ObjCSubstitutionContext context) const; - - /// Strip Objective-C "__kindof" types from the given type. - QualType stripObjCKindOfType(const ASTContext &ctx) const; - - /// Remove all qualifiers including _Atomic. - /// - /// Like getUnqualifiedType(), the type may still be qualified if it is a - /// sugared array type. To strip qualifiers even from within a sugared array - /// type, use in conjunction with ASTContext::getUnqualifiedArrayType. - QualType getAtomicUnqualifiedType() const; - -private: - // These methods are implemented in a separate translation unit; - // "static"-ize them to avoid creating temporary QualTypes in the - // caller. - static bool isConstant(QualType T, const ASTContext& Ctx); - static QualType getDesugaredType(QualType T, const ASTContext &Context); - static SplitQualType getSplitDesugaredType(QualType T); - static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); - static QualType getSingleStepDesugaredTypeImpl(QualType type, - const ASTContext &C); - static QualType IgnoreParens(QualType T); - static DestructionKind isDestructedTypeImpl(QualType type); - - /// Check if \param RD is or contains a non-trivial C union. - static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD); - static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD); - static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD); -}; - -raw_ostream &operator<<(raw_ostream &OS, QualType QT); - -} // namespace clang - -namespace llvm { - -/// Implement simplify_type for QualType, so that we can dyn_cast from QualType -/// to a specific Type class. -template<> struct simplify_type< ::clang::QualType> { - using SimpleType = const ::clang::Type *; - - static SimpleType getSimplifiedValue(::clang::QualType Val) { - return Val.getTypePtr(); - } -}; - -// Teach SmallPtrSet that QualType is "basically a pointer". -template<> -struct PointerLikeTypeTraits { - static inline void *getAsVoidPointer(clang::QualType P) { - return P.getAsOpaquePtr(); - } - - static inline clang::QualType getFromVoidPointer(void *P) { - return clang::QualType::getFromOpaquePtr(P); - } - - // Various qualifiers go in low bits. - static constexpr int NumLowBitsAvailable = 0; -}; - -} // namespace llvm - -namespace clang { - -/// Base class that is common to both the \c ExtQuals and \c Type -/// classes, which allows \c QualType to access the common fields between the -/// two. -class ExtQualsTypeCommonBase { - friend class ExtQuals; - friend class QualType; - friend class Type; - friend class ASTReader; - - /// The "base" type of an extended qualifiers type (\c ExtQuals) or - /// a self-referential pointer (for \c Type). - /// - /// This pointer allows an efficient mapping from a QualType to its - /// underlying type pointer. - const Type *const BaseType; - - /// The canonical type of this type. A QualType. - QualType CanonicalType; - - ExtQualsTypeCommonBase(const Type *baseType, QualType canon) - : BaseType(baseType), CanonicalType(canon) {} -}; - -/// We can encode up to four bits in the low bits of a -/// type pointer, but there are many more type qualifiers that we want -/// to be able to apply to an arbitrary type. Therefore we have this -/// struct, intended to be heap-allocated and used by QualType to -/// store qualifiers. -/// -/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers -/// in three low bits on the QualType pointer; a fourth bit records whether -/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, -/// Objective-C GC attributes) are much more rare. -class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase, - public llvm::FoldingSetNode { - // NOTE: changing the fast qualifiers should be straightforward as - // long as you don't make 'const' non-fast. - // 1. Qualifiers: - // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). - // Fast qualifiers must occupy the low-order bits. - // b) Update Qualifiers::FastWidth and FastMask. - // 2. QualType: - // a) Update is{Volatile,Restrict}Qualified(), defined inline. - // b) Update remove{Volatile,Restrict}, defined near the end of - // this header. - // 3. ASTContext: - // a) Update get{Volatile,Restrict}Type. - - /// The immutable set of qualifiers applied by this node. Always contains - /// extended qualifiers. - Qualifiers Quals; - - ExtQuals *this_() { return this; } - -public: - ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) - : ExtQualsTypeCommonBase(baseType, - canon.isNull() ? QualType(this_(), 0) : canon), - Quals(quals) { - assert(Quals.hasNonFastQualifiers() - && "ExtQuals created with no fast qualifiers"); - assert(!Quals.hasFastQualifiers() - && "ExtQuals created with fast qualifiers"); - } - - Qualifiers getQualifiers() const { return Quals; } - - bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } - Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } - - bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } - Qualifiers::ObjCLifetime getObjCLifetime() const { - return Quals.getObjCLifetime(); - } - - bool hasAddressSpace() const { return Quals.hasAddressSpace(); } - LangAS getAddressSpace() const { return Quals.getAddressSpace(); } - - const Type *getBaseType() const { return BaseType; } - -public: - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getBaseType(), Quals); - } - - static void Profile(llvm::FoldingSetNodeID &ID, - const Type *BaseType, - Qualifiers Quals) { - assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); - ID.AddPointer(BaseType); - Quals.Profile(ID); - } -}; - -/// The kind of C++11 ref-qualifier associated with a function type. -/// This determines whether a member function's "this" object can be an -/// lvalue, rvalue, or neither. -enum RefQualifierKind { - /// No ref-qualifier was provided. - RQ_None = 0, - - /// An lvalue ref-qualifier was provided (\c &). - RQ_LValue, - - /// An rvalue ref-qualifier was provided (\c &&). - RQ_RValue -}; - -/// Which keyword(s) were used to create an AutoType. -enum class AutoTypeKeyword { - /// auto - Auto, - - /// decltype(auto) - DecltypeAuto, - - /// __auto_type (GNU extension) - GNUAutoType -}; - -enum class ArraySizeModifier; -enum class ElaboratedTypeKeyword; -enum class VectorKind; - -/// The base class of the type hierarchy. -/// -/// A central concept with types is that each type always has a canonical -/// type. A canonical type is the type with any typedef names stripped out -/// of it or the types it references. For example, consider: -/// -/// typedef int foo; -/// typedef foo* bar; -/// 'int *' 'foo *' 'bar' -/// -/// There will be a Type object created for 'int'. Since int is canonical, its -/// CanonicalType pointer points to itself. There is also a Type for 'foo' (a -/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next -/// there is a PointerType that represents 'int*', which, like 'int', is -/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical -/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type -/// is also 'int*'. -/// -/// Non-canonical types are useful for emitting diagnostics, without losing -/// information about typedefs being used. Canonical types are useful for type -/// comparisons (they allow by-pointer equality tests) and useful for reasoning -/// about whether something has a particular form (e.g. is a function type), -/// because they implicitly, recursively, strip all typedefs out of a type. -/// -/// Types, once created, are immutable. -/// -class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { -public: - enum TypeClass { -#define TYPE(Class, Base) Class, -#define LAST_TYPE(Class) TypeLast = Class -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.inc" - }; - -private: - /// Bitfields required by the Type class. - class TypeBitfields { - friend class Type; - template friend class TypePropertyCache; - - /// TypeClass bitfield - Enum that specifies what subclass this belongs to. - LLVM_PREFERRED_TYPE(TypeClass) - unsigned TC : 8; - - /// Store information on the type dependency. - LLVM_PREFERRED_TYPE(TypeDependence) - unsigned Dependence : llvm::BitWidth; - - /// True if the cache (i.e. the bitfields here starting with - /// 'Cache') is valid. - LLVM_PREFERRED_TYPE(bool) - mutable unsigned CacheValid : 1; - - /// Linkage of this type. - LLVM_PREFERRED_TYPE(Linkage) - mutable unsigned CachedLinkage : 3; - - /// Whether this type involves and local or unnamed types. - LLVM_PREFERRED_TYPE(bool) - mutable unsigned CachedLocalOrUnnamed : 1; - - /// Whether this type comes from an AST file. - LLVM_PREFERRED_TYPE(bool) - mutable unsigned FromAST : 1; - - bool isCacheValid() const { - return CacheValid; - } - - Linkage getLinkage() const { - assert(isCacheValid() && "getting linkage from invalid cache"); - return static_cast(CachedLinkage); - } - - bool hasLocalOrUnnamedType() const { - assert(isCacheValid() && "getting linkage from invalid cache"); - return CachedLocalOrUnnamed; - } - }; - enum { NumTypeBits = 8 + llvm::BitWidth + 6 }; - -protected: - // These classes allow subclasses to somewhat cleanly pack bitfields - // into Type. - - class ArrayTypeBitfields { - friend class ArrayType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// CVR qualifiers from declarations like - /// 'int X[static restrict 4]'. For function parameters only. - LLVM_PREFERRED_TYPE(Qualifiers) - unsigned IndexTypeQuals : 3; - - /// Storage class qualifiers from declarations like - /// 'int X[static restrict 4]'. For function parameters only. - LLVM_PREFERRED_TYPE(ArraySizeModifier) - unsigned SizeModifier : 3; - }; - enum { NumArrayTypeBits = NumTypeBits + 6 }; - - class ConstantArrayTypeBitfields { - friend class ConstantArrayType; - - LLVM_PREFERRED_TYPE(ArrayTypeBitfields) - unsigned : NumArrayTypeBits; - - /// Whether we have a stored size expression. - LLVM_PREFERRED_TYPE(bool) - unsigned HasExternalSize : 1; - - LLVM_PREFERRED_TYPE(unsigned) - unsigned SizeWidth : 5; - }; - - class BuiltinTypeBitfields { - friend class BuiltinType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The kind (BuiltinType::Kind) of builtin type this is. - static constexpr unsigned NumOfBuiltinTypeBits = 9; - unsigned Kind : NumOfBuiltinTypeBits; - }; - -public: - static constexpr int FunctionTypeNumParamsWidth = 16; - static constexpr int FunctionTypeNumParamsLimit = (1 << 16) - 1; - -protected: - /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. - /// Only common bits are stored here. Additional uncommon bits are stored - /// in a trailing object after FunctionProtoType. - class FunctionTypeBitfields { - friend class FunctionProtoType; - friend class FunctionType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The ref-qualifier associated with a \c FunctionProtoType. - /// - /// This is a value of type \c RefQualifierKind. - LLVM_PREFERRED_TYPE(RefQualifierKind) - unsigned RefQualifier : 2; - - /// Used only by FunctionProtoType, put here to pack with the - /// other bitfields. - /// The qualifiers are part of FunctionProtoType because... - /// - /// C++ 8.3.5p4: The return type, the parameter type list and the - /// cv-qualifier-seq, [...], are part of the function type. - LLVM_PREFERRED_TYPE(Qualifiers) - unsigned FastTypeQuals : Qualifiers::FastWidth; - /// Whether this function has extended Qualifiers. - LLVM_PREFERRED_TYPE(bool) - unsigned HasExtQuals : 1; - - /// The type of exception specification this function has. - LLVM_PREFERRED_TYPE(ExceptionSpecificationType) - unsigned ExceptionSpecType : 4; - - /// Whether this function has extended parameter information. - LLVM_PREFERRED_TYPE(bool) - unsigned HasExtParameterInfos : 1; - - /// Whether this function has extra bitfields for the prototype. - LLVM_PREFERRED_TYPE(bool) - unsigned HasExtraBitfields : 1; - - /// Whether the function is variadic. - LLVM_PREFERRED_TYPE(bool) - unsigned Variadic : 1; - - /// Whether this function has a trailing return type. - LLVM_PREFERRED_TYPE(bool) - unsigned HasTrailingReturn : 1; - - /// Whether this function has is a cfi unchecked callee. - LLVM_PREFERRED_TYPE(bool) - unsigned CFIUncheckedCallee : 1; - - /// Extra information which affects how the function is called, like - /// regparm and the calling convention. - LLVM_PREFERRED_TYPE(CallingConv) - unsigned ExtInfo : 14; - - /// The number of parameters this function has, not counting '...'. - /// According to [implimits] 8 bits should be enough here but this is - /// somewhat easy to exceed with metaprogramming and so we would like to - /// keep NumParams as wide as reasonably possible. - unsigned NumParams : FunctionTypeNumParamsWidth; - }; - - class ObjCObjectTypeBitfields { - friend class ObjCObjectType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The number of type arguments stored directly on this object type. - unsigned NumTypeArgs : 7; - - /// The number of protocols stored directly on this object type. - unsigned NumProtocols : 6; - - /// Whether this is a "kindof" type. - LLVM_PREFERRED_TYPE(bool) - unsigned IsKindOf : 1; - }; - - class ReferenceTypeBitfields { - friend class ReferenceType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// True if the type was originally spelled with an lvalue sigil. - /// This is never true of rvalue references but can also be false - /// on lvalue references because of C++0x [dcl.typedef]p9, - /// as follows: - /// - /// typedef int &ref; // lvalue, spelled lvalue - /// typedef int &&rvref; // rvalue - /// ref &a; // lvalue, inner ref, spelled lvalue - /// ref &&a; // lvalue, inner ref - /// rvref &a; // lvalue, inner ref, spelled lvalue - /// rvref &&a; // rvalue, inner ref - LLVM_PREFERRED_TYPE(bool) - unsigned SpelledAsLValue : 1; - - /// True if the inner type is a reference type. This only happens - /// in non-canonical forms. - LLVM_PREFERRED_TYPE(bool) - unsigned InnerRef : 1; - }; - - class KeywordWrapperBitfields { - template friend class KeywordWrapper; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// An ElaboratedTypeKeyword. 8 bits for efficient access. - LLVM_PREFERRED_TYPE(ElaboratedTypeKeyword) - unsigned Keyword : 8; - }; - - enum { NumTypeWithKeywordBits = NumTypeBits + 8 }; - - class TagTypeBitfields { - friend class TagType; - - LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) - unsigned : NumTypeWithKeywordBits; - - /// Whether the TagType has a trailing Qualifier. - LLVM_PREFERRED_TYPE(bool) - unsigned HasQualifier : 1; - - /// Whether the TagType owns the Tag. - LLVM_PREFERRED_TYPE(bool) - unsigned OwnsTag : 1; - - /// Whether the TagType was created from an injected name. - LLVM_PREFERRED_TYPE(bool) - unsigned IsInjected : 1; - }; - - class VectorTypeBitfields { - friend class VectorType; - friend class DependentVectorType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The kind of vector, either a generic vector type or some - /// target-specific vector type such as for AltiVec or Neon. - LLVM_PREFERRED_TYPE(VectorKind) - unsigned VecKind : 4; - /// The number of elements in the vector. - uint32_t NumElements; - }; - - class AttributedTypeBitfields { - friend class AttributedType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - LLVM_PREFERRED_TYPE(attr::Kind) - unsigned AttrKind : 32 - NumTypeBits; - }; - - class AutoTypeBitfields { - friend class AutoType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// Was this placeholder type spelled as 'auto', 'decltype(auto)', - /// or '__auto_type'? AutoTypeKeyword value. - LLVM_PREFERRED_TYPE(AutoTypeKeyword) - unsigned Keyword : 2; - - /// The number of template arguments in the type-constraints, which is - /// expected to be able to hold at least 1024 according to [implimits]. - /// However as this limit is somewhat easy to hit with template - /// metaprogramming we'd prefer to keep it as large as possible. - /// At the moment it has been left as a non-bitfield since this type - /// safely fits in 64 bits as an unsigned, so there is no reason to - /// introduce the performance impact of a bitfield. - unsigned NumArgs; - }; - - class TypeOfBitfields { - friend class TypeOfType; - friend class TypeOfExprType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - LLVM_PREFERRED_TYPE(TypeOfKind) - unsigned Kind : 1; - }; - - class UnresolvedUsingBitfields { - friend class UnresolvedUsingType; - - LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) - unsigned : NumTypeWithKeywordBits; - - /// True if there is a non-null qualifier. - LLVM_PREFERRED_TYPE(bool) - unsigned hasQualifier : 1; - }; - - class UsingBitfields { - friend class UsingType; - - LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) - unsigned : NumTypeWithKeywordBits; - - /// True if there is a non-null qualifier. - LLVM_PREFERRED_TYPE(bool) - unsigned hasQualifier : 1; - }; - - class TypedefBitfields { - friend class TypedefType; - - LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) - unsigned : NumTypeWithKeywordBits; - - /// True if there is a non-null qualifier. - LLVM_PREFERRED_TYPE(bool) - unsigned hasQualifier : 1; - - /// True if the underlying type is different from the declared one. - LLVM_PREFERRED_TYPE(bool) - unsigned hasTypeDifferentFromDecl : 1; - }; - - class TemplateTypeParmTypeBitfields { - friend class TemplateTypeParmType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The depth of the template parameter. - unsigned Depth : 15; - - /// Whether this is a template parameter pack. - LLVM_PREFERRED_TYPE(bool) - unsigned ParameterPack : 1; - - /// The index of the template parameter. - unsigned Index : 16; - }; - - class SubstTemplateTypeParmTypeBitfields { - friend class SubstTemplateTypeParmType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasNonCanonicalUnderlyingType : 1; - - // The index of the template parameter this substitution represents. - unsigned Index : 15; - - LLVM_PREFERRED_TYPE(bool) - unsigned Final : 1; - - /// Represents the index within a pack if this represents a substitution - /// from a pack expansion. This index starts at the end of the pack and - /// increments towards the beginning. - /// Positive non-zero number represents the index + 1. - /// Zero means this is not substituted from an expansion. - unsigned PackIndex : 15; - }; - - class SubstPackTypeBitfields { - friend class SubstPackType; - friend class SubstTemplateTypeParmPackType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The number of template arguments in \c Arguments, which is - /// expected to be able to hold at least 1024 according to [implimits]. - /// However as this limit is somewhat easy to hit with template - /// metaprogramming we'd prefer to keep it as large as possible. - unsigned NumArgs : 16; - - // The index of the template parameter this substitution represents. - // Only used by SubstTemplateTypeParmPackType. We keep it in the same - // class to avoid dealing with complexities of bitfields that go over - // the size of `unsigned`. - unsigned SubstTemplTypeParmPackIndex : 16; - }; - - class TemplateSpecializationTypeBitfields { - friend class TemplateSpecializationType; - - LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) - unsigned : NumTypeWithKeywordBits; - - /// Whether this template specialization type is a substituted type alias. - LLVM_PREFERRED_TYPE(bool) - unsigned TypeAlias : 1; - - /// The number of template arguments named in this class template - /// specialization, which is expected to be able to hold at least 1024 - /// according to [implimits]. However, as this limit is somewhat easy to - /// hit with template metaprogramming we'd prefer to keep it as large - /// as possible. At the moment it has been left as a non-bitfield since - /// this type safely fits in 64 bits as an unsigned, so there is no reason - /// to introduce the performance impact of a bitfield. - unsigned NumArgs; - }; - - class DependentTemplateSpecializationTypeBitfields { - friend class DependentTemplateSpecializationType; - - LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) - unsigned : NumTypeWithKeywordBits; - - /// The number of template arguments named in this class template - /// specialization, which is expected to be able to hold at least 1024 - /// according to [implimits]. However, as this limit is somewhat easy to - /// hit with template metaprogramming we'd prefer to keep it as large - /// as possible. At the moment it has been left as a non-bitfield since - /// this type safely fits in 64 bits as an unsigned, so there is no reason - /// to introduce the performance impact of a bitfield. - unsigned NumArgs; - }; - - class PackExpansionTypeBitfields { - friend class PackExpansionType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// The number of expansions that this pack expansion will - /// generate when substituted (+1), which is expected to be able to - /// hold at least 1024 according to [implimits]. However, as this limit - /// is somewhat easy to hit with template metaprogramming we'd prefer to - /// keep it as large as possible. At the moment it has been left as a - /// non-bitfield since this type safely fits in 64 bits as an unsigned, so - /// there is no reason to introduce the performance impact of a bitfield. - /// - /// This field will only have a non-zero value when some of the parameter - /// packs that occur within the pattern have been substituted but others - /// have not. - unsigned NumExpansions; - }; - - enum class PredefinedSugarKind { - /// The "size_t" type. - SizeT, - - /// The signed integer type corresponding to "size_t". - SignedSizeT, - - /// The "ptrdiff_t" type. - PtrdiffT, - - // Indicates how many items the enum has. - Last = PtrdiffT - }; - - class PresefinedSugarTypeBitfields { - friend class PredefinedSugarType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - LLVM_PREFERRED_TYPE(PredefinedSugarKind) - unsigned Kind : 8; - }; - - class CountAttributedTypeBitfields { - friend class CountAttributedType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - static constexpr unsigned NumCoupledDeclsBits = 4; - unsigned NumCoupledDecls : NumCoupledDeclsBits; - LLVM_PREFERRED_TYPE(bool) - unsigned CountInBytes : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned OrNull : 1; - }; - static_assert(sizeof(CountAttributedTypeBitfields) <= sizeof(unsigned)); - - union { - TypeBitfields TypeBits; - ArrayTypeBitfields ArrayTypeBits; - ConstantArrayTypeBitfields ConstantArrayTypeBits; - AttributedTypeBitfields AttributedTypeBits; - AutoTypeBitfields AutoTypeBits; - TypeOfBitfields TypeOfBits; - TypedefBitfields TypedefBits; - UnresolvedUsingBitfields UnresolvedUsingBits; - UsingBitfields UsingBits; - BuiltinTypeBitfields BuiltinTypeBits; - FunctionTypeBitfields FunctionTypeBits; - ObjCObjectTypeBitfields ObjCObjectTypeBits; - ReferenceTypeBitfields ReferenceTypeBits; - KeywordWrapperBitfields KeywordWrapperBits; - TagTypeBitfields TagTypeBits; - VectorTypeBitfields VectorTypeBits; - TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits; - SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits; - SubstPackTypeBitfields SubstPackTypeBits; - TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; - DependentTemplateSpecializationTypeBitfields - DependentTemplateSpecializationTypeBits; - PackExpansionTypeBitfields PackExpansionTypeBits; - CountAttributedTypeBitfields CountAttributedTypeBits; - PresefinedSugarTypeBitfields PredefinedSugarTypeBits; - }; - -private: - template friend class TypePropertyCache; - - /// Set whether this type comes from an AST file. - void setFromAST(bool V = true) const { - TypeBits.FromAST = V; - } - -protected: - friend class ASTContext; - - Type(TypeClass tc, QualType canon, TypeDependence Dependence) - : ExtQualsTypeCommonBase(this, - canon.isNull() ? QualType(this_(), 0) : canon) { - static_assert(sizeof(*this) <= - alignof(decltype(*this)) + sizeof(ExtQualsTypeCommonBase), - "changing bitfields changed sizeof(Type)!"); - static_assert(alignof(decltype(*this)) % TypeAlignment == 0, - "Insufficient alignment!"); - TypeBits.TC = tc; - TypeBits.Dependence = static_cast(Dependence); - TypeBits.CacheValid = false; - TypeBits.CachedLocalOrUnnamed = false; - TypeBits.CachedLinkage = llvm::to_underlying(Linkage::Invalid); - TypeBits.FromAST = false; - } - - // silence VC++ warning C4355: 'this' : used in base member initializer list - Type *this_() { return this; } - - void setDependence(TypeDependence D) { - TypeBits.Dependence = static_cast(D); - } - - void addDependence(TypeDependence D) { setDependence(getDependence() | D); } - -public: - friend class ASTReader; - friend class ASTWriter; - template friend class serialization::AbstractTypeReader; - template friend class serialization::AbstractTypeWriter; - - Type(const Type &) = delete; - Type(Type &&) = delete; - Type &operator=(const Type &) = delete; - Type &operator=(Type &&) = delete; - - TypeClass getTypeClass() const { return static_cast(TypeBits.TC); } - - /// Whether this type comes from an AST file. - bool isFromAST() const { return TypeBits.FromAST; } - - /// Whether this type is or contains an unexpanded parameter - /// pack, used to support C++0x variadic templates. - /// - /// A type that contains a parameter pack shall be expanded by the - /// ellipsis operator at some point. For example, the typedef in the - /// following example contains an unexpanded parameter pack 'T': - /// - /// \code - /// template - /// struct X { - /// typedef T* pointer_types; // ill-formed; T is a parameter pack. - /// }; - /// \endcode - /// - /// Note that this routine does not specify which - bool containsUnexpandedParameterPack() const { - return getDependence() & TypeDependence::UnexpandedPack; - } - - /// Determines if this type would be canonical if it had no further - /// qualification. - bool isCanonicalUnqualified() const { - return CanonicalType == QualType(this, 0); - } - - /// Pull a single level of sugar off of this locally-unqualified type. - /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() - /// or QualType::getSingleStepDesugaredType(const ASTContext&). - QualType getLocallyUnqualifiedSingleStepDesugaredType() const; - - /// As an extension, we classify types as one of "sized" or "sizeless"; - /// every type is one or the other. Standard types are all sized; - /// sizeless types are purely an extension. - /// - /// Sizeless types contain data with no specified size, alignment, - /// or layout. - bool isSizelessType() const; - bool isSizelessBuiltinType() const; - - /// Returns true for all scalable vector types. - bool isSizelessVectorType() const; - - /// Returns true for SVE scalable vector types. - bool isSVESizelessBuiltinType() const; - - /// Returns true for RVV scalable vector types. - bool isRVVSizelessBuiltinType() const; - - /// Check if this is a WebAssembly Externref Type. - bool isWebAssemblyExternrefType() const; - - /// Returns true if this is a WebAssembly table type: either an array of - /// reference types, or a pointer to a reference type (which can only be - /// created by array to pointer decay). - bool isWebAssemblyTableType() const; - - /// Determines if this is a sizeless type supported by the - /// 'arm_sve_vector_bits' type attribute, which can be applied to a single - /// SVE vector or predicate, excluding tuple types such as svint32x4_t. - bool isSveVLSBuiltinType() const; - - /// Returns the representative type for the element of an SVE builtin type. - /// This is used to represent fixed-length SVE vectors created with the - /// 'arm_sve_vector_bits' type attribute as VectorType. - QualType getSveEltType(const ASTContext &Ctx) const; - - /// Determines if this is a sizeless type supported by the - /// 'riscv_rvv_vector_bits' type attribute, which can be applied to a single - /// RVV vector or mask. - bool isRVVVLSBuiltinType() const; - - /// Returns the representative type for the element of an RVV builtin type. - /// This is used to represent fixed-length RVV vectors created with the - /// 'riscv_rvv_vector_bits' type attribute as VectorType. - QualType getRVVEltType(const ASTContext &Ctx) const; - - /// Returns the representative type for the element of a sizeless vector - /// builtin type. - QualType getSizelessVectorEltType(const ASTContext &Ctx) const; - - /// Types are partitioned into 3 broad categories (C99 6.2.5p1): - /// object types, function types, and incomplete types. - - /// Return true if this is an incomplete type. - /// A type that can describe objects, but which lacks information needed to - /// determine its size (e.g. void, or a fwd declared struct). Clients of this - /// routine will need to determine if the size is actually required. - /// - /// Def If non-null, and the type refers to some kind of declaration - /// that can be completed (such as a C struct, C++ class, or Objective-C - /// class), will be set to the declaration. - bool isIncompleteType(NamedDecl **Def = nullptr) const; - - /// Return true if this is an incomplete or object - /// type, in other words, not a function type. - bool isIncompleteOrObjectType() const { - return !isFunctionType(); - } - - /// \returns True if the type is incomplete and it is also a type that - /// cannot be completed by a later type definition. - /// - /// E.g. For `void` this is true but for `struct ForwardDecl;` this is false - /// because a definition for `ForwardDecl` could be provided later on in the - /// translation unit. - /// - /// Note even for types that this function returns true for it is still - /// possible for the declarations that contain this type to later have a - /// complete type in a translation unit. E.g.: - /// - /// \code{.c} - /// // This decl has type 'char[]' which is incomplete and cannot be later - /// // completed by another by another type declaration. - /// extern char foo[]; - /// // This decl now has complete type 'char[5]'. - /// char foo[5]; // foo has a complete type - /// \endcode - bool isAlwaysIncompleteType() const; - - /// Determine whether this type is an object type. - bool isObjectType() const { - // C++ [basic.types]p8: - // An object type is a (possibly cv-qualified) type that is not a - // function type, not a reference type, and not a void type. - return !isReferenceType() && !isFunctionType() && !isVoidType(); - } - - /// Return true if this is a literal type - /// (C++11 [basic.types]p10) - bool isLiteralType(const ASTContext &Ctx) const; - - /// Determine if this type is a structural type, per C++20 [temp.param]p7. - bool isStructuralType() const; - - /// Test if this type is a standard-layout type. - /// (C++0x [basic.type]p9) - bool isStandardLayoutType() const; - - /// Helper methods to distinguish type categories. All type predicates - /// operate on the canonical type, ignoring typedefs and qualifiers. - - /// Returns true if the type is a builtin type. - bool isBuiltinType() const; - - /// Test for a particular builtin type. - bool isSpecificBuiltinType(unsigned K) const; - - /// Test for a type which does not represent an actual type-system type but - /// is instead used as a placeholder for various convenient purposes within - /// Clang. All such types are BuiltinTypes. - bool isPlaceholderType() const; - const BuiltinType *getAsPlaceholderType() const; - - /// Test for a specific placeholder type. - bool isSpecificPlaceholderType(unsigned K) const; - - /// Test for a placeholder type other than Overload; see - /// BuiltinType::isNonOverloadPlaceholderType. - bool isNonOverloadPlaceholderType() const; - - /// isIntegerType() does *not* include complex integers (a GCC extension). - /// isComplexIntegerType() can be used to test for complex integers. - bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) - bool isEnumeralType() const; - - /// Determine whether this type is a scoped enumeration type. - bool isScopedEnumeralType() const; - bool isBooleanType() const; - bool isCharType() const; - bool isWideCharType() const; - bool isChar8Type() const; - bool isChar16Type() const; - bool isChar32Type() const; - bool isAnyCharacterType() const; - bool isUnicodeCharacterType() const; - bool isIntegralType(const ASTContext &Ctx) const; - - /// Determine whether this type is an integral or enumeration type. - bool isIntegralOrEnumerationType() const; - - /// Determine whether this type is an integral or unscoped enumeration type. - bool isIntegralOrUnscopedEnumerationType() const; - bool isUnscopedEnumerationType() const; - - /// Floating point categories. - bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) - /// isComplexType() does *not* include complex integers (a GCC extension). - /// isComplexIntegerType() can be used to test for complex integers. - bool isComplexType() const; // C99 6.2.5p11 (complex) - bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. - bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) - bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) - bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 - bool isFloat32Type() const; - bool isDoubleType() const; - bool isBFloat16Type() const; - bool isMFloat8Type() const; - bool isFloat128Type() const; - bool isIbm128Type() const; - bool isRealType() const; // C99 6.2.5p17 (real floating + integer) - bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) - bool isVoidType() const; // C99 6.2.5p19 - bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) - bool isAggregateType() const; - bool isFundamentalType() const; - bool isCompoundType() const; - - // Type Predicates: Check to see if this type is structurally the specified - // type, ignoring typedefs and qualifiers. - bool isFunctionType() const; - bool isFunctionNoProtoType() const { return getAs(); } - bool isFunctionProtoType() const { return getAs(); } - bool isPointerType() const; - bool isPointerOrReferenceType() const; - bool isSignableType(const ASTContext &Ctx) const; - bool isSignablePointerType() const; - bool isSignableIntegerType(const ASTContext &Ctx) const; - bool isAnyPointerType() const; // Any C pointer or ObjC object pointer - bool isCountAttributedType() const; - bool isCFIUncheckedCalleeFunctionType() const; - bool hasPointeeToToCFIUncheckedCalleeFunctionType() const; - bool isBlockPointerType() const; - bool isVoidPointerType() const; - bool isReferenceType() const; - bool isLValueReferenceType() const; - bool isRValueReferenceType() const; - bool isObjectPointerType() const; - bool isFunctionPointerType() const; - bool isFunctionReferenceType() const; - bool isMemberPointerType() const; - bool isMemberFunctionPointerType() const; - bool isMemberDataPointerType() const; - bool isArrayType() const; - bool isConstantArrayType() const; - bool isIncompleteArrayType() const; - bool isVariableArrayType() const; - bool isArrayParameterType() const; - bool isDependentSizedArrayType() const; - bool isRecordType() const; - bool isClassType() const; - bool isStructureType() const; - bool isStructureTypeWithFlexibleArrayMember() const; - bool isObjCBoxableRecordType() const; - bool isInterfaceType() const; - bool isStructureOrClassType() const; - bool isUnionType() const; - bool isComplexIntegerType() const; // GCC _Complex integer type. - bool isVectorType() const; // GCC vector type. - bool isExtVectorType() const; // Extended vector type. - bool isExtVectorBoolType() const; // Extended vector type with bool element. - // Extended vector type with bool element that is packed. HLSL doesn't pack - // its bool vectors. - bool isPackedVectorBoolType(const ASTContext &ctx) const; - bool isSubscriptableVectorType() const; - bool isMatrixType() const; // Matrix type. - bool isConstantMatrixType() const; // Constant matrix type. - bool isDependentAddressSpaceType() const; // value-dependent address space qualifier - bool isObjCObjectPointerType() const; // pointer to ObjC object - bool isObjCRetainableType() const; // ObjC object or block pointer - bool isObjCLifetimeType() const; // (array of)* retainable type - bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type - bool isObjCNSObjectType() const; // __attribute__((NSObject)) - bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class)) - // FIXME: change this to 'raw' interface type, so we can used 'interface' type - // for the common case. - bool isObjCObjectType() const; // NSString or typeof(*(id)0) - bool isObjCQualifiedInterfaceType() const; // NSString - bool isObjCQualifiedIdType() const; // id - bool isObjCQualifiedClassType() const; // Class - bool isObjCObjectOrInterfaceType() const; - bool isObjCIdType() const; // id - bool isDecltypeType() const; - /// Was this type written with the special inert-in-ARC __unsafe_unretained - /// qualifier? - /// - /// This approximates the answer to the following question: if this - /// translation unit were compiled in ARC, would this type be qualified - /// with __unsafe_unretained? - bool isObjCInertUnsafeUnretainedType() const { - return hasAttr(attr::ObjCInertUnsafeUnretained); - } - - /// Whether the type is Objective-C 'id' or a __kindof type of an - /// object type, e.g., __kindof NSView * or __kindof id - /// . - /// - /// \param bound Will be set to the bound on non-id subtype types, - /// which will be (possibly specialized) Objective-C class type, or - /// null for 'id. - bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, - const ObjCObjectType *&bound) const; - - bool isObjCClassType() const; // Class - - /// Whether the type is Objective-C 'Class' or a __kindof type of an - /// Class type, e.g., __kindof Class . - /// - /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound - /// here because Objective-C's type system cannot express "a class - /// object for a subclass of NSFoo". - bool isObjCClassOrClassKindOfType() const; - - bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; - bool isObjCSelType() const; // Class - bool isObjCBuiltinType() const; // 'id' or 'Class' - bool isObjCARCBridgableType() const; - bool isCARCBridgableType() const; - bool isTemplateTypeParmType() const; // C++ template type parameter - bool isNullPtrType() const; // C++11 std::nullptr_t or - // C23 nullptr_t - bool isNothrowT() const; // C++ std::nothrow_t - bool isAlignValT() const; // C++17 std::align_val_t - bool isStdByteType() const; // C++17 std::byte - bool isAtomicType() const; // C11 _Atomic() - bool isUndeducedAutoType() const; // C++11 auto or - // C++14 decltype(auto) - bool isTypedefNameType() const; // typedef or alias template - -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ - bool is##Id##Type() const; -#include "clang/Basic/OpenCLImageTypes.def" - - bool isImageType() const; // Any OpenCL image type - - bool isSamplerT() const; // OpenCL sampler_t - bool isEventT() const; // OpenCL event_t - bool isClkEventT() const; // OpenCL clk_event_t - bool isQueueT() const; // OpenCL queue_t - bool isReserveIDT() const; // OpenCL reserve_id_t - -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ - bool is##Id##Type() const; -#include "clang/Basic/OpenCLExtensionTypes.def" - // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension - bool isOCLIntelSubgroupAVCType() const; - bool isOCLExtOpaqueType() const; // Any OpenCL extension type - - bool isPipeType() const; // OpenCL pipe type - bool isBitIntType() const; // Bit-precise integer type - bool isOpenCLSpecificType() const; // Any OpenCL specific type - -#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const; -#include "clang/Basic/HLSLIntangibleTypes.def" - bool isHLSLSpecificType() const; // Any HLSL specific type - bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type - bool isHLSLAttributedResourceType() const; - bool isHLSLInlineSpirvType() const; - bool isHLSLResourceRecord() const; - bool isHLSLResourceRecordArray() const; - bool isHLSLIntangibleType() - const; // Any HLSL intangible type (builtin, array, class) - - /// Determines if this type, which must satisfy - /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather - /// than implicitly __strong. - bool isObjCARCImplicitlyUnretainedType() const; - - /// Check if the type is the CUDA device builtin surface type. - bool isCUDADeviceBuiltinSurfaceType() const; - /// Check if the type is the CUDA device builtin texture type. - bool isCUDADeviceBuiltinTextureType() const; - - /// Return the implicit lifetime for this type, which must not be dependent. - Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; - - enum ScalarTypeKind { - STK_CPointer, - STK_BlockPointer, - STK_ObjCObjectPointer, - STK_MemberPointer, - STK_Bool, - STK_Integral, - STK_Floating, - STK_IntegralComplex, - STK_FloatingComplex, - STK_FixedPoint - }; - - /// Given that this is a scalar type, classify it. - ScalarTypeKind getScalarTypeKind() const; - - TypeDependence getDependence() const { - return static_cast(TypeBits.Dependence); - } - - /// Whether this type is an error type. - bool containsErrors() const { - return getDependence() & TypeDependence::Error; - } - - /// Whether this type is a dependent type, meaning that its definition - /// somehow depends on a template parameter (C++ [temp.dep.type]). - bool isDependentType() const { - return getDependence() & TypeDependence::Dependent; - } - - /// Determine whether this type is an instantiation-dependent type, - /// meaning that the type involves a template parameter (even if the - /// definition does not actually depend on the type substituted for that - /// template parameter). - bool isInstantiationDependentType() const { - return getDependence() & TypeDependence::Instantiation; - } - - /// Determine whether this type is an undeduced type, meaning that - /// it somehow involves a C++11 'auto' type or similar which has not yet been - /// deduced. - bool isUndeducedType() const; - - /// Whether this type is a variably-modified type (C99 6.7.5). - bool isVariablyModifiedType() const { - return getDependence() & TypeDependence::VariablyModified; - } - - /// Whether this type involves a variable-length array type - /// with a definite size. - bool hasSizedVLAType() const; - - /// Whether this type is or contains a local or unnamed type. - bool hasUnnamedOrLocalType() const; - - bool isOverloadableType() const; - - /// Determine wither this type is a C++ elaborated-type-specifier. - bool isElaboratedTypeSpecifier() const; - - bool canDecayToPointerType() const; - - /// Whether this type is represented natively as a pointer. This includes - /// pointers, references, block pointers, and Objective-C interface, - /// qualified id, and qualified interface types, as well as nullptr_t. - bool hasPointerRepresentation() const; - - /// Whether this type can represent an objective pointer type for the - /// purpose of GC'ability - bool hasObjCPointerRepresentation() const; - - /// Determine whether this type has an integer representation - /// of some sort, e.g., it is an integer type or a vector. - bool hasIntegerRepresentation() const; - - /// Determine whether this type has an signed integer representation - /// of some sort, e.g., it is an signed integer type or a vector. - bool hasSignedIntegerRepresentation() const; - - /// Determine whether this type has an unsigned integer representation - /// of some sort, e.g., it is an unsigned integer type or a vector. - bool hasUnsignedIntegerRepresentation() const; - - /// Determine whether this type has a floating-point representation - /// of some sort, e.g., it is a floating-point type or a vector thereof. - bool hasFloatingRepresentation() const; - - /// Determine whether this type has a boolean representation -- i.e., it is a - /// boolean type, an enum type whose underlying type is a boolean type, or a - /// vector of booleans. - bool hasBooleanRepresentation() const; - - // Type Checking Functions: Check to see if this type is structurally the - // specified type, ignoring typedefs and qualifiers, and return a pointer to - // the best type we can. - const RecordType *getAsStructureType() const; - /// NOTE: getAs*ArrayType are methods on ASTContext. - const RecordType *getAsUnionType() const; - const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. - const ObjCObjectType *getAsObjCInterfaceType() const; - - // The following is a convenience method that returns an ObjCObjectPointerType - // for object declared using an interface. - const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; - const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; - const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; - const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; - - /// Retrieves the CXXRecordDecl that this type refers to, either - /// because the type is a RecordType or because it is the injected-class-name - /// type of a class template or class template partial specialization. - CXXRecordDecl *getAsCXXRecordDecl() const; - - /// Retrieves the RecordDecl this type refers to. - RecordDecl *getAsRecordDecl() const; - - /// Retrieves the TagDecl that this type refers to, either - /// because the type is a TagType or because it is the injected-class-name - /// type of a class template or class template partial specialization. - TagDecl *getAsTagDecl() const; - - /// If this is a pointer or reference to a RecordType, return the - /// CXXRecordDecl that the type refers to. - /// - /// If this is not a pointer or reference, or the type being pointed to does - /// not refer to a CXXRecordDecl, returns NULL. - const CXXRecordDecl *getPointeeCXXRecordDecl() const; - - /// Get the DeducedType whose type will be deduced for a variable with - /// an initializer of this type. This looks through declarators like pointer - /// types, but not through decltype or typedefs. - DeducedType *getContainedDeducedType() const; - - /// Get the AutoType whose type will be deduced for a variable with - /// an initializer of this type. This looks through declarators like pointer - /// types, but not through decltype or typedefs. - AutoType *getContainedAutoType() const { - return dyn_cast_or_null(getContainedDeducedType()); - } - - /// Determine whether this type was written with a leading 'auto' - /// corresponding to a trailing return type (possibly for a nested - /// function type within a pointer to function type or similar). - bool hasAutoForTrailingReturnType() const; - - /// Member-template getAs'. Look through sugar for - /// an instance of \. This scheme will eventually - /// replace the specific getAsXXXX methods above. - /// - /// There are some specializations of this member template listed - /// immediately following this class. - template const T *getAs() const; - - /// 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 - /// name for a class template specialization. - const TemplateSpecializationType * - getAsNonAliasTemplateSpecializationType() const; - - const TemplateSpecializationType * - castAsNonAliasTemplateSpecializationType() const { - const auto *TST = getAsNonAliasTemplateSpecializationType(); - assert(TST && "not a TemplateSpecializationType"); - return TST; - } - - /// Member-template getAsAdjusted. Look through specific kinds - /// of sugar (parens, attributes, etc) for an instance of \. - /// This is used when you need to walk over sugar nodes that represent some - /// kind of type adjustment from a type that was written as a \ - /// to another type that is still canonically a \. - template const T *getAsAdjusted() const; - - /// A variant of getAs<> for array types which silently discards - /// qualifiers from the outermost type. - const ArrayType *getAsArrayTypeUnsafe() const; - - /// Member-template castAs. Look through sugar for - /// the underlying instance of \. - /// - /// This method has the same relationship to getAs as cast has - /// to dyn_cast; which is to say, the underlying type *must* - /// have the intended type, and this method will never return null. - template const T *castAs() const; - - /// A variant of castAs<> for array type which silently discards - /// qualifiers from the outermost type. - const ArrayType *castAsArrayTypeUnsafe() const; - - /// If this type represents a qualified-id, this returns its nested name - /// specifier. For example, for the qualified-id "foo::bar::baz", this returns - /// "foo::bar". Returns null if this type represents an unqualified-id. - NestedNameSpecifier getPrefix() const; - - /// Determine whether this type had the specified attribute applied to it - /// (looking through top-level type sugar). - bool hasAttr(attr::Kind AK) const; - - /// Get the base element type of this type, potentially discarding type - /// qualifiers. This should never be used when type qualifiers - /// are meaningful. - const Type *getBaseElementTypeUnsafe() const; - - /// If this is an array type, return the element type of the array, - /// potentially with type qualifiers missing. - /// This should never be used when type qualifiers are meaningful. - const Type *getArrayElementTypeNoTypeQual() const; - - /// If this is a pointer type, return the pointee type. - /// If this is an array type, return the array element type. - /// This should never be used when type qualifiers are meaningful. - const Type *getPointeeOrArrayElementType() const; - - /// If this is a pointer, ObjC object pointer, or block - /// pointer, this returns the respective pointee. - QualType getPointeeType() const; - - /// Return the specified type with any "sugar" removed from the type, - /// removing any typedefs, typeofs, etc., as well as any qualifiers. - const Type *getUnqualifiedDesugaredType() const; - - /// Return true if this is an integer type that is - /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], - /// or an enum decl which has a signed representation. - bool isSignedIntegerType() const; - - /// Return true if this is an integer type that is - /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], - /// or an enum decl which has an unsigned representation. - bool isUnsignedIntegerType() const; - - /// Determines whether this is an integer type that is signed or an - /// enumeration types whose underlying type is a signed integer type. - bool isSignedIntegerOrEnumerationType() const; - - /// Determines whether this is an integer type that is unsigned or an - /// enumeration types whose underlying type is a unsigned integer type. - bool isUnsignedIntegerOrEnumerationType() const; - - /// Return true if this is a fixed point type according to - /// ISO/IEC JTC1 SC22 WG14 N1169. - bool isFixedPointType() const; - - /// Return true if this is a fixed point or integer type. - bool isFixedPointOrIntegerType() const; - - /// Return true if this can be converted to (or from) a fixed point type. - bool isConvertibleToFixedPointType() const; - - /// Return true if this is a saturated fixed point type according to - /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. - bool isSaturatedFixedPointType() const; - - /// Return true if this is a saturated fixed point type according to - /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. - bool isUnsaturatedFixedPointType() const; - - /// Return true if this is a fixed point type that is signed according - /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. - bool isSignedFixedPointType() const; - - /// Return true if this is a fixed point type that is unsigned according - /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. - bool isUnsignedFixedPointType() const; - - /// Return true if this is not a variable sized type, - /// according to the rules of C99 6.7.5p3. It is not legal to call this on - /// incomplete types. - bool isConstantSizeType() const; - - /// Returns true if this type can be represented by some - /// set of type specifiers. - bool isSpecifierType() const; - - /// Determine the linkage of this type. - Linkage getLinkage() const; - - /// Determine the visibility of this type. - Visibility getVisibility() const { - return getLinkageAndVisibility().getVisibility(); - } - - /// Return true if the visibility was explicitly set is the code. - bool isVisibilityExplicit() const { - return getLinkageAndVisibility().isVisibilityExplicit(); - } - - /// Determine the linkage and visibility of this type. - LinkageInfo getLinkageAndVisibility() const; - - /// True if the computed linkage is valid. Used for consistency - /// checking. Should always return true. - bool isLinkageValid() const; - - /// Determine the nullability of the given type. - /// - /// Note that nullability is only captured as sugar within the type - /// system, not as part of the canonical type, so nullability will - /// be lost by canonicalization and desugaring. - std::optional getNullability() const; - - /// Determine whether the given type can have a nullability - /// specifier applied to it, i.e., if it is any kind of pointer type. - /// - /// \param ResultIfUnknown The value to return if we don't yet know whether - /// this type can have nullability because it is dependent. - bool canHaveNullability(bool ResultIfUnknown = true) const; - - /// Retrieve the set of substitutions required when accessing a member - /// of the Objective-C receiver type that is declared in the given context. - /// - /// \c *this is the type of the object we're operating on, e.g., the - /// receiver for a message send or the base of a property access, and is - /// expected to be of some object or object pointer type. - /// - /// \param dc The declaration context for which we are building up a - /// substitution mapping, which should be an Objective-C class, extension, - /// category, or method within. - /// - /// \returns an array of type arguments that can be substituted for - /// the type parameters of the given declaration context in any type described - /// within that context, or an empty optional to indicate that no - /// substitution is required. - std::optional> - getObjCSubstitutions(const DeclContext *dc) const; - - /// Determines if this is an ObjC interface type that may accept type - /// parameters. - bool acceptsObjCTypeParams() const; - - const char *getTypeClassName() const; - - QualType getCanonicalTypeInternal() const { - return CanonicalType; - } - - CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h - void dump() const; - void dump(llvm::raw_ostream &OS, const ASTContext &Context) const; -}; - -/// This will check for a TypedefType by removing any existing sugar -/// until it reaches a TypedefType or a non-sugared type. -template <> const TypedefType *Type::getAs() const; -template <> const UsingType *Type::getAs() const; - -/// This will check for a TemplateSpecializationType by removing any -/// existing sugar until it reaches a TemplateSpecializationType or a -/// non-sugared type. -template <> const TemplateSpecializationType *Type::getAs() const; - -/// This will check for an AttributedType by removing any existing sugar -/// until it reaches an AttributedType or a non-sugared type. -template <> const AttributedType *Type::getAs() const; - -/// This will check for a BoundsAttributedType by removing any existing -/// sugar until it reaches an BoundsAttributedType or a non-sugared type. -template <> const BoundsAttributedType *Type::getAs() const; - -/// This will check for a CountAttributedType by removing any existing -/// 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. -#define TYPE(Class, Base) -#define LEAF_TYPE(Class) \ -template <> inline const Class##Type *Type::getAs() const { \ - return dyn_cast(CanonicalType); \ -} \ -template <> inline const Class##Type *Type::castAs() const { \ - return cast(CanonicalType); \ -} -#include "clang/AST/TypeNodes.inc" - -/// This class is used for builtin types like 'int'. Builtin -/// types are always canonical and have a literal name field. -class BuiltinType : public Type { -public: - enum Kind { -// OpenCL image types -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id, -#include "clang/Basic/OpenCLImageTypes.def" -// OpenCL extension types -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id, -#include "clang/Basic/OpenCLExtensionTypes.def" -// SVE Types -#define SVE_TYPE(Name, Id, SingletonId) Id, -#include "clang/Basic/AArch64ACLETypes.def" -// PPC MMA Types -#define PPC_VECTOR_TYPE(Name, Id, Size) Id, -#include "clang/Basic/PPCTypes.def" -// RVV Types -#define RVV_TYPE(Name, Id, SingletonId) Id, -#include "clang/Basic/RISCVVTypes.def" -// WebAssembly reference types -#define WASM_TYPE(Name, Id, SingletonId) Id, -#include "clang/Basic/WebAssemblyReferenceTypes.def" -// AMDGPU types -#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) Id, -#include "clang/Basic/AMDGPUTypes.def" -// HLSL intangible Types -#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) Id, -#include "clang/Basic/HLSLIntangibleTypes.def" -// All other builtin types -#define BUILTIN_TYPE(Id, SingletonId) Id, -#define LAST_BUILTIN_TYPE(Id) LastKind = Id -#include "clang/AST/BuiltinTypes.def" - }; - -private: - friend class ASTContext; // ASTContext creates these. - - BuiltinType(Kind K) - : Type(Builtin, QualType(), - K == Dependent ? TypeDependence::DependentInstantiation - : TypeDependence::None) { - static_assert(Kind::LastKind < - (1 << BuiltinTypeBitfields::NumOfBuiltinTypeBits) && - "Defined builtin type exceeds the allocated space for serial " - "numbering"); - BuiltinTypeBits.Kind = K; - } - -public: - Kind getKind() const { return static_cast(BuiltinTypeBits.Kind); } - StringRef getName(const PrintingPolicy &Policy) const; - - const char *getNameAsCString(const PrintingPolicy &Policy) const { - // The StringRef is null-terminated. - StringRef str = getName(Policy); - assert(!str.empty() && str.data()[str.size()] == '\0'); - return str.data(); - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - bool isInteger() const { - return getKind() >= Bool && getKind() <= Int128; - } - - bool isSignedInteger() const { - return getKind() >= Char_S && getKind() <= Int128; - } - - bool isUnsignedInteger() const { - return getKind() >= Bool && getKind() <= UInt128; - } - - bool isFloatingPoint() const { - return getKind() >= Half && getKind() <= Ibm128; - } - - bool isSVEBool() const { return getKind() == Kind::SveBool; } - - bool isSVECount() const { return getKind() == Kind::SveCount; } - - /// Determines whether the given kind corresponds to a placeholder type. - static bool isPlaceholderTypeKind(Kind K) { - return K >= Overload; - } - - /// Determines whether this type is a placeholder type, i.e. a type - /// which cannot appear in arbitrary positions in a fully-formed - /// expression. - bool isPlaceholderType() const { - return isPlaceholderTypeKind(getKind()); - } - - /// Determines whether this type is a placeholder type other than - /// Overload. Most placeholder types require only syntactic - /// information about their context in order to be resolved (e.g. - /// whether it is a call expression), which means they can (and - /// should) be resolved in an earlier "phase" of analysis. - /// Overload expressions sometimes pick up further information - /// from their context, like whether the context expects a - /// specific function-pointer type, and so frequently need - /// special treatment. - bool isNonOverloadPlaceholderType() const { - return getKind() > Overload; - } - - static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } -}; - -/// Complex values, per C99 6.2.5p11. This supports the C99 complex -/// types (_Complex float etc) as well as the GCC integer complex extensions. -class ComplexType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType ElementType; - - ComplexType(QualType Element, QualType CanonicalPtr) - : Type(Complex, CanonicalPtr, Element->getDependence()), - ElementType(Element) {} - -public: - QualType getElementType() const { return ElementType; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { - ID.AddPointer(Element.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Complex; } -}; - -/// Sugar for parentheses used when specifying types. -class ParenType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType Inner; - - ParenType(QualType InnerType, QualType CanonType) - : Type(Paren, CanonType, InnerType->getDependence()), Inner(InnerType) {} - -public: - QualType getInnerType() const { return Inner; } - - bool isSugared() const { return true; } - QualType desugar() const { return getInnerType(); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getInnerType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { - Inner.Profile(ID); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Paren; } -}; - -/// PointerType - C99 6.7.5.1 - Pointer Declarators. -class PointerType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType PointeeType; - - PointerType(QualType Pointee, QualType CanonicalPtr) - : Type(Pointer, CanonicalPtr, Pointee->getDependence()), - PointeeType(Pointee) {} - -public: - QualType getPointeeType() const { return PointeeType; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPointeeType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { - ID.AddPointer(Pointee.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } -}; - -/// [BoundsSafety] Represents information of declarations referenced by the -/// arguments of the `counted_by` attribute and the likes. -class TypeCoupledDeclRefInfo { -public: - using BaseTy = llvm::PointerIntPair; - -private: - enum { - DerefShift = 0, - DerefMask = 1, - }; - BaseTy Data; - -public: - /// \p D is to a declaration referenced by the argument of attribute. \p Deref - /// indicates whether \p D is referenced as a dereferenced form, e.g., \p - /// Deref is true for `*n` in `int *__counted_by(*n)`. - TypeCoupledDeclRefInfo(ValueDecl *D = nullptr, bool Deref = false); - - bool isDeref() const; - ValueDecl *getDecl() const; - unsigned getInt() const; - void *getOpaqueValue() const; - bool operator==(const TypeCoupledDeclRefInfo &Other) const; - void setFromOpaqueValue(void *V); -}; - -/// [BoundsSafety] Represents a parent type class for CountAttributedType and -/// similar sugar types that will be introduced to represent a type with a -/// bounds attribute. -/// -/// Provides a common interface to navigate declarations referred to by the -/// bounds expression. - -class BoundsAttributedType : public Type, public llvm::FoldingSetNode { - QualType WrappedTy; - -protected: - ArrayRef Decls; // stored in trailing objects - - BoundsAttributedType(TypeClass TC, QualType Wrapped, QualType Canon); - -public: - bool isSugared() const { return true; } - QualType desugar() const { return WrappedTy; } - - using decl_iterator = const TypeCoupledDeclRefInfo *; - using decl_range = llvm::iterator_range; - - decl_iterator dependent_decl_begin() const { return Decls.begin(); } - decl_iterator dependent_decl_end() const { return Decls.end(); } - - unsigned getNumCoupledDecls() const { return Decls.size(); } - - decl_range dependent_decls() const { - return decl_range(dependent_decl_begin(), dependent_decl_end()); - } - - ArrayRef getCoupledDecls() const { - return {dependent_decl_begin(), dependent_decl_end()}; - } - - bool referencesFieldDecls() const; - - static bool classof(const Type *T) { - // Currently, only `class CountAttributedType` inherits - // `BoundsAttributedType` but the subclass will grow as we add more bounds - // annotations. - switch (T->getTypeClass()) { - case CountAttributed: - return true; - default: - return false; - } - } -}; - -/// Represents a sugar type with `__counted_by` or `__sized_by` annotations, -/// including their `_or_null` variants. -class CountAttributedType final - : public BoundsAttributedType, - public llvm::TrailingObjects { - friend class ASTContext; - - Expr *CountExpr; - /// \p CountExpr represents the argument of __counted_by or the likes. \p - /// CountInBytes indicates that \p CountExpr is a byte count (i.e., - /// __sized_by(_or_null)) \p OrNull means it's an or_null variant (i.e., - /// __counted_by_or_null or __sized_by_or_null) \p CoupledDecls contains the - /// list of declarations referenced by \p CountExpr, which the type depends on - /// for the bounds information. - CountAttributedType(QualType Wrapped, QualType Canon, Expr *CountExpr, - bool CountInBytes, bool OrNull, - ArrayRef CoupledDecls); - - unsigned numTrailingObjects(OverloadToken) const { - return CountAttributedTypeBits.NumCoupledDecls; - } - -public: - enum DynamicCountPointerKind { - CountedBy = 0, - SizedBy, - CountedByOrNull, - SizedByOrNull, - }; - - Expr *getCountExpr() const { return CountExpr; } - bool isCountInBytes() const { return CountAttributedTypeBits.CountInBytes; } - bool isOrNull() const { return CountAttributedTypeBits.OrNull; } - - DynamicCountPointerKind getKind() const { - if (isOrNull()) - return isCountInBytes() ? SizedByOrNull : CountedByOrNull; - return isCountInBytes() ? SizedBy : CountedBy; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, desugar(), CountExpr, isCountInBytes(), isOrNull()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType WrappedTy, - Expr *CountExpr, bool CountInBytes, bool Nullable); - - static bool classof(const Type *T) { - return T->getTypeClass() == CountAttributed; - } - - StringRef getAttributeName(bool WithMacroPrefix) const; -}; - -/// Represents a type which was implicitly adjusted by the semantic -/// engine for arbitrary reasons. For example, array and function types can -/// decay, and function types can have their calling conventions adjusted. -class AdjustedType : public Type, public llvm::FoldingSetNode { - QualType OriginalTy; - QualType AdjustedTy; - -protected: - friend class ASTContext; // ASTContext creates these. - - AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, - QualType CanonicalPtr) - : Type(TC, CanonicalPtr, OriginalTy->getDependence()), - OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} - -public: - QualType getOriginalType() const { return OriginalTy; } - QualType getAdjustedType() const { return AdjustedTy; } - - bool isSugared() const { return true; } - QualType desugar() const { return AdjustedTy; } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, OriginalTy, AdjustedTy); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { - ID.AddPointer(Orig.getAsOpaquePtr()); - ID.AddPointer(New.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed; - } -}; - -/// Represents a pointer type decayed from an array or function type. -class DecayedType : public AdjustedType { - friend class ASTContext; // ASTContext creates these. - - inline - DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); - -public: - QualType getDecayedType() const { return getAdjustedType(); } - - inline QualType getPointeeType() const; - - static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } -}; - -/// Pointer to a block type. -/// This type is to represent types syntactically represented as -/// "void (^)(int)", etc. Pointee is required to always be a function type. -class BlockPointerType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - // Block is some kind of pointer type - QualType PointeeType; - - BlockPointerType(QualType Pointee, QualType CanonicalCls) - : Type(BlockPointer, CanonicalCls, Pointee->getDependence()), - PointeeType(Pointee) {} - -public: - // Get the pointee type. Pointee is required to always be a function type. - QualType getPointeeType() const { return PointeeType; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPointeeType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { - ID.AddPointer(Pointee.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == BlockPointer; - } -}; - -/// Base for LValueReferenceType and RValueReferenceType -class ReferenceType : public Type, public llvm::FoldingSetNode { - QualType PointeeType; - -protected: - ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, - bool SpelledAsLValue) - : Type(tc, CanonicalRef, Referencee->getDependence()), - PointeeType(Referencee) { - ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; - ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); - } - -public: - bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } - bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } - - QualType getPointeeTypeAsWritten() const { return PointeeType; } - - QualType getPointeeType() const { - // FIXME: this might strip inner qualifiers; okay? - const ReferenceType *T = this; - while (T->isInnerRef()) - T = T->PointeeType->castAs(); - return T->PointeeType; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, PointeeType, isSpelledAsLValue()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, - QualType Referencee, - bool SpelledAsLValue) { - ID.AddPointer(Referencee.getAsOpaquePtr()); - ID.AddBoolean(SpelledAsLValue); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == LValueReference || - T->getTypeClass() == RValueReference; - } -}; - -/// An lvalue reference type, per C++11 [dcl.ref]. -class LValueReferenceType : public ReferenceType { - friend class ASTContext; // ASTContext creates these - - LValueReferenceType(QualType Referencee, QualType CanonicalRef, - bool SpelledAsLValue) - : ReferenceType(LValueReference, Referencee, CanonicalRef, - SpelledAsLValue) {} - -public: - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == LValueReference; - } -}; - -/// An rvalue reference type, per C++11 [dcl.ref]. -class RValueReferenceType : public ReferenceType { - friend class ASTContext; // ASTContext creates these - - RValueReferenceType(QualType Referencee, QualType CanonicalRef) - : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {} - -public: - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == RValueReference; - } -}; - -/// A pointer to member type per C++ 8.3.3 - Pointers to members. -/// -/// This includes both pointers to data members and pointer to member functions. -class MemberPointerType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType PointeeType; - - /// The class of which the pointee is a member. Must ultimately be a - /// CXXRecordType, but could be a typedef or a template parameter too. - NestedNameSpecifier Qualifier; - - MemberPointerType(QualType Pointee, NestedNameSpecifier Qualifier, - QualType CanonicalPtr) - : Type(MemberPointer, CanonicalPtr, - (toTypeDependence(Qualifier.getDependence()) & - ~TypeDependence::VariablyModified) | - Pointee->getDependence()), - PointeeType(Pointee), Qualifier(Qualifier) {} - -public: - QualType getPointeeType() const { return PointeeType; } - - /// Returns true if the member type (i.e. the pointee type) is a - /// function type rather than a data-member type. - bool isMemberFunctionPointer() const { - return PointeeType->isFunctionProtoType(); - } - - /// Returns true if the member type (i.e. the pointee type) is a - /// data type rather than a function type. - bool isMemberDataPointer() const { - return !PointeeType->isFunctionProtoType(); - } - - NestedNameSpecifier getQualifier() const { return Qualifier; } - /// Note: this can trigger extra deserialization when external AST sources are - /// used. Prefer `getCXXRecordDecl()` unless you really need the most recent - /// decl. - CXXRecordDecl *getMostRecentCXXRecordDecl() const; - - bool isSugared() const; - QualType desugar() const { - return isSugared() ? getCanonicalTypeInternal() : QualType(this, 0); - } - - void Profile(llvm::FoldingSetNodeID &ID) { - // FIXME: `getMostRecentCXXRecordDecl()` should be possible to use here, - // however when external AST sources are used it causes nondeterminism - // issues (see https://github.com/llvm/llvm-project/pull/137910). - Profile(ID, getPointeeType(), getQualifier(), getCXXRecordDecl()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - const NestedNameSpecifier Qualifier, - const CXXRecordDecl *Cls); - - static bool classof(const Type *T) { - return T->getTypeClass() == MemberPointer; - } - -private: - CXXRecordDecl *getCXXRecordDecl() const; -}; - -/// Capture whether this is a normal array (e.g. int X[4]) -/// an array with a static size (e.g. int X[static 4]), or an array -/// with a star size (e.g. int X[*]). -/// 'static' is only allowed on function parameters. -enum class ArraySizeModifier { Normal, Static, Star }; - -/// Represents an array type, per C99 6.7.5.2 - Array Declarators. -class ArrayType : public Type, public llvm::FoldingSetNode { -private: - /// The element type of the array. - QualType ElementType; - -protected: - friend class ASTContext; // ASTContext creates these. - - ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, - unsigned tq, const Expr *sz = nullptr); - -public: - QualType getElementType() const { return ElementType; } - - ArraySizeModifier getSizeModifier() const { - return ArraySizeModifier(ArrayTypeBits.SizeModifier); - } - - Qualifiers getIndexTypeQualifiers() const { - return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); - } - - unsigned getIndexTypeCVRQualifiers() const { - return ArrayTypeBits.IndexTypeQuals; - } - - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArray || - T->getTypeClass() == VariableArray || - T->getTypeClass() == IncompleteArray || - T->getTypeClass() == DependentSizedArray || - T->getTypeClass() == ArrayParameter; - } -}; - -/// Represents the canonical version of C arrays with a specified constant size. -/// For example, the canonical type for 'int A[4 + 4*100]' is a -/// ConstantArrayType where the element type is 'int' and the size is 404. -class ConstantArrayType : public ArrayType { - friend class ASTContext; // ASTContext creates these. - - struct ExternalSize { - ExternalSize(const llvm::APInt &Sz, const Expr *SE) - : Size(Sz), SizeExpr(SE) {} - llvm::APInt Size; // Allows us to unique the type. - const Expr *SizeExpr; - }; - - union { - uint64_t Size; - ExternalSize *SizePtr; - }; - - ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz, - ArraySizeModifier SM, unsigned TQ) - : ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) { - ConstantArrayTypeBits.HasExternalSize = false; - ConstantArrayTypeBits.SizeWidth = Width / 8; - // The in-structure size stores the size in bytes rather than bits so we - // drop the three least significant bits since they're always zero anyways. - assert(Width < 0xFF && "Type width in bits must be less than 8 bits"); - } - - ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr, - ArraySizeModifier SM, unsigned TQ) - : ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr), - SizePtr(SzPtr) { - ConstantArrayTypeBits.HasExternalSize = true; - ConstantArrayTypeBits.SizeWidth = 0; - - assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) && - "canonical constant array should not have size expression"); - } - - static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET, - QualType Can, const llvm::APInt &Sz, - const Expr *SzExpr, ArraySizeModifier SzMod, - unsigned Qual); - -protected: - ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can) - : ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(), - ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) { - ConstantArrayTypeBits.HasExternalSize = - ATy->ConstantArrayTypeBits.HasExternalSize; - if (!ConstantArrayTypeBits.HasExternalSize) { - ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth; - Size = ATy->Size; - } else - SizePtr = ATy->SizePtr; - } - -public: - /// Return the constant array size as an APInt. - llvm::APInt getSize() const { - return ConstantArrayTypeBits.HasExternalSize - ? SizePtr->Size - : llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size); - } - - /// Return the bit width of the size type. - unsigned getSizeBitWidth() const { - return ConstantArrayTypeBits.HasExternalSize - ? SizePtr->Size.getBitWidth() - : static_cast(ConstantArrayTypeBits.SizeWidth * 8); - } - - /// Return true if the size is zero. - bool isZeroSize() const { - return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero() - : 0 == Size; - } - - /// Return the size zero-extended as a uint64_t. - uint64_t getZExtSize() const { - return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue() - : Size; - } - - /// Return the size sign-extended as a uint64_t. - int64_t getSExtSize() const { - return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue() - : static_cast(Size); - } - - /// Return the size zero-extended to uint64_t or UINT64_MAX if the value is - /// larger than UINT64_MAX. - uint64_t getLimitedSize() const { - return ConstantArrayTypeBits.HasExternalSize - ? SizePtr->Size.getLimitedValue() - : Size; - } - - /// Return a pointer to the size expression. - const Expr *getSizeExpr() const { - return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - /// Determine the number of bits required to address a member of - // an array with the given element type and number of elements. - static unsigned getNumAddressingBits(const ASTContext &Context, - QualType ElementType, - const llvm::APInt &NumElements); - - unsigned getNumAddressingBits(const ASTContext &Context) const; - - /// Determine the maximum number of active bits that an array's size - /// can require, which limits the maximum size of the array. - static unsigned getMaxSizeBits(const ASTContext &Context); - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(), - getSizeModifier(), getIndexTypeCVRQualifiers()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, - QualType ET, uint64_t ArraySize, const Expr *SizeExpr, - ArraySizeModifier SizeMod, unsigned TypeQuals); - - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArray || - T->getTypeClass() == ArrayParameter; - } -}; - -/// Represents a constant array type that does not decay to a pointer when used -/// as a function parameter. -class ArrayParameterType : public ConstantArrayType { - friend class ASTContext; // ASTContext creates these. - - ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy) - : ConstantArrayType(ArrayParameter, ATy, CanTy) {} - -public: - static bool classof(const Type *T) { - return T->getTypeClass() == ArrayParameter; - } - - QualType getConstantArrayType(const ASTContext &Ctx) const; -}; - -/// Represents a C array with an unspecified size. For example 'int A[]' has -/// an IncompleteArrayType where the element type is 'int' and the size is -/// unspecified. -class IncompleteArrayType : public ArrayType { - friend class ASTContext; // ASTContext creates these. - - IncompleteArrayType(QualType et, QualType can, - ArraySizeModifier sm, unsigned tq) - : ArrayType(IncompleteArray, et, can, sm, tq) {} - -public: - friend class StmtIteratorBase; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == IncompleteArray; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getSizeModifier(), - getIndexTypeCVRQualifiers()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, - ArraySizeModifier SizeMod, unsigned TypeQuals) { - ID.AddPointer(ET.getAsOpaquePtr()); - ID.AddInteger(llvm::to_underlying(SizeMod)); - ID.AddInteger(TypeQuals); - } -}; - -/// Represents a C array with a specified size that is not an -/// integer-constant-expression. For example, 'int s[x+foo()]'. -/// Since the size expression is an arbitrary expression, we store it as such. -/// -/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and -/// should not be: two lexically equivalent variable array types could mean -/// different things, for example, these variables do not have the same type -/// dynamically: -/// -/// void foo(int x) { -/// int Y[x]; -/// ++x; -/// int Z[x]; -/// } -/// -/// FIXME: Even constant array types might be represented by a -/// VariableArrayType, as in: -/// -/// void func(int n) { -/// int array[7][n]; -/// } -/// -/// Even though 'array' is a constant-size array of seven elements of type -/// variable-length array of size 'n', it will be represented as a -/// VariableArrayType whose 'SizeExpr' is an IntegerLiteral whose value is 7. -/// Instead, this should be a ConstantArrayType whose element is a -/// VariableArrayType, which models the type better. -class VariableArrayType : public ArrayType { - friend class ASTContext; // ASTContext creates these. - - /// An assignment-expression. VLA's are only permitted within - /// a function block. - Stmt *SizeExpr; - - VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, - unsigned tq) - : ArrayType(VariableArray, et, can, sm, tq, e), SizeExpr((Stmt *)e) {} - -public: - friend class StmtIteratorBase; - - Expr *getSizeExpr() const { - // We use C-style casts instead of cast<> here because we do not wish - // to have a dependency of Type.h on Stmt.h/Expr.h. - return (Expr*) SizeExpr; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == VariableArray; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - llvm_unreachable("Cannot unique VariableArrayTypes."); - } -}; - -/// Represents an array type in C++ whose size is a value-dependent expression. -/// -/// For example: -/// \code -/// template -/// class array { -/// T data[Size]; -/// }; -/// \endcode -/// -/// For these types, we won't actually know what the array bound is -/// until template instantiation occurs, at which point this will -/// become either a ConstantArrayType or a VariableArrayType. -class DependentSizedArrayType : public ArrayType { - friend class ASTContext; // ASTContext creates these. - - /// An assignment expression that will instantiate to the - /// size of the array. - /// - /// The expression itself might be null, in which case the array - /// type will have its size deduced from an initializer. - Stmt *SizeExpr; - - DependentSizedArrayType(QualType et, QualType can, Expr *e, - ArraySizeModifier sm, unsigned tq); - -public: - friend class StmtIteratorBase; - - Expr *getSizeExpr() const { - // We use C-style casts instead of cast<> here because we do not wish - // to have a dependency of Type.h on Stmt.h/Expr.h. - return (Expr*) SizeExpr; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentSizedArray; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getElementType(), - getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType ET, ArraySizeModifier SizeMod, - unsigned TypeQuals, Expr *E); -}; - -/// Represents an extended address space qualifier where the input address space -/// value is dependent. Non-dependent address spaces are not represented with a -/// special Type subclass; they are stored on an ExtQuals node as part of a QualType. -/// -/// For example: -/// \code -/// template -/// class AddressSpace { -/// typedef T __attribute__((address_space(AddrSpace))) type; -/// } -/// \endcode -class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; - - Expr *AddrSpaceExpr; - QualType PointeeType; - SourceLocation loc; - - DependentAddressSpaceType(QualType PointeeType, QualType can, - Expr *AddrSpaceExpr, SourceLocation loc); - -public: - Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } - QualType getPointeeType() const { return PointeeType; } - SourceLocation getAttributeLoc() const { return loc; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentAddressSpace; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType PointeeType, Expr *AddrSpaceExpr); -}; - -/// Represents an extended vector type where either the type or size is -/// dependent. -/// -/// For example: -/// \code -/// template -/// class vector { -/// typedef T __attribute__((ext_vector_type(Size))) type; -/// } -/// \endcode -class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; - - Expr *SizeExpr; - - /// The element type of the array. - QualType ElementType; - - SourceLocation loc; - - DependentSizedExtVectorType(QualType ElementType, QualType can, - Expr *SizeExpr, SourceLocation loc); - -public: - Expr *getSizeExpr() const { return SizeExpr; } - QualType getElementType() const { return ElementType; } - SourceLocation getAttributeLoc() const { return loc; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentSizedExtVector; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getElementType(), getSizeExpr()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType ElementType, Expr *SizeExpr); -}; - -enum class VectorKind { - /// not a target-specific vector type - Generic, - - /// is AltiVec vector - AltiVecVector, - - /// is AltiVec 'vector Pixel' - AltiVecPixel, - - /// is AltiVec 'vector bool ...' - AltiVecBool, - - /// is ARM Neon vector - Neon, - - /// is ARM Neon polynomial vector - NeonPoly, - - /// is AArch64 SVE fixed-length data vector - SveFixedLengthData, - - /// is AArch64 SVE fixed-length predicate vector - SveFixedLengthPredicate, - - /// is RISC-V RVV fixed-length data vector - RVVFixedLengthData, - - /// is RISC-V RVV fixed-length mask vector - RVVFixedLengthMask, - - RVVFixedLengthMask_1, - RVVFixedLengthMask_2, - RVVFixedLengthMask_4 -}; - -/// Represents a GCC generic vector type. This type is created using -/// __attribute__((vector_size(n)), where "n" specifies the vector size in -/// bytes; or from an Altivec __vector or vector declaration. -/// Since the constructor takes the number of vector elements, the -/// client is responsible for converting the size into the number of elements. -class VectorType : public Type, public llvm::FoldingSetNode { -protected: - friend class ASTContext; // ASTContext creates these. - - /// The element type of the vector. - QualType ElementType; - - VectorType(QualType vecType, unsigned nElements, QualType canonType, - VectorKind vecKind); - - VectorType(TypeClass tc, QualType vecType, unsigned nElements, - QualType canonType, VectorKind vecKind); - -public: - QualType getElementType() const { return ElementType; } - unsigned getNumElements() const { return VectorTypeBits.NumElements; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - VectorKind getVectorKind() const { - return VectorKind(VectorTypeBits.VecKind); - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getNumElements(), - getTypeClass(), getVectorKind()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, - unsigned NumElements, TypeClass TypeClass, - VectorKind VecKind) { - ID.AddPointer(ElementType.getAsOpaquePtr()); - ID.AddInteger(NumElements); - ID.AddInteger(TypeClass); - ID.AddInteger(llvm::to_underlying(VecKind)); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; - } -}; - -/// Represents a vector type where either the type or size is dependent. -//// -/// For example: -/// \code -/// template -/// class vector { -/// typedef T __attribute__((vector_size(Size))) type; -/// } -/// \endcode -class DependentVectorType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; - - QualType ElementType; - Expr *SizeExpr; - SourceLocation Loc; - - DependentVectorType(QualType ElementType, QualType CanonType, Expr *SizeExpr, - SourceLocation Loc, VectorKind vecKind); - -public: - Expr *getSizeExpr() const { return SizeExpr; } - QualType getElementType() const { return ElementType; } - SourceLocation getAttributeLoc() const { return Loc; } - VectorKind getVectorKind() const { - return VectorKind(VectorTypeBits.VecKind); - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentVector; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType ElementType, const Expr *SizeExpr, - VectorKind VecKind); -}; - -/// ExtVectorType - Extended vector type. This type is created using -/// __attribute__((ext_vector_type(n)), where "n" is the number of elements. -/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This -/// class enables syntactic extensions, like Vector Components for accessing -/// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL -/// Shading Language). -class ExtVectorType : public VectorType { - friend class ASTContext; // ASTContext creates these. - - ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) - : VectorType(ExtVector, vecType, nElements, canonType, - VectorKind::Generic) {} - -public: - static int getPointAccessorIdx(char c) { - switch (c) { - default: return -1; - case 'x': case 'r': return 0; - case 'y': case 'g': return 1; - case 'z': case 'b': return 2; - case 'w': case 'a': return 3; - } - } - - static int getNumericAccessorIdx(char c) { - switch (c) { - default: return -1; - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'A': - case 'a': return 10; - case 'B': - case 'b': return 11; - case 'C': - case 'c': return 12; - case 'D': - case 'd': return 13; - case 'E': - case 'e': return 14; - case 'F': - case 'f': return 15; - } - } - - static int getAccessorIdx(char c, bool isNumericAccessor) { - if (isNumericAccessor) - return getNumericAccessorIdx(c); - else - return getPointAccessorIdx(c); - } - - bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const { - if (int idx = getAccessorIdx(c, isNumericAccessor)+1) - return unsigned(idx-1) < getNumElements(); - return false; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ExtVector; - } -}; - -/// Represents a matrix type, as defined in the Matrix Types clang extensions. -/// __attribute__((matrix_type(rows, columns))), where "rows" specifies -/// number of rows and "columns" specifies the number of columns. -class MatrixType : public Type, public llvm::FoldingSetNode { -protected: - friend class ASTContext; - - /// The element type of the matrix. - QualType ElementType; - - MatrixType(QualType ElementTy, QualType CanonElementTy); - - MatrixType(TypeClass TypeClass, QualType ElementTy, QualType CanonElementTy, - const Expr *RowExpr = nullptr, const Expr *ColumnExpr = nullptr); - -public: - /// Returns type of the elements being stored in the matrix - QualType getElementType() const { return ElementType; } - - /// Valid elements types are the following: - /// * an integer type (as in C23 6.2.5p22), but excluding enumerated types - /// and _Bool - /// * the standard floating types float or double - /// * a half-precision floating point type, if one is supported on the target - static bool isValidElementType(QualType T) { - return T->isDependentType() || - (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType()); - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantMatrix || - T->getTypeClass() == DependentSizedMatrix; - } -}; - -/// Represents a concrete matrix type with constant number of rows and columns -class ConstantMatrixType final : public MatrixType { -protected: - friend class ASTContext; - - /// Number of rows and columns. - unsigned NumRows; - unsigned NumColumns; - - static constexpr unsigned MaxElementsPerDimension = (1 << 20) - 1; - - ConstantMatrixType(QualType MatrixElementType, unsigned NRows, - unsigned NColumns, QualType CanonElementType); - - ConstantMatrixType(TypeClass typeClass, QualType MatrixType, unsigned NRows, - unsigned NColumns, QualType CanonElementType); - -public: - /// Returns the number of rows in the matrix. - unsigned getNumRows() const { return NumRows; } - - /// Returns the number of columns in the matrix. - unsigned getNumColumns() const { return NumColumns; } - - /// Returns the number of elements required to embed the matrix into a vector. - unsigned getNumElementsFlattened() const { - return getNumRows() * getNumColumns(); - } - - /// Returns true if \p NumElements is a valid matrix dimension. - static constexpr bool isDimensionValid(size_t NumElements) { - return NumElements > 0 && NumElements <= MaxElementsPerDimension; - } - - /// Returns the maximum number of elements per dimension. - static constexpr unsigned getMaxElementsPerDimension() { - return MaxElementsPerDimension; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getNumRows(), getNumColumns(), - getTypeClass()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, - unsigned NumRows, unsigned NumColumns, - TypeClass TypeClass) { - ID.AddPointer(ElementType.getAsOpaquePtr()); - ID.AddInteger(NumRows); - ID.AddInteger(NumColumns); - ID.AddInteger(TypeClass); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantMatrix; - } -}; - -/// Represents a matrix type where the type and the number of rows and columns -/// is dependent on a template. -class DependentSizedMatrixType final : public MatrixType { - friend class ASTContext; - - Expr *RowExpr; - Expr *ColumnExpr; - - SourceLocation loc; - - DependentSizedMatrixType(QualType ElementType, QualType CanonicalType, - Expr *RowExpr, Expr *ColumnExpr, SourceLocation loc); - -public: - Expr *getRowExpr() const { return RowExpr; } - Expr *getColumnExpr() const { return ColumnExpr; } - SourceLocation getAttributeLoc() const { return loc; } - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentSizedMatrix; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getElementType(), getRowExpr(), getColumnExpr()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType ElementType, Expr *RowExpr, Expr *ColumnExpr); -}; - -/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base -/// class of FunctionNoProtoType and FunctionProtoType. -class FunctionType : public Type { - // The type returned by the function. - QualType ResultType; - -public: - /// Interesting information about a specific parameter that can't simply - /// be reflected in parameter's type. This is only used by FunctionProtoType - /// but is in FunctionType to make this class available during the - /// specification of the bases of FunctionProtoType. - /// - /// It makes sense to model language features this way when there's some - /// sort of parameter-specific override (such as an attribute) that - /// affects how the function is called. For example, the ARC ns_consumed - /// attribute changes whether a parameter is passed at +0 (the default) - /// or +1 (ns_consumed). This must be reflected in the function type, - /// but isn't really a change to the parameter type. - /// - /// One serious disadvantage of modelling language features this way is - /// that they generally do not work with language features that attempt - /// to destructure types. For example, template argument deduction will - /// not be able to match a parameter declared as - /// T (*)(U) - /// against an argument of type - /// void (*)(__attribute__((ns_consumed)) id) - /// because the substitution of T=void, U=id into the former will - /// not produce the latter. - class ExtParameterInfo { - enum { - ABIMask = 0x0F, - IsConsumed = 0x10, - HasPassObjSize = 0x20, - IsNoEscape = 0x40, - }; - unsigned char Data = 0; - - public: - ExtParameterInfo() = default; - - /// Return the ABI treatment of this parameter. - ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } - ExtParameterInfo withABI(ParameterABI kind) const { - ExtParameterInfo copy = *this; - copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); - return copy; - } - - /// Is this parameter considered "consumed" by Objective-C ARC? - /// Consumed parameters must have retainable object type. - bool isConsumed() const { return (Data & IsConsumed); } - ExtParameterInfo withIsConsumed(bool consumed) const { - ExtParameterInfo copy = *this; - if (consumed) - copy.Data |= IsConsumed; - else - copy.Data &= ~IsConsumed; - return copy; - } - - bool hasPassObjectSize() const { return Data & HasPassObjSize; } - ExtParameterInfo withHasPassObjectSize() const { - ExtParameterInfo Copy = *this; - Copy.Data |= HasPassObjSize; - return Copy; - } - - bool isNoEscape() const { return Data & IsNoEscape; } - ExtParameterInfo withIsNoEscape(bool NoEscape) const { - ExtParameterInfo Copy = *this; - if (NoEscape) - Copy.Data |= IsNoEscape; - else - Copy.Data &= ~IsNoEscape; - return Copy; - } - - unsigned char getOpaqueValue() const { return Data; } - static ExtParameterInfo getFromOpaqueValue(unsigned char data) { - ExtParameterInfo result; - result.Data = data; - return result; - } - - friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { - return lhs.Data == rhs.Data; - } - - friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { - return lhs.Data != rhs.Data; - } - }; - - /// A class which abstracts out some details necessary for - /// making a call. - /// - /// It is not actually used directly for storing this information in - /// a FunctionType, although FunctionType does currently use the - /// same bit-pattern. - /// - // If you add a field (say Foo), other than the obvious places (both, - // constructors, compile failures), what you need to update is - // * Operator== - // * getFoo - // * withFoo - // * functionType. Add Foo, getFoo. - // * ASTContext::getFooType - // * ASTContext::mergeFunctionTypes - // * FunctionNoProtoType::Profile - // * FunctionProtoType::Profile - // * TypePrinter::PrintFunctionProto - // * AST read and write - // * Codegen - class ExtInfo { - friend class FunctionType; - - // Feel free to rearrange or add bits, but if you go over 16, you'll need to - // adjust the Bits field below, and if you add bits, you'll need to adjust - // Type::FunctionTypeBitfields::ExtInfo as well. - - // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|cmsenscall| - // |0 .. 5| 6 | 7 | 8 |9 .. 11| 12 | 13 | - // - // regparm is either 0 (no regparm attribute) or the regparm value+1. - enum { CallConvMask = 0x3F }; - enum { NoReturnMask = 0x40 }; - enum { ProducesResultMask = 0x80 }; - enum { NoCallerSavedRegsMask = 0x100 }; - enum { RegParmMask = 0xe00, RegParmOffset = 9 }; - enum { NoCfCheckMask = 0x1000 }; - enum { CmseNSCallMask = 0x2000 }; - uint16_t Bits = CC_C; - - ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} - - public: - // Constructor with no defaults. Use this when you know that you - // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, - bool producesResult, bool noCallerSavedRegs, bool NoCfCheck, - bool cmseNSCall) { - assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); - Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | - (producesResult ? ProducesResultMask : 0) | - (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | - (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | - (NoCfCheck ? NoCfCheckMask : 0) | - (cmseNSCall ? CmseNSCallMask : 0); - } - - // Constructor with all defaults. Use when for example creating a - // function known to use defaults. - ExtInfo() = default; - - // Constructor with just the calling convention, which is an important part - // of the canonical type. - ExtInfo(CallingConv CC) : Bits(CC) {} - - bool getNoReturn() const { return Bits & NoReturnMask; } - bool getProducesResult() const { return Bits & ProducesResultMask; } - bool getCmseNSCall() const { return Bits & CmseNSCallMask; } - bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } - bool getNoCfCheck() const { return Bits & NoCfCheckMask; } - bool getHasRegParm() const { return ((Bits & RegParmMask) >> RegParmOffset) != 0; } - - unsigned getRegParm() const { - unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset; - if (RegParm > 0) - --RegParm; - return RegParm; - } - - CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } - - bool operator==(ExtInfo Other) const { - return Bits == Other.Bits; - } - bool operator!=(ExtInfo Other) const { - return Bits != Other.Bits; - } - - // Note that we don't have setters. That is by design, use - // the following with methods instead of mutating these objects. - - ExtInfo withNoReturn(bool noReturn) const { - if (noReturn) - return ExtInfo(Bits | NoReturnMask); - else - return ExtInfo(Bits & ~NoReturnMask); - } - - ExtInfo withProducesResult(bool producesResult) const { - if (producesResult) - return ExtInfo(Bits | ProducesResultMask); - else - return ExtInfo(Bits & ~ProducesResultMask); - } - - ExtInfo withCmseNSCall(bool cmseNSCall) const { - if (cmseNSCall) - return ExtInfo(Bits | CmseNSCallMask); - else - return ExtInfo(Bits & ~CmseNSCallMask); - } - - ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { - if (noCallerSavedRegs) - return ExtInfo(Bits | NoCallerSavedRegsMask); - else - return ExtInfo(Bits & ~NoCallerSavedRegsMask); - } - - ExtInfo withNoCfCheck(bool noCfCheck) const { - if (noCfCheck) - return ExtInfo(Bits | NoCfCheckMask); - else - return ExtInfo(Bits & ~NoCfCheckMask); - } - - ExtInfo withRegParm(unsigned RegParm) const { - assert(RegParm < 7 && "Invalid regparm value"); - return ExtInfo((Bits & ~RegParmMask) | - ((RegParm + 1) << RegParmOffset)); - } - - ExtInfo withCallingConv(CallingConv cc) const { - return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger(Bits); - } - }; - - /// A simple holder for a QualType representing a type in an - /// exception specification. Unfortunately needed by FunctionProtoType - /// because TrailingObjects cannot handle repeated types. - struct ExceptionType { QualType Type; }; - - /// A simple holder for various uncommon bits which do not fit in - /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the - /// alignment of subsequent objects in TrailingObjects. - struct alignas(void *) FunctionTypeExtraBitfields { - /// The number of types in the exception specification. - /// A whole unsigned is not needed here and according to - /// [implimits] 8 bits would be enough here. - unsigned NumExceptionType : 10; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasExtraAttributeInfo : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasArmTypeAttributes : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned EffectsHaveConditions : 1; - unsigned NumFunctionEffects : 4; - - FunctionTypeExtraBitfields() - : NumExceptionType(0), HasExtraAttributeInfo(false), - HasArmTypeAttributes(false), EffectsHaveConditions(false), - NumFunctionEffects(0) {} - }; - - /// A holder for extra information from attributes which aren't part of an - /// \p AttributedType. - struct alignas(void *) FunctionTypeExtraAttributeInfo { - /// A CFI "salt" that differentiates functions with the same prototype. - StringRef CFISalt; - - operator bool() const { return !CFISalt.empty(); } - - void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddString(CFISalt); } - }; - - /// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number - /// of function type attributes that can be set on function types, including - /// function pointers. - enum AArch64SMETypeAttributes : uint16_t { - SME_NormalFunction = 0, - SME_PStateSMEnabledMask = 1 << 0, - SME_PStateSMCompatibleMask = 1 << 1, - - // Describes the value of the state using ArmStateValue. - SME_ZAShift = 2, - SME_ZAMask = 0b111 << SME_ZAShift, - SME_ZT0Shift = 5, - SME_ZT0Mask = 0b111 << SME_ZT0Shift, - - // A bit to tell whether a function is agnostic about sme ZA state. - SME_AgnosticZAStateShift = 8, - SME_AgnosticZAStateMask = 1 << SME_AgnosticZAStateShift, - - SME_AttributeMask = - 0b1'111'111'11 // We can't support more than 9 bits because of - // the bitmask in FunctionTypeArmAttributes - // and ExtProtoInfo. - }; - - enum ArmStateValue : unsigned { - ARM_None = 0, - ARM_Preserves = 1, - ARM_In = 2, - ARM_Out = 3, - ARM_InOut = 4, - }; - - static ArmStateValue getArmZAState(unsigned AttrBits) { - return static_cast((AttrBits & SME_ZAMask) >> SME_ZAShift); - } - - static ArmStateValue getArmZT0State(unsigned AttrBits) { - return static_cast((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift); - } - - /// A holder for Arm type attributes as described in the Arm C/C++ - /// Language extensions which are not particularly common to all - /// types and therefore accounted separately from FunctionTypeBitfields. - struct alignas(void *) FunctionTypeArmAttributes { - /// Any AArch64 SME ACLE type attributes that need to be propagated - /// on declarations and function pointers. - LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes) - unsigned AArch64SMEAttributes : 9; - - FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {} - }; - -protected: - FunctionType(TypeClass tc, QualType res, QualType Canonical, - TypeDependence Dependence, ExtInfo Info) - : Type(tc, Canonical, Dependence), ResultType(res) { - FunctionTypeBits.ExtInfo = Info.Bits; - } - - Qualifiers getFastTypeQuals() const { - if (isFunctionProtoType()) - return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals); - - return Qualifiers(); - } - -public: - QualType getReturnType() const { return ResultType; } - - bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } - unsigned getRegParmType() const { return getExtInfo().getRegParm(); } - - /// Determine whether this function type includes the GNU noreturn - /// attribute. The C++11 [[noreturn]] attribute does not affect the function - /// type. - bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } - - /// Determine whether this is a function prototype that includes the - /// cfi_unchecked_callee attribute. - bool getCFIUncheckedCalleeAttr() const; - - bool getCmseNSCallAttr() const { return getExtInfo().getCmseNSCall(); } - CallingConv getCallConv() const { return getExtInfo().getCC(); } - ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } - - static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, - "Const, volatile and restrict are assumed to be a subset of " - "the fast qualifiers."); - - bool isConst() const { return getFastTypeQuals().hasConst(); } - bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } - bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } - - /// Determine the type of an expression that calls a function of - /// this type. - QualType getCallResultType(const ASTContext &Context) const { - return getReturnType().getNonLValueExprType(Context); - } - - static StringRef getNameForCallConv(CallingConv CC); - - static bool classof(const Type *T) { - return T->getTypeClass() == FunctionNoProto || - T->getTypeClass() == FunctionProto; - } -}; - -/// Represents a K&R-style 'int foo()' function, which has -/// no information available about its arguments. -class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) - : FunctionType(FunctionNoProto, Result, Canonical, - Result->getDependence() & - ~(TypeDependence::DependentInstantiation | - TypeDependence::UnexpandedPack), - Info) {} - -public: - // No additional state past what FunctionType provides. - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getReturnType(), getExtInfo()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, - ExtInfo Info) { - Info.Profile(ID); - ID.AddPointer(ResultType.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == FunctionNoProto; - } -}; - -// ------------------------------------------------------------------------------ - -/// Represents an abstract function effect, using just an enumeration describing -/// its kind. -class FunctionEffect { -public: - /// Identifies the particular effect. - enum class Kind : uint8_t { - NonBlocking, - NonAllocating, - Blocking, - Allocating, - Last = Allocating - }; - constexpr static size_t KindCount = static_cast(Kind::Last) + 1; - - /// Flags describing some behaviors of the effect. - using Flags = unsigned; - enum FlagBit : Flags { - // Can verification inspect callees' implementations? (e.g. nonblocking: - // yes, tcb+types: no). This also implies the need for 2nd-pass - // verification. - FE_InferrableOnCallees = 0x1, - - // Language constructs which effects can diagnose as disallowed. - FE_ExcludeThrow = 0x2, - FE_ExcludeCatch = 0x4, - FE_ExcludeObjCMessageSend = 0x8, - FE_ExcludeStaticLocalVars = 0x10, - FE_ExcludeThreadLocalVars = 0x20 - }; - -private: - Kind FKind; - - // Expansion: for hypothetical TCB+types, there could be one Kind for TCB, - // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would - // be considered for uniqueness. - -public: - explicit FunctionEffect(Kind K) : FKind(K) {} - - /// The kind of the effect. - Kind kind() const { return FKind; } - - /// Return the opposite kind, for effects which have opposites. - Kind oppositeKind() const; - - /// For serialization. - uint32_t toOpaqueInt32() const { return uint32_t(FKind); } - static FunctionEffect fromOpaqueInt32(uint32_t Value) { - return FunctionEffect(Kind(Value)); - } - - /// Flags describing some behaviors of the effect. - Flags flags() const { - switch (kind()) { - case Kind::NonBlocking: - return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | - FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars | - FE_ExcludeThreadLocalVars; - case Kind::NonAllocating: - // Same as NonBlocking, except without FE_ExcludeStaticLocalVars. - return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | - FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars; - case Kind::Blocking: - case Kind::Allocating: - return 0; - } - llvm_unreachable("unknown effect kind"); - } - - /// The description printed in diagnostics, e.g. 'nonblocking'. - StringRef name() const; - - friend raw_ostream &operator<<(raw_ostream &OS, - const FunctionEffect &Effect) { - OS << Effect.name(); - return OS; - } - - /// Determine whether the effect is allowed to be inferred on the callee, - /// which is either a FunctionDecl or BlockDecl. If the returned optional - /// is empty, inference is permitted; otherwise it holds the effect which - /// blocked inference. - /// Example: This allows nonblocking(false) to prevent inference for the - /// function. - std::optional - effectProhibitingInference(const Decl &Callee, - FunctionEffectKindSet CalleeFX) const; - - // Return false for success. When true is returned for a direct call, then the - // FE_InferrableOnCallees flag may trigger inference rather than an immediate - // diagnostic. Caller should be assumed to have the effect (it may not have it - // explicitly when inferring). - bool shouldDiagnoseFunctionCall(bool Direct, - FunctionEffectKindSet CalleeFX) const; - - friend bool operator==(FunctionEffect LHS, FunctionEffect RHS) { - return LHS.FKind == RHS.FKind; - } - friend bool operator!=(FunctionEffect LHS, FunctionEffect RHS) { - return !(LHS == RHS); - } - friend bool operator<(FunctionEffect LHS, FunctionEffect RHS) { - return LHS.FKind < RHS.FKind; - } -}; - -/// Wrap a function effect's condition expression in another struct so -/// that FunctionProtoType's TrailingObjects can treat it separately. -class EffectConditionExpr { - Expr *Cond = nullptr; // if null, unconditional. - -public: - EffectConditionExpr() = default; - EffectConditionExpr(Expr *E) : Cond(E) {} - - Expr *getCondition() const { return Cond; } - - bool operator==(const EffectConditionExpr &RHS) const { - return Cond == RHS.Cond; - } -}; - -/// A FunctionEffect plus a potential boolean expression determining whether -/// the effect is declared (e.g. nonblocking(expr)). Generally the condition -/// expression when present, is dependent. -struct FunctionEffectWithCondition { - FunctionEffect Effect; - EffectConditionExpr Cond; - - FunctionEffectWithCondition(FunctionEffect E, const EffectConditionExpr &C) - : Effect(E), Cond(C) {} - - /// Return a textual description of the effect, and its condition, if any. - std::string description() const; - - friend raw_ostream &operator<<(raw_ostream &OS, - const FunctionEffectWithCondition &CFE); -}; - -/// Support iteration in parallel through a pair of FunctionEffect and -/// EffectConditionExpr containers. -template class FunctionEffectIterator { - friend Container; - - const Container *Outer = nullptr; - size_t Idx = 0; - -public: - FunctionEffectIterator(); - FunctionEffectIterator(const Container &O, size_t I) : Outer(&O), Idx(I) {} - bool operator==(const FunctionEffectIterator &Other) const { - return Idx == Other.Idx; - } - bool operator!=(const FunctionEffectIterator &Other) const { - return Idx != Other.Idx; - } - - FunctionEffectIterator operator++() { - ++Idx; - return *this; - } - - FunctionEffectWithCondition operator*() const { - assert(Outer != nullptr && "invalid FunctionEffectIterator"); - bool HasConds = !Outer->Conditions.empty(); - return FunctionEffectWithCondition{Outer->Effects[Idx], - HasConds ? Outer->Conditions[Idx] - : EffectConditionExpr()}; - } -}; - -/// An immutable set of FunctionEffects and possibly conditions attached to -/// them. The effects and conditions reside in memory not managed by this object -/// (typically, trailing objects in FunctionProtoType, or borrowed references -/// from a FunctionEffectSet). -/// -/// Invariants: -/// - there is never more than one instance of any given effect. -/// - the array of conditions is either empty or has the same size as the -/// array of effects. -/// - some conditions may be null expressions; each condition pertains to -/// the effect at the same array index. -/// -/// Also, if there are any conditions, at least one of those expressions will be -/// dependent, but this is only asserted in the constructor of -/// FunctionProtoType. -/// -/// See also FunctionEffectSet, in Sema, which provides a mutable set. -class FunctionEffectsRef { - // Restrict classes which can call the private constructor -- these friends - // all maintain the required invariants. FunctionEffectSet is generally the - // only way in which the arrays are created; FunctionProtoType will not - // reorder them. - friend FunctionProtoType; - friend FunctionEffectSet; - - ArrayRef Effects; - ArrayRef Conditions; - - // The arrays are expected to have been sorted by the caller, with the - // effects in order. The conditions array must be empty or the same size - // as the effects array, since the conditions are associated with the effects - // at the same array indices. - FunctionEffectsRef(ArrayRef FX, - ArrayRef Conds) - : Effects(FX), Conditions(Conds) {} - -public: - /// Extract the effects from a Type if it is a function, block, or member - /// function pointer, or a reference or pointer to one. - static FunctionEffectsRef get(QualType QT); - - /// Asserts invariants. - static FunctionEffectsRef create(ArrayRef FX, - ArrayRef Conds); - - FunctionEffectsRef() = default; - - bool empty() const { return Effects.empty(); } - size_t size() const { return Effects.size(); } - - ArrayRef effects() const { return Effects; } - ArrayRef conditions() const { return Conditions; } - - using iterator = FunctionEffectIterator; - friend iterator; - iterator begin() const { return iterator(*this, 0); } - iterator end() const { return iterator(*this, size()); } - - friend bool operator==(const FunctionEffectsRef &LHS, - const FunctionEffectsRef &RHS) { - return LHS.Effects == RHS.Effects && LHS.Conditions == RHS.Conditions; - } - friend bool operator!=(const FunctionEffectsRef &LHS, - const FunctionEffectsRef &RHS) { - return !(LHS == RHS); - } - - void dump(llvm::raw_ostream &OS) const; -}; - -/// A mutable set of FunctionEffect::Kind. -class FunctionEffectKindSet { - // For now this only needs to be a bitmap. - constexpr static size_t EndBitPos = FunctionEffect::KindCount; - using KindBitsT = std::bitset; - - KindBitsT KindBits{}; - - explicit FunctionEffectKindSet(KindBitsT KB) : KindBits(KB) {} - - // Functions to translate between an effect kind, starting at 1, and a - // position in the bitset. - - constexpr static size_t kindToPos(FunctionEffect::Kind K) { - return static_cast(K); - } - - constexpr static FunctionEffect::Kind posToKind(size_t Pos) { - return static_cast(Pos); - } - - // Iterates through the bits which are set. - class iterator { - const FunctionEffectKindSet *Outer = nullptr; - size_t Idx = 0; - - // If Idx does not reference a set bit, advance it until it does, - // or until it reaches EndBitPos. - void advanceToNextSetBit() { - while (Idx < EndBitPos && !Outer->KindBits.test(Idx)) - ++Idx; - } - - public: - iterator(); - iterator(const FunctionEffectKindSet &O, size_t I) : Outer(&O), Idx(I) { - advanceToNextSetBit(); - } - bool operator==(const iterator &Other) const { return Idx == Other.Idx; } - bool operator!=(const iterator &Other) const { return Idx != Other.Idx; } - - iterator operator++() { - ++Idx; - advanceToNextSetBit(); - return *this; - } - - FunctionEffect operator*() const { - assert(Idx < EndBitPos && "Dereference of end iterator"); - return FunctionEffect(posToKind(Idx)); - } - }; - -public: - FunctionEffectKindSet() = default; - explicit FunctionEffectKindSet(FunctionEffectsRef FX) { insert(FX); } - - iterator begin() const { return iterator(*this, 0); } - iterator end() const { return iterator(*this, EndBitPos); } - - void insert(FunctionEffect Effect) { KindBits.set(kindToPos(Effect.kind())); } - void insert(FunctionEffectsRef FX) { - for (FunctionEffect Item : FX.effects()) - insert(Item); - } - void insert(FunctionEffectKindSet Set) { KindBits |= Set.KindBits; } - - bool empty() const { return KindBits.none(); } - bool contains(const FunctionEffect::Kind EK) const { - return KindBits.test(kindToPos(EK)); - } - void dump(llvm::raw_ostream &OS) const; - - static FunctionEffectKindSet difference(FunctionEffectKindSet LHS, - FunctionEffectKindSet RHS) { - return FunctionEffectKindSet(LHS.KindBits & ~RHS.KindBits); - } -}; - -/// A mutable set of FunctionEffects and possibly conditions attached to them. -/// Used to compare and merge effects on declarations. -/// -/// Has the same invariants as FunctionEffectsRef. -class FunctionEffectSet { - SmallVector Effects; - SmallVector Conditions; - -public: - FunctionEffectSet() = default; - - explicit FunctionEffectSet(const FunctionEffectsRef &FX) - : Effects(FX.effects()), Conditions(FX.conditions()) {} - - bool empty() const { return Effects.empty(); } - size_t size() const { return Effects.size(); } - - using iterator = FunctionEffectIterator; - friend iterator; - iterator begin() const { return iterator(*this, 0); } - iterator end() const { return iterator(*this, size()); } - - operator FunctionEffectsRef() const { return {Effects, Conditions}; } - - void dump(llvm::raw_ostream &OS) const; - - // Mutators - - // On insertion, a conflict occurs when attempting to insert an - // effect which is opposite an effect already in the set, or attempting - // to insert an effect which is already in the set but with a condition - // which is not identical. - struct Conflict { - FunctionEffectWithCondition Kept; - FunctionEffectWithCondition Rejected; - }; - using Conflicts = SmallVector; - - // Returns true for success (obviating a check of Errs.empty()). - bool insert(const FunctionEffectWithCondition &NewEC, Conflicts &Errs); - - // Returns true for success (obviating a check of Errs.empty()). - bool insert(const FunctionEffectsRef &Set, Conflicts &Errs); - - // Set operations - - static FunctionEffectSet getUnion(FunctionEffectsRef LHS, - FunctionEffectsRef RHS, Conflicts &Errs); - static FunctionEffectSet getIntersection(FunctionEffectsRef LHS, - FunctionEffectsRef RHS); -}; - -/// Represents a prototype with parameter type info, e.g. -/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no -/// parameters, not as having a single void parameter. Such a type can have -/// an exception specification, but this specification is not part of the -/// canonical type. FunctionProtoType has several trailing objects, some of -/// which optional. For more information about the trailing objects see -/// the first comment inside FunctionProtoType. -class FunctionProtoType final - : public FunctionType, - public llvm::FoldingSetNode, - private llvm::TrailingObjects< - FunctionProtoType, QualType, SourceLocation, - FunctionType::FunctionTypeExtraBitfields, - FunctionType::FunctionTypeExtraAttributeInfo, - FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType, - Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers, - FunctionEffect, EffectConditionExpr> { - friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - - // FunctionProtoType is followed by several trailing objects, some of - // which optional. They are in order: - // - // * An array of getNumParams() QualType holding the parameter types. - // Always present. Note that for the vast majority of FunctionProtoType, - // these will be the only trailing objects. - // - // * Optionally if the function is variadic, the SourceLocation of the - // ellipsis. - // - // * Optionally if some extra data is stored in FunctionTypeExtraBitfields - // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): - // a single FunctionTypeExtraBitfields. Present if and only if - // hasExtraBitfields() is true. - // - // * Optionally exactly one of: - // * an array of getNumExceptions() ExceptionType, - // * a single Expr *, - // * a pair of FunctionDecl *, - // * a single FunctionDecl * - // used to store information about the various types of exception - // specification. See getExceptionSpecSize for the details. - // - // * Optionally an array of getNumParams() ExtParameterInfo holding - // an ExtParameterInfo for each of the parameters. Present if and - // only if hasExtParameterInfos() is true. - // - // * Optionally a Qualifiers object to represent extra qualifiers that can't - // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and - // only if hasExtQualifiers() is true. - // - // * Optionally, an array of getNumFunctionEffects() FunctionEffect. - // Present only when getNumFunctionEffects() > 0 - // - // * Optionally, an array of getNumFunctionEffects() EffectConditionExpr. - // Present only when getNumFunctionEffectConditions() > 0. - // - // The optional FunctionTypeExtraBitfields has to be before the data - // related to the exception specification since it contains the number - // of exception types. - // - // We put the ExtParameterInfos later. If all were equal, it would make - // more sense to put these before the exception specification, because - // it's much easier to skip past them compared to the elaborate switch - // required to skip the exception specification. However, all is not - // equal; ExtParameterInfos are used to model very uncommon features, - // and it's better not to burden the more common paths. - -public: - /// Holds information about the various types of exception specification. - /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is - /// used to group together the various bits of information about the - /// exception specification. - struct ExceptionSpecInfo { - /// The kind of exception specification this is. - ExceptionSpecificationType Type = EST_None; - - /// Explicitly-specified list of exception types. - ArrayRef Exceptions; - - /// Noexcept expression, if this is a computed noexcept specification. - Expr *NoexceptExpr = nullptr; - - /// The function whose exception specification this is, for - /// EST_Unevaluated and EST_Uninstantiated. - FunctionDecl *SourceDecl = nullptr; - - /// The function template whose exception specification this is instantiated - /// from, for EST_Uninstantiated. - FunctionDecl *SourceTemplate = nullptr; - - ExceptionSpecInfo() = default; - - ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} - - void instantiate(); - }; - - /// Extra information about a function prototype. ExtProtoInfo is not - /// stored as such in FunctionProtoType but is used to group together - /// the various bits of extra information about a function prototype. - struct ExtProtoInfo { - FunctionType::ExtInfo ExtInfo; - Qualifiers TypeQuals; - RefQualifierKind RefQualifier = RQ_None; - ExceptionSpecInfo ExceptionSpec; - const ExtParameterInfo *ExtParameterInfos = nullptr; - SourceLocation EllipsisLoc; - FunctionEffectsRef FunctionEffects; - FunctionTypeExtraAttributeInfo ExtraAttributeInfo; - - LLVM_PREFERRED_TYPE(bool) - unsigned Variadic : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned HasTrailingReturn : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned CFIUncheckedCallee : 1; - LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes) - unsigned AArch64SMEAttributes : 9; - - ExtProtoInfo() - : Variadic(false), HasTrailingReturn(false), CFIUncheckedCallee(false), - AArch64SMEAttributes(SME_NormalFunction) {} - - ExtProtoInfo(CallingConv CC) - : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), - CFIUncheckedCallee(false), AArch64SMEAttributes(SME_NormalFunction) {} - - ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { - ExtProtoInfo Result(*this); - Result.ExceptionSpec = ESI; - return Result; - } - - ExtProtoInfo withCFIUncheckedCallee(bool CFIUncheckedCallee) { - ExtProtoInfo Result(*this); - Result.CFIUncheckedCallee = CFIUncheckedCallee; - return Result; - } - - bool requiresFunctionProtoTypeExtraBitfields() const { - return ExceptionSpec.Type == EST_Dynamic || - requiresFunctionProtoTypeArmAttributes() || - requiresFunctionProtoTypeExtraAttributeInfo() || - !FunctionEffects.empty(); - } - - bool requiresFunctionProtoTypeArmAttributes() const { - return AArch64SMEAttributes != SME_NormalFunction; - } - - bool requiresFunctionProtoTypeExtraAttributeInfo() const { - return static_cast(ExtraAttributeInfo); - } - - void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) { - if (Enable) - AArch64SMEAttributes |= Kind; - else - AArch64SMEAttributes &= ~Kind; - } - }; - -private: - unsigned numTrailingObjects(OverloadToken) const { - return getNumParams(); - } - - unsigned numTrailingObjects(OverloadToken) const { - return isVariadic(); - } - - unsigned numTrailingObjects(OverloadToken) const { - return hasArmTypeAttributes(); - } - - unsigned numTrailingObjects(OverloadToken) const { - return hasExtraBitfields(); - } - - unsigned - numTrailingObjects(OverloadToken) const { - return hasExtraAttributeInfo(); - } - - unsigned numTrailingObjects(OverloadToken) const { - return getExceptionSpecSize().NumExceptionType; - } - - unsigned numTrailingObjects(OverloadToken) const { - return getExceptionSpecSize().NumExprPtr; - } - - unsigned numTrailingObjects(OverloadToken) const { - return getExceptionSpecSize().NumFunctionDeclPtr; - } - - unsigned numTrailingObjects(OverloadToken) const { - return hasExtParameterInfos() ? getNumParams() : 0; - } - - unsigned numTrailingObjects(OverloadToken) const { - return hasExtQualifiers() ? 1 : 0; - } - - unsigned numTrailingObjects(OverloadToken) const { - return getNumFunctionEffects(); - } - - /// Determine whether there are any argument types that - /// contain an unexpanded parameter pack. - static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, - unsigned numArgs) { - for (unsigned Idx = 0; Idx < numArgs; ++Idx) - if (ArgArray[Idx]->containsUnexpandedParameterPack()) - return true; - - return false; - } - - FunctionProtoType(QualType result, ArrayRef params, - QualType canonical, const ExtProtoInfo &epi); - - /// This struct is returned by getExceptionSpecSize and is used to - /// translate an ExceptionSpecificationType to the number and kind - /// of trailing objects related to the exception specification. - struct ExceptionSpecSizeHolder { - unsigned NumExceptionType; - unsigned NumExprPtr; - unsigned NumFunctionDeclPtr; - }; - - /// Return the number and kind of trailing objects - /// related to the exception specification. - static ExceptionSpecSizeHolder - getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { - switch (EST) { - case EST_None: - case EST_DynamicNone: - case EST_MSAny: - case EST_BasicNoexcept: - case EST_Unparsed: - case EST_NoThrow: - return {0, 0, 0}; - - case EST_Dynamic: - return {NumExceptions, 0, 0}; - - case EST_DependentNoexcept: - case EST_NoexceptFalse: - case EST_NoexceptTrue: - return {0, 1, 0}; - - case EST_Uninstantiated: - return {0, 0, 2}; - - case EST_Unevaluated: - return {0, 0, 1}; - } - llvm_unreachable("bad exception specification kind"); - } - - /// Return the number and kind of trailing objects - /// related to the exception specification. - ExceptionSpecSizeHolder getExceptionSpecSize() const { - return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); - } - - /// Whether the trailing FunctionTypeExtraBitfields is present. - bool hasExtraBitfields() const { - assert((getExceptionSpecType() != EST_Dynamic || - FunctionTypeBits.HasExtraBitfields) && - "ExtraBitfields are required for given ExceptionSpecType"); - return FunctionTypeBits.HasExtraBitfields; - - } - - bool hasExtraAttributeInfo() const { - return FunctionTypeBits.HasExtraBitfields && - getTrailingObjects() - ->HasExtraAttributeInfo; - } - - bool hasArmTypeAttributes() const { - return FunctionTypeBits.HasExtraBitfields && - getTrailingObjects() - ->HasArmTypeAttributes; - } - - bool hasExtQualifiers() const { - return FunctionTypeBits.HasExtQuals; - } - -public: - unsigned getNumParams() const { return FunctionTypeBits.NumParams; } - - QualType getParamType(unsigned i) const { - assert(i < getNumParams() && "invalid parameter index"); - return param_type_begin()[i]; - } - - ArrayRef getParamTypes() const { - return {param_type_begin(), param_type_end()}; - } - - ExtProtoInfo getExtProtoInfo() const { - ExtProtoInfo EPI; - EPI.ExtInfo = getExtInfo(); - EPI.Variadic = isVariadic(); - EPI.EllipsisLoc = getEllipsisLoc(); - EPI.HasTrailingReturn = hasTrailingReturn(); - EPI.CFIUncheckedCallee = hasCFIUncheckedCallee(); - EPI.ExceptionSpec = getExceptionSpecInfo(); - EPI.TypeQuals = getMethodQuals(); - EPI.RefQualifier = getRefQualifier(); - EPI.ExtParameterInfos = getExtParameterInfosOrNull(); - EPI.ExtraAttributeInfo = getExtraAttributeInfo(); - EPI.AArch64SMEAttributes = getAArch64SMEAttributes(); - EPI.FunctionEffects = getFunctionEffects(); - return EPI; - } - - /// Get the kind of exception specification on this function. - ExceptionSpecificationType getExceptionSpecType() const { - return static_cast( - FunctionTypeBits.ExceptionSpecType); - } - - /// Return whether this function has any kind of exception spec. - bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } - - /// Return whether this function has a dynamic (throw) exception spec. - bool hasDynamicExceptionSpec() const { - return isDynamicExceptionSpec(getExceptionSpecType()); - } - - /// Return whether this function has a noexcept exception spec. - bool hasNoexceptExceptionSpec() const { - return isNoexceptExceptionSpec(getExceptionSpecType()); - } - - /// Return whether this function has a dependent exception spec. - bool hasDependentExceptionSpec() const; - - /// Return whether this function has an instantiation-dependent exception - /// spec. - bool hasInstantiationDependentExceptionSpec() const; - - /// Return all the available information about this type's exception spec. - ExceptionSpecInfo getExceptionSpecInfo() const { - ExceptionSpecInfo Result; - Result.Type = getExceptionSpecType(); - if (Result.Type == EST_Dynamic) { - Result.Exceptions = exceptions(); - } else if (isComputedNoexcept(Result.Type)) { - Result.NoexceptExpr = getNoexceptExpr(); - } else if (Result.Type == EST_Uninstantiated) { - Result.SourceDecl = getExceptionSpecDecl(); - Result.SourceTemplate = getExceptionSpecTemplate(); - } else if (Result.Type == EST_Unevaluated) { - Result.SourceDecl = getExceptionSpecDecl(); - } - return Result; - } - - /// Return the number of types in the exception specification. - unsigned getNumExceptions() const { - return getExceptionSpecType() == EST_Dynamic - ? getTrailingObjects() - ->NumExceptionType - : 0; - } - - /// Return the ith exception type, where 0 <= i < getNumExceptions(). - QualType getExceptionType(unsigned i) const { - assert(i < getNumExceptions() && "Invalid exception number!"); - return exception_begin()[i]; - } - - /// Return the expression inside noexcept(expression), or a null pointer - /// if there is none (because the exception spec is not of this form). - Expr *getNoexceptExpr() const { - if (!isComputedNoexcept(getExceptionSpecType())) - return nullptr; - return *getTrailingObjects(); - } - - /// If this function type has an exception specification which hasn't - /// been determined yet (either because it has not been evaluated or because - /// it has not been instantiated), this is the function whose exception - /// specification is represented by this type. - FunctionDecl *getExceptionSpecDecl() const { - if (getExceptionSpecType() != EST_Uninstantiated && - getExceptionSpecType() != EST_Unevaluated) - return nullptr; - return getTrailingObjects()[0]; - } - - /// If this function type has an uninstantiated exception - /// specification, this is the function whose exception specification - /// should be instantiated to find the exception specification for - /// this type. - FunctionDecl *getExceptionSpecTemplate() const { - if (getExceptionSpecType() != EST_Uninstantiated) - return nullptr; - return getTrailingObjects()[1]; - } - - /// Determine whether this function type has a non-throwing exception - /// specification. - CanThrowResult canThrow() const; - - /// Determine whether this function type has a non-throwing exception - /// specification. If this depends on template arguments, returns - /// \c ResultIfDependent. - bool isNothrow(bool ResultIfDependent = false) const { - return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; - } - - /// Whether this function prototype is variadic. - bool isVariadic() const { return FunctionTypeBits.Variadic; } - - SourceLocation getEllipsisLoc() const { - return isVariadic() ? *getTrailingObjects() - : SourceLocation(); - } - - /// Determines whether this function prototype contains a - /// parameter pack at the end. - /// - /// A function template whose last parameter is a parameter pack can be - /// called with an arbitrary number of arguments, much like a variadic - /// function. - bool isTemplateVariadic() const; - - /// Whether this function prototype has a trailing return type. - bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } - - bool hasCFIUncheckedCallee() const { - return FunctionTypeBits.CFIUncheckedCallee; - } - - Qualifiers getMethodQuals() const { - if (hasExtQualifiers()) - return *getTrailingObjects(); - else - return getFastTypeQuals(); - } - - /// Retrieve the ref-qualifier associated with this function type. - RefQualifierKind getRefQualifier() const { - return static_cast(FunctionTypeBits.RefQualifier); - } - - using param_type_iterator = const QualType *; - - ArrayRef param_types() const { - return {param_type_begin(), param_type_end()}; - } - - param_type_iterator param_type_begin() const { - return getTrailingObjects(); - } - - param_type_iterator param_type_end() const { - return param_type_begin() + getNumParams(); - } - - using exception_iterator = const QualType *; - - ArrayRef exceptions() const { - return {exception_begin(), exception_end()}; - } - - exception_iterator exception_begin() const { - return reinterpret_cast( - getTrailingObjects()); - } - - exception_iterator exception_end() const { - return exception_begin() + getNumExceptions(); - } - - /// Is there any interesting extra information for any of the parameters - /// of this function type? - bool hasExtParameterInfos() const { - return FunctionTypeBits.HasExtParameterInfos; - } - - ArrayRef getExtParameterInfos() const { - assert(hasExtParameterInfos()); - return ArrayRef(getTrailingObjects(), - getNumParams()); - } - - /// Return a pointer to the beginning of the array of extra parameter - /// information, if present, or else null if none of the parameters - /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos. - const ExtParameterInfo *getExtParameterInfosOrNull() const { - if (!hasExtParameterInfos()) - return nullptr; - return getTrailingObjects(); - } - - /// Return the extra attribute information. - FunctionTypeExtraAttributeInfo getExtraAttributeInfo() const { - if (hasExtraAttributeInfo()) - return *getTrailingObjects(); - return FunctionTypeExtraAttributeInfo(); - } - - /// Return a bitmask describing the SME attributes on the function type, see - /// AArch64SMETypeAttributes for their values. - unsigned getAArch64SMEAttributes() const { - if (!hasArmTypeAttributes()) - return SME_NormalFunction; - return getTrailingObjects() - ->AArch64SMEAttributes; - } - - ExtParameterInfo getExtParameterInfo(unsigned I) const { - assert(I < getNumParams() && "parameter index out of range"); - if (hasExtParameterInfos()) - return getTrailingObjects()[I]; - return ExtParameterInfo(); - } - - ParameterABI getParameterABI(unsigned I) const { - assert(I < getNumParams() && "parameter index out of range"); - if (hasExtParameterInfos()) - return getTrailingObjects()[I].getABI(); - return ParameterABI::Ordinary; - } - - bool isParamConsumed(unsigned I) const { - assert(I < getNumParams() && "parameter index out of range"); - if (hasExtParameterInfos()) - return getTrailingObjects()[I].isConsumed(); - return false; - } - - unsigned getNumFunctionEffects() const { - return hasExtraBitfields() - ? getTrailingObjects() - ->NumFunctionEffects - : 0; - } - - // For serialization. - ArrayRef getFunctionEffectsWithoutConditions() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects(); - if (Bitfields->NumFunctionEffects > 0) - return getTrailingObjects( - Bitfields->NumFunctionEffects); - } - return {}; - } - - unsigned getNumFunctionEffectConditions() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects(); - if (Bitfields->EffectsHaveConditions) - return Bitfields->NumFunctionEffects; - } - return 0; - } - - // For serialization. - ArrayRef getFunctionEffectConditions() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects(); - if (Bitfields->EffectsHaveConditions) - return getTrailingObjects( - Bitfields->NumFunctionEffects); - } - return {}; - } - - // Combines effects with their conditions. - FunctionEffectsRef getFunctionEffects() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects(); - if (Bitfields->NumFunctionEffects > 0) { - const size_t NumConds = Bitfields->EffectsHaveConditions - ? Bitfields->NumFunctionEffects - : 0; - return FunctionEffectsRef( - getTrailingObjects(Bitfields->NumFunctionEffects), - {NumConds ? getTrailingObjects() : nullptr, - NumConds}); - } - } - return {}; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void printExceptionSpecification(raw_ostream &OS, - const PrintingPolicy &Policy) const; - - static bool classof(const Type *T) { - return T->getTypeClass() == FunctionProto; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); - static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, - param_type_iterator ArgTys, unsigned NumArgs, - const ExtProtoInfo &EPI, const ASTContext &Context, - bool Canonical); -}; - -/// The elaboration keyword that precedes a qualified type name or -/// introduces an elaborated-type-specifier. -enum class ElaboratedTypeKeyword { - /// The "struct" keyword introduces the elaborated-type-specifier. - Struct, - - /// The "__interface" keyword introduces the elaborated-type-specifier. - Interface, - - /// The "union" keyword introduces the elaborated-type-specifier. - Union, - - /// The "class" keyword introduces the elaborated-type-specifier. - Class, - - /// The "enum" keyword introduces the elaborated-type-specifier. - Enum, - - /// The "typename" keyword precedes the qualified type name, e.g., - /// \c typename T::type. - Typename, - - /// No keyword precedes the qualified type name. - None -}; - -/// The kind of a tag type. -enum class TagTypeKind { - /// The "struct" keyword. - Struct, - - /// The "__interface" keyword. - Interface, - - /// The "union" keyword. - Union, - - /// The "class" keyword. - Class, - - /// The "enum" keyword. - Enum -}; - -/// Provides a few static helpers for converting and printing -/// elaborated type keyword and tag type kind enumerations. -struct KeywordHelpers { - /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. - static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); - - /// Converts a type specifier (DeclSpec::TST) into a tag type kind. - /// It is an error to provide a type specifier which *isn't* a tag kind here. - static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); - - /// Converts a TagTypeKind into an elaborated type keyword. - static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); - - /// Converts an elaborated type keyword into a TagTypeKind. - /// It is an error to provide an elaborated type keyword - /// which *isn't* a tag kind here. - static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); - - static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); - - static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); - - static StringRef getTagTypeKindName(TagTypeKind Kind) { - return getKeywordName(getKeywordForTagTypeKind(Kind)); - } -}; - -template class KeywordWrapper : public T, public KeywordHelpers { -protected: - template - KeywordWrapper(ElaboratedTypeKeyword Keyword, As &&...as) - : T(std::forward(as)...) { - this->KeywordWrapperBits.Keyword = llvm::to_underlying(Keyword); - } - -public: - ElaboratedTypeKeyword getKeyword() const { - return static_cast(this->KeywordWrapperBits.Keyword); - } - - class CannotCastToThisType {}; - static CannotCastToThisType classof(const T *); -}; - -/// A helper class for Type nodes having an ElaboratedTypeKeyword. -/// The keyword in stored in the free bits of the base class. -class TypeWithKeyword : public KeywordWrapper { -protected: - TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, - QualType Canonical, TypeDependence Dependence) - : KeywordWrapper(Keyword, tc, Canonical, Dependence) {} -}; - -template struct FoldingSetPlaceholder : llvm::FoldingSetNode { - void Profile(llvm::FoldingSetNodeID &ID) { getType()->Profile(ID); } - - inline const T *getType() const { - constexpr unsigned long Offset = - llvm::alignTo(sizeof(T), alignof(FoldingSetPlaceholder)); - const auto *Addr = reinterpret_cast( - reinterpret_cast(this) - Offset); - assert(llvm::isAddrAligned(llvm::Align(alignof(T)), Addr)); - return Addr; - } -}; - -/// Represents the dependent type named by a dependently-scoped -/// typename using declaration, e.g. -/// using typename Base::foo; -/// -/// Template instantiation turns these into the underlying type. -class UnresolvedUsingType final - : public TypeWithKeyword, - private llvm::TrailingObjects, - NestedNameSpecifier> { - friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - - UnresolvedUsingTypenameDecl *Decl; - - unsigned numTrailingObjects( - OverloadToken>) const { - assert(UnresolvedUsingBits.hasQualifier || - getKeyword() != ElaboratedTypeKeyword::None); - return 1; - } - - FoldingSetPlaceholder *getFoldingSetPlaceholder() { - assert(numTrailingObjects( - OverloadToken>{}) == - 1); - return getTrailingObjects>(); - } - - UnresolvedUsingType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, - const UnresolvedUsingTypenameDecl *D, - const Type *CanonicalType); - -public: - NestedNameSpecifier getQualifier() const { - return UnresolvedUsingBits.hasQualifier - ? *getTrailingObjects() - : std::nullopt; - } - - UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, - const UnresolvedUsingTypenameDecl *D) { - static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7); - ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword)); - if (Qualifier) - Qualifier.Profile(ID); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getKeyword(), getQualifier(), getDecl()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == UnresolvedUsing; - } -}; - -class UsingType final : public TypeWithKeyword, - public llvm::FoldingSetNode, - llvm::TrailingObjects { - UsingShadowDecl *D; - QualType UnderlyingType; - - friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - - UsingType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, - const UsingShadowDecl *D, QualType UnderlyingType); - -public: - NestedNameSpecifier getQualifier() const { - return UsingBits.hasQualifier ? *getTrailingObjects() : std::nullopt; - } - - UsingShadowDecl *getDecl() const { return D; } - - QualType desugar() const { return UnderlyingType; } - bool isSugared() const { return true; } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, const UsingShadowDecl *D, - QualType UnderlyingType) { - static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7); - ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword)); - UnderlyingType.Profile(ID); - if (Qualifier) - Qualifier.Profile(ID); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getKeyword(), getQualifier(), D, desugar()); - } - static bool classof(const Type *T) { return T->getTypeClass() == Using; } -}; - -class TypedefType final - : public TypeWithKeyword, - private llvm::TrailingObjects, - NestedNameSpecifier, QualType> { - TypedefNameDecl *Decl; - friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - - unsigned - numTrailingObjects(OverloadToken>) const { - assert(TypedefBits.hasQualifier || TypedefBits.hasTypeDifferentFromDecl || - getKeyword() != ElaboratedTypeKeyword::None); - return 1; - } - - unsigned numTrailingObjects(OverloadToken) const { - return TypedefBits.hasQualifier; - } - - TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, const TypedefNameDecl *D, - QualType UnderlyingType, bool HasTypeDifferentFromDecl); - - FoldingSetPlaceholder *getFoldingSetPlaceholder() { - assert(numTrailingObjects( - OverloadToken>{}) == 1); - return getTrailingObjects>(); - } - -public: - NestedNameSpecifier getQualifier() const { - return TypedefBits.hasQualifier ? *getTrailingObjects() - : std::nullopt; - } - - TypedefNameDecl *getDecl() const { return Decl; } - - bool isSugared() const { return true; } - - // This always has the 'same' type as declared, but not necessarily identical. - QualType desugar() const; - - // Internal helper, for debugging purposes. - bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, - const TypedefNameDecl *Decl, QualType Underlying) { - - ID.AddInteger(uintptr_t(Decl) | (Keyword != ElaboratedTypeKeyword::None) | - (!Qualifier << 1)); - if (Keyword != ElaboratedTypeKeyword::None) - ID.AddInteger(llvm::to_underlying(Keyword)); - if (Qualifier) - Qualifier.Profile(ID); - if (!Underlying.isNull()) - Underlying.Profile(ID); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getKeyword(), getQualifier(), getDecl(), - typeMatchesDecl() ? QualType() : desugar()); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } -}; - -/// Sugar type that represents a type that was qualified by a qualifier written -/// as a macro invocation. -class MacroQualifiedType : public Type { - friend class ASTContext; // ASTContext creates these. - - QualType UnderlyingTy; - const IdentifierInfo *MacroII; - - MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy, - const IdentifierInfo *MacroII) - : Type(MacroQualified, CanonTy, UnderlyingTy->getDependence()), - UnderlyingTy(UnderlyingTy), MacroII(MacroII) { - assert(isa(UnderlyingTy) && - "Expected a macro qualified type to only wrap attributed types."); - } - -public: - const IdentifierInfo *getMacroIdentifier() const { return MacroII; } - QualType getUnderlyingType() const { return UnderlyingTy; } - - /// Return this attributed type's modified type with no qualifiers attached to - /// it. - QualType getModifiedType() const; - - bool isSugared() const { return true; } - QualType desugar() const; - - static bool classof(const Type *T) { - return T->getTypeClass() == MacroQualified; - } -}; - -/// Represents a `typeof` (or __typeof__) expression (a C23 feature and GCC -/// extension) or a `typeof_unqual` expression (a C23 feature). -class TypeOfExprType : public Type { - Expr *TOExpr; - const ASTContext &Context; - -protected: - friend class ASTContext; // ASTContext creates these. - - TypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind, - QualType Can = QualType()); - -public: - Expr *getUnderlyingExpr() const { return TOExpr; } - - /// Returns the kind of 'typeof' type this is. - TypeOfKind getKind() const { - return static_cast(TypeOfBits.Kind); - } - - /// Remove a single level of sugar. - QualType desugar() const; - - /// Returns whether this type directly provides sugar. - bool isSugared() const; - - static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } -}; - -/// Internal representation of canonical, dependent -/// `typeof(expr)` types. -/// -/// This class is used internally by the ASTContext to manage -/// canonical, dependent types, only. Clients will only see instances -/// of this class via TypeOfExprType nodes. -class DependentTypeOfExprType : public TypeOfExprType, - public llvm::FoldingSetNode { -public: - DependentTypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind) - : TypeOfExprType(Context, E, Kind) {} - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getUnderlyingExpr(), - getKind() == TypeOfKind::Unqualified); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - Expr *E, bool IsUnqual); -}; - -/// Represents `typeof(type)`, a C23 feature and GCC extension, or -/// `typeof_unqual(type), a C23 feature. -class TypeOfType : public Type { - friend class ASTContext; // ASTContext creates these. - - QualType TOType; - const ASTContext &Context; - - TypeOfType(const ASTContext &Context, QualType T, QualType Can, - TypeOfKind Kind); - -public: - QualType getUnmodifiedType() const { return TOType; } - - /// Remove a single level of sugar. - QualType desugar() const; - - /// Returns whether this type directly provides sugar. - bool isSugared() const { return true; } - - /// Returns the kind of 'typeof' type this is. - TypeOfKind getKind() const { - return static_cast(TypeOfBits.Kind); - } - - static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } -}; - -/// Represents the type `decltype(expr)` (C++11). -class DecltypeType : public Type { - Expr *E; - QualType UnderlyingType; - -protected: - friend class ASTContext; // ASTContext creates these. - - DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); - -public: - Expr *getUnderlyingExpr() const { return E; } - QualType getUnderlyingType() const { return UnderlyingType; } - - /// Remove a single level of sugar. - QualType desugar() const; - - /// Returns whether this type directly provides sugar. - bool isSugared() const; - - static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } -}; - -/// Internal representation of canonical, dependent -/// decltype(expr) types. -/// -/// This class is used internally by the ASTContext to manage -/// canonical, dependent types, only. Clients will only see instances -/// of this class via DecltypeType nodes. -class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { -public: - DependentDecltypeType(Expr *E); - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getUnderlyingExpr()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - Expr *E); -}; - -class PackIndexingType final - : public Type, - public llvm::FoldingSetNode, - private llvm::TrailingObjects { - friend TrailingObjects; - - QualType Pattern; - Expr *IndexExpr; - - unsigned Size : 31; - - LLVM_PREFERRED_TYPE(bool) - unsigned FullySubstituted : 1; - -protected: - friend class ASTContext; // ASTContext creates these. - PackIndexingType(QualType Canonical, QualType Pattern, Expr *IndexExpr, - bool FullySubstituted, ArrayRef Expansions = {}); - -public: - Expr *getIndexExpr() const { return IndexExpr; } - QualType getPattern() const { return Pattern; } - - bool isSugared() const { return hasSelectedType(); } - - QualType desugar() const { - if (hasSelectedType()) - return getSelectedType(); - return QualType(this, 0); - } - - QualType getSelectedType() const { - assert(hasSelectedType() && "Type is dependant"); - return *(getExpansionsPtr() + *getSelectedIndex()); - } - - UnsignedOrNone getSelectedIndex() const; - - bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; } - - bool isFullySubstituted() const { return FullySubstituted; } - - bool expandsToEmptyPack() const { return isFullySubstituted() && Size == 0; } - - ArrayRef getExpansions() const { - return {getExpansionsPtr(), Size}; - } - - static bool classof(const Type *T) { - return T->getTypeClass() == PackIndexing; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context); - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType Pattern, Expr *E, bool FullySubstituted, - ArrayRef Expansions); - -private: - const QualType *getExpansionsPtr() const { return getTrailingObjects(); } - - static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr, - ArrayRef Expansions = {}); -}; - -/// A unary type transform, which is a type constructed from another. -class UnaryTransformType : public Type, public llvm::FoldingSetNode { -public: - enum UTTKind { -#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum, -#include "clang/Basic/TransformTypeTraits.def" - }; - -private: - /// The untransformed type. - QualType BaseType; - - /// The transformed type if not dependent, otherwise the same as BaseType. - QualType UnderlyingType; - - UTTKind UKind; - -protected: - friend class ASTContext; - - UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, - QualType CanonicalTy); - -public: - bool isSugared() const { return !isDependentType(); } - QualType desugar() const { return UnderlyingType; } - - QualType getUnderlyingType() const { return UnderlyingType; } - QualType getBaseType() const { return BaseType; } - - UTTKind getUTTKind() const { return UKind; } - - static bool classof(const Type *T) { - return T->getTypeClass() == UnaryTransform; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, - QualType UnderlyingType, UTTKind UKind) { - BaseType.Profile(ID); - UnderlyingType.Profile(ID); - ID.AddInteger(UKind); - } -}; - -class TagType : public TypeWithKeyword { - friend class ASTContext; // ASTContext creates these. - - /// Stores the TagDecl associated with this type. The decl may point to any - /// TagDecl that declares the entity. - TagDecl *decl; - - void *getTrailingPointer() const; - NestedNameSpecifier &getTrailingQualifier() const; - -protected: - TagType(TypeClass TC, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag, - bool IsInjected, const Type *CanonicalType); - -public: - // FIXME: Temporarily renamed from `getDecl` in order to facilitate - // rebasing, due to change in behaviour. This should be renamed back - // to `getDecl` once the change is settled. - TagDecl *getOriginalDecl() const { return decl; } - - NestedNameSpecifier getQualifier() const; - - /// Does the TagType own this declaration of the Tag? - bool isTagOwned() const { return TagTypeBits.OwnsTag; } - - bool isInjected() const { return TagTypeBits.IsInjected; } - - ClassTemplateDecl *getTemplateDecl() const; - TemplateName getTemplateName(const ASTContext &Ctx) const; - ArrayRef getTemplateArgs(const ASTContext &Ctx) const; - - bool isSugared() const { return false; } - QualType desugar() const { return getCanonicalTypeInternal(); } - - static bool classof(const Type *T) { - return T->getTypeClass() == Enum || T->getTypeClass() == Record || - T->getTypeClass() == InjectedClassName; - } -}; - -struct TagTypeFoldingSetPlaceholder : public llvm::FoldingSetNode { - static constexpr size_t getOffset() { - return alignof(TagType) - - (sizeof(TagTypeFoldingSetPlaceholder) % alignof(TagType)); - } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, const TagDecl *Tag, - bool OwnsTag, bool IsInjected) { - ID.AddInteger(uintptr_t(Tag) | OwnsTag | (IsInjected << 1) | - ((Keyword != ElaboratedTypeKeyword::None) << 2)); - if (Keyword != ElaboratedTypeKeyword::None) - ID.AddInteger(llvm::to_underlying(Keyword)); - if (Qualifier) - Qualifier.Profile(ID); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - const TagType *T = getTagType(); - Profile(ID, T->getKeyword(), T->getQualifier(), T->getOriginalDecl(), - T->isTagOwned(), T->isInjected()); - } - - TagType *getTagType() { - return reinterpret_cast(reinterpret_cast(this + 1) + - getOffset()); - } - const TagType *getTagType() const { - return const_cast(this)->getTagType(); - } - static TagTypeFoldingSetPlaceholder *fromTagType(TagType *T) { - return reinterpret_cast( - reinterpret_cast(T) - getOffset()) - - 1; - } -}; - -/// A helper class that allows the use of isa/cast/dyncast -/// to detect TagType objects of structs/unions/classes. -class RecordType final : public TagType { - using TagType::TagType; - -public: - // FIXME: Temporarily renamed from `getDecl` in order to facilitate - // rebasing, due to change in behaviour. This should be renamed back - // to `getDecl` once the change is settled. - RecordDecl *getOriginalDecl() const { - return reinterpret_cast(TagType::getOriginalDecl()); - } - - /// Recursively check all fields in the record for const-ness. If any field - /// is declared const, return true. Otherwise, return false. - bool hasConstFields() const; - - static bool classof(const Type *T) { return T->getTypeClass() == Record; } -}; - -/// A helper class that allows the use of isa/cast/dyncast -/// to detect TagType objects of enums. -class EnumType final : public TagType { - using TagType::TagType; - -public: - // FIXME: Temporarily renamed from `getDecl` in order to facilitate - // rebasing, due to change in behaviour. This should be renamed back - // to `getDecl` once the change is settled. - EnumDecl *getOriginalDecl() const { - return reinterpret_cast(TagType::getOriginalDecl()); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Enum; } -}; - -/// The injected class name of a C++ class template or class -/// template partial specialization. Used to record that a type was -/// spelled with a bare identifier rather than as a template-id; the -/// equivalent for non-templated classes is just RecordType. -/// -/// Injected class name types are always dependent. Template -/// instantiation turns these into RecordTypes. -/// -/// Injected class name types are always canonical. This works -/// because it is impossible to compare an injected class name type -/// with the corresponding non-injected template type, for the same -/// reason that it is impossible to directly compare template -/// parameters from different dependent contexts: injected class name -/// types can only occur within the scope of a particular templated -/// declaration, and within that scope every template specialization -/// will canonicalize to the injected class name (when appropriate -/// according to the rules of the language). -class InjectedClassNameType final : public TagType { - friend class ASTContext; // ASTContext creates these. - - InjectedClassNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier Qualifier, const TagDecl *TD, - bool IsInjected, const Type *CanonicalType); - -public: - // FIXME: Temporarily renamed from `getDecl` in order to facilitate - // rebasing, due to change in behaviour. This should be renamed back - // to `getDecl` once the change is settled. - CXXRecordDecl *getOriginalDecl() const { - return reinterpret_cast(TagType::getOriginalDecl()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == InjectedClassName; - } -}; - -/// An attributed type is a type to which a type attribute has been applied. -/// -/// The "modified type" is the fully-sugared type to which the attributed -/// type was applied; generally it is not canonically equivalent to the -/// attributed type. The "equivalent type" is the minimally-desugared type -/// which the type is canonically equivalent to. -/// -/// For example, in the following attributed type: -/// int32_t __attribute__((vector_size(16))) -/// - the modified type is the TypedefType for int32_t -/// - the equivalent type is VectorType(16, int32_t) -/// - the canonical type is VectorType(16, int) -class AttributedType : public Type, public llvm::FoldingSetNode { -public: - using Kind = attr::Kind; - -private: - friend class ASTContext; // ASTContext creates these - - const Attr *Attribute; - - QualType ModifiedType; - QualType EquivalentType; - - AttributedType(QualType canon, attr::Kind attrKind, QualType modified, - QualType equivalent) - : AttributedType(canon, attrKind, nullptr, modified, equivalent) {} - - AttributedType(QualType canon, const Attr *attr, QualType modified, - QualType equivalent); - -private: - AttributedType(QualType canon, attr::Kind attrKind, const Attr *attr, - QualType modified, QualType equivalent); - -public: - Kind getAttrKind() const { - return static_cast(AttributedTypeBits.AttrKind); - } - - const Attr *getAttr() const { return Attribute; } - - QualType getModifiedType() const { return ModifiedType; } - QualType getEquivalentType() const { return EquivalentType; } - - bool isSugared() const { return true; } - QualType desugar() const { return getEquivalentType(); } - - /// Does this attribute behave like a type qualifier? - /// - /// A type qualifier adjusts a type to provide specialized rules for - /// a specific object, like the standard const and volatile qualifiers. - /// This includes attributes controlling things like nullability, - /// address spaces, and ARC ownership. The value of the object is still - /// largely described by the modified type. - /// - /// In contrast, many type attributes "rewrite" their modified type to - /// produce a fundamentally different type, not necessarily related in any - /// formalizable way to the original type. For example, calling convention - /// and vector attributes are not simple type qualifiers. - /// - /// Type qualifiers are often, but not always, reflected in the canonical - /// type. - bool isQualifier() const; - - bool isMSTypeSpec() const; - - bool isWebAssemblyFuncrefSpec() const; - - bool isCallingConv() const; - - std::optional getImmediateNullability() const; - - /// Strip off the top-level nullability annotation on the given - /// type, if it's there. - /// - /// \param T The type to strip. If the type is exactly an - /// AttributedType specifying nullability (without looking through - /// type sugar), the nullability is returned and this type changed - /// to the underlying modified type. - /// - /// \returns the top-level nullability, if present. - static std::optional stripOuterNullability(QualType &T); - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute); - } - - static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, - QualType modified, QualType equivalent, - const Attr *attr) { - ID.AddInteger(attrKind); - ID.AddPointer(modified.getAsOpaquePtr()); - ID.AddPointer(equivalent.getAsOpaquePtr()); - ID.AddPointer(attr); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == Attributed; - } -}; - -class BTFTagAttributedType : public Type, public llvm::FoldingSetNode { -private: - friend class ASTContext; // ASTContext creates these - - QualType WrappedType; - const BTFTypeTagAttr *BTFAttr; - - BTFTagAttributedType(QualType Canon, QualType Wrapped, - const BTFTypeTagAttr *BTFAttr) - : Type(BTFTagAttributed, Canon, Wrapped->getDependence()), - WrappedType(Wrapped), BTFAttr(BTFAttr) {} - -public: - QualType getWrappedType() const { return WrappedType; } - const BTFTypeTagAttr *getAttr() const { return BTFAttr; } - - bool isSugared() const { return true; } - QualType desugar() const { return getWrappedType(); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, WrappedType, BTFAttr); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped, - const BTFTypeTagAttr *BTFAttr) { - ID.AddPointer(Wrapped.getAsOpaquePtr()); - ID.AddPointer(BTFAttr); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == BTFTagAttributed; - } -}; - -class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode { -public: - struct Attributes { - // Data gathered from HLSL resource attributes - llvm::dxil::ResourceClass ResourceClass; - - LLVM_PREFERRED_TYPE(bool) - uint8_t IsROV : 1; - - LLVM_PREFERRED_TYPE(bool) - uint8_t RawBuffer : 1; - - Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false, - bool RawBuffer = false) - : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {} - - Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {} - - friend bool operator==(const Attributes &LHS, const Attributes &RHS) { - return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) == - std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer); - } - friend bool operator!=(const Attributes &LHS, const Attributes &RHS) { - return !(LHS == RHS); - } - }; - -private: - friend class ASTContext; // ASTContext creates these - - QualType WrappedType; - QualType ContainedType; - const Attributes Attrs; - - HLSLAttributedResourceType(QualType Wrapped, QualType Contained, - const Attributes &Attrs) - : Type(HLSLAttributedResource, QualType(), - Contained.isNull() ? TypeDependence::None - : Contained->getDependence()), - WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {} - -public: - QualType getWrappedType() const { return WrappedType; } - QualType getContainedType() const { return ContainedType; } - bool hasContainedType() const { return !ContainedType.isNull(); } - const Attributes &getAttrs() const { return Attrs; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, WrappedType, ContainedType, Attrs); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped, - QualType Contained, const Attributes &Attrs) { - ID.AddPointer(Wrapped.getAsOpaquePtr()); - ID.AddPointer(Contained.getAsOpaquePtr()); - ID.AddInteger(static_cast(Attrs.ResourceClass)); - ID.AddBoolean(Attrs.IsROV); - ID.AddBoolean(Attrs.RawBuffer); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == HLSLAttributedResource; - } - - // Returns handle type from HLSL resource, if the type is a resource - static const HLSLAttributedResourceType * - findHandleTypeOnResource(const Type *RT); -}; - -/// Instances of this class represent operands to a SPIR-V type instruction. -class SpirvOperand { -public: - enum SpirvOperandKind : unsigned char { - Invalid, ///< Uninitialized. - ConstantId, ///< Integral value to represent as a SPIR-V OpConstant - ///< instruction ID. - Literal, ///< Integral value to represent as an immediate literal. - TypeId, ///< Type to represent as a SPIR-V type ID. - - Max, - }; - -private: - SpirvOperandKind Kind = Invalid; - - QualType ResultType; - llvm::APInt Value; // Signedness of constants is represented by ResultType. - -public: - SpirvOperand() : Kind(Invalid), ResultType(), Value() {} - - SpirvOperand(SpirvOperandKind Kind, QualType ResultType, llvm::APInt Value) - : Kind(Kind), ResultType(ResultType), Value(std::move(Value)) {} - - SpirvOperand(const SpirvOperand &Other) { *this = Other; } - ~SpirvOperand() {} - - SpirvOperand &operator=(const SpirvOperand &Other) = default; - - bool operator==(const SpirvOperand &Other) const { - return Kind == Other.Kind && ResultType == Other.ResultType && - Value == Other.Value; - } - - bool operator!=(const SpirvOperand &Other) const { return !(*this == Other); } - - SpirvOperandKind getKind() const { return Kind; } - - bool isValid() const { return Kind != Invalid && Kind < Max; } - bool isConstant() const { return Kind == ConstantId; } - bool isLiteral() const { return Kind == Literal; } - bool isType() const { return Kind == TypeId; } - - llvm::APInt getValue() const { - assert((isConstant() || isLiteral()) && - "This is not an operand with a value!"); - return Value; - } - - QualType getResultType() const { - assert((isConstant() || isType()) && - "This is not an operand with a result type!"); - return ResultType; - } - - static SpirvOperand createConstant(QualType ResultType, llvm::APInt Val) { - return SpirvOperand(ConstantId, ResultType, std::move(Val)); - } - - static SpirvOperand createLiteral(llvm::APInt Val) { - return SpirvOperand(Literal, QualType(), std::move(Val)); - } - - static SpirvOperand createType(QualType T) { - return SpirvOperand(TypeId, T, llvm::APSInt()); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger(Kind); - ID.AddPointer(ResultType.getAsOpaquePtr()); - Value.Profile(ID); - } -}; - -/// Represents an arbitrary, user-specified SPIR-V type instruction. -class HLSLInlineSpirvType final - : public Type, - public llvm::FoldingSetNode, - private llvm::TrailingObjects { - friend class ASTContext; // ASTContext creates these - friend TrailingObjects; - -private: - uint32_t Opcode; - uint32_t Size; - uint32_t Alignment; - size_t NumOperands; - - HLSLInlineSpirvType(uint32_t Opcode, uint32_t Size, uint32_t Alignment, - ArrayRef Operands) - : Type(HLSLInlineSpirv, QualType(), TypeDependence::None), Opcode(Opcode), - Size(Size), Alignment(Alignment), NumOperands(Operands.size()) { - for (size_t I = 0; I < NumOperands; I++) { - // Since Operands are stored as a trailing object, they have not been - // initialized yet. Call the constructor manually. - auto *Operand = new (&getTrailingObjects()[I]) SpirvOperand(); - *Operand = Operands[I]; - } - } - -public: - uint32_t getOpcode() const { return Opcode; } - uint32_t getSize() const { return Size; } - uint32_t getAlignment() const { return Alignment; } - ArrayRef getOperands() const { - return getTrailingObjects(NumOperands); - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Opcode, Size, Alignment, getOperands()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, uint32_t Opcode, - uint32_t Size, uint32_t Alignment, - ArrayRef Operands) { - ID.AddInteger(Opcode); - ID.AddInteger(Size); - ID.AddInteger(Alignment); - for (auto &Operand : Operands) - Operand.Profile(ID); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == HLSLInlineSpirv; - } -}; - -class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these - - // The associated TemplateTypeParmDecl for the non-canonical type. - TemplateTypeParmDecl *TTPDecl; - - TemplateTypeParmType(unsigned D, unsigned I, bool PP, - TemplateTypeParmDecl *TTPDecl, QualType Canon) - : Type(TemplateTypeParm, Canon, - TypeDependence::DependentInstantiation | - (PP ? TypeDependence::UnexpandedPack : TypeDependence::None)), - TTPDecl(TTPDecl) { - assert(!TTPDecl == Canon.isNull()); - TemplateTypeParmTypeBits.Depth = D; - TemplateTypeParmTypeBits.Index = I; - TemplateTypeParmTypeBits.ParameterPack = PP; - } - -public: - unsigned getDepth() const { return TemplateTypeParmTypeBits.Depth; } - unsigned getIndex() const { return TemplateTypeParmTypeBits.Index; } - bool isParameterPack() const { - return TemplateTypeParmTypeBits.ParameterPack; - } - - TemplateTypeParmDecl *getDecl() const { return TTPDecl; } - - IdentifierInfo *getIdentifier() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, - unsigned Index, bool ParameterPack, - TemplateTypeParmDecl *TTPDecl) { - ID.AddInteger(Depth); - ID.AddInteger(Index); - ID.AddBoolean(ParameterPack); - ID.AddPointer(TTPDecl); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == TemplateTypeParm; - } -}; - -/// Represents the result of substituting a type for a template -/// type parameter. -/// -/// Within an instantiated template, all template type parameters have -/// been replaced with these. They are used solely to record that a -/// type was originally written as a template type parameter; -/// therefore they are never canonical. -class SubstTemplateTypeParmType final - : public Type, - public llvm::FoldingSetNode, - private llvm::TrailingObjects { - friend class ASTContext; - friend class llvm::TrailingObjects; - - Decl *AssociatedDecl; - - SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, - unsigned Index, UnsignedOrNone PackIndex, - bool Final); - -public: - /// Gets the type that was substituted for the template - /// parameter. - QualType getReplacementType() const { - return SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType - ? *getTrailingObjects() - : getCanonicalTypeInternal(); - } - - /// A template-like entity which owns the whole pattern being substituted. - /// This will usually own a set of template parameters, or in some - /// cases might even be a template parameter itself. - Decl *getAssociatedDecl() const { return AssociatedDecl; } - - /// Gets the template parameter declaration that was substituted for. - const TemplateTypeParmDecl *getReplacedParameter() const; - - /// Returns the index of the replaced parameter in the associated declaration. - /// This should match the result of `getReplacedParameter()->getIndex()`. - unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; } - - // This substitution is Final, which means the substitution is fully - // sugared: it doesn't need to be resugared later. - unsigned getFinal() const { return SubstTemplateTypeParmTypeBits.Final; } - - UnsignedOrNone getPackIndex() const { - return UnsignedOrNone::fromInternalRepresentation( - SubstTemplateTypeParmTypeBits.PackIndex); - } - - bool isSugared() const { return true; } - QualType desugar() const { return getReplacementType(); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(), - getPackIndex(), getFinal()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement, - const Decl *AssociatedDecl, unsigned Index, - UnsignedOrNone PackIndex, bool Final); - - static bool classof(const Type *T) { - return T->getTypeClass() == SubstTemplateTypeParm; - } -}; - -/// Represents the result of substituting a set of types as a template argument -/// that needs to be expanded later. -/// -/// These types are always dependent and produced depending on the situations: -/// - SubstTemplateTypeParmPack is an expansion that had to be delayed, -/// - SubstBuiltinTemplatePackType is an expansion from a builtin. -class SubstPackType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; - - /// A pointer to the set of template arguments that this - /// parameter pack is instantiated with. - const TemplateArgument *Arguments; - -protected: - SubstPackType(TypeClass Derived, QualType Canon, - const TemplateArgument &ArgPack); - -public: - unsigned getNumArgs() const { return SubstPackTypeBits.NumArgs; } - - TemplateArgument getArgumentPack() const; - - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - const TemplateArgument &ArgPack); - - static bool classof(const Type *T) { - return T->getTypeClass() == SubstTemplateTypeParmPack || - T->getTypeClass() == SubstBuiltinTemplatePack; - } -}; - -/// Represents the result of substituting a builtin template as a pack. -class SubstBuiltinTemplatePackType : public SubstPackType { - friend class ASTContext; - - SubstBuiltinTemplatePackType(QualType Canon, const TemplateArgument &ArgPack); - -public: - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - /// Mark that we reuse the Profile. We do not introduce new fields. - using SubstPackType::Profile; - - static bool classof(const Type *T) { - return T->getTypeClass() == SubstBuiltinTemplatePack; - } -}; - -/// Represents the result of substituting a set of types for a template -/// type parameter pack. -/// -/// When a pack expansion in the source code contains multiple parameter packs -/// and those parameter packs correspond to different levels of template -/// parameter lists, this type node is used to represent a template type -/// parameter pack from an outer level, which has already had its argument pack -/// substituted but that still lives within a pack expansion that itself -/// could not be instantiated. When actually performing a substitution into -/// that pack expansion (e.g., when all template parameters have corresponding -/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType -/// at the current pack substitution index. -class SubstTemplateTypeParmPackType : public SubstPackType { - friend class ASTContext; - - /// A pointer to the set of template arguments that this - /// parameter pack is instantiated with. - const TemplateArgument *Arguments; - - llvm::PointerIntPair AssociatedDeclAndFinal; - - SubstTemplateTypeParmPackType(QualType Canon, Decl *AssociatedDecl, - unsigned Index, bool Final, - const TemplateArgument &ArgPack); - -public: - IdentifierInfo *getIdentifier() const; - - /// A template-like entity which owns the whole pattern being substituted. - /// This will usually own a set of template parameters, or in some - /// cases might even be a template parameter itself. - Decl *getAssociatedDecl() const; - - /// Gets the template parameter declaration that was substituted for. - const TemplateTypeParmDecl *getReplacedParameter() const; - - /// Returns the index of the replaced parameter in the associated declaration. - /// This should match the result of `getReplacedParameter()->getIndex()`. - unsigned getIndex() const { - return SubstPackTypeBits.SubstTemplTypeParmPackIndex; - } - - // This substitution will be Final, which means the substitution will be fully - // sugared: it doesn't need to be resugared later. - bool getFinal() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl, - unsigned Index, bool Final, - const TemplateArgument &ArgPack); - - static bool classof(const Type *T) { - return T->getTypeClass() == SubstTemplateTypeParmPack; - } -}; - -/// Common base class for placeholders for types that get replaced by -/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced -/// class template types, and constrained type names. -/// -/// These types are usually a placeholder for a deduced type. However, before -/// the initializer is attached, or (usually) if the initializer is -/// type-dependent, there is no deduced type and the type is canonical. In -/// the latter case, it is also a dependent type. -class DeducedType : public Type { - QualType DeducedAsType; - -protected: - DeducedType(TypeClass TC, QualType DeducedAsType, - TypeDependence ExtraDependence, QualType Canon) - : Type(TC, Canon, - ExtraDependence | (DeducedAsType.isNull() - ? TypeDependence::None - : DeducedAsType->getDependence() & - ~TypeDependence::VariablyModified)), - DeducedAsType(DeducedAsType) {} - -public: - bool isSugared() const { return !DeducedAsType.isNull(); } - QualType desugar() const { - return isSugared() ? DeducedAsType : QualType(this, 0); - } - - /// Get the type deduced for this placeholder type, or null if it - /// has not been deduced. - QualType getDeducedType() const { return DeducedAsType; } - bool isDeduced() const { - return !DeducedAsType.isNull() || isDependentType(); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == Auto || - T->getTypeClass() == DeducedTemplateSpecialization; - } -}; - -/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained -/// by a type-constraint. -class AutoType : public DeducedType { - friend class ASTContext; // ASTContext creates these - - TemplateDecl *TypeConstraintConcept; - - AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD, - ArrayRef TypeConstraintArgs); - -public: - ArrayRef getTypeConstraintArguments() const { - return {reinterpret_cast(this + 1), - AutoTypeBits.NumArgs}; - } - - TemplateDecl *getTypeConstraintConcept() const { - return TypeConstraintConcept; - } - - bool isConstrained() const { - return TypeConstraintConcept != nullptr; - } - - bool isDecltypeAuto() const { - return getKeyword() == AutoTypeKeyword::DecltypeAuto; - } - - bool isGNUAutoType() const { - return getKeyword() == AutoTypeKeyword::GNUAutoType; - } - - AutoTypeKeyword getKeyword() const { - return (AutoTypeKeyword)AutoTypeBits.Keyword; - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context); - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType Deduced, AutoTypeKeyword Keyword, - bool IsDependent, TemplateDecl *CD, - ArrayRef Arguments); - - static bool classof(const Type *T) { - return T->getTypeClass() == Auto; - } -}; - -/// Represents a C++17 deduced template specialization type. -class DeducedTemplateSpecializationType : public KeywordWrapper, - public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these - - /// The name of the template whose arguments will be deduced. - TemplateName Template; - - DeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword, - TemplateName Template, - QualType DeducedAsType, - bool IsDeducedAsDependent, QualType Canon) - : KeywordWrapper(Keyword, DeducedTemplateSpecialization, DeducedAsType, - toTypeDependence(Template.getDependence()) | - (IsDeducedAsDependent - ? TypeDependence::DependentInstantiation - : TypeDependence::None), - Canon), - Template(Template) {} - -public: - /// Retrieve the name of the template that we are deducing. - TemplateName getTemplateName() const { return Template; } - - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getKeyword(), getTemplateName(), getDeducedType(), - isDependentType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - TemplateName Template, QualType Deduced, - bool IsDependent) { - ID.AddInteger(llvm::to_underlying(Keyword)); - Template.Profile(ID); - Deduced.Profile(ID); - ID.AddBoolean(IsDependent || Template.isDependent()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == DeducedTemplateSpecialization; - } -}; - -/// Represents a type template specialization; the template -/// must be a class template, a type alias template, or a template -/// template parameter. A template which cannot be resolved to one of -/// these, e.g. because it is written with a dependent scope -/// specifier, is instead represented as a -/// @c DependentTemplateSpecializationType. -/// -/// A non-dependent template specialization type is always "sugar", -/// typically for a \c RecordType. For example, a class template -/// specialization type of \c vector will refer to a tag type for -/// the instantiation \c std::vector> -/// -/// Template specializations are dependent if either the template or -/// any of the template arguments are dependent, in which case the -/// type may also be canonical. -/// -/// Instances of this type are allocated with a trailing array of -/// TemplateArguments, followed by a QualType representing the -/// non-canonical aliased type when the template is a type alias -/// template. -class TemplateSpecializationType : public TypeWithKeyword, - public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these - - /// The name of the template being specialized. This is - /// either a TemplateName::Template (in which case it is a - /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a - /// TypeAliasTemplateDecl*), a - /// TemplateName::SubstTemplateTemplateParmPack, or a - /// TemplateName::SubstTemplateTemplateParm (in which case the - /// replacement must, recursively, be one of these). - TemplateName Template; - - TemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, - bool IsAlias, ArrayRef Args, - QualType Underlying); - -public: - /// Determine whether any of the given template arguments are dependent. - /// - /// The converted arguments should be supplied when known; whether an - /// argument is dependent can depend on the conversions performed on it - /// (for example, a 'const int' passed as a template argument might be - /// dependent if the parameter is a reference but non-dependent if the - /// parameter is an int). - /// - /// Note that the \p Args parameter is unused: this is intentional, to remind - /// the caller that they need to pass in the converted arguments, not the - /// specified arguments. - static bool - anyDependentTemplateArguments(ArrayRef Args, - ArrayRef Converted); - static bool - anyDependentTemplateArguments(const TemplateArgumentListInfo &, - ArrayRef Converted); - static bool anyInstantiationDependentTemplateArguments( - ArrayRef Args); - - /// True if this template specialization type matches a current - /// instantiation in the context in which it is found. - bool isCurrentInstantiation() const { - return isa(getCanonicalTypeInternal()); - } - - /// Determine if this template specialization type is for a type alias - /// template that has been substituted. - /// - /// Nearly every template specialization type whose template is an alias - /// template will be substituted. However, this is not the case when - /// the specialization contains a pack expansion but the template alias - /// does not have a corresponding parameter pack, e.g., - /// - /// \code - /// template struct S; - /// template using A = S; - /// template struct X { - /// typedef A type; // not a type alias - /// }; - /// \endcode - bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } - - /// Get the aliased type, if this is a specialization of a type alias - /// template. - QualType getAliasedType() const; - - /// Retrieve the name of the template that we are specializing. - TemplateName getTemplateName() const { return Template; } - - ArrayRef template_arguments() const { - return {reinterpret_cast(this + 1), - TemplateSpecializationTypeBits.NumArgs}; - } - - bool isSugared() const; - - QualType desugar() const { - return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); - static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - ArrayRef Args, QualType Underlying, - const ASTContext &Context); - - static bool classof(const Type *T) { - return T->getTypeClass() == TemplateSpecialization; - } -}; - -/// Print a template argument list, including the '<' and '>' -/// enclosing the template arguments. -void printTemplateArgumentList(raw_ostream &OS, - ArrayRef Args, - const PrintingPolicy &Policy, - const TemplateParameterList *TPL = nullptr); - -void printTemplateArgumentList(raw_ostream &OS, - ArrayRef Args, - const PrintingPolicy &Policy, - const TemplateParameterList *TPL = nullptr); - -void printTemplateArgumentList(raw_ostream &OS, - const TemplateArgumentListInfo &Args, - const PrintingPolicy &Policy, - const TemplateParameterList *TPL = nullptr); - -/// Make a best-effort determination of whether the type T can be produced by -/// substituting Args into the default argument of Param. -bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg, - const NamedDecl *Param, - ArrayRef Args, - unsigned Depth); - -/// Represents a qualified type name for which the type name is -/// dependent. -/// -/// DependentNameType represents a class of dependent types that involve a -/// possibly dependent nested-name-specifier (e.g., "T::") followed by a -/// name of a type. The DependentNameType may start with a "typename" (for a -/// typename-specifier), "class", "struct", "union", or "enum" (for a -/// dependent elaborated-type-specifier), or nothing (in contexts where we -/// know that we must be referring to a type, e.g., in a base class specifier). -/// Typically the nested-name-specifier is dependent, but in MSVC compatibility -/// mode, this type is used with non-dependent names to delay name lookup until -/// instantiation. -class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these - - /// The nested name specifier containing the qualifier. - NestedNameSpecifier NNS; - - /// The type that this typename specifier refers to. - const IdentifierInfo *Name; - - DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier NNS, - const IdentifierInfo *Name, QualType CanonType) - : TypeWithKeyword(Keyword, DependentName, CanonType, - TypeDependence::DependentInstantiation | - (NNS ? toTypeDependence(NNS.getDependence()) - : TypeDependence::Dependent)), - NNS(NNS), Name(Name) { - assert(Name); - } - -public: - /// Retrieve the qualification on this type. - NestedNameSpecifier getQualifier() const { return NNS; } - - /// Retrieve the identifier that terminates this type name. - /// For example, "type" in "typename T::type". - const IdentifierInfo *getIdentifier() const { - return Name; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getKeyword(), NNS, Name); - } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier NNS, const IdentifierInfo *Name) { - ID.AddInteger(llvm::to_underlying(Keyword)); - NNS.Profile(ID); - ID.AddPointer(Name); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentName; - } -}; - -/// Represents a template specialization type whose template cannot be -/// resolved, e.g. -/// A::template B -class DependentTemplateSpecializationType : public TypeWithKeyword { - friend class ASTContext; // ASTContext creates these - - DependentTemplateStorage Name; - - DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, - const DependentTemplateStorage &Name, - ArrayRef Args, - QualType Canon); - -public: - const DependentTemplateStorage &getDependentTemplateName() const { - return Name; - } - - ArrayRef template_arguments() const { - return {reinterpret_cast(this + 1), - DependentTemplateSpecializationTypeBits.NumArgs}; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getKeyword(), Name, template_arguments()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - ElaboratedTypeKeyword Keyword, - const DependentTemplateStorage &Name, - ArrayRef Args); - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentTemplateSpecialization; - } -}; - -/// Represents a pack expansion of types. -/// -/// Pack expansions are part of C++11 variadic templates. A pack -/// expansion contains a pattern, which itself contains one or more -/// "unexpanded" parameter packs. When instantiated, a pack expansion -/// produces a series of types, each instantiated from the pattern of -/// the expansion, where the Ith instantiation of the pattern uses the -/// Ith arguments bound to each of the unexpanded parameter packs. The -/// pack expansion is considered to "expand" these unexpanded -/// parameter packs. -/// -/// \code -/// template struct tuple; -/// -/// template -/// struct tuple_of_references { -/// typedef tuple type; -/// }; -/// \endcode -/// -/// Here, the pack expansion \c Types&... is represented via a -/// PackExpansionType whose pattern is Types&. -class PackExpansionType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these - - /// The pattern of the pack expansion. - QualType Pattern; - - PackExpansionType(QualType Pattern, QualType Canon, - UnsignedOrNone NumExpansions) - : Type(PackExpansion, Canon, - (Pattern->getDependence() | TypeDependence::Dependent | - TypeDependence::Instantiation) & - ~TypeDependence::UnexpandedPack), - Pattern(Pattern) { - PackExpansionTypeBits.NumExpansions = - NumExpansions ? *NumExpansions + 1 : 0; - } - -public: - /// Retrieve the pattern of this pack expansion, which is the - /// type that will be repeatedly instantiated when instantiating the - /// pack expansion itself. - QualType getPattern() const { return Pattern; } - - /// Retrieve the number of expansions that this pack expansion will - /// generate, if known. - UnsignedOrNone getNumExpansions() const { - if (PackExpansionTypeBits.NumExpansions) - return PackExpansionTypeBits.NumExpansions - 1; - return std::nullopt; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPattern(), getNumExpansions()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, - UnsignedOrNone NumExpansions) { - ID.AddPointer(Pattern.getAsOpaquePtr()); - ID.AddInteger(NumExpansions.toInternalRepresentation()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == PackExpansion; - } -}; - -/// This class wraps the list of protocol qualifiers. For types that can -/// take ObjC protocol qualifers, they can subclass this class. -template -class ObjCProtocolQualifiers { -protected: - ObjCProtocolQualifiers() = default; - - ObjCProtocolDecl * const *getProtocolStorage() const { - return const_cast(this)->getProtocolStorage(); - } - - ObjCProtocolDecl **getProtocolStorage() { - return static_cast(this)->getProtocolStorageImpl(); - } - - void setNumProtocols(unsigned N) { - static_cast(this)->setNumProtocolsImpl(N); - } - - void initialize(ArrayRef protocols) { - setNumProtocols(protocols.size()); - assert(getNumProtocols() == protocols.size() && - "bitfield overflow in protocol count"); - if (!protocols.empty()) - memcpy(getProtocolStorage(), protocols.data(), - protocols.size() * sizeof(ObjCProtocolDecl*)); - } - -public: - using qual_iterator = ObjCProtocolDecl * const *; - using qual_range = llvm::iterator_range; - - qual_range quals() const { return qual_range(qual_begin(), qual_end()); } - qual_iterator qual_begin() const { return getProtocolStorage(); } - qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } - - bool qual_empty() const { return getNumProtocols() == 0; } - - /// Return the number of qualifying protocols in this type, or 0 if - /// there are none. - unsigned getNumProtocols() const { - return static_cast(this)->getNumProtocolsImpl(); - } - - /// Fetch a protocol by index. - ObjCProtocolDecl *getProtocol(unsigned I) const { - assert(I < getNumProtocols() && "Out-of-range protocol access"); - return qual_begin()[I]; - } - - /// Retrieve all of the protocol qualifiers. - ArrayRef getProtocols() const { - return ArrayRef(qual_begin(), getNumProtocols()); - } -}; - -/// Represents a type parameter type in Objective C. It can take -/// a list of protocols. -class ObjCTypeParamType : public Type, - public ObjCProtocolQualifiers, - public llvm::FoldingSetNode { - friend class ASTContext; - friend class ObjCProtocolQualifiers; - - /// The number of protocols stored on this type. - unsigned NumProtocols : 6; - - ObjCTypeParamDecl *OTPDecl; - - /// The protocols are stored after the ObjCTypeParamType node. In the - /// canonical type, the list of protocols are sorted alphabetically - /// and uniqued. - ObjCProtocolDecl **getProtocolStorageImpl(); - - /// Return the number of qualifying protocols in this interface type, - /// or 0 if there are none. - unsigned getNumProtocolsImpl() const { - return NumProtocols; - } - - void setNumProtocolsImpl(unsigned N) { - NumProtocols = N; - } - - ObjCTypeParamType(const ObjCTypeParamDecl *D, - QualType can, - ArrayRef protocols); - -public: - bool isSugared() const { return true; } - QualType desugar() const { return getCanonicalTypeInternal(); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCTypeParam; - } - - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - const ObjCTypeParamDecl *OTPDecl, - QualType CanonicalType, - ArrayRef protocols); - - ObjCTypeParamDecl *getDecl() const { return OTPDecl; } -}; - -/// Represents a class type in Objective C. -/// -/// Every Objective C type is a combination of a base type, a set of -/// type arguments (optional, for parameterized classes) and a list of -/// protocols. -/// -/// Given the following declarations: -/// \code -/// \@class C; -/// \@protocol P; -/// \endcode -/// -/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType -/// with base C and no protocols. -/// -/// 'C

' is an unspecialized ObjCObjectType with base C and protocol list [P]. -/// 'C' is a specialized ObjCObjectType with type arguments 'C*' and no -/// protocol list. -/// 'C

' is a specialized ObjCObjectType with base C, type arguments 'C*', -/// and protocol list [P]. -/// -/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose -/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType -/// and no protocols. -/// -/// 'id

' is an ObjCObjectPointerType whose pointee is an ObjCObjectType -/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually -/// this should get its own sugar class to better represent the source. -class ObjCObjectType : public Type, - public ObjCProtocolQualifiers { - friend class ObjCProtocolQualifiers; - - // ObjCObjectType.NumTypeArgs - the number of type arguments stored - // after the ObjCObjectPointerType node. - // ObjCObjectType.NumProtocols - the number of protocols stored - // after the type arguments of ObjCObjectPointerType node. - // - // These protocols are those written directly on the type. If - // protocol qualifiers ever become additive, the iterators will need - // to get kindof complicated. - // - // In the canonical object type, these are sorted alphabetically - // and uniqued. - - /// Either a BuiltinType or an InterfaceType or sugar for either. - QualType BaseType; - - /// Cached superclass type. - mutable llvm::PointerIntPair - CachedSuperClassType; - - QualType *getTypeArgStorage(); - const QualType *getTypeArgStorage() const { - return const_cast(this)->getTypeArgStorage(); - } - - ObjCProtocolDecl **getProtocolStorageImpl(); - /// Return the number of qualifying protocols in this interface type, - /// or 0 if there are none. - unsigned getNumProtocolsImpl() const { - return ObjCObjectTypeBits.NumProtocols; - } - void setNumProtocolsImpl(unsigned N) { - ObjCObjectTypeBits.NumProtocols = N; - } - -protected: - enum Nonce_ObjCInterface { Nonce_ObjCInterface }; - - ObjCObjectType(QualType Canonical, QualType Base, - ArrayRef typeArgs, - ArrayRef protocols, - bool isKindOf); - - ObjCObjectType(enum Nonce_ObjCInterface) - : Type(ObjCInterface, QualType(), TypeDependence::None), - BaseType(QualType(this_(), 0)) { - ObjCObjectTypeBits.NumProtocols = 0; - ObjCObjectTypeBits.NumTypeArgs = 0; - ObjCObjectTypeBits.IsKindOf = 0; - } - - void computeSuperClassTypeSlow() const; - -public: - /// Gets the base type of this object type. This is always (possibly - /// sugar for) one of: - /// - the 'id' builtin type (as opposed to the 'id' type visible to the - /// user, which is a typedef for an ObjCObjectPointerType) - /// - the 'Class' builtin type (same caveat) - /// - an ObjCObjectType (currently always an ObjCInterfaceType) - QualType getBaseType() const { return BaseType; } - - bool isObjCId() const { - return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); - } - - bool isObjCClass() const { - return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); - } - - bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } - bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } - bool isObjCUnqualifiedIdOrClass() const { - if (!qual_empty()) return false; - if (const BuiltinType *T = getBaseType()->getAs()) - return T->getKind() == BuiltinType::ObjCId || - T->getKind() == BuiltinType::ObjCClass; - return false; - } - bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } - bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } - - /// Gets the interface declaration for this object type, if the base type - /// really is an interface. - ObjCInterfaceDecl *getInterface() const; - - /// Determine whether this object type is "specialized", meaning - /// that it has type arguments. - bool isSpecialized() const; - - /// Determine whether this object type was written with type arguments. - bool isSpecializedAsWritten() const { - return ObjCObjectTypeBits.NumTypeArgs > 0; - } - - /// Determine whether this object type is "unspecialized", meaning - /// that it has no type arguments. - bool isUnspecialized() const { return !isSpecialized(); } - - /// Determine whether this object type is "unspecialized" as - /// written, meaning that it has no type arguments. - bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } - - /// Retrieve the type arguments of this object type (semantically). - ArrayRef getTypeArgs() const; - - /// Retrieve the type arguments of this object type as they were - /// written. - ArrayRef getTypeArgsAsWritten() const { - return {getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs}; - } - - /// Whether this is a "__kindof" type as written. - bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } - - /// Whether this ia a "__kindof" type (semantically). - bool isKindOfType() const; - - /// Retrieve the type of the superclass of this object type. - /// - /// This operation substitutes any type arguments into the - /// superclass of the current class type, potentially producing a - /// specialization of the superclass type. Produces a null type if - /// there is no superclass. - QualType getSuperClassType() const { - if (!CachedSuperClassType.getInt()) - computeSuperClassTypeSlow(); - - assert(CachedSuperClassType.getInt() && "Superclass not set?"); - return QualType(CachedSuperClassType.getPointer(), 0); - } - - /// Strip off the Objective-C "kindof" type and (with it) any - /// protocol qualifiers. - QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCObject || - T->getTypeClass() == ObjCInterface; - } -}; - -/// A class providing a concrete implementation -/// of ObjCObjectType, so as to not increase the footprint of -/// ObjCInterfaceType. Code outside of ASTContext and the core type -/// system should not reference this type. -class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { - friend class ASTContext; - - // If anyone adds fields here, ObjCObjectType::getProtocolStorage() - // will need to be modified. - - ObjCObjectTypeImpl(QualType Canonical, QualType Base, - ArrayRef typeArgs, - ArrayRef protocols, - bool isKindOf) - : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} - -public: - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - QualType Base, - ArrayRef typeArgs, - ArrayRef protocols, - bool isKindOf); -}; - -inline QualType *ObjCObjectType::getTypeArgStorage() { - return reinterpret_cast(static_cast(this)+1); -} - -inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { - return reinterpret_cast( - getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); -} - -inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { - return reinterpret_cast( - static_cast(this)+1); -} - -/// Interfaces are the core concept in Objective-C for object oriented design. -/// They basically correspond to C++ classes. There are two kinds of interface -/// types: normal interfaces like `NSString`, and qualified interfaces, which -/// are qualified with a protocol list like `NSString`. -/// -/// ObjCInterfaceType guarantees the following properties when considered -/// as a subtype of its superclass, ObjCObjectType: -/// - There are no protocol qualifiers. To reinforce this, code which -/// tries to invoke the protocol methods via an ObjCInterfaceType will -/// fail to compile. -/// - It is its own base type. That is, if T is an ObjCInterfaceType*, -/// T->getBaseType() == QualType(T, 0). -class ObjCInterfaceType : public ObjCObjectType { - friend class ASTContext; // ASTContext creates these. - friend class ASTReader; - template friend class serialization::AbstractTypeReader; - - ObjCInterfaceDecl *Decl; - - ObjCInterfaceType(const ObjCInterfaceDecl *D) - : ObjCObjectType(Nonce_ObjCInterface), - Decl(const_cast(D)) {} - -public: - /// Get the declaration of this interface. - ObjCInterfaceDecl *getDecl() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCInterface; - } - - // Nonsense to "hide" certain members of ObjCObjectType within this - // class. People asking for protocols on an ObjCInterfaceType are - // not going to get what they want: ObjCInterfaceTypes are - // guaranteed to have no protocols. - enum { - qual_iterator, - qual_begin, - qual_end, - getNumProtocols, - getProtocol - }; -}; - -inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { - QualType baseType = getBaseType(); - while (const auto *ObjT = baseType->getAs()) { - if (const auto *T = dyn_cast(ObjT)) - return T->getDecl(); - - baseType = ObjT->getBaseType(); - } - - return nullptr; -} - -/// Represents a pointer to an Objective C object. -/// -/// These are constructed from pointer declarators when the pointee type is -/// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class' -/// types are typedefs for these, and the protocol-qualified types 'id

' -/// and 'Class

' are translated into these. -/// -/// Pointers to pointers to Objective C objects are still PointerTypes; -/// only the first level of pointer gets it own type implementation. -class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType PointeeType; - - ObjCObjectPointerType(QualType Canonical, QualType Pointee) - : Type(ObjCObjectPointer, Canonical, Pointee->getDependence()), - PointeeType(Pointee) {} - -public: - /// Gets the type pointed to by this ObjC pointer. - /// The result will always be an ObjCObjectType or sugar thereof. - QualType getPointeeType() const { return PointeeType; } - - /// Gets the type pointed to by this ObjC pointer. Always returns non-null. - /// - /// This method is equivalent to getPointeeType() except that - /// it discards any typedefs (or other sugar) between this - /// type and the "outermost" object type. So for: - /// \code - /// \@class A; \@protocol P; \@protocol Q; - /// typedef A

AP; - /// typedef A A1; - /// typedef A1

A1P; - /// typedef A1P A1PQ; - /// \endcode - /// For 'A*', getObjectType() will return 'A'. - /// For 'A

*', getObjectType() will return 'A

'. - /// For 'AP*', getObjectType() will return 'A

'. - /// For 'A1*', getObjectType() will return 'A'. - /// For 'A1

*', getObjectType() will return 'A1

'. - /// For 'A1P*', getObjectType() will return 'A1

'. - /// For 'A1PQ*', getObjectType() will return 'A1', because - /// adding protocols to a protocol-qualified base discards the - /// old qualifiers (for now). But if it didn't, getObjectType() - /// would return 'A1P' (and we'd have to make iterating over - /// qualifiers more complicated). - const ObjCObjectType *getObjectType() const { - return PointeeType->castAs(); - } - - /// If this pointer points to an Objective C - /// \@interface type, gets the type for that interface. Any protocol - /// qualifiers on the interface are ignored. - /// - /// \return null if the base type for this pointer is 'id' or 'Class' - const ObjCInterfaceType *getInterfaceType() const; - - /// If this pointer points to an Objective \@interface - /// type, gets the declaration for that interface. - /// - /// \return null if the base type for this pointer is 'id' or 'Class' - ObjCInterfaceDecl *getInterfaceDecl() const { - return getObjectType()->getInterface(); - } - - /// True if this is equivalent to the 'id' type, i.e. if - /// its object type is the primitive 'id' type with no protocols. - bool isObjCIdType() const { - return getObjectType()->isObjCUnqualifiedId(); - } - - /// True if this is equivalent to the 'Class' type, - /// i.e. if its object tive is the primitive 'Class' type with no protocols. - bool isObjCClassType() const { - return getObjectType()->isObjCUnqualifiedClass(); - } - - /// True if this is equivalent to the 'id' or 'Class' type, - bool isObjCIdOrClassType() const { - return getObjectType()->isObjCUnqualifiedIdOrClass(); - } - - /// True if this is equivalent to 'id

' for some non-empty set of - /// protocols. - bool isObjCQualifiedIdType() const { - return getObjectType()->isObjCQualifiedId(); - } - - /// True if this is equivalent to 'Class

' for some non-empty set of - /// protocols. - bool isObjCQualifiedClassType() const { - return getObjectType()->isObjCQualifiedClass(); - } - - /// Whether this is a "__kindof" type. - bool isKindOfType() const { return getObjectType()->isKindOfType(); } - - /// Whether this type is specialized, meaning that it has type arguments. - bool isSpecialized() const { return getObjectType()->isSpecialized(); } - - /// Whether this type is specialized, meaning that it has type arguments. - bool isSpecializedAsWritten() const { - return getObjectType()->isSpecializedAsWritten(); - } - - /// Whether this type is unspecialized, meaning that is has no type arguments. - bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } - - /// Determine whether this object type is "unspecialized" as - /// written, meaning that it has no type arguments. - bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } - - /// Retrieve the type arguments for this type. - ArrayRef getTypeArgs() const { - return getObjectType()->getTypeArgs(); - } - - /// Retrieve the type arguments for this type. - ArrayRef getTypeArgsAsWritten() const { - return getObjectType()->getTypeArgsAsWritten(); - } - - /// An iterator over the qualifiers on the object type. Provided - /// for convenience. This will always iterate over the full set of - /// protocols on a type, not just those provided directly. - using qual_iterator = ObjCObjectType::qual_iterator; - using qual_range = llvm::iterator_range; - - qual_range quals() const { return qual_range(qual_begin(), qual_end()); } - - qual_iterator qual_begin() const { - return getObjectType()->qual_begin(); - } - - qual_iterator qual_end() const { - return getObjectType()->qual_end(); - } - - bool qual_empty() const { return getObjectType()->qual_empty(); } - - /// Return the number of qualifying protocols on the object type. - unsigned getNumProtocols() const { - return getObjectType()->getNumProtocols(); - } - - /// Retrieve a qualifying protocol by index on the object type. - ObjCProtocolDecl *getProtocol(unsigned I) const { - return getObjectType()->getProtocol(I); - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - /// Retrieve the type of the superclass of this object pointer type. - /// - /// This operation substitutes any type arguments into the - /// superclass of the current class type, potentially producing a - /// pointer to a specialization of the superclass type. Produces a - /// null type if there is no superclass. - QualType getSuperClassType() const; - - /// Strip off the Objective-C "kindof" type and (with it) any - /// protocol qualifiers. - const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( - const ASTContext &ctx) const; - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPointeeType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { - ID.AddPointer(T.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCObjectPointer; - } -}; - -class AtomicType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType ValueType; - - AtomicType(QualType ValTy, QualType Canonical) - : Type(Atomic, Canonical, ValTy->getDependence()), ValueType(ValTy) {} - -public: - /// Gets the type contained by this atomic type, i.e. - /// the type returned by performing an atomic load of this atomic type. - QualType getValueType() const { return ValueType; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getValueType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { - ID.AddPointer(T.getAsOpaquePtr()); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == Atomic; - } -}; - -/// PipeType - OpenCL20. -class PipeType : public Type, public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these. - - QualType ElementType; - bool isRead; - - PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) - : Type(Pipe, CanonicalPtr, elemType->getDependence()), - ElementType(elemType), isRead(isRead) {} - -public: - QualType getElementType() const { return ElementType; } - - bool isSugared() const { return false; } - - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), isReadOnly()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) { - ID.AddPointer(T.getAsOpaquePtr()); - ID.AddBoolean(isRead); - } - - static bool classof(const Type *T) { - return T->getTypeClass() == Pipe; - } - - bool isReadOnly() const { return isRead; } -}; - -/// A fixed int type of a specified bitwidth. -class BitIntType final : public Type, public llvm::FoldingSetNode { - friend class ASTContext; - LLVM_PREFERRED_TYPE(bool) - unsigned IsUnsigned : 1; - unsigned NumBits : 24; - -protected: - BitIntType(bool isUnsigned, unsigned NumBits); - -public: - bool isUnsigned() const { return IsUnsigned; } - bool isSigned() const { return !IsUnsigned; } - unsigned getNumBits() const { return NumBits; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, isUnsigned(), getNumBits()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, bool IsUnsigned, - unsigned NumBits) { - ID.AddBoolean(IsUnsigned); - ID.AddInteger(NumBits); - } - - static bool classof(const Type *T) { return T->getTypeClass() == BitInt; } -}; - -class DependentBitIntType final : public Type, public llvm::FoldingSetNode { - friend class ASTContext; - llvm::PointerIntPair ExprAndUnsigned; - -protected: - DependentBitIntType(bool IsUnsigned, Expr *NumBits); - -public: - bool isUnsigned() const; - bool isSigned() const { return !isUnsigned(); } - Expr *getNumBitsExpr() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, isUnsigned(), getNumBitsExpr()); - } - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - bool IsUnsigned, Expr *NumBitsExpr); - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentBitInt; - } -}; - -class PredefinedSugarType final : public Type { -public: - friend class ASTContext; - using Kind = PredefinedSugarKind; - -private: - PredefinedSugarType(Kind KD, const IdentifierInfo *IdentName, - QualType CanonicalType) - : Type(PredefinedSugar, CanonicalType, TypeDependence::None), - Name(IdentName) { - PredefinedSugarTypeBits.Kind = llvm::to_underlying(KD); - } - - static StringRef getName(Kind KD); - - const IdentifierInfo *Name; - -public: - bool isSugared() const { return true; } - - QualType desugar() const { return getCanonicalTypeInternal(); } - - Kind getKind() const { return Kind(PredefinedSugarTypeBits.Kind); } - - const IdentifierInfo *getIdentifier() const { return Name; } - - static bool classof(const Type *T) { - return T->getTypeClass() == PredefinedSugar; - } -}; - -/// A qualifier set is used to build a set of qualifiers. -class QualifierCollector : public Qualifiers { -public: - QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} - - /// Collect any qualifiers on the given type and return an - /// unqualified type. The qualifiers are assumed to be consistent - /// with those already in the type. - const Type *strip(QualType type) { - addFastQualifiers(type.getLocalFastQualifiers()); - if (!type.hasLocalNonFastQualifiers()) - return type.getTypePtrUnsafe(); - - const ExtQuals *extQuals = type.getExtQualsUnsafe(); - addConsistentQualifiers(extQuals->getQualifiers()); - return extQuals->getBaseType(); - } - - /// Apply the collected qualifiers to the given type. - QualType apply(const ASTContext &Context, QualType QT) const; - - /// Apply the collected qualifiers to the given type. - QualType apply(const ASTContext &Context, const Type* T) const; -}; - -/// A container of type source information. -/// -/// A client can read the relevant info using TypeLoc wrappers, e.g: -/// @code -/// TypeLoc TL = TypeSourceInfo->getTypeLoc(); -/// TL.getBeginLoc().print(OS, SrcMgr); -/// @endcode -class alignas(8) TypeSourceInfo { - // Contains a memory block after the class, used for type source information, - // allocated by ASTContext. - friend class ASTContext; - - QualType Ty; - - TypeSourceInfo(QualType ty, size_t DataSize); // implemented in TypeLoc.h - -public: - /// Return the type wrapped by this type source info. - QualType getType() const { return Ty; } - - /// Return the TypeLoc wrapper for the type source info. - TypeLoc getTypeLoc() const; // implemented in TypeLoc.h - - /// Override the type stored in this TypeSourceInfo. Use with caution! - void overrideType(QualType T) { Ty = T; } -}; - -// Inline function definitions. - -inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { - SplitQualType desugar = - Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); - desugar.Quals.addConsistentQualifiers(Quals); - return desugar; -} - -inline const Type *QualType::getTypePtr() const { - return getCommonPtr()->BaseType; -} - -inline const Type *QualType::getTypePtrOrNull() const { - return (isNull() ? nullptr : getCommonPtr()->BaseType); -} - -inline bool QualType::isReferenceable() const { - // C++ [defns.referenceable] - // type that is either an object type, a function type that does not have - // cv-qualifiers or a ref-qualifier, or a reference type. - const Type &Self = **this; - if (Self.isObjectType() || Self.isReferenceType()) - return true; - if (const auto *F = Self.getAs()) - return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None; - - return false; -} - -inline SplitQualType QualType::split() const { - if (!hasLocalNonFastQualifiers()) - return SplitQualType(getTypePtrUnsafe(), - Qualifiers::fromFastMask(getLocalFastQualifiers())); - - const ExtQuals *eq = getExtQualsUnsafe(); - Qualifiers qs = eq->getQualifiers(); - qs.addFastQualifiers(getLocalFastQualifiers()); - return SplitQualType(eq->getBaseType(), qs); -} - -inline Qualifiers QualType::getLocalQualifiers() const { - Qualifiers Quals; - if (hasLocalNonFastQualifiers()) - Quals = getExtQualsUnsafe()->getQualifiers(); - Quals.addFastQualifiers(getLocalFastQualifiers()); - return Quals; -} - -inline Qualifiers QualType::getQualifiers() const { - Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); - quals.addFastQualifiers(getLocalFastQualifiers()); - return quals; -} - -inline unsigned QualType::getCVRQualifiers() const { - unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); - cvr |= getLocalCVRQualifiers(); - return cvr; -} - -inline QualType QualType::getCanonicalType() const { - QualType canon = getCommonPtr()->CanonicalType; - return canon.withFastQualifiers(getLocalFastQualifiers()); -} - -inline bool QualType::isCanonical() const { - return getTypePtr()->isCanonicalUnqualified(); -} - -inline bool QualType::isCanonicalAsParam() const { - if (!isCanonical()) return false; - if (hasLocalQualifiers()) return false; - - const Type *T = getTypePtr(); - if (T->isVariablyModifiedType() && T->hasSizedVLAType()) - return false; - - return !isa(T) && - (!isa(T) || isa(T)); -} - -inline bool QualType::isConstQualified() const { - return isLocalConstQualified() || - getCommonPtr()->CanonicalType.isLocalConstQualified(); -} - -inline bool QualType::isRestrictQualified() const { - return isLocalRestrictQualified() || - getCommonPtr()->CanonicalType.isLocalRestrictQualified(); -} - - -inline bool QualType::isVolatileQualified() const { - return isLocalVolatileQualified() || - getCommonPtr()->CanonicalType.isLocalVolatileQualified(); -} - -inline bool QualType::hasQualifiers() const { - return hasLocalQualifiers() || - getCommonPtr()->CanonicalType.hasLocalQualifiers(); -} - -inline QualType QualType::getUnqualifiedType() const { - if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) - return QualType(getTypePtr(), 0); - - return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); -} - -inline SplitQualType QualType::getSplitUnqualifiedType() const { - if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) - return split(); - - return getSplitUnqualifiedTypeImpl(*this); -} - -inline void QualType::removeLocalConst() { - removeLocalFastQualifiers(Qualifiers::Const); -} - -inline void QualType::removeLocalRestrict() { - removeLocalFastQualifiers(Qualifiers::Restrict); -} - -inline void QualType::removeLocalVolatile() { - removeLocalFastQualifiers(Qualifiers::Volatile); -} - -/// Check if this type has any address space qualifier. -inline bool QualType::hasAddressSpace() const { - return getQualifiers().hasAddressSpace(); -} - -/// Return the address space of this type. -inline LangAS QualType::getAddressSpace() const { - return getQualifiers().getAddressSpace(); -} - -/// Return the gc attribute of this type. -inline Qualifiers::GC QualType::getObjCGCAttr() const { - return getQualifiers().getObjCGCAttr(); -} - -inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const { - if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) - return hasNonTrivialToPrimitiveDefaultInitializeCUnion(RD); - return false; -} - -inline bool QualType::hasNonTrivialToPrimitiveDestructCUnion() const { - if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) - return hasNonTrivialToPrimitiveDestructCUnion(RD); - return false; -} - -inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const { - if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) - return hasNonTrivialToPrimitiveCopyCUnion(RD); - return false; -} - -inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { - if (const auto *PT = t.getAs()) { - if (const auto *FT = PT->getPointeeType()->getAs()) - return FT->getExtInfo(); - } else if (const auto *FT = t.getAs()) - return FT->getExtInfo(); - - return FunctionType::ExtInfo(); -} - -inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { - return getFunctionExtInfo(*t); -} - -/// Determine whether this type is more -/// qualified than the Other type. For example, "const volatile int" -/// is more qualified than "const int", "volatile int", and -/// "int". However, it is not more qualified than "const volatile -/// int". -inline bool QualType::isMoreQualifiedThan(QualType other, - const ASTContext &Ctx) const { - Qualifiers MyQuals = getQualifiers(); - Qualifiers OtherQuals = other.getQualifiers(); - return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, Ctx)); -} - -/// Determine whether this type is at last -/// as qualified as the Other type. For example, "const volatile -/// int" is at least as qualified as "const int", "volatile int", -/// "int", and "const volatile int". -inline bool QualType::isAtLeastAsQualifiedAs(QualType other, - const ASTContext &Ctx) const { - Qualifiers OtherQuals = other.getQualifiers(); - - // Ignore __unaligned qualifier if this type is a void. - if (getUnqualifiedType()->isVoidType()) - OtherQuals.removeUnaligned(); - - return getQualifiers().compatiblyIncludes(OtherQuals, Ctx); -} - -/// If Type is a reference type (e.g., const -/// int&), returns the type that the reference refers to ("const -/// int"). Otherwise, returns the type itself. This routine is used -/// throughout Sema to implement C++ 5p6: -/// -/// If an expression initially has the type "reference to T" (8.3.2, -/// 8.5.3), the type is adjusted to "T" prior to any further -/// analysis, the expression designates the object or function -/// denoted by the reference, and the expression is an lvalue. -inline QualType QualType::getNonReferenceType() const { - if (const auto *RefType = (*this)->getAs()) - return RefType->getPointeeType(); - else - return *this; -} - -inline bool QualType::isCForbiddenLValueType() const { - return ((getTypePtr()->isVoidType() && !hasQualifiers()) || - getTypePtr()->isFunctionType()); -} - -/// Tests whether the type is categorized as a fundamental type. -/// -/// \returns True for types specified in C++0x [basic.fundamental]. -inline bool Type::isFundamentalType() const { - return isVoidType() || - isNullPtrType() || - // FIXME: It's really annoying that we don't have an - // 'isArithmeticType()' which agrees with the standard definition. - (isArithmeticType() && !isEnumeralType()); -} - -/// Tests whether the type is categorized as a compound type. -/// -/// \returns True for types specified in C++0x [basic.compound]. -inline bool Type::isCompoundType() const { - // C++0x [basic.compound]p1: - // Compound types can be constructed in the following ways: - // -- arrays of objects of a given type [...]; - return isArrayType() || - // -- functions, which have parameters of given types [...]; - isFunctionType() || - // -- pointers to void or objects or functions [...]; - isPointerType() || - // -- references to objects or functions of a given type. [...] - isReferenceType() || - // -- classes containing a sequence of objects of various types, [...]; - isRecordType() || - // -- unions, which are classes capable of containing objects of different - // types at different times; - isUnionType() || - // -- enumerations, which comprise a set of named constant values. [...]; - isEnumeralType() || - // -- pointers to non-static class members, [...]. - isMemberPointerType(); -} - -inline bool Type::isFunctionType() const { - return isa(CanonicalType); -} - -inline bool Type::isPointerType() const { - return isa(CanonicalType); -} - -inline bool Type::isPointerOrReferenceType() const { - return isPointerType() || isReferenceType(); -} - -inline bool Type::isAnyPointerType() const { - return isPointerType() || isObjCObjectPointerType(); -} - -inline bool Type::isSignableType(const ASTContext &Ctx) const { - return isSignablePointerType() || isSignableIntegerType(Ctx); -} - -inline bool Type::isSignablePointerType() const { - return isPointerType() || isObjCClassType() || isObjCQualifiedClassType(); -} - -inline bool Type::isBlockPointerType() const { - return isa(CanonicalType); -} - -inline bool Type::isReferenceType() const { - return isa(CanonicalType); -} - -inline bool Type::isLValueReferenceType() const { - return isa(CanonicalType); -} - -inline bool Type::isRValueReferenceType() const { - return isa(CanonicalType); -} - -inline bool Type::isObjectPointerType() const { - // Note: an "object pointer type" is not the same thing as a pointer to an - // object type; rather, it is a pointer to an object type or a pointer to cv - // void. - if (const auto *T = getAs()) - return !T->getPointeeType()->isFunctionType(); - else - return false; -} - -inline bool Type::isCFIUncheckedCalleeFunctionType() const { - if (const auto *Fn = getAs()) - return Fn->hasCFIUncheckedCallee(); - return false; -} - -inline bool Type::hasPointeeToToCFIUncheckedCalleeFunctionType() const { - QualType Pointee; - if (const auto *PT = getAs()) - Pointee = PT->getPointeeType(); - else if (const auto *RT = getAs()) - Pointee = RT->getPointeeType(); - else if (const auto *MPT = getAs()) - Pointee = MPT->getPointeeType(); - else if (const auto *DT = getAs()) - Pointee = DT->getPointeeType(); - else - return false; - return Pointee->isCFIUncheckedCalleeFunctionType(); -} - -inline bool Type::isFunctionPointerType() const { - if (const auto *T = getAs()) - return T->getPointeeType()->isFunctionType(); - else - return false; -} - -inline bool Type::isFunctionReferenceType() const { - if (const auto *T = getAs()) - return T->getPointeeType()->isFunctionType(); - else - return false; -} - -inline bool Type::isMemberPointerType() const { - return isa(CanonicalType); -} - -inline bool Type::isMemberFunctionPointerType() const { - if (const auto *T = getAs()) - return T->isMemberFunctionPointer(); - else - return false; -} - -inline bool Type::isMemberDataPointerType() const { - if (const auto *T = getAs()) - return T->isMemberDataPointer(); - else - return false; -} - -inline bool Type::isArrayType() const { - return isa(CanonicalType); -} - -inline bool Type::isConstantArrayType() const { - return isa(CanonicalType); -} - -inline bool Type::isIncompleteArrayType() const { - return isa(CanonicalType); -} - -inline bool Type::isVariableArrayType() const { - return isa(CanonicalType); -} - -inline bool Type::isArrayParameterType() const { - return isa(CanonicalType); -} - -inline bool Type::isDependentSizedArrayType() const { - return isa(CanonicalType); -} - -inline bool Type::isBuiltinType() const { - return isa(CanonicalType); -} - -inline bool Type::isRecordType() const { - return isa(CanonicalType); -} - -inline bool Type::isEnumeralType() const { - return isa(CanonicalType); -} - -inline bool Type::isAnyComplexType() const { - return isa(CanonicalType); -} - -inline bool Type::isVectorType() const { - return isa(CanonicalType); -} - -inline bool Type::isExtVectorType() const { - return isa(CanonicalType); -} - -inline bool Type::isExtVectorBoolType() const { - if (!isExtVectorType()) - return false; - return cast(CanonicalType)->getElementType()->isBooleanType(); -} - -inline bool Type::isSubscriptableVectorType() const { - return isVectorType() || isSveVLSBuiltinType(); -} - -inline bool Type::isMatrixType() const { - return isa(CanonicalType); -} - -inline bool Type::isConstantMatrixType() const { - return isa(CanonicalType); -} - -inline bool Type::isDependentAddressSpaceType() const { - return isa(CanonicalType); -} - -inline bool Type::isObjCObjectPointerType() const { - return isa(CanonicalType); -} - -inline bool Type::isObjCObjectType() const { - return isa(CanonicalType); -} - -inline bool Type::isObjCObjectOrInterfaceType() const { - return isa(CanonicalType) || - isa(CanonicalType); -} - -inline bool Type::isAtomicType() const { - return isa(CanonicalType); -} - -inline bool Type::isUndeducedAutoType() const { - return isa(CanonicalType); -} - -inline bool Type::isObjCQualifiedIdType() const { - if (const auto *OPT = getAs()) - return OPT->isObjCQualifiedIdType(); - return false; -} - -inline bool Type::isObjCQualifiedClassType() const { - if (const auto *OPT = getAs()) - return OPT->isObjCQualifiedClassType(); - return false; -} - -inline bool Type::isObjCIdType() const { - if (const auto *OPT = getAs()) - return OPT->isObjCIdType(); - return false; -} - -inline bool Type::isObjCClassType() const { - if (const auto *OPT = getAs()) - return OPT->isObjCClassType(); - return false; -} - -inline bool Type::isObjCSelType() const { - if (const auto *OPT = getAs()) - return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); - return false; -} - -inline bool Type::isObjCBuiltinType() const { - return isObjCIdType() || isObjCClassType() || isObjCSelType(); -} - -inline bool Type::isDecltypeType() const { - return isa(this); -} - -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ - inline bool Type::is##Id##Type() const { \ - return isSpecificBuiltinType(BuiltinType::Id); \ - } -#include "clang/Basic/OpenCLImageTypes.def" - -inline bool Type::isSamplerT() const { - return isSpecificBuiltinType(BuiltinType::OCLSampler); -} - -inline bool Type::isEventT() const { - return isSpecificBuiltinType(BuiltinType::OCLEvent); -} - -inline bool Type::isClkEventT() const { - return isSpecificBuiltinType(BuiltinType::OCLClkEvent); -} - -inline bool Type::isQueueT() const { - return isSpecificBuiltinType(BuiltinType::OCLQueue); -} - -inline bool Type::isReserveIDT() const { - return isSpecificBuiltinType(BuiltinType::OCLReserveID); -} - -inline bool Type::isImageType() const { -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() || - return -#include "clang/Basic/OpenCLImageTypes.def" - false; // end boolean or operation -} - -inline bool Type::isPipeType() const { - return isa(CanonicalType); -} - -inline bool Type::isBitIntType() const { - return isa(CanonicalType); -} - -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ - inline bool Type::is##Id##Type() const { \ - return isSpecificBuiltinType(BuiltinType::Id); \ - } -#include "clang/Basic/OpenCLExtensionTypes.def" - -inline bool Type::isOCLIntelSubgroupAVCType() const { -#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \ - isOCLIntelSubgroupAVC##Id##Type() || - return -#include "clang/Basic/OpenCLExtensionTypes.def" - false; // end of boolean or operation -} - -inline bool Type::isOCLExtOpaqueType() const { -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() || - return -#include "clang/Basic/OpenCLExtensionTypes.def" - false; // end of boolean or operation -} - -inline bool Type::isOpenCLSpecificType() const { - return isSamplerT() || isEventT() || isImageType() || isClkEventT() || - isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType(); -} - -#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \ - inline bool Type::is##Id##Type() const { \ - return isSpecificBuiltinType(BuiltinType::Id); \ - } -#include "clang/Basic/HLSLIntangibleTypes.def" - -inline bool Type::isHLSLBuiltinIntangibleType() const { -#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() || - return -#include "clang/Basic/HLSLIntangibleTypes.def" - false; -} - -inline bool Type::isHLSLSpecificType() const { - return isHLSLBuiltinIntangibleType() || isHLSLAttributedResourceType() || - isHLSLInlineSpirvType(); -} - -inline bool Type::isHLSLAttributedResourceType() const { - return isa(this); -} - -inline bool Type::isHLSLInlineSpirvType() const { - return isa(this); +inline CXXRecordDecl *Type::getAsCXXRecordDecl() const { + const auto *TT = dyn_cast(CanonicalType); + if (!isa_and_present(TT)) + return nullptr; + auto *TD = TT->getOriginalDecl(); + if (isa(TT) && !isa(TD)) + return nullptr; + return cast(TD)->getDefinitionOrSelf(); } -inline bool Type::isTemplateTypeParmType() const { - return isa(CanonicalType); +inline CXXRecordDecl *Type::castAsCXXRecordDecl() const { + const auto *TT = cast(CanonicalType); + return cast(TT->getOriginalDecl())->getDefinitionOrSelf(); } -inline bool Type::isSpecificBuiltinType(unsigned K) const { - if (const BuiltinType *BT = getAs()) { - return BT->getKind() == static_cast(K); - } - return false; +inline RecordDecl *Type::getAsRecordDecl() const { + const auto *TT = dyn_cast(CanonicalType); + if (!isa_and_present(TT)) + return nullptr; + return cast(TT->getOriginalDecl())->getDefinitionOrSelf(); } -inline bool Type::isPlaceholderType() const { - if (const auto *BT = dyn_cast(this)) - return BT->isPlaceholderType(); - return false; +inline RecordDecl *Type::castAsRecordDecl() const { + const auto *TT = cast(CanonicalType); + return cast(TT->getOriginalDecl())->getDefinitionOrSelf(); } -inline const BuiltinType *Type::getAsPlaceholderType() const { - if (const auto *BT = dyn_cast(this)) - if (BT->isPlaceholderType()) - return BT; +inline EnumDecl *Type::getAsEnumDecl() const { + if (const auto *TT = dyn_cast(CanonicalType)) + return TT->getOriginalDecl()->getDefinitionOrSelf(); return nullptr; } -inline bool Type::isSpecificPlaceholderType(unsigned K) const { - assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); - return isSpecificBuiltinType(K); -} - -inline bool Type::isNonOverloadPlaceholderType() const { - if (const auto *BT = dyn_cast(this)) - return BT->isNonOverloadPlaceholderType(); - return false; -} - -inline bool Type::isVoidType() const { - return isSpecificBuiltinType(BuiltinType::Void); -} - -inline bool Type::isHalfType() const { - // FIXME: Should we allow complex __fp16? Probably not. - return isSpecificBuiltinType(BuiltinType::Half); -} - -inline bool Type::isFloat16Type() const { - return isSpecificBuiltinType(BuiltinType::Float16); -} - -inline bool Type::isFloat32Type() const { - return isSpecificBuiltinType(BuiltinType::Float); -} - -inline bool Type::isDoubleType() const { - return isSpecificBuiltinType(BuiltinType::Double); -} - -inline bool Type::isBFloat16Type() const { - return isSpecificBuiltinType(BuiltinType::BFloat16); -} - -inline bool Type::isMFloat8Type() const { - return isSpecificBuiltinType(BuiltinType::MFloat8); -} - -inline bool Type::isFloat128Type() const { - return isSpecificBuiltinType(BuiltinType::Float128); -} - -inline bool Type::isIbm128Type() const { - return isSpecificBuiltinType(BuiltinType::Ibm128); -} - -inline bool Type::isNullPtrType() const { - return isSpecificBuiltinType(BuiltinType::NullPtr); -} - -bool IsEnumDeclComplete(EnumDecl *); -bool IsEnumDeclScoped(EnumDecl *); - -inline bool Type::isIntegerType() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->isInteger(); - if (const EnumType *ET = dyn_cast(CanonicalType)) { - // Incomplete enum types are not treated as integer types. - // FIXME: In C++, enum types are never integer types. - return IsEnumDeclComplete(ET->getOriginalDecl()) && - !IsEnumDeclScoped(ET->getOriginalDecl()); - } - return isBitIntType(); -} - -inline bool Type::isFixedPointType() const { - if (const auto *BT = dyn_cast(CanonicalType)) { - return BT->getKind() >= BuiltinType::ShortAccum && - BT->getKind() <= BuiltinType::SatULongFract; - } - return false; -} - -inline bool Type::isFixedPointOrIntegerType() const { - return isFixedPointType() || isIntegerType(); -} - -inline bool Type::isConvertibleToFixedPointType() const { - return isRealFloatingType() || isFixedPointOrIntegerType(); +inline EnumDecl *Type::castAsEnumDecl() const { + return cast(CanonicalType) + ->getOriginalDecl() + ->getDefinitionOrSelf(); } -inline bool Type::isSaturatedFixedPointType() const { - if (const auto *BT = dyn_cast(CanonicalType)) { - return BT->getKind() >= BuiltinType::SatShortAccum && - BT->getKind() <= BuiltinType::SatULongFract; - } - return false; +inline TagDecl *Type::getAsTagDecl() const { + if (const auto *TT = dyn_cast(CanonicalType)) + return TT->getOriginalDecl()->getDefinitionOrSelf(); + return nullptr; } -inline bool Type::isUnsaturatedFixedPointType() const { - return isFixedPointType() && !isSaturatedFixedPointType(); +inline TagDecl *Type::castAsTagDecl() const { + return cast(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf(); } -inline bool Type::isSignedFixedPointType() const { - if (const auto *BT = dyn_cast(CanonicalType)) { - return ((BT->getKind() >= BuiltinType::ShortAccum && - BT->getKind() <= BuiltinType::LongAccum) || - (BT->getKind() >= BuiltinType::ShortFract && - BT->getKind() <= BuiltinType::LongFract) || - (BT->getKind() >= BuiltinType::SatShortAccum && - BT->getKind() <= BuiltinType::SatLongAccum) || - (BT->getKind() >= BuiltinType::SatShortFract && - BT->getKind() <= BuiltinType::SatLongFract)); - } +inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const { + if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + return hasNonTrivialToPrimitiveDefaultInitializeCUnion(RD); return false; } -inline bool Type::isUnsignedFixedPointType() const { - return isFixedPointType() && !isSignedFixedPointType(); -} - -inline bool Type::isScalarType() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() > BuiltinType::Void && - BT->getKind() <= BuiltinType::NullPtr; - if (const EnumType *ET = dyn_cast(CanonicalType)) - // Enums are scalar types, but only if they are defined. Incomplete enums - // are not treated as scalar types. - return IsEnumDeclComplete(ET->getOriginalDecl()); - return isa(CanonicalType) || - isa(CanonicalType) || - isa(CanonicalType) || - isa(CanonicalType) || - isa(CanonicalType) || - isBitIntType(); -} - -inline bool Type::isIntegralOrEnumerationType() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->isInteger(); - - // Check for a complete enum type; incomplete enum types are not properly an - // enumeration type in the sense required here. - if (const auto *ET = dyn_cast(CanonicalType)) - return IsEnumDeclComplete(ET->getOriginalDecl()); - - return isBitIntType(); -} - -inline bool Type::isBooleanType() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Bool; +inline bool QualType::hasNonTrivialToPrimitiveDestructCUnion() const { + if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + return hasNonTrivialToPrimitiveDestructCUnion(RD); return false; } -inline bool Type::isUndeducedType() const { - auto *DT = getContainedDeducedType(); - return DT && !DT->isDeduced(); -} - -/// Determines whether this is a type for which one can define -/// an overloaded operator. -inline bool Type::isOverloadableType() const { - if (!isDependentType()) - return isRecordType() || isEnumeralType(); - return !isArrayType() && !isFunctionType() && !isAnyPointerType() && - !isMemberPointerType(); -} - -/// Determines whether this type is written as a typedef-name. -inline bool Type::isTypedefNameType() const { - if (getAs()) - return true; - if (auto *TST = getAs()) - return TST->isTypeAlias(); +inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const { + if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + return hasNonTrivialToPrimitiveCopyCUnion(RD); return false; } -/// Determines whether this type can decay to a pointer type. -inline bool Type::canDecayToPointerType() const { - return isFunctionType() || (isArrayType() && !isArrayParameterType()); -} - -inline bool Type::hasPointerRepresentation() const { - return (isPointerType() || isReferenceType() || isBlockPointerType() || - isObjCObjectPointerType() || isNullPtrType()); -} - -inline bool Type::hasObjCPointerRepresentation() const { - return isObjCObjectPointerType(); -} - -inline const Type *Type::getBaseElementTypeUnsafe() const { - const Type *type = this; - while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) - type = arrayType->getElementType().getTypePtr(); - return type; -} - -inline const Type *Type::getPointeeOrArrayElementType() const { - const Type *type = this; - if (type->isAnyPointerType()) - return type->getPointeeType().getTypePtr(); - else if (type->isArrayType()) - return type->getBaseElementTypeUnsafe(); - return type; -} -/// Insertion operator for partial diagnostics. This allows sending adress -/// spaces into a diagnostic with <<. -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, - LangAS AS) { - PD.AddTaggedVal(llvm::to_underlying(AS), - DiagnosticsEngine::ArgumentKind::ak_addrspace); - return PD; -} - -/// Insertion operator for partial diagnostics. This allows sending Qualifiers -/// into a diagnostic with <<. -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, - Qualifiers Q) { - PD.AddTaggedVal(Q.getAsOpaqueValue(), - DiagnosticsEngine::ArgumentKind::ak_qual); - return PD; -} - -/// Insertion operator for partial diagnostics. This allows sending QualType's -/// into a diagnostic with <<. -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, - QualType T) { - PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), - DiagnosticsEngine::ak_qualtype); - return PD; -} - -// Helper class template that is used by Type::getAs to ensure that one does -// not try to look through a qualified type to get to an array type. -template -using TypeIsArrayType = - std::integral_constant::value || - std::is_base_of::value>; - -// Member-template getAs'. -template const T *Type::getAs() const { - static_assert(!TypeIsArrayType::value, - "ArrayType cannot be used with getAs!"); - - // If this is directly a T type, return it. - if (const auto *Ty = dyn_cast(this)) - return Ty; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) - return nullptr; - - // If this is a typedef for the type, strip the typedef off without - // losing all typedef information. - return cast(getUnqualifiedDesugaredType()); -} - -template const T *Type::getAsAdjusted() const { - static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAsAdjusted!"); - - // If this is directly a T type, return it. - if (const auto *Ty = dyn_cast(this)) - return Ty; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) - return nullptr; - - // Strip off type adjustments that do not modify the underlying nature of the - // type. - const Type *Ty = this; - while (Ty) { - if (const auto *A = dyn_cast(Ty)) - Ty = A->getModifiedType().getTypePtr(); - else if (const auto *A = dyn_cast(Ty)) - Ty = A->getWrappedType().getTypePtr(); - else if (const auto *A = dyn_cast(Ty)) - Ty = A->getWrappedType().getTypePtr(); - else if (const auto *P = dyn_cast(Ty)) - Ty = P->desugar().getTypePtr(); - else if (const auto *A = dyn_cast(Ty)) - Ty = A->desugar().getTypePtr(); - else if (const auto *M = dyn_cast(Ty)) - Ty = M->desugar().getTypePtr(); - else - break; - } - - // Just because the canonical type is correct does not mean we can use cast<>, - // since we may not have stripped off all the sugar down to the base type. - return dyn_cast(Ty); -} - -inline const ArrayType *Type::getAsArrayTypeUnsafe() const { - // If this is directly an array type, return it. - if (const auto *arr = dyn_cast(this)) - return arr; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) - return nullptr; - - // If this is a typedef for the type, strip the typedef off without - // losing all typedef information. - return cast(getUnqualifiedDesugaredType()); -} - -template const T *Type::castAs() const { - static_assert(!TypeIsArrayType::value, - "ArrayType cannot be used with castAs!"); - - if (const auto *ty = dyn_cast(this)) return ty; - assert(isa(CanonicalType)); - return cast(getUnqualifiedDesugaredType()); -} - -inline const ArrayType *Type::castAsArrayTypeUnsafe() const { - assert(isa(CanonicalType)); - if (const auto *arr = dyn_cast(this)) return arr; - return cast(getUnqualifiedDesugaredType()); -} - -DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr, - QualType CanonicalPtr) - : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { -#ifndef NDEBUG - QualType Adjusted = getAdjustedType(); - (void)AttributedType::stripOuterNullability(Adjusted); - assert(isa(Adjusted)); -#endif -} - -QualType DecayedType::getPointeeType() const { - QualType Decayed = getDecayedType(); - (void)AttributedType::stripOuterNullability(Decayed); - return cast(Decayed)->getPointeeType(); -} - -// Get the decimal string representation of a fixed point type, represented -// as a scaled integer. -// TODO: At some point, we should change the arguments to instead just accept an -// APFixedPoint instead of APSInt and scale. -void FixedPointValueToString(SmallVectorImpl &Str, llvm::APSInt Val, - unsigned Scale); - -inline FunctionEffectsRef FunctionEffectsRef::get(QualType QT) { - const Type *TypePtr = QT.getTypePtr(); - while (true) { - if (QualType Pointee = TypePtr->getPointeeType(); !Pointee.isNull()) - TypePtr = Pointee.getTypePtr(); - else if (TypePtr->isArrayType()) - TypePtr = TypePtr->getBaseElementTypeUnsafe(); - else - break; - } - if (const auto *FPT = TypePtr->getAs()) - return FPT->getFunctionEffects(); - return {}; -} - } // namespace clang #endif // LLVM_CLANG_AST_TYPE_H diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h new file mode 100644 index 0000000000000..db2ab04e4471c --- /dev/null +++ b/clang/include/clang/AST/TypeBase.h @@ -0,0 +1,9281 @@ +//===- TypeBase.h - C Language Family Type Representation -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// C Language Family Type Representation +/// +/// This file defines the clang::Type interface and subclasses, used to +/// represent types for languages in the C family. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPE_BASE_H +#define LLVM_CLANG_AST_TYPE_BASE_H + +#include "clang/AST/DependenceFlags.h" +#include "clang/AST/NestedNameSpecifierBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/PointerAuthOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/Visibility.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLForwardCompat.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DXILABI.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/TrailingObjects.h" +#include "llvm/Support/type_traits.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace clang { + +class BTFTypeTagAttr; +class ExtQuals; +class QualType; +class ConceptDecl; +class ValueDecl; +class TagDecl; +class TemplateParameterList; +class Type; +class Attr; + +enum { + TypeAlignmentInBits = 4, + TypeAlignment = 1 << TypeAlignmentInBits +}; + +namespace serialization { + template class AbstractTypeReader; + template class AbstractTypeWriter; +} + +} // namespace clang + +namespace llvm { + + template + struct PointerLikeTypeTraits; + template<> + struct PointerLikeTypeTraits< ::clang::Type*> { + static inline void *getAsVoidPointer(::clang::Type *P) { return P; } + + static inline ::clang::Type *getFromVoidPointer(void *P) { + return static_cast< ::clang::Type*>(P); + } + + static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits; + }; + + template<> + struct PointerLikeTypeTraits< ::clang::ExtQuals*> { + static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } + + static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { + return static_cast< ::clang::ExtQuals*>(P); + } + + static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits; + }; + +} // namespace llvm + +namespace clang { + +class ASTContext; +template class CanQual; +class CXXRecordDecl; +class DeclContext; +class EnumDecl; +class Expr; +class ExtQualsTypeCommonBase; +class FunctionDecl; +class FunctionEffectsRef; +class FunctionEffectKindSet; +class FunctionEffectSet; +class IdentifierInfo; +class NamedDecl; +class ObjCInterfaceDecl; +class ObjCProtocolDecl; +class ObjCTypeParamDecl; +struct PrintingPolicy; +class RecordDecl; +class Stmt; +class TagDecl; +class ClassTemplateDecl; +class TemplateArgument; +class TemplateArgumentListInfo; +class TemplateArgumentLoc; +class TemplateTypeParmDecl; +class TypedefNameDecl; +class UnresolvedUsingTypenameDecl; +class UsingShadowDecl; + +using CanQualType = CanQual; + +// Provide forward declarations for all of the *Type classes. +#define TYPE(Class, Base) class Class##Type; +#include "clang/AST/TypeNodes.inc" + +/// Pointer-authentication qualifiers. +class PointerAuthQualifier { + enum : uint32_t { + EnabledShift = 0, + EnabledBits = 1, + EnabledMask = 1 << EnabledShift, + AddressDiscriminatedShift = EnabledShift + EnabledBits, + AddressDiscriminatedBits = 1, + AddressDiscriminatedMask = 1 << AddressDiscriminatedShift, + AuthenticationModeShift = + AddressDiscriminatedShift + AddressDiscriminatedBits, + AuthenticationModeBits = 2, + AuthenticationModeMask = ((1 << AuthenticationModeBits) - 1) + << AuthenticationModeShift, + IsaPointerShift = AuthenticationModeShift + AuthenticationModeBits, + IsaPointerBits = 1, + IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift, + AuthenticatesNullValuesShift = IsaPointerShift + IsaPointerBits, + AuthenticatesNullValuesBits = 1, + AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1) + << AuthenticatesNullValuesShift, + KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits, + KeyBits = 10, + KeyMask = ((1 << KeyBits) - 1) << KeyShift, + DiscriminatorShift = KeyShift + KeyBits, + DiscriminatorBits = 16, + DiscriminatorMask = ((1u << DiscriminatorBits) - 1) << DiscriminatorShift, + }; + + // bits: |0 |1 |2..3 |4 | + // |Enabled|Address|AuthenticationMode|ISA pointer| + // bits: |5 |6..15| 16...31 | + // |AuthenticatesNull|Key |Discriminator| + uint32_t Data = 0; + + // The following static assertions check that each of the 32 bits is present + // exactly in one of the constants. + static_assert((EnabledBits + AddressDiscriminatedBits + + AuthenticationModeBits + IsaPointerBits + + AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) == + 32, + "PointerAuthQualifier should be exactly 32 bits"); + static_assert((EnabledMask + AddressDiscriminatedMask + + AuthenticationModeMask + IsaPointerMask + + AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) == + 0xFFFFFFFF, + "All masks should cover the entire bits"); + static_assert((EnabledMask ^ AddressDiscriminatedMask ^ + AuthenticationModeMask ^ IsaPointerMask ^ + AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) == + 0xFFFFFFFF, + "All masks should cover the entire bits"); + + PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated, + unsigned ExtraDiscriminator, + PointerAuthenticationMode AuthenticationMode, + bool IsIsaPointer, bool AuthenticatesNullValues) + : Data(EnabledMask | + (IsAddressDiscriminated + ? llvm::to_underlying(AddressDiscriminatedMask) + : 0) | + (Key << KeyShift) | + (llvm::to_underlying(AuthenticationMode) + << AuthenticationModeShift) | + (ExtraDiscriminator << DiscriminatorShift) | + (IsIsaPointer << IsaPointerShift) | + (AuthenticatesNullValues << AuthenticatesNullValuesShift)) { + assert(Key <= KeyNoneInternal); + assert(ExtraDiscriminator <= MaxDiscriminator); + assert((Data == 0) == + (getAuthenticationMode() == PointerAuthenticationMode::None)); + } + +public: + enum { + KeyNoneInternal = (1u << KeyBits) - 1, + + /// The maximum supported pointer-authentication key. + MaxKey = KeyNoneInternal - 1, + + /// The maximum supported pointer-authentication discriminator. + MaxDiscriminator = (1u << DiscriminatorBits) - 1 + }; + +public: + PointerAuthQualifier() = default; + + static PointerAuthQualifier + Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator, + PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer, + bool AuthenticatesNullValues) { + if (Key == PointerAuthKeyNone) + Key = KeyNoneInternal; + assert(Key <= KeyNoneInternal && "out-of-range key value"); + return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator, + AuthenticationMode, IsIsaPointer, + AuthenticatesNullValues); + } + + bool isPresent() const { + assert((Data == 0) == + (getAuthenticationMode() == PointerAuthenticationMode::None)); + return Data != 0; + } + + explicit operator bool() const { return isPresent(); } + + unsigned getKey() const { + assert(isPresent()); + return (Data & KeyMask) >> KeyShift; + } + + bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; } + + bool isAddressDiscriminated() const { + assert(isPresent()); + return (Data & AddressDiscriminatedMask) >> AddressDiscriminatedShift; + } + + unsigned getExtraDiscriminator() const { + assert(isPresent()); + return (Data >> DiscriminatorShift); + } + + PointerAuthenticationMode getAuthenticationMode() const { + return PointerAuthenticationMode((Data & AuthenticationModeMask) >> + AuthenticationModeShift); + } + + bool isIsaPointer() const { + assert(isPresent()); + return (Data & IsaPointerMask) >> IsaPointerShift; + } + + bool authenticatesNullValues() const { + assert(isPresent()); + return (Data & AuthenticatesNullValuesMask) >> AuthenticatesNullValuesShift; + } + + PointerAuthQualifier withoutKeyNone() const { + return hasKeyNone() ? PointerAuthQualifier() : *this; + } + + friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) { + return Lhs.Data == Rhs.Data; + } + friend bool operator!=(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) { + return Lhs.Data != Rhs.Data; + } + + bool isEquivalent(PointerAuthQualifier Other) const { + return withoutKeyNone() == Other.withoutKeyNone(); + } + + uint32_t getAsOpaqueValue() const { return Data; } + + // Deserialize pointer-auth qualifiers from an opaque representation. + static PointerAuthQualifier fromOpaqueValue(uint32_t Opaque) { + PointerAuthQualifier Result; + Result.Data = Opaque; + assert((Result.Data == 0) == + (Result.getAuthenticationMode() == PointerAuthenticationMode::None)); + return Result; + } + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const; + + bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; + void print(raw_ostream &OS, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); } +}; + +/// The collection of all-type qualifiers we support. +/// Clang supports five independent qualifiers: +/// * C99: const, volatile, and restrict +/// * MS: __unaligned +/// * Embedded C (TR18037): address spaces +/// * Objective C: the GC attributes (none, weak, or strong) +class Qualifiers { +public: + Qualifiers() = default; + enum TQ : uint64_t { + // NOTE: These flags must be kept in sync with DeclSpec::TQ. + Const = 0x1, + Restrict = 0x2, + Volatile = 0x4, + CVRMask = Const | Volatile | Restrict + }; + + enum GC { + GCNone = 0, + Weak, + Strong + }; + + enum ObjCLifetime { + /// There is no lifetime qualification on this type. + OCL_None, + + /// This object can be modified without requiring retains or + /// releases. + OCL_ExplicitNone, + + /// Assigning into this object requires the old value to be + /// released and the new value to be retained. The timing of the + /// release of the old value is inexact: it may be moved to + /// immediately after the last known point where the value is + /// live. + OCL_Strong, + + /// Reading or writing from this object requires a barrier call. + OCL_Weak, + + /// Assigning into this object requires a lifetime extension. + OCL_Autoreleasing + }; + + enum : uint64_t { + /// The maximum supported address space number. + /// 23 bits should be enough for anyone. + MaxAddressSpace = 0x7fffffu, + + /// The width of the "fast" qualifier mask. + FastWidth = 3, + + /// The fast qualifier mask. + FastMask = (1 << FastWidth) - 1 + }; + + /// Returns the common set of qualifiers while removing them from + /// the given sets. + static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { + Qualifiers Q; + PointerAuthQualifier LPtrAuth = L.getPointerAuth(); + if (LPtrAuth.isPresent() && + LPtrAuth.getKey() != PointerAuthQualifier::KeyNoneInternal && + LPtrAuth == R.getPointerAuth()) { + Q.setPointerAuth(LPtrAuth); + PointerAuthQualifier Empty; + L.setPointerAuth(Empty); + R.setPointerAuth(Empty); + } + + // If both are only CVR-qualified, bit operations are sufficient. + if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { + Q.Mask = L.Mask & R.Mask; + L.Mask &= ~Q.Mask; + R.Mask &= ~Q.Mask; + return Q; + } + + unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); + Q.addCVRQualifiers(CommonCRV); + L.removeCVRQualifiers(CommonCRV); + R.removeCVRQualifiers(CommonCRV); + + if (L.getObjCGCAttr() == R.getObjCGCAttr()) { + Q.setObjCGCAttr(L.getObjCGCAttr()); + L.removeObjCGCAttr(); + R.removeObjCGCAttr(); + } + + if (L.getObjCLifetime() == R.getObjCLifetime()) { + Q.setObjCLifetime(L.getObjCLifetime()); + L.removeObjCLifetime(); + R.removeObjCLifetime(); + } + + if (L.getAddressSpace() == R.getAddressSpace()) { + Q.setAddressSpace(L.getAddressSpace()); + L.removeAddressSpace(); + R.removeAddressSpace(); + } + return Q; + } + + static Qualifiers fromFastMask(unsigned Mask) { + Qualifiers Qs; + Qs.addFastQualifiers(Mask); + return Qs; + } + + static Qualifiers fromCVRMask(unsigned CVR) { + Qualifiers Qs; + Qs.addCVRQualifiers(CVR); + return Qs; + } + + static Qualifiers fromCVRUMask(unsigned CVRU) { + Qualifiers Qs; + Qs.addCVRUQualifiers(CVRU); + return Qs; + } + + // Deserialize qualifiers from an opaque representation. + static Qualifiers fromOpaqueValue(uint64_t opaque) { + Qualifiers Qs; + Qs.Mask = opaque; + return Qs; + } + + // Serialize these qualifiers into an opaque representation. + uint64_t getAsOpaqueValue() const { return Mask; } + + bool hasConst() const { return Mask & Const; } + bool hasOnlyConst() const { return Mask == Const; } + void removeConst() { Mask &= ~Const; } + void addConst() { Mask |= Const; } + Qualifiers withConst() const { + Qualifiers Qs = *this; + Qs.addConst(); + return Qs; + } + + bool hasVolatile() const { return Mask & Volatile; } + bool hasOnlyVolatile() const { return Mask == Volatile; } + void removeVolatile() { Mask &= ~Volatile; } + void addVolatile() { Mask |= Volatile; } + Qualifiers withVolatile() const { + Qualifiers Qs = *this; + Qs.addVolatile(); + return Qs; + } + + bool hasRestrict() const { return Mask & Restrict; } + bool hasOnlyRestrict() const { return Mask == Restrict; } + void removeRestrict() { Mask &= ~Restrict; } + void addRestrict() { Mask |= Restrict; } + Qualifiers withRestrict() const { + Qualifiers Qs = *this; + Qs.addRestrict(); + return Qs; + } + + bool hasCVRQualifiers() const { return getCVRQualifiers(); } + unsigned getCVRQualifiers() const { return Mask & CVRMask; } + unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); } + + void setCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask = (Mask & ~CVRMask) | mask; + } + void removeCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask &= ~static_cast(mask); + } + void removeCVRQualifiers() { + removeCVRQualifiers(CVRMask); + } + void addCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask |= mask; + } + void addCVRUQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits"); + Mask |= mask; + } + + bool hasUnaligned() const { return Mask & UMask; } + void setUnaligned(bool flag) { + Mask = (Mask & ~UMask) | (flag ? UMask : 0); + } + void removeUnaligned() { Mask &= ~UMask; } + void addUnaligned() { Mask |= UMask; } + + bool hasObjCGCAttr() const { return Mask & GCAttrMask; } + GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } + void setObjCGCAttr(GC type) { + Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); + } + void removeObjCGCAttr() { setObjCGCAttr(GCNone); } + void addObjCGCAttr(GC type) { + assert(type); + setObjCGCAttr(type); + } + Qualifiers withoutObjCGCAttr() const { + Qualifiers qs = *this; + qs.removeObjCGCAttr(); + return qs; + } + Qualifiers withoutObjCLifetime() const { + Qualifiers qs = *this; + qs.removeObjCLifetime(); + return qs; + } + Qualifiers withoutAddressSpace() const { + Qualifiers qs = *this; + qs.removeAddressSpace(); + return qs; + } + + bool hasObjCLifetime() const { return Mask & LifetimeMask; } + ObjCLifetime getObjCLifetime() const { + return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); + } + void setObjCLifetime(ObjCLifetime type) { + Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); + } + void removeObjCLifetime() { setObjCLifetime(OCL_None); } + void addObjCLifetime(ObjCLifetime type) { + assert(type); + assert(!hasObjCLifetime()); + Mask |= (type << LifetimeShift); + } + + /// True if the lifetime is neither None or ExplicitNone. + bool hasNonTrivialObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime > OCL_ExplicitNone); + } + + /// True if the lifetime is either strong or weak. + bool hasStrongOrWeakObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime == OCL_Strong || lifetime == OCL_Weak); + } + + bool hasAddressSpace() const { return Mask & AddressSpaceMask; } + LangAS getAddressSpace() const { + return static_cast((Mask & AddressSpaceMask) >> AddressSpaceShift); + } + bool hasTargetSpecificAddressSpace() const { + return isTargetAddressSpace(getAddressSpace()); + } + /// Get the address space attribute value to be printed by diagnostics. + unsigned getAddressSpaceAttributePrintValue() const { + auto Addr = getAddressSpace(); + // This function is not supposed to be used with language specific + // address spaces. If that happens, the diagnostic message should consider + // printing the QualType instead of the address space value. + assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); + if (Addr != LangAS::Default) + return toTargetAddressSpace(Addr); + // TODO: The diagnostic messages where Addr may be 0 should be fixed + // since it cannot differentiate the situation where 0 denotes the default + // address space or user specified __attribute__((address_space(0))). + return 0; + } + void setAddressSpace(LangAS space) { + assert((unsigned)space <= MaxAddressSpace); + Mask = (Mask & ~AddressSpaceMask) + | (((uint32_t) space) << AddressSpaceShift); + } + void removeAddressSpace() { setAddressSpace(LangAS::Default); } + void addAddressSpace(LangAS space) { + assert(space != LangAS::Default); + setAddressSpace(space); + } + + bool hasPointerAuth() const { return Mask & PtrAuthMask; } + PointerAuthQualifier getPointerAuth() const { + return PointerAuthQualifier::fromOpaqueValue(Mask >> PtrAuthShift); + } + void setPointerAuth(PointerAuthQualifier Q) { + Mask = (Mask & ~PtrAuthMask) | + (uint64_t(Q.getAsOpaqueValue()) << PtrAuthShift); + } + void removePointerAuth() { Mask &= ~PtrAuthMask; } + void addPointerAuth(PointerAuthQualifier Q) { + assert(Q.isPresent()); + setPointerAuth(Q); + } + + // Fast qualifiers are those that can be allocated directly + // on a QualType object. + bool hasFastQualifiers() const { return getFastQualifiers(); } + unsigned getFastQualifiers() const { return Mask & FastMask; } + void setFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask = (Mask & ~FastMask) | mask; + } + void removeFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask &= ~static_cast(mask); + } + void removeFastQualifiers() { + removeFastQualifiers(FastMask); + } + void addFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask |= mask; + } + + /// Return true if the set contains any qualifiers which require an ExtQuals + /// node to be allocated. + bool hasNonFastQualifiers() const { return Mask & ~FastMask; } + Qualifiers getNonFastQualifiers() const { + Qualifiers Quals = *this; + Quals.setFastQualifiers(0); + return Quals; + } + + /// Return true if the set contains any qualifiers. + bool hasQualifiers() const { return Mask; } + bool empty() const { return !Mask; } + + /// Add the qualifiers from the given set to this set. + void addQualifiers(Qualifiers Q) { + // If the other set doesn't have any non-boolean qualifiers, just + // bit-or it in. + if (!(Q.Mask & ~CVRMask)) + Mask |= Q.Mask; + else { + Mask |= (Q.Mask & CVRMask); + if (Q.hasAddressSpace()) + addAddressSpace(Q.getAddressSpace()); + if (Q.hasObjCGCAttr()) + addObjCGCAttr(Q.getObjCGCAttr()); + if (Q.hasObjCLifetime()) + addObjCLifetime(Q.getObjCLifetime()); + if (Q.hasPointerAuth()) + addPointerAuth(Q.getPointerAuth()); + } + } + + /// Remove the qualifiers from the given set from this set. + void removeQualifiers(Qualifiers Q) { + // If the other set doesn't have any non-boolean qualifiers, just + // bit-and the inverse in. + if (!(Q.Mask & ~CVRMask)) + Mask &= ~Q.Mask; + else { + Mask &= ~(Q.Mask & CVRMask); + if (getObjCGCAttr() == Q.getObjCGCAttr()) + removeObjCGCAttr(); + if (getObjCLifetime() == Q.getObjCLifetime()) + removeObjCLifetime(); + if (getAddressSpace() == Q.getAddressSpace()) + removeAddressSpace(); + if (getPointerAuth() == Q.getPointerAuth()) + removePointerAuth(); + } + } + + /// Add the qualifiers from the given set to this set, given that + /// they don't conflict. + void addConsistentQualifiers(Qualifiers qs) { + assert(getAddressSpace() == qs.getAddressSpace() || + !hasAddressSpace() || !qs.hasAddressSpace()); + assert(getObjCGCAttr() == qs.getObjCGCAttr() || + !hasObjCGCAttr() || !qs.hasObjCGCAttr()); + assert(getObjCLifetime() == qs.getObjCLifetime() || + !hasObjCLifetime() || !qs.hasObjCLifetime()); + assert(!hasPointerAuth() || !qs.hasPointerAuth() || + getPointerAuth() == qs.getPointerAuth()); + Mask |= qs.Mask; + } + + /// Returns true if address space A is equal to or a superset of B. + /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of + /// overlapping address spaces. + /// CL1.1 or CL1.2: + /// every address space is a superset of itself. + /// CL2.0 adds: + /// __generic is a superset of any address space except for __constant. + static bool isAddressSpaceSupersetOf(LangAS A, LangAS B, + const ASTContext &Ctx) { + // Address spaces must match exactly. + return A == B || isTargetAddressSpaceSupersetOf(A, B, Ctx); + } + + static bool isTargetAddressSpaceSupersetOf(LangAS A, LangAS B, + const ASTContext &Ctx); + + /// Returns true if the address space in these qualifiers is equal to or + /// a superset of the address space in the argument qualifiers. + bool isAddressSpaceSupersetOf(Qualifiers other, const ASTContext &Ctx) const { + return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(), + Ctx); + } + + /// Determines if these qualifiers compatibly include another set. + /// Generally this answers the question of whether an object with the other + /// qualifiers can be safely used as an object with these qualifiers. + bool compatiblyIncludes(Qualifiers other, const ASTContext &Ctx) const { + return isAddressSpaceSupersetOf(other, Ctx) && + // ObjC GC qualifiers can match, be added, or be removed, but can't + // be changed. + (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || + !other.hasObjCGCAttr()) && + // Pointer-auth qualifiers must match exactly. + getPointerAuth() == other.getPointerAuth() && + // ObjC lifetime qualifiers must match exactly. + getObjCLifetime() == other.getObjCLifetime() && + // CVR qualifiers may subset. + (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) && + // U qualifier may superset. + (!other.hasUnaligned() || hasUnaligned()); + } + + /// Determines if these qualifiers compatibly include another set of + /// qualifiers from the narrow perspective of Objective-C ARC lifetime. + /// + /// One set of Objective-C lifetime qualifiers compatibly includes the other + /// if the lifetime qualifiers match, or if both are non-__weak and the + /// including set also contains the 'const' qualifier, or both are non-__weak + /// and one is None (which can only happen in non-ARC modes). + bool compatiblyIncludesObjCLifetime(Qualifiers other) const { + if (getObjCLifetime() == other.getObjCLifetime()) + return true; + + if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) + return false; + + if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None) + return true; + + return hasConst(); + } + + /// Determine whether this set of qualifiers is a strict superset of + /// another set of qualifiers, not considering qualifier compatibility. + bool isStrictSupersetOf(Qualifiers Other) const; + + bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } + bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } + + explicit operator bool() const { return hasQualifiers(); } + + Qualifiers &operator+=(Qualifiers R) { + addQualifiers(R); + return *this; + } + + // Union two qualifier sets. If an enumerated qualifier appears + // in both sets, use the one from the right. + friend Qualifiers operator+(Qualifiers L, Qualifiers R) { + L += R; + return L; + } + + Qualifiers &operator-=(Qualifiers R) { + removeQualifiers(R); + return *this; + } + + /// Compute the difference between two qualifier sets. + friend Qualifiers operator-(Qualifiers L, Qualifiers R) { + L -= R; + return L; + } + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const; + + static std::string getAddrSpaceAsString(LangAS AS); + + bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool appendSpaceIfNonEmpty = false) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } + +private: + // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|32 ... 63| + // |C R V|U|GCAttr|Lifetime|AddressSpace| PtrAuth | + uint64_t Mask = 0; + static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t), + "PointerAuthQualifier must be 32 bits"); + + static constexpr uint64_t PtrAuthShift = 32; + static constexpr uint64_t PtrAuthMask = UINT64_C(0xffffffff) << PtrAuthShift; + + static constexpr uint64_t UMask = 0x8; + static constexpr uint64_t UShift = 3; + static constexpr uint64_t GCAttrMask = 0x30; + static constexpr uint64_t GCAttrShift = 4; + static constexpr uint64_t LifetimeMask = 0x1C0; + static constexpr uint64_t LifetimeShift = 6; + static constexpr uint64_t AddressSpaceMask = + ~(CVRMask | UMask | GCAttrMask | LifetimeMask | PtrAuthMask); + static constexpr uint64_t AddressSpaceShift = 9; +}; + +class QualifiersAndAtomic { + Qualifiers Quals; + bool HasAtomic; + +public: + QualifiersAndAtomic() : HasAtomic(false) {} + QualifiersAndAtomic(Qualifiers Quals, bool HasAtomic) + : Quals(Quals), HasAtomic(HasAtomic) {} + + operator Qualifiers() const { return Quals; } + + bool hasVolatile() const { return Quals.hasVolatile(); } + bool hasConst() const { return Quals.hasConst(); } + bool hasRestrict() const { return Quals.hasRestrict(); } + bool hasAtomic() const { return HasAtomic; } + + void addVolatile() { Quals.addVolatile(); } + void addConst() { Quals.addConst(); } + void addRestrict() { Quals.addRestrict(); } + void addAtomic() { HasAtomic = true; } + + void removeVolatile() { Quals.removeVolatile(); } + void removeConst() { Quals.removeConst(); } + void removeRestrict() { Quals.removeRestrict(); } + void removeAtomic() { HasAtomic = false; } + + QualifiersAndAtomic withVolatile() { + return {Quals.withVolatile(), HasAtomic}; + } + QualifiersAndAtomic withConst() { return {Quals.withConst(), HasAtomic}; } + QualifiersAndAtomic withRestrict() { + return {Quals.withRestrict(), HasAtomic}; + } + QualifiersAndAtomic withAtomic() { return {Quals, true}; } + + QualifiersAndAtomic &operator+=(Qualifiers RHS) { + Quals += RHS; + return *this; + } +}; + +/// A std::pair-like structure for storing a qualified type split +/// into its local qualifiers and its locally-unqualified type. +struct SplitQualType { + /// The locally-unqualified type. + const Type *Ty = nullptr; + + /// The local qualifiers. + Qualifiers Quals; + + SplitQualType() = default; + SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} + + SplitQualType getSingleStepDesugaredType() const; // end of this file + + // Make std::tie work. + std::pair asPair() const { + return std::pair(Ty, Quals); + } + + friend bool operator==(SplitQualType a, SplitQualType b) { + return a.Ty == b.Ty && a.Quals == b.Quals; + } + friend bool operator!=(SplitQualType a, SplitQualType b) { + return a.Ty != b.Ty || a.Quals != b.Quals; + } +}; + +/// The kind of type we are substituting Objective-C type arguments into. +/// +/// The kind of substitution affects the replacement of type parameters when +/// no concrete type information is provided, e.g., when dealing with an +/// unspecialized type. +enum class ObjCSubstitutionContext { + /// An ordinary type. + Ordinary, + + /// The result type of a method or function. + Result, + + /// The parameter type of a method or function. + Parameter, + + /// The type of a property. + Property, + + /// The superclass of a type. + Superclass, +}; + +/// The kind of 'typeof' expression we're after. +enum class TypeOfKind : uint8_t { + Qualified, + Unqualified, +}; + +/// A (possibly-)qualified type. +/// +/// For efficiency, we don't store CV-qualified types as nodes on their +/// own: instead each reference to a type stores the qualifiers. This +/// greatly reduces the number of nodes we need to allocate for types (for +/// example we only need one for 'int', 'const int', 'volatile int', +/// 'const volatile int', etc). +/// +/// As an added efficiency bonus, instead of making this a pair, we +/// just store the two bits we care about in the low bits of the +/// pointer. To handle the packing/unpacking, we make QualType be a +/// simple wrapper class that acts like a smart pointer. A third bit +/// indicates whether there are extended qualifiers present, in which +/// case the pointer points to a special structure. +class QualType { + friend class QualifierCollector; + + // Thankfully, these are efficiently composable. + llvm::PointerIntPair, + Qualifiers::FastWidth> Value; + + const ExtQuals *getExtQualsUnsafe() const { + return cast(Value.getPointer()); + } + + const Type *getTypePtrUnsafe() const { + return cast(Value.getPointer()); + } + + const ExtQualsTypeCommonBase *getCommonPtr() const { + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + auto CommonPtrVal = reinterpret_cast(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + return reinterpret_cast(CommonPtrVal); + } + +public: + QualType() = default; + QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} + QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {} + + unsigned getLocalFastQualifiers() const { return Value.getInt(); } + void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } + + bool UseExcessPrecision(const ASTContext &Ctx); + + /// Retrieves a pointer to the underlying (unqualified) type. + /// + /// This function requires that the type not be NULL. If the type might be + /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). + const Type *getTypePtr() const; + + const Type *getTypePtrOrNull() const; + + /// Retrieves a pointer to the name of the base type. + const IdentifierInfo *getBaseTypeIdentifier() const; + + /// Divides a QualType into its unqualified type and a set of local + /// qualifiers. + SplitQualType split() const; + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + + static QualType getFromOpaquePtr(const void *Ptr) { + QualType T; + T.Value.setFromOpaqueValue(const_cast(Ptr)); + return T; + } + + const Type &operator*() const { + return *getTypePtr(); + } + + const Type *operator->() const { + return getTypePtr(); + } + + bool isCanonical() const; + bool isCanonicalAsParam() const; + + /// Return true if this QualType doesn't point to a type yet. + bool isNull() const { + return Value.getPointer().isNull(); + } + + // Determines if a type can form `T&`. + bool isReferenceable() const; + + /// Determine whether this particular QualType instance has the + /// "const" qualifier set, without looking through typedefs that may have + /// added "const" at a different level. + bool isLocalConstQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Const); + } + + /// Determine whether this type is const-qualified. + bool isConstQualified() const; + + enum class NonConstantStorageReason { + MutableField, + NonConstNonReferenceType, + NonTrivialCtor, + NonTrivialDtor, + }; + /// Determine whether instances of this type can be placed in immutable + /// storage. + /// If ExcludeCtor is true, the duration when the object's constructor runs + /// will not be considered. The caller will need to verify that the object is + /// not written to during its construction. ExcludeDtor works similarly. + std::optional + isNonConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, + bool ExcludeDtor); + + bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, + bool ExcludeDtor) { + return !isNonConstantStorage(Ctx, ExcludeCtor, ExcludeDtor); + } + + /// Determine whether this particular QualType instance has the + /// "restrict" qualifier set, without looking through typedefs that may have + /// added "restrict" at a different level. + bool isLocalRestrictQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Restrict); + } + + /// Determine whether this type is restrict-qualified. + bool isRestrictQualified() const; + + /// Determine whether this particular QualType instance has the + /// "volatile" qualifier set, without looking through typedefs that may have + /// added "volatile" at a different level. + bool isLocalVolatileQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Volatile); + } + + /// Determine whether this type is volatile-qualified. + bool isVolatileQualified() const; + + /// Determine whether this particular QualType instance has any + /// qualifiers, without looking through any typedefs that might add + /// qualifiers at a different level. + bool hasLocalQualifiers() const { + return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); + } + + /// Determine whether this type has any qualifiers. + bool hasQualifiers() const; + + /// Determine whether this particular QualType instance has any + /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType + /// instance. + bool hasLocalNonFastQualifiers() const { + return isa(Value.getPointer()); + } + + /// Retrieve the set of qualifiers local to this particular QualType + /// instance, not including any qualifiers acquired through typedefs or + /// other sugar. + Qualifiers getLocalQualifiers() const; + + /// Retrieve the set of qualifiers applied to this type. + Qualifiers getQualifiers() const; + + /// Retrieve the set of CVR (const-volatile-restrict) qualifiers + /// local to this particular QualType instance, not including any qualifiers + /// acquired through typedefs or other sugar. + unsigned getLocalCVRQualifiers() const { + return getLocalFastQualifiers(); + } + + /// Retrieve the set of CVR (const-volatile-restrict) qualifiers + /// applied to this type. + unsigned getCVRQualifiers() const; + + bool isConstant(const ASTContext& Ctx) const { + return QualType::isConstant(*this, Ctx); + } + + /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). + bool isPODType(const ASTContext &Context) const; + + /// Return true if this is a POD type according to the rules of the C++98 + /// standard, regardless of the current compilation's language. + bool isCXX98PODType(const ASTContext &Context) const; + + /// Return true if this is a POD type according to the more relaxed rules + /// of the C++11 standard, regardless of the current compilation's language. + /// (C++0x [basic.types]p9). Note that, unlike + /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account. + bool isCXX11PODType(const ASTContext &Context) const; + + /// Return true if this is a trivial type per (C++0x [basic.types]p9) + bool isTrivialType(const ASTContext &Context) const; + + /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) + bool isTriviallyCopyableType(const ASTContext &Context) const; + + /// Return true if the type is safe to bitwise copy using memcpy/memmove. + /// + /// This is an extension in clang: bitwise cloneable types act as trivially + /// copyable types, meaning their underlying bytes can be safely copied by + /// memcpy or memmove. After the copy, the destination object has the same + /// object representation. + /// + /// However, there are cases where it is not safe to copy: + /// - When sanitizers, such as AddressSanitizer, add padding with poison, + /// which can cause issues if those poisoned padding bits are accessed. + /// - Types with Objective-C lifetimes, where specific runtime + /// semantics may not be preserved during a bitwise copy. + bool isBitwiseCloneableType(const ASTContext &Context) const; + + /// Return true if this is a trivially copyable type + bool isTriviallyCopyConstructibleType(const ASTContext &Context) const; + + /// Returns true if it is a class and it might be dynamic. + bool mayBeDynamicClass() const; + + /// Returns true if it is not a class or if the class might not be dynamic. + bool mayBeNotDynamicClass() const; + + /// Returns true if it is a WebAssembly Reference Type. + bool isWebAssemblyReferenceType() const; + + /// Returns true if it is a WebAssembly Externref Type. + bool isWebAssemblyExternrefType() const; + + /// Returns true if it is a WebAssembly Funcref Type. + bool isWebAssemblyFuncrefType() const; + + // Don't promise in the API that anything besides 'const' can be + // easily added. + + /// Add the `const` type qualifier to this QualType. + void addConst() { + addFastQualifiers(Qualifiers::Const); + } + QualType withConst() const { + return withFastQualifiers(Qualifiers::Const); + } + + /// Add the `volatile` type qualifier to this QualType. + void addVolatile() { + addFastQualifiers(Qualifiers::Volatile); + } + QualType withVolatile() const { + return withFastQualifiers(Qualifiers::Volatile); + } + + /// Add the `restrict` qualifier to this QualType. + void addRestrict() { + addFastQualifiers(Qualifiers::Restrict); + } + QualType withRestrict() const { + return withFastQualifiers(Qualifiers::Restrict); + } + + QualType withCVRQualifiers(unsigned CVR) const { + return withFastQualifiers(CVR); + } + + void addFastQualifiers(unsigned TQs) { + assert(!(TQs & ~Qualifiers::FastMask) + && "non-fast qualifier bits set in mask!"); + Value.setInt(Value.getInt() | TQs); + } + + void removeLocalConst(); + void removeLocalVolatile(); + void removeLocalRestrict(); + + void removeLocalFastQualifiers() { Value.setInt(0); } + void removeLocalFastQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); + Value.setInt(Value.getInt() & ~Mask); + } + + // Creates a type with the given qualifiers in addition to any + // qualifiers already on this type. + QualType withFastQualifiers(unsigned TQs) const { + QualType T = *this; + T.addFastQualifiers(TQs); + return T; + } + + // Creates a type with exactly the given fast qualifiers, removing + // any existing fast qualifiers. + QualType withExactLocalFastQualifiers(unsigned TQs) const { + return withoutLocalFastQualifiers().withFastQualifiers(TQs); + } + + // Removes fast qualifiers, but leaves any extended qualifiers in place. + QualType withoutLocalFastQualifiers() const { + QualType T = *this; + T.removeLocalFastQualifiers(); + return T; + } + + QualType getCanonicalType() const; + + /// Return this type with all of the instance-specific qualifiers + /// removed, but without removing any qualifiers that may have been applied + /// through typedefs. + QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } + + /// Retrieve the unqualified variant of the given type, + /// removing as little sugar as possible. + /// + /// This routine looks through various kinds of sugar to find the + /// least-desugared type that is unqualified. For example, given: + /// + /// \code + /// typedef int Integer; + /// typedef const Integer CInteger; + /// typedef CInteger DifferenceType; + /// \endcode + /// + /// Executing \c getUnqualifiedType() on the type \c DifferenceType will + /// desugar until we hit the type \c Integer, which has no qualifiers on it. + /// + /// The resulting type might still be qualified if it's sugar for an array + /// type. To strip qualifiers even from within a sugared array type, use + /// ASTContext::getUnqualifiedArrayType. + /// + /// Note: In C, the _Atomic qualifier is special (see C23 6.2.5p32 for + /// details), and it is not stripped by this function. Use + /// getAtomicUnqualifiedType() to strip qualifiers including _Atomic. + inline QualType getUnqualifiedType() const; + + /// Retrieve the unqualified variant of the given type, removing as little + /// sugar as possible. + /// + /// Like getUnqualifiedType(), but also returns the set of + /// qualifiers that were built up. + /// + /// The resulting type might still be qualified if it's sugar for an array + /// type. To strip qualifiers even from within a sugared array type, use + /// ASTContext::getUnqualifiedArrayType. + inline SplitQualType getSplitUnqualifiedType() const; + + /// Determine whether this type is more qualified than the other + /// given type, requiring exact equality for non-CVR qualifiers. + bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const; + + /// Determine whether this type is at least as qualified as the other + /// given type, requiring exact equality for non-CVR qualifiers. + bool isAtLeastAsQualifiedAs(QualType Other, const ASTContext &Ctx) const; + + QualType getNonReferenceType() const; + + /// Determine the type of a (typically non-lvalue) expression with the + /// specified result type. + /// + /// This routine should be used for expressions for which the return type is + /// explicitly specified (e.g., in a cast or call) and isn't necessarily + /// an lvalue. It removes a top-level reference (since there are no + /// expressions of reference type) and deletes top-level cvr-qualifiers + /// from non-class types (in C++) or all types (in C). + QualType getNonLValueExprType(const ASTContext &Context) const; + + /// Remove an outer pack expansion type (if any) from this type. Used as part + /// of converting the type of a declaration to the type of an expression that + /// references that expression. It's meaningless for an expression to have a + /// pack expansion type. + QualType getNonPackExpansionType() const; + + /// Return the specified type with any "sugar" removed from + /// the type. This takes off typedefs, typeof's etc. If the outer level of + /// the type is already concrete, it returns it unmodified. This is similar + /// to getting the canonical type, but it doesn't remove *all* typedefs. For + /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is + /// concrete. + /// + /// Qualifiers are left in place. + QualType getDesugaredType(const ASTContext &Context) const { + return getDesugaredType(*this, Context); + } + + SplitQualType getSplitDesugaredType() const { + return getSplitDesugaredType(*this); + } + + /// Return the specified type with one level of "sugar" removed from + /// the type. + /// + /// This routine takes off the first typedef, typeof, etc. If the outer level + /// of the type is already concrete, it returns it unmodified. + QualType getSingleStepDesugaredType(const ASTContext &Context) const { + return getSingleStepDesugaredTypeImpl(*this, Context); + } + + /// Returns the specified type after dropping any + /// outer-level parentheses. + QualType IgnoreParens() const { + if (isa(*this)) + return QualType::IgnoreParens(*this); + return *this; + } + + /// Indicate whether the specified types and qualifiers are identical. + friend bool operator==(const QualType &LHS, const QualType &RHS) { + return LHS.Value == RHS.Value; + } + friend bool operator!=(const QualType &LHS, const QualType &RHS) { + return LHS.Value != RHS.Value; + } + friend bool operator<(const QualType &LHS, const QualType &RHS) { + return LHS.Value < RHS.Value; + } + + static std::string getAsString(SplitQualType split, + const PrintingPolicy &Policy) { + return getAsString(split.Ty, split.Quals, Policy); + } + static std::string getAsString(const Type *ty, Qualifiers qs, + const PrintingPolicy &Policy); + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const; + + void print(raw_ostream &OS, const PrintingPolicy &Policy, + const Twine &PlaceHolder = Twine(), + unsigned Indentation = 0) const; + + static void print(SplitQualType split, raw_ostream &OS, + const PrintingPolicy &policy, const Twine &PlaceHolder, + unsigned Indentation = 0) { + return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); + } + + static void print(const Type *ty, Qualifiers qs, + raw_ostream &OS, const PrintingPolicy &policy, + const Twine &PlaceHolder, + unsigned Indentation = 0); + + void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const; + + static void getAsStringInternal(SplitQualType split, std::string &out, + const PrintingPolicy &policy) { + return getAsStringInternal(split.Ty, split.Quals, out, policy); + } + + static void getAsStringInternal(const Type *ty, Qualifiers qs, + std::string &out, + const PrintingPolicy &policy); + + class StreamedQualTypeHelper { + const QualType &T; + const PrintingPolicy &Policy; + const Twine &PlaceHolder; + unsigned Indentation; + + public: + StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, + const Twine &PlaceHolder, unsigned Indentation) + : T(T), Policy(Policy), PlaceHolder(PlaceHolder), + Indentation(Indentation) {} + + friend raw_ostream &operator<<(raw_ostream &OS, + const StreamedQualTypeHelper &SQT) { + SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation); + return OS; + } + }; + + StreamedQualTypeHelper stream(const PrintingPolicy &Policy, + const Twine &PlaceHolder = Twine(), + unsigned Indentation = 0) const { + return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation); + } + + void dump(const char *s) const; + void dump() const; + void dump(llvm::raw_ostream &OS, const ASTContext &Context) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } + + /// Check if this type has any address space qualifier. + inline bool hasAddressSpace() const; + + /// Return the address space of this type. + inline LangAS getAddressSpace() const; + + /// Returns true if address space qualifiers overlap with T address space + /// qualifiers. + /// OpenCL C defines conversion rules for pointers to different address spaces + /// and notion of overlapping address spaces. + /// CL1.1 or CL1.2: + /// address spaces overlap iff they are they same. + /// OpenCL C v2.0 s6.5.5 adds: + /// __generic overlaps with any address space except for __constant. + bool isAddressSpaceOverlapping(QualType T, const ASTContext &Ctx) const { + Qualifiers Q = getQualifiers(); + Qualifiers TQ = T.getQualifiers(); + // Address spaces overlap if at least one of them is a superset of another + return Q.isAddressSpaceSupersetOf(TQ, Ctx) || + TQ.isAddressSpaceSupersetOf(Q, Ctx); + } + + /// Returns gc attribute of this type. + inline Qualifiers::GC getObjCGCAttr() const; + + /// true when Type is objc's weak. + bool isObjCGCWeak() const { + return getObjCGCAttr() == Qualifiers::Weak; + } + + /// true when Type is objc's strong. + bool isObjCGCStrong() const { + return getObjCGCAttr() == Qualifiers::Strong; + } + + /// Returns lifetime attribute of this type. + Qualifiers::ObjCLifetime getObjCLifetime() const { + return getQualifiers().getObjCLifetime(); + } + + bool hasNonTrivialObjCLifetime() const { + return getQualifiers().hasNonTrivialObjCLifetime(); + } + + bool hasStrongOrWeakObjCLifetime() const { + return getQualifiers().hasStrongOrWeakObjCLifetime(); + } + + // true when Type is objc's weak and weak is enabled but ARC isn't. + bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; + + PointerAuthQualifier getPointerAuth() const { + return getQualifiers().getPointerAuth(); + } + + bool hasAddressDiscriminatedPointerAuth() const { + if (PointerAuthQualifier PtrAuth = getPointerAuth()) + return PtrAuth.isAddressDiscriminated(); + return false; + } + + enum PrimitiveDefaultInitializeKind { + /// The type does not fall into any of the following categories. Note that + /// this case is zero-valued so that values of this enum can be used as a + /// boolean condition for non-triviality. + PDIK_Trivial, + + /// The type is an Objective-C retainable pointer type that is qualified + /// with the ARC __strong qualifier. + PDIK_ARCStrong, + + /// The type is an Objective-C retainable pointer type that is qualified + /// with the ARC __weak qualifier. + PDIK_ARCWeak, + + /// The type is a struct containing a field whose type is not PCK_Trivial. + PDIK_Struct + }; + + /// Functions to query basic properties of non-trivial C struct types. + + /// Check if this is a non-trivial type that would cause a C struct + /// transitively containing this type to be non-trivial to default initialize + /// and return the kind. + PrimitiveDefaultInitializeKind + isNonTrivialToPrimitiveDefaultInitialize() const; + + enum PrimitiveCopyKind { + /// The type does not fall into any of the following categories. Note that + /// this case is zero-valued so that values of this enum can be used as a + /// boolean condition for non-triviality. + PCK_Trivial, + + /// The type would be trivial except that it is volatile-qualified. Types + /// that fall into one of the other non-trivial cases may additionally be + /// volatile-qualified. + PCK_VolatileTrivial, + + /// The type is an Objective-C retainable pointer type that is qualified + /// with the ARC __strong qualifier. + PCK_ARCStrong, + + /// The type is an Objective-C retainable pointer type that is qualified + /// with the ARC __weak qualifier. + PCK_ARCWeak, + + /// The type is an address-discriminated signed pointer type. + PCK_PtrAuth, + + /// The type is a struct containing a field whose type is neither + /// PCK_Trivial nor PCK_VolatileTrivial. + /// Note that a C++ struct type does not necessarily match this; C++ copying + /// semantics are too complex to express here, in part because they depend + /// on the exact constructor or assignment operator that is chosen by + /// overload resolution to do the copy. + PCK_Struct + }; + + /// Check if this is a non-trivial type that would cause a C struct + /// transitively containing this type to be non-trivial to copy and return the + /// kind. + PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const; + + /// Check if this is a non-trivial type that would cause a C struct + /// transitively containing this type to be non-trivial to destructively + /// move and return the kind. Destructive move in this context is a C++-style + /// move in which the source object is placed in a valid but unspecified state + /// after it is moved, as opposed to a truly destructive move in which the + /// source object is placed in an uninitialized state. + PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const; + + enum DestructionKind { + DK_none, + DK_cxx_destructor, + DK_objc_strong_lifetime, + DK_objc_weak_lifetime, + DK_nontrivial_c_struct + }; + + /// Returns a nonzero value if objects of this type require + /// non-trivial work to clean up after. Non-zero because it's + /// conceivable that qualifiers (objc_gc(weak)?) could make + /// something require destruction. + DestructionKind isDestructedType() const { + return isDestructedTypeImpl(*this); + } + + /// Check if this is or contains a C union that is non-trivial to + /// default-initialize, which is a union that has a member that is non-trivial + /// to default-initialize. If this returns true, + /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct. + bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const; + + /// Check if this is or contains a C union that is non-trivial to destruct, + /// which is a union that has a member that is non-trivial to destruct. If + /// this returns true, isDestructedType returns DK_nontrivial_c_struct. + bool hasNonTrivialToPrimitiveDestructCUnion() const; + + /// Check if this is or contains a C union that is non-trivial to copy, which + /// is a union that has a member that is non-trivial to copy. If this returns + /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct. + bool hasNonTrivialToPrimitiveCopyCUnion() const; + + /// Determine whether expressions of the given type are forbidden + /// from being lvalues in C. + /// + /// The expression types that are forbidden to be lvalues are: + /// - 'void', but not qualified void + /// - function types + /// + /// The exact rule here is C99 6.3.2.1: + /// An lvalue is an expression with an object type or an incomplete + /// type other than void. + bool isCForbiddenLValueType() const; + + /// Substitute type arguments for the Objective-C type parameters used in the + /// subject type. + /// + /// \param ctx ASTContext in which the type exists. + /// + /// \param typeArgs The type arguments that will be substituted for the + /// Objective-C type parameters in the subject type, which are generally + /// computed via \c Type::getObjCSubstitutions. If empty, the type + /// parameters will be replaced with their bounds or id/Class, as appropriate + /// for the context. + /// + /// \param context The context in which the subject type was written. + /// + /// \returns the resulting type. + QualType substObjCTypeArgs(ASTContext &ctx, + ArrayRef typeArgs, + ObjCSubstitutionContext context) const; + + /// Substitute type arguments from an object type for the Objective-C type + /// parameters used in the subject type. + /// + /// This operation combines the computation of type arguments for + /// substitution (\c Type::getObjCSubstitutions) with the actual process of + /// substitution (\c QualType::substObjCTypeArgs) for the convenience of + /// callers that need to perform a single substitution in isolation. + /// + /// \param objectType The type of the object whose member type we're + /// substituting into. For example, this might be the receiver of a message + /// or the base of a property access. + /// + /// \param dc The declaration context from which the subject type was + /// retrieved, which indicates (for example) which type parameters should + /// be substituted. + /// + /// \param context The context in which the subject type was written. + /// + /// \returns the subject type after replacing all of the Objective-C type + /// parameters with their corresponding arguments. + QualType substObjCMemberType(QualType objectType, + const DeclContext *dc, + ObjCSubstitutionContext context) const; + + /// Strip Objective-C "__kindof" types from the given type. + QualType stripObjCKindOfType(const ASTContext &ctx) const; + + /// Remove all qualifiers including _Atomic. + /// + /// Like getUnqualifiedType(), the type may still be qualified if it is a + /// sugared array type. To strip qualifiers even from within a sugared array + /// type, use in conjunction with ASTContext::getUnqualifiedArrayType. + QualType getAtomicUnqualifiedType() const; + +private: + // These methods are implemented in a separate translation unit; + // "static"-ize them to avoid creating temporary QualTypes in the + // caller. + static bool isConstant(QualType T, const ASTContext& Ctx); + static QualType getDesugaredType(QualType T, const ASTContext &Context); + static SplitQualType getSplitDesugaredType(QualType T); + static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); + static QualType getSingleStepDesugaredTypeImpl(QualType type, + const ASTContext &C); + static QualType IgnoreParens(QualType T); + static DestructionKind isDestructedTypeImpl(QualType type); + + /// Check if \param RD is or contains a non-trivial C union. + static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD); + static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD); + static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD); +}; + +raw_ostream &operator<<(raw_ostream &OS, QualType QT); + +} // namespace clang + +namespace llvm { + +/// Implement simplify_type for QualType, so that we can dyn_cast from QualType +/// to a specific Type class. +template<> struct simplify_type< ::clang::QualType> { + using SimpleType = const ::clang::Type *; + + static SimpleType getSimplifiedValue(::clang::QualType Val) { + return Val.getTypePtr(); + } +}; + +// Teach SmallPtrSet that QualType is "basically a pointer". +template<> +struct PointerLikeTypeTraits { + static inline void *getAsVoidPointer(clang::QualType P) { + return P.getAsOpaquePtr(); + } + + static inline clang::QualType getFromVoidPointer(void *P) { + return clang::QualType::getFromOpaquePtr(P); + } + + // Various qualifiers go in low bits. + static constexpr int NumLowBitsAvailable = 0; +}; + +} // namespace llvm + +namespace clang { + +/// Base class that is common to both the \c ExtQuals and \c Type +/// classes, which allows \c QualType to access the common fields between the +/// two. +class ExtQualsTypeCommonBase { + friend class ExtQuals; + friend class QualType; + friend class Type; + friend class ASTReader; + + /// The "base" type of an extended qualifiers type (\c ExtQuals) or + /// a self-referential pointer (for \c Type). + /// + /// This pointer allows an efficient mapping from a QualType to its + /// underlying type pointer. + const Type *const BaseType; + + /// The canonical type of this type. A QualType. + QualType CanonicalType; + + ExtQualsTypeCommonBase(const Type *baseType, QualType canon) + : BaseType(baseType), CanonicalType(canon) {} +}; + +/// We can encode up to four bits in the low bits of a +/// type pointer, but there are many more type qualifiers that we want +/// to be able to apply to an arbitrary type. Therefore we have this +/// struct, intended to be heap-allocated and used by QualType to +/// store qualifiers. +/// +/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers +/// in three low bits on the QualType pointer; a fourth bit records whether +/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, +/// Objective-C GC attributes) are much more rare. +class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase, + public llvm::FoldingSetNode { + // NOTE: changing the fast qualifiers should be straightforward as + // long as you don't make 'const' non-fast. + // 1. Qualifiers: + // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). + // Fast qualifiers must occupy the low-order bits. + // b) Update Qualifiers::FastWidth and FastMask. + // 2. QualType: + // a) Update is{Volatile,Restrict}Qualified(), defined inline. + // b) Update remove{Volatile,Restrict}, defined near the end of + // this header. + // 3. ASTContext: + // a) Update get{Volatile,Restrict}Type. + + /// The immutable set of qualifiers applied by this node. Always contains + /// extended qualifiers. + Qualifiers Quals; + + ExtQuals *this_() { return this; } + +public: + ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) + : ExtQualsTypeCommonBase(baseType, + canon.isNull() ? QualType(this_(), 0) : canon), + Quals(quals) { + assert(Quals.hasNonFastQualifiers() + && "ExtQuals created with no fast qualifiers"); + assert(!Quals.hasFastQualifiers() + && "ExtQuals created with fast qualifiers"); + } + + Qualifiers getQualifiers() const { return Quals; } + + bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } + Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + + bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } + Qualifiers::ObjCLifetime getObjCLifetime() const { + return Quals.getObjCLifetime(); + } + + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } + LangAS getAddressSpace() const { return Quals.getAddressSpace(); } + + const Type *getBaseType() const { return BaseType; } + +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getBaseType(), Quals); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + const Type *BaseType, + Qualifiers Quals) { + assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); + ID.AddPointer(BaseType); + Quals.Profile(ID); + } +}; + +/// The kind of C++11 ref-qualifier associated with a function type. +/// This determines whether a member function's "this" object can be an +/// lvalue, rvalue, or neither. +enum RefQualifierKind { + /// No ref-qualifier was provided. + RQ_None = 0, + + /// An lvalue ref-qualifier was provided (\c &). + RQ_LValue, + + /// An rvalue ref-qualifier was provided (\c &&). + RQ_RValue +}; + +/// Which keyword(s) were used to create an AutoType. +enum class AutoTypeKeyword { + /// auto + Auto, + + /// decltype(auto) + DecltypeAuto, + + /// __auto_type (GNU extension) + GNUAutoType +}; + +enum class ArraySizeModifier; +enum class ElaboratedTypeKeyword; +enum class VectorKind; + +/// The base class of the type hierarchy. +/// +/// A central concept with types is that each type always has a canonical +/// type. A canonical type is the type with any typedef names stripped out +/// of it or the types it references. For example, consider: +/// +/// typedef int foo; +/// typedef foo* bar; +/// 'int *' 'foo *' 'bar' +/// +/// There will be a Type object created for 'int'. Since int is canonical, its +/// CanonicalType pointer points to itself. There is also a Type for 'foo' (a +/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next +/// there is a PointerType that represents 'int*', which, like 'int', is +/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical +/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type +/// is also 'int*'. +/// +/// Non-canonical types are useful for emitting diagnostics, without losing +/// information about typedefs being used. Canonical types are useful for type +/// comparisons (they allow by-pointer equality tests) and useful for reasoning +/// about whether something has a particular form (e.g. is a function type), +/// because they implicitly, recursively, strip all typedefs out of a type. +/// +/// Types, once created, are immutable. +/// +class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { +public: + enum TypeClass { +#define TYPE(Class, Base) Class, +#define LAST_TYPE(Class) TypeLast = Class +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.inc" + }; + +private: + /// Bitfields required by the Type class. + class TypeBitfields { + friend class Type; + template friend class TypePropertyCache; + + /// TypeClass bitfield - Enum that specifies what subclass this belongs to. + LLVM_PREFERRED_TYPE(TypeClass) + unsigned TC : 8; + + /// Store information on the type dependency. + LLVM_PREFERRED_TYPE(TypeDependence) + unsigned Dependence : llvm::BitWidth; + + /// True if the cache (i.e. the bitfields here starting with + /// 'Cache') is valid. + LLVM_PREFERRED_TYPE(bool) + mutable unsigned CacheValid : 1; + + /// Linkage of this type. + LLVM_PREFERRED_TYPE(Linkage) + mutable unsigned CachedLinkage : 3; + + /// Whether this type involves and local or unnamed types. + LLVM_PREFERRED_TYPE(bool) + mutable unsigned CachedLocalOrUnnamed : 1; + + /// Whether this type comes from an AST file. + LLVM_PREFERRED_TYPE(bool) + mutable unsigned FromAST : 1; + + bool isCacheValid() const { + return CacheValid; + } + + Linkage getLinkage() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return static_cast(CachedLinkage); + } + + bool hasLocalOrUnnamedType() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return CachedLocalOrUnnamed; + } + }; + enum { NumTypeBits = 8 + llvm::BitWidth + 6 }; + +protected: + // These classes allow subclasses to somewhat cleanly pack bitfields + // into Type. + + class ArrayTypeBitfields { + friend class ArrayType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// CVR qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + LLVM_PREFERRED_TYPE(Qualifiers) + unsigned IndexTypeQuals : 3; + + /// Storage class qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + LLVM_PREFERRED_TYPE(ArraySizeModifier) + unsigned SizeModifier : 3; + }; + enum { NumArrayTypeBits = NumTypeBits + 6 }; + + class ConstantArrayTypeBitfields { + friend class ConstantArrayType; + + LLVM_PREFERRED_TYPE(ArrayTypeBitfields) + unsigned : NumArrayTypeBits; + + /// Whether we have a stored size expression. + LLVM_PREFERRED_TYPE(bool) + unsigned HasExternalSize : 1; + + LLVM_PREFERRED_TYPE(unsigned) + unsigned SizeWidth : 5; + }; + + class BuiltinTypeBitfields { + friend class BuiltinType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The kind (BuiltinType::Kind) of builtin type this is. + static constexpr unsigned NumOfBuiltinTypeBits = 9; + unsigned Kind : NumOfBuiltinTypeBits; + }; + +public: + static constexpr int FunctionTypeNumParamsWidth = 16; + static constexpr int FunctionTypeNumParamsLimit = (1 << 16) - 1; + +protected: + /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. + /// Only common bits are stored here. Additional uncommon bits are stored + /// in a trailing object after FunctionProtoType. + class FunctionTypeBitfields { + friend class FunctionProtoType; + friend class FunctionType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + LLVM_PREFERRED_TYPE(RefQualifierKind) + unsigned RefQualifier : 2; + + /// Used only by FunctionProtoType, put here to pack with the + /// other bitfields. + /// The qualifiers are part of FunctionProtoType because... + /// + /// C++ 8.3.5p4: The return type, the parameter type list and the + /// cv-qualifier-seq, [...], are part of the function type. + LLVM_PREFERRED_TYPE(Qualifiers) + unsigned FastTypeQuals : Qualifiers::FastWidth; + /// Whether this function has extended Qualifiers. + LLVM_PREFERRED_TYPE(bool) + unsigned HasExtQuals : 1; + + /// The type of exception specification this function has. + LLVM_PREFERRED_TYPE(ExceptionSpecificationType) + unsigned ExceptionSpecType : 4; + + /// Whether this function has extended parameter information. + LLVM_PREFERRED_TYPE(bool) + unsigned HasExtParameterInfos : 1; + + /// Whether this function has extra bitfields for the prototype. + LLVM_PREFERRED_TYPE(bool) + unsigned HasExtraBitfields : 1; + + /// Whether the function is variadic. + LLVM_PREFERRED_TYPE(bool) + unsigned Variadic : 1; + + /// Whether this function has a trailing return type. + LLVM_PREFERRED_TYPE(bool) + unsigned HasTrailingReturn : 1; + + /// Whether this function has is a cfi unchecked callee. + LLVM_PREFERRED_TYPE(bool) + unsigned CFIUncheckedCallee : 1; + + /// Extra information which affects how the function is called, like + /// regparm and the calling convention. + LLVM_PREFERRED_TYPE(CallingConv) + unsigned ExtInfo : 14; + + /// The number of parameters this function has, not counting '...'. + /// According to [implimits] 8 bits should be enough here but this is + /// somewhat easy to exceed with metaprogramming and so we would like to + /// keep NumParams as wide as reasonably possible. + unsigned NumParams : FunctionTypeNumParamsWidth; + }; + + class ObjCObjectTypeBitfields { + friend class ObjCObjectType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The number of type arguments stored directly on this object type. + unsigned NumTypeArgs : 7; + + /// The number of protocols stored directly on this object type. + unsigned NumProtocols : 6; + + /// Whether this is a "kindof" type. + LLVM_PREFERRED_TYPE(bool) + unsigned IsKindOf : 1; + }; + + class ReferenceTypeBitfields { + friend class ReferenceType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// True if the type was originally spelled with an lvalue sigil. + /// This is never true of rvalue references but can also be false + /// on lvalue references because of C++0x [dcl.typedef]p9, + /// as follows: + /// + /// typedef int &ref; // lvalue, spelled lvalue + /// typedef int &&rvref; // rvalue + /// ref &a; // lvalue, inner ref, spelled lvalue + /// ref &&a; // lvalue, inner ref + /// rvref &a; // lvalue, inner ref, spelled lvalue + /// rvref &&a; // rvalue, inner ref + LLVM_PREFERRED_TYPE(bool) + unsigned SpelledAsLValue : 1; + + /// True if the inner type is a reference type. This only happens + /// in non-canonical forms. + LLVM_PREFERRED_TYPE(bool) + unsigned InnerRef : 1; + }; + + class KeywordWrapperBitfields { + template friend class KeywordWrapper; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// An ElaboratedTypeKeyword. 8 bits for efficient access. + LLVM_PREFERRED_TYPE(ElaboratedTypeKeyword) + unsigned Keyword : 8; + }; + + enum { NumTypeWithKeywordBits = NumTypeBits + 8 }; + + class TagTypeBitfields { + friend class TagType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// Whether the TagType has a trailing Qualifier. + LLVM_PREFERRED_TYPE(bool) + unsigned HasQualifier : 1; + + /// Whether the TagType owns the Tag. + LLVM_PREFERRED_TYPE(bool) + unsigned OwnsTag : 1; + + /// Whether the TagType was created from an injected name. + LLVM_PREFERRED_TYPE(bool) + unsigned IsInjected : 1; + }; + + class VectorTypeBitfields { + friend class VectorType; + friend class DependentVectorType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The kind of vector, either a generic vector type or some + /// target-specific vector type such as for AltiVec or Neon. + LLVM_PREFERRED_TYPE(VectorKind) + unsigned VecKind : 4; + /// The number of elements in the vector. + uint32_t NumElements; + }; + + class AttributedTypeBitfields { + friend class AttributedType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + LLVM_PREFERRED_TYPE(attr::Kind) + unsigned AttrKind : 32 - NumTypeBits; + }; + + class AutoTypeBitfields { + friend class AutoType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// Was this placeholder type spelled as 'auto', 'decltype(auto)', + /// or '__auto_type'? AutoTypeKeyword value. + LLVM_PREFERRED_TYPE(AutoTypeKeyword) + unsigned Keyword : 2; + + /// The number of template arguments in the type-constraints, which is + /// expected to be able to hold at least 1024 according to [implimits]. + /// However as this limit is somewhat easy to hit with template + /// metaprogramming we'd prefer to keep it as large as possible. + /// At the moment it has been left as a non-bitfield since this type + /// safely fits in 64 bits as an unsigned, so there is no reason to + /// introduce the performance impact of a bitfield. + unsigned NumArgs; + }; + + class TypeOfBitfields { + friend class TypeOfType; + friend class TypeOfExprType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + LLVM_PREFERRED_TYPE(TypeOfKind) + unsigned Kind : 1; + }; + + class UnresolvedUsingBitfields { + friend class UnresolvedUsingType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// True if there is a non-null qualifier. + LLVM_PREFERRED_TYPE(bool) + unsigned hasQualifier : 1; + }; + + class UsingBitfields { + friend class UsingType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// True if there is a non-null qualifier. + LLVM_PREFERRED_TYPE(bool) + unsigned hasQualifier : 1; + }; + + class TypedefBitfields { + friend class TypedefType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// True if there is a non-null qualifier. + LLVM_PREFERRED_TYPE(bool) + unsigned hasQualifier : 1; + + /// True if the underlying type is different from the declared one. + LLVM_PREFERRED_TYPE(bool) + unsigned hasTypeDifferentFromDecl : 1; + }; + + class TemplateTypeParmTypeBitfields { + friend class TemplateTypeParmType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The depth of the template parameter. + unsigned Depth : 15; + + /// Whether this is a template parameter pack. + LLVM_PREFERRED_TYPE(bool) + unsigned ParameterPack : 1; + + /// The index of the template parameter. + unsigned Index : 16; + }; + + class SubstTemplateTypeParmTypeBitfields { + friend class SubstTemplateTypeParmType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + LLVM_PREFERRED_TYPE(bool) + unsigned HasNonCanonicalUnderlyingType : 1; + + // The index of the template parameter this substitution represents. + unsigned Index : 15; + + LLVM_PREFERRED_TYPE(bool) + unsigned Final : 1; + + /// Represents the index within a pack if this represents a substitution + /// from a pack expansion. This index starts at the end of the pack and + /// increments towards the beginning. + /// Positive non-zero number represents the index + 1. + /// Zero means this is not substituted from an expansion. + unsigned PackIndex : 15; + }; + + class SubstPackTypeBitfields { + friend class SubstPackType; + friend class SubstTemplateTypeParmPackType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The number of template arguments in \c Arguments, which is + /// expected to be able to hold at least 1024 according to [implimits]. + /// However as this limit is somewhat easy to hit with template + /// metaprogramming we'd prefer to keep it as large as possible. + unsigned NumArgs : 16; + + // The index of the template parameter this substitution represents. + // Only used by SubstTemplateTypeParmPackType. We keep it in the same + // class to avoid dealing with complexities of bitfields that go over + // the size of `unsigned`. + unsigned SubstTemplTypeParmPackIndex : 16; + }; + + class TemplateSpecializationTypeBitfields { + friend class TemplateSpecializationType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// Whether this template specialization type is a substituted type alias. + LLVM_PREFERRED_TYPE(bool) + unsigned TypeAlias : 1; + + /// The number of template arguments named in this class template + /// specialization, which is expected to be able to hold at least 1024 + /// according to [implimits]. However, as this limit is somewhat easy to + /// hit with template metaprogramming we'd prefer to keep it as large + /// as possible. At the moment it has been left as a non-bitfield since + /// this type safely fits in 64 bits as an unsigned, so there is no reason + /// to introduce the performance impact of a bitfield. + unsigned NumArgs; + }; + + class DependentTemplateSpecializationTypeBitfields { + friend class DependentTemplateSpecializationType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// The number of template arguments named in this class template + /// specialization, which is expected to be able to hold at least 1024 + /// according to [implimits]. However, as this limit is somewhat easy to + /// hit with template metaprogramming we'd prefer to keep it as large + /// as possible. At the moment it has been left as a non-bitfield since + /// this type safely fits in 64 bits as an unsigned, so there is no reason + /// to introduce the performance impact of a bitfield. + unsigned NumArgs; + }; + + class PackExpansionTypeBitfields { + friend class PackExpansionType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + /// The number of expansions that this pack expansion will + /// generate when substituted (+1), which is expected to be able to + /// hold at least 1024 according to [implimits]. However, as this limit + /// is somewhat easy to hit with template metaprogramming we'd prefer to + /// keep it as large as possible. At the moment it has been left as a + /// non-bitfield since this type safely fits in 64 bits as an unsigned, so + /// there is no reason to introduce the performance impact of a bitfield. + /// + /// This field will only have a non-zero value when some of the parameter + /// packs that occur within the pattern have been substituted but others + /// have not. + unsigned NumExpansions; + }; + + enum class PredefinedSugarKind { + /// The "size_t" type. + SizeT, + + /// The signed integer type corresponding to "size_t". + SignedSizeT, + + /// The "ptrdiff_t" type. + PtrdiffT, + + // Indicates how many items the enum has. + Last = PtrdiffT + }; + + class PresefinedSugarTypeBitfields { + friend class PredefinedSugarType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + LLVM_PREFERRED_TYPE(PredefinedSugarKind) + unsigned Kind : 8; + }; + + class CountAttributedTypeBitfields { + friend class CountAttributedType; + + LLVM_PREFERRED_TYPE(TypeBitfields) + unsigned : NumTypeBits; + + static constexpr unsigned NumCoupledDeclsBits = 4; + unsigned NumCoupledDecls : NumCoupledDeclsBits; + LLVM_PREFERRED_TYPE(bool) + unsigned CountInBytes : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned OrNull : 1; + }; + static_assert(sizeof(CountAttributedTypeBitfields) <= sizeof(unsigned)); + + union { + TypeBitfields TypeBits; + ArrayTypeBitfields ArrayTypeBits; + ConstantArrayTypeBitfields ConstantArrayTypeBits; + AttributedTypeBitfields AttributedTypeBits; + AutoTypeBitfields AutoTypeBits; + TypeOfBitfields TypeOfBits; + TypedefBitfields TypedefBits; + UnresolvedUsingBitfields UnresolvedUsingBits; + UsingBitfields UsingBits; + BuiltinTypeBitfields BuiltinTypeBits; + FunctionTypeBitfields FunctionTypeBits; + ObjCObjectTypeBitfields ObjCObjectTypeBits; + ReferenceTypeBitfields ReferenceTypeBits; + KeywordWrapperBitfields KeywordWrapperBits; + TagTypeBitfields TagTypeBits; + VectorTypeBitfields VectorTypeBits; + TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits; + SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits; + SubstPackTypeBitfields SubstPackTypeBits; + TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; + DependentTemplateSpecializationTypeBitfields + DependentTemplateSpecializationTypeBits; + PackExpansionTypeBitfields PackExpansionTypeBits; + CountAttributedTypeBitfields CountAttributedTypeBits; + PresefinedSugarTypeBitfields PredefinedSugarTypeBits; + }; + +private: + template friend class TypePropertyCache; + + /// Set whether this type comes from an AST file. + void setFromAST(bool V = true) const { + TypeBits.FromAST = V; + } + +protected: + friend class ASTContext; + + Type(TypeClass tc, QualType canon, TypeDependence Dependence) + : ExtQualsTypeCommonBase(this, + canon.isNull() ? QualType(this_(), 0) : canon) { + static_assert(sizeof(*this) <= + alignof(decltype(*this)) + sizeof(ExtQualsTypeCommonBase), + "changing bitfields changed sizeof(Type)!"); + static_assert(alignof(decltype(*this)) % TypeAlignment == 0, + "Insufficient alignment!"); + TypeBits.TC = tc; + TypeBits.Dependence = static_cast(Dependence); + TypeBits.CacheValid = false; + TypeBits.CachedLocalOrUnnamed = false; + TypeBits.CachedLinkage = llvm::to_underlying(Linkage::Invalid); + TypeBits.FromAST = false; + } + + // silence VC++ warning C4355: 'this' : used in base member initializer list + Type *this_() { return this; } + + void setDependence(TypeDependence D) { + TypeBits.Dependence = static_cast(D); + } + + void addDependence(TypeDependence D) { setDependence(getDependence() | D); } + +public: + friend class ASTReader; + friend class ASTWriter; + template friend class serialization::AbstractTypeReader; + template friend class serialization::AbstractTypeWriter; + + Type(const Type &) = delete; + Type(Type &&) = delete; + Type &operator=(const Type &) = delete; + Type &operator=(Type &&) = delete; + + TypeClass getTypeClass() const { return static_cast(TypeBits.TC); } + + /// Whether this type comes from an AST file. + bool isFromAST() const { return TypeBits.FromAST; } + + /// Whether this type is or contains an unexpanded parameter + /// pack, used to support C++0x variadic templates. + /// + /// A type that contains a parameter pack shall be expanded by the + /// ellipsis operator at some point. For example, the typedef in the + /// following example contains an unexpanded parameter pack 'T': + /// + /// \code + /// template + /// struct X { + /// typedef T* pointer_types; // ill-formed; T is a parameter pack. + /// }; + /// \endcode + /// + /// Note that this routine does not specify which + bool containsUnexpandedParameterPack() const { + return getDependence() & TypeDependence::UnexpandedPack; + } + + /// Determines if this type would be canonical if it had no further + /// qualification. + bool isCanonicalUnqualified() const { + return CanonicalType == QualType(this, 0); + } + + /// Pull a single level of sugar off of this locally-unqualified type. + /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() + /// or QualType::getSingleStepDesugaredType(const ASTContext&). + QualType getLocallyUnqualifiedSingleStepDesugaredType() const; + + /// As an extension, we classify types as one of "sized" or "sizeless"; + /// every type is one or the other. Standard types are all sized; + /// sizeless types are purely an extension. + /// + /// Sizeless types contain data with no specified size, alignment, + /// or layout. + bool isSizelessType() const; + bool isSizelessBuiltinType() const; + + /// Returns true for all scalable vector types. + bool isSizelessVectorType() const; + + /// Returns true for SVE scalable vector types. + bool isSVESizelessBuiltinType() const; + + /// Returns true for RVV scalable vector types. + bool isRVVSizelessBuiltinType() const; + + /// Check if this is a WebAssembly Externref Type. + bool isWebAssemblyExternrefType() const; + + /// Returns true if this is a WebAssembly table type: either an array of + /// reference types, or a pointer to a reference type (which can only be + /// created by array to pointer decay). + bool isWebAssemblyTableType() const; + + /// Determines if this is a sizeless type supported by the + /// 'arm_sve_vector_bits' type attribute, which can be applied to a single + /// SVE vector or predicate, excluding tuple types such as svint32x4_t. + bool isSveVLSBuiltinType() const; + + /// Returns the representative type for the element of an SVE builtin type. + /// This is used to represent fixed-length SVE vectors created with the + /// 'arm_sve_vector_bits' type attribute as VectorType. + QualType getSveEltType(const ASTContext &Ctx) const; + + /// Determines if this is a sizeless type supported by the + /// 'riscv_rvv_vector_bits' type attribute, which can be applied to a single + /// RVV vector or mask. + bool isRVVVLSBuiltinType() const; + + /// Returns the representative type for the element of an RVV builtin type. + /// This is used to represent fixed-length RVV vectors created with the + /// 'riscv_rvv_vector_bits' type attribute as VectorType. + QualType getRVVEltType(const ASTContext &Ctx) const; + + /// Returns the representative type for the element of a sizeless vector + /// builtin type. + QualType getSizelessVectorEltType(const ASTContext &Ctx) const; + + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): + /// object types, function types, and incomplete types. + + /// Return true if this is an incomplete type. + /// A type that can describe objects, but which lacks information needed to + /// determine its size (e.g. void, or a fwd declared struct). Clients of this + /// routine will need to determine if the size is actually required. + /// + /// Def If non-null, and the type refers to some kind of declaration + /// that can be completed (such as a C struct, C++ class, or Objective-C + /// class), will be set to the declaration. + bool isIncompleteType(NamedDecl **Def = nullptr) const; + + /// Return true if this is an incomplete or object + /// type, in other words, not a function type. + bool isIncompleteOrObjectType() const { + return !isFunctionType(); + } + + /// \returns True if the type is incomplete and it is also a type that + /// cannot be completed by a later type definition. + /// + /// E.g. For `void` this is true but for `struct ForwardDecl;` this is false + /// because a definition for `ForwardDecl` could be provided later on in the + /// translation unit. + /// + /// Note even for types that this function returns true for it is still + /// possible for the declarations that contain this type to later have a + /// complete type in a translation unit. E.g.: + /// + /// \code{.c} + /// // This decl has type 'char[]' which is incomplete and cannot be later + /// // completed by another by another type declaration. + /// extern char foo[]; + /// // This decl now has complete type 'char[5]'. + /// char foo[5]; // foo has a complete type + /// \endcode + bool isAlwaysIncompleteType() const; + + /// Determine whether this type is an object type. + bool isObjectType() const { + // C++ [basic.types]p8: + // An object type is a (possibly cv-qualified) type that is not a + // function type, not a reference type, and not a void type. + return !isReferenceType() && !isFunctionType() && !isVoidType(); + } + + /// Return true if this is a literal type + /// (C++11 [basic.types]p10) + bool isLiteralType(const ASTContext &Ctx) const; + + /// Determine if this type is a structural type, per C++20 [temp.param]p7. + bool isStructuralType() const; + + /// Test if this type is a standard-layout type. + /// (C++0x [basic.type]p9) + bool isStandardLayoutType() const; + + /// Helper methods to distinguish type categories. All type predicates + /// operate on the canonical type, ignoring typedefs and qualifiers. + + /// Returns true if the type is a builtin type. + bool isBuiltinType() const; + + /// Test for a particular builtin type. + bool isSpecificBuiltinType(unsigned K) const; + + /// Test for a type which does not represent an actual type-system type but + /// is instead used as a placeholder for various convenient purposes within + /// Clang. All such types are BuiltinTypes. + bool isPlaceholderType() const; + const BuiltinType *getAsPlaceholderType() const; + + /// Test for a specific placeholder type. + bool isSpecificPlaceholderType(unsigned K) const; + + /// Test for a placeholder type other than Overload; see + /// BuiltinType::isNonOverloadPlaceholderType. + bool isNonOverloadPlaceholderType() const; + + /// isIntegerType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) + bool isEnumeralType() const; + + /// Determine whether this type is a scoped enumeration type. + bool isScopedEnumeralType() const; + bool isBooleanType() const; + bool isCharType() const; + bool isWideCharType() const; + bool isChar8Type() const; + bool isChar16Type() const; + bool isChar32Type() const; + bool isAnyCharacterType() const; + bool isUnicodeCharacterType() const; + bool isIntegralType(const ASTContext &Ctx) const; + + /// Determine whether this type is an integral or enumeration type. + bool isIntegralOrEnumerationType() const; + + /// Determine whether this type is an integral or unscoped enumeration type. + bool isIntegralOrUnscopedEnumerationType() const; + bool isUnscopedEnumerationType() const; + + /// Floating point categories. + bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) + /// isComplexType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isComplexType() const; // C99 6.2.5p11 (complex) + bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. + bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) + bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) + bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 + bool isFloat32Type() const; + bool isDoubleType() const; + bool isBFloat16Type() const; + bool isMFloat8Type() const; + bool isFloat128Type() const; + bool isIbm128Type() const; + bool isRealType() const; // C99 6.2.5p17 (real floating + integer) + bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) + bool isVoidType() const; // C99 6.2.5p19 + bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) + bool isAggregateType() const; + bool isFundamentalType() const; + bool isCompoundType() const; + + // Type Predicates: Check to see if this type is structurally the specified + // type, ignoring typedefs and qualifiers. + bool isFunctionType() const; + bool isFunctionNoProtoType() const { return getAs(); } + bool isFunctionProtoType() const { return getAs(); } + bool isPointerType() const; + bool isPointerOrReferenceType() const; + bool isSignableType(const ASTContext &Ctx) const; + bool isSignablePointerType() const; + bool isSignableIntegerType(const ASTContext &Ctx) const; + bool isAnyPointerType() const; // Any C pointer or ObjC object pointer + bool isCountAttributedType() const; + bool isCFIUncheckedCalleeFunctionType() const; + bool hasPointeeToToCFIUncheckedCalleeFunctionType() const; + bool isBlockPointerType() const; + bool isVoidPointerType() const; + bool isReferenceType() const; + bool isLValueReferenceType() const; + bool isRValueReferenceType() const; + bool isObjectPointerType() const; + bool isFunctionPointerType() const; + bool isFunctionReferenceType() const; + bool isMemberPointerType() const; + bool isMemberFunctionPointerType() const; + bool isMemberDataPointerType() const; + bool isArrayType() const; + bool isConstantArrayType() const; + bool isIncompleteArrayType() const; + bool isVariableArrayType() const; + bool isArrayParameterType() const; + bool isDependentSizedArrayType() const; + bool isRecordType() const; + bool isClassType() const; + bool isStructureType() const; + bool isStructureTypeWithFlexibleArrayMember() const; + bool isObjCBoxableRecordType() const; + bool isInterfaceType() const; + bool isStructureOrClassType() const; + bool isUnionType() const; + bool isComplexIntegerType() const; // GCC _Complex integer type. + bool isVectorType() const; // GCC vector type. + bool isExtVectorType() const; // Extended vector type. + bool isExtVectorBoolType() const; // Extended vector type with bool element. + // Extended vector type with bool element that is packed. HLSL doesn't pack + // its bool vectors. + bool isPackedVectorBoolType(const ASTContext &ctx) const; + bool isSubscriptableVectorType() const; + bool isMatrixType() const; // Matrix type. + bool isConstantMatrixType() const; // Constant matrix type. + bool isDependentAddressSpaceType() const; // value-dependent address space qualifier + bool isObjCObjectPointerType() const; // pointer to ObjC object + bool isObjCRetainableType() const; // ObjC object or block pointer + bool isObjCLifetimeType() const; // (array of)* retainable type + bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type + bool isObjCNSObjectType() const; // __attribute__((NSObject)) + bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class)) + // FIXME: change this to 'raw' interface type, so we can used 'interface' type + // for the common case. + bool isObjCObjectType() const; // NSString or typeof(*(id)0) + bool isObjCQualifiedInterfaceType() const; // NSString + bool isObjCQualifiedIdType() const; // id + bool isObjCQualifiedClassType() const; // Class + bool isObjCObjectOrInterfaceType() const; + bool isObjCIdType() const; // id + bool isDecltypeType() const; + /// Was this type written with the special inert-in-ARC __unsafe_unretained + /// qualifier? + /// + /// This approximates the answer to the following question: if this + /// translation unit were compiled in ARC, would this type be qualified + /// with __unsafe_unretained? + bool isObjCInertUnsafeUnretainedType() const { + return hasAttr(attr::ObjCInertUnsafeUnretained); + } + + /// Whether the type is Objective-C 'id' or a __kindof type of an + /// object type, e.g., __kindof NSView * or __kindof id + /// . + /// + /// \param bound Will be set to the bound on non-id subtype types, + /// which will be (possibly specialized) Objective-C class type, or + /// null for 'id. + bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, + const ObjCObjectType *&bound) const; + + bool isObjCClassType() const; // Class + + /// Whether the type is Objective-C 'Class' or a __kindof type of an + /// Class type, e.g., __kindof Class . + /// + /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound + /// here because Objective-C's type system cannot express "a class + /// object for a subclass of NSFoo". + bool isObjCClassOrClassKindOfType() const; + + bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; + bool isObjCSelType() const; // Class + bool isObjCBuiltinType() const; // 'id' or 'Class' + bool isObjCARCBridgableType() const; + bool isCARCBridgableType() const; + bool isTemplateTypeParmType() const; // C++ template type parameter + bool isNullPtrType() const; // C++11 std::nullptr_t or + // C23 nullptr_t + bool isNothrowT() const; // C++ std::nothrow_t + bool isAlignValT() const; // C++17 std::align_val_t + bool isStdByteType() const; // C++17 std::byte + bool isAtomicType() const; // C11 _Atomic() + bool isUndeducedAutoType() const; // C++11 auto or + // C++14 decltype(auto) + bool isTypedefNameType() const; // typedef or alias template + +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + bool is##Id##Type() const; +#include "clang/Basic/OpenCLImageTypes.def" + + bool isImageType() const; // Any OpenCL image type + + bool isSamplerT() const; // OpenCL sampler_t + bool isEventT() const; // OpenCL event_t + bool isClkEventT() const; // OpenCL clk_event_t + bool isQueueT() const; // OpenCL queue_t + bool isReserveIDT() const; // OpenCL reserve_id_t + +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + bool is##Id##Type() const; +#include "clang/Basic/OpenCLExtensionTypes.def" + // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension + bool isOCLIntelSubgroupAVCType() const; + bool isOCLExtOpaqueType() const; // Any OpenCL extension type + + bool isPipeType() const; // OpenCL pipe type + bool isBitIntType() const; // Bit-precise integer type + bool isOpenCLSpecificType() const; // Any OpenCL specific type + +#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const; +#include "clang/Basic/HLSLIntangibleTypes.def" + bool isHLSLSpecificType() const; // Any HLSL specific type + bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type + bool isHLSLAttributedResourceType() const; + bool isHLSLInlineSpirvType() const; + bool isHLSLResourceRecord() const; + bool isHLSLResourceRecordArray() const; + bool isHLSLIntangibleType() + const; // Any HLSL intangible type (builtin, array, class) + + /// Determines if this type, which must satisfy + /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather + /// than implicitly __strong. + bool isObjCARCImplicitlyUnretainedType() const; + + /// Check if the type is the CUDA device builtin surface type. + bool isCUDADeviceBuiltinSurfaceType() const; + /// Check if the type is the CUDA device builtin texture type. + bool isCUDADeviceBuiltinTextureType() const; + + /// Return the implicit lifetime for this type, which must not be dependent. + Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; + + enum ScalarTypeKind { + STK_CPointer, + STK_BlockPointer, + STK_ObjCObjectPointer, + STK_MemberPointer, + STK_Bool, + STK_Integral, + STK_Floating, + STK_IntegralComplex, + STK_FloatingComplex, + STK_FixedPoint + }; + + /// Given that this is a scalar type, classify it. + ScalarTypeKind getScalarTypeKind() const; + + TypeDependence getDependence() const { + return static_cast(TypeBits.Dependence); + } + + /// Whether this type is an error type. + bool containsErrors() const { + return getDependence() & TypeDependence::Error; + } + + /// Whether this type is a dependent type, meaning that its definition + /// somehow depends on a template parameter (C++ [temp.dep.type]). + bool isDependentType() const { + return getDependence() & TypeDependence::Dependent; + } + + /// Determine whether this type is an instantiation-dependent type, + /// meaning that the type involves a template parameter (even if the + /// definition does not actually depend on the type substituted for that + /// template parameter). + bool isInstantiationDependentType() const { + return getDependence() & TypeDependence::Instantiation; + } + + /// Determine whether this type is an undeduced type, meaning that + /// it somehow involves a C++11 'auto' type or similar which has not yet been + /// deduced. + bool isUndeducedType() const; + + /// Whether this type is a variably-modified type (C99 6.7.5). + bool isVariablyModifiedType() const { + return getDependence() & TypeDependence::VariablyModified; + } + + /// Whether this type involves a variable-length array type + /// with a definite size. + bool hasSizedVLAType() const; + + /// Whether this type is or contains a local or unnamed type. + bool hasUnnamedOrLocalType() const; + + bool isOverloadableType() const; + + /// Determine wither this type is a C++ elaborated-type-specifier. + bool isElaboratedTypeSpecifier() const; + + bool canDecayToPointerType() const; + + /// Whether this type is represented natively as a pointer. This includes + /// pointers, references, block pointers, and Objective-C interface, + /// qualified id, and qualified interface types, as well as nullptr_t. + bool hasPointerRepresentation() const; + + /// Whether this type can represent an objective pointer type for the + /// purpose of GC'ability + bool hasObjCPointerRepresentation() const; + + /// Determine whether this type has an integer representation + /// of some sort, e.g., it is an integer type or a vector. + bool hasIntegerRepresentation() const; + + /// Determine whether this type has an signed integer representation + /// of some sort, e.g., it is an signed integer type or a vector. + bool hasSignedIntegerRepresentation() const; + + /// Determine whether this type has an unsigned integer representation + /// of some sort, e.g., it is an unsigned integer type or a vector. + bool hasUnsignedIntegerRepresentation() const; + + /// Determine whether this type has a floating-point representation + /// of some sort, e.g., it is a floating-point type or a vector thereof. + bool hasFloatingRepresentation() const; + + /// Determine whether this type has a boolean representation -- i.e., it is a + /// boolean type, an enum type whose underlying type is a boolean type, or a + /// vector of booleans. + bool hasBooleanRepresentation() const; + + // Type Checking Functions: Check to see if this type is structurally the + // specified type, ignoring typedefs and qualifiers, and return a pointer to + // the best type we can. + const RecordType *getAsStructureType() const; + /// NOTE: getAs*ArrayType are methods on ASTContext. + const RecordType *getAsUnionType() const; + const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. + const ObjCObjectType *getAsObjCInterfaceType() const; + + // The following is a convenience method that returns an ObjCObjectPointerType + // for object declared using an interface. + const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; + const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; + const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; + const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; + + /// Retrieves the CXXRecordDecl that this type refers to, either + /// because the type is a RecordType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + inline CXXRecordDecl *getAsCXXRecordDecl() const; + inline CXXRecordDecl *castAsCXXRecordDecl() const; + + /// Retrieves the RecordDecl this type refers to. + inline RecordDecl *getAsRecordDecl() const; + inline RecordDecl *castAsRecordDecl() const; + + /// Retrieves the EnumDecl this type refers to. + inline EnumDecl *getAsEnumDecl() const; + inline EnumDecl *castAsEnumDecl() const; + + /// Retrieves the TagDecl that this type refers to, either + /// because the type is a TagType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + inline TagDecl *getAsTagDecl() const; + inline TagDecl *castAsTagDecl() const; + + /// If this is a pointer or reference to a RecordType, return the + /// CXXRecordDecl that the type refers to. + /// + /// If this is not a pointer or reference, or the type being pointed to does + /// not refer to a CXXRecordDecl, returns NULL. + const CXXRecordDecl *getPointeeCXXRecordDecl() const; + + /// Get the DeducedType whose type will be deduced for a variable with + /// an initializer of this type. This looks through declarators like pointer + /// types, but not through decltype or typedefs. + DeducedType *getContainedDeducedType() const; + + /// Get the AutoType whose type will be deduced for a variable with + /// an initializer of this type. This looks through declarators like pointer + /// types, but not through decltype or typedefs. + AutoType *getContainedAutoType() const { + return dyn_cast_or_null(getContainedDeducedType()); + } + + /// Determine whether this type was written with a leading 'auto' + /// corresponding to a trailing return type (possibly for a nested + /// function type within a pointer to function type or similar). + bool hasAutoForTrailingReturnType() const; + + /// Member-template getAs'. Look through sugar for + /// an instance of \. This scheme will eventually + /// replace the specific getAsXXXX methods above. + /// + /// 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 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 const T *getAsCanonical() const { + return dyn_cast(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 const T *castAsCanonical() const { + return cast(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 + /// name for a class template specialization. + const TemplateSpecializationType * + getAsNonAliasTemplateSpecializationType() const; + + const TemplateSpecializationType * + castAsNonAliasTemplateSpecializationType() const { + const auto *TST = getAsNonAliasTemplateSpecializationType(); + assert(TST && "not a TemplateSpecializationType"); + return TST; + } + + /// Member-template getAsAdjusted. Look through specific kinds + /// of sugar (parens, attributes, etc) for an instance of \. + /// This is used when you need to walk over sugar nodes that represent some + /// kind of type adjustment from a type that was written as a \ + /// to another type that is still canonically a \. + template const T *getAsAdjusted() const; + + /// A variant of getAs<> for array types which silently discards + /// qualifiers from the outermost type. + const ArrayType *getAsArrayTypeUnsafe() const; + + /// Member-template castAs. Look through sugar for + /// the underlying instance of \. + /// + /// This method has the same relationship to getAs as cast has + /// to dyn_cast; which is to say, the underlying type *must* + /// have the intended type, and this method will never return null. + template const T *castAs() const; + + /// A variant of castAs<> for array type which silently discards + /// qualifiers from the outermost type. + const ArrayType *castAsArrayTypeUnsafe() const; + + /// If this type represents a qualified-id, this returns its nested name + /// specifier. For example, for the qualified-id "foo::bar::baz", this returns + /// "foo::bar". Returns null if this type represents an unqualified-id. + NestedNameSpecifier getPrefix() const; + + /// Determine whether this type had the specified attribute applied to it + /// (looking through top-level type sugar). + bool hasAttr(attr::Kind AK) const; + + /// Get the base element type of this type, potentially discarding type + /// qualifiers. This should never be used when type qualifiers + /// are meaningful. + const Type *getBaseElementTypeUnsafe() const; + + /// If this is an array type, return the element type of the array, + /// potentially with type qualifiers missing. + /// This should never be used when type qualifiers are meaningful. + const Type *getArrayElementTypeNoTypeQual() const; + + /// If this is a pointer type, return the pointee type. + /// If this is an array type, return the array element type. + /// This should never be used when type qualifiers are meaningful. + const Type *getPointeeOrArrayElementType() const; + + /// If this is a pointer, ObjC object pointer, or block + /// pointer, this returns the respective pointee. + QualType getPointeeType() const; + + /// Return the specified type with any "sugar" removed from the type, + /// removing any typedefs, typeofs, etc., as well as any qualifiers. + const Type *getUnqualifiedDesugaredType() const; + + /// Return true if this is an integer type that is + /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], + /// or an enum decl which has a signed representation. + bool isSignedIntegerType() const; + + /// Return true if this is an integer type that is + /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], + /// or an enum decl which has an unsigned representation. + bool isUnsignedIntegerType() const; + + /// Determines whether this is an integer type that is signed or an + /// enumeration types whose underlying type is a signed integer type. + bool isSignedIntegerOrEnumerationType() const; + + /// Determines whether this is an integer type that is unsigned or an + /// enumeration types whose underlying type is a unsigned integer type. + bool isUnsignedIntegerOrEnumerationType() const; + + /// Return true if this is a fixed point type according to + /// ISO/IEC JTC1 SC22 WG14 N1169. + bool isFixedPointType() const; + + /// Return true if this is a fixed point or integer type. + bool isFixedPointOrIntegerType() const; + + /// Return true if this can be converted to (or from) a fixed point type. + bool isConvertibleToFixedPointType() const; + + /// Return true if this is a saturated fixed point type according to + /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. + bool isSaturatedFixedPointType() const; + + /// Return true if this is a saturated fixed point type according to + /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. + bool isUnsaturatedFixedPointType() const; + + /// Return true if this is a fixed point type that is signed according + /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. + bool isSignedFixedPointType() const; + + /// Return true if this is a fixed point type that is unsigned according + /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. + bool isUnsignedFixedPointType() const; + + /// Return true if this is not a variable sized type, + /// according to the rules of C99 6.7.5p3. It is not legal to call this on + /// incomplete types. + bool isConstantSizeType() const; + + /// Returns true if this type can be represented by some + /// set of type specifiers. + bool isSpecifierType() const; + + /// Determine the linkage of this type. + Linkage getLinkage() const; + + /// Determine the visibility of this type. + Visibility getVisibility() const { + return getLinkageAndVisibility().getVisibility(); + } + + /// Return true if the visibility was explicitly set is the code. + bool isVisibilityExplicit() const { + return getLinkageAndVisibility().isVisibilityExplicit(); + } + + /// Determine the linkage and visibility of this type. + LinkageInfo getLinkageAndVisibility() const; + + /// True if the computed linkage is valid. Used for consistency + /// checking. Should always return true. + bool isLinkageValid() const; + + /// Determine the nullability of the given type. + /// + /// Note that nullability is only captured as sugar within the type + /// system, not as part of the canonical type, so nullability will + /// be lost by canonicalization and desugaring. + std::optional getNullability() const; + + /// Determine whether the given type can have a nullability + /// specifier applied to it, i.e., if it is any kind of pointer type. + /// + /// \param ResultIfUnknown The value to return if we don't yet know whether + /// this type can have nullability because it is dependent. + bool canHaveNullability(bool ResultIfUnknown = true) const; + + /// Retrieve the set of substitutions required when accessing a member + /// of the Objective-C receiver type that is declared in the given context. + /// + /// \c *this is the type of the object we're operating on, e.g., the + /// receiver for a message send or the base of a property access, and is + /// expected to be of some object or object pointer type. + /// + /// \param dc The declaration context for which we are building up a + /// substitution mapping, which should be an Objective-C class, extension, + /// category, or method within. + /// + /// \returns an array of type arguments that can be substituted for + /// the type parameters of the given declaration context in any type described + /// within that context, or an empty optional to indicate that no + /// substitution is required. + std::optional> + getObjCSubstitutions(const DeclContext *dc) const; + + /// Determines if this is an ObjC interface type that may accept type + /// parameters. + bool acceptsObjCTypeParams() const; + + const char *getTypeClassName() const; + + QualType getCanonicalTypeInternal() const { + return CanonicalType; + } + + CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h + void dump() const; + void dump(llvm::raw_ostream &OS, const ASTContext &Context) const; +}; + +/// This will check for a TypedefType by removing any existing sugar +/// until it reaches a TypedefType or a non-sugared type. +template <> const TypedefType *Type::getAs() const; +template <> const UsingType *Type::getAs() const; + +/// This will check for a TemplateSpecializationType by removing any +/// existing sugar until it reaches a TemplateSpecializationType or a +/// non-sugared type. +template <> const TemplateSpecializationType *Type::getAs() const; + +/// This will check for an AttributedType by removing any existing sugar +/// until it reaches an AttributedType or a non-sugared type. +template <> const AttributedType *Type::getAs() const; + +/// This will check for a BoundsAttributedType by removing any existing +/// sugar until it reaches an BoundsAttributedType or a non-sugared type. +template <> const BoundsAttributedType *Type::getAs() const; + +/// This will check for a CountAttributedType by removing any existing +/// sugar until it reaches an CountAttributedType or a non-sugared type. +template <> const CountAttributedType *Type::getAs() const; + +// We can do always canonical types faster, because we don't have to +// worry about preserving decoration. +#define TYPE(Class, Base) +#define ALWAYS_CANONICAL_TYPE(Class) \ + template <> inline const Class##Type *Type::getAs() const { \ + return dyn_cast(CanonicalType); \ + } \ + template <> inline const Class##Type *Type::castAs() const { \ + return cast(CanonicalType); \ + } +#include "clang/AST/TypeNodes.inc" + +/// This class is used for builtin types like 'int'. Builtin +/// types are always canonical and have a literal name field. +class BuiltinType : public Type { +public: + enum Kind { +// OpenCL image types +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id, +#include "clang/Basic/OpenCLImageTypes.def" +// OpenCL extension types +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id, +#include "clang/Basic/OpenCLExtensionTypes.def" +// SVE Types +#define SVE_TYPE(Name, Id, SingletonId) Id, +#include "clang/Basic/AArch64ACLETypes.def" +// PPC MMA Types +#define PPC_VECTOR_TYPE(Name, Id, Size) Id, +#include "clang/Basic/PPCTypes.def" +// RVV Types +#define RVV_TYPE(Name, Id, SingletonId) Id, +#include "clang/Basic/RISCVVTypes.def" +// WebAssembly reference types +#define WASM_TYPE(Name, Id, SingletonId) Id, +#include "clang/Basic/WebAssemblyReferenceTypes.def" +// AMDGPU types +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) Id, +#include "clang/Basic/AMDGPUTypes.def" +// HLSL intangible Types +#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) Id, +#include "clang/Basic/HLSLIntangibleTypes.def" +// All other builtin types +#define BUILTIN_TYPE(Id, SingletonId) Id, +#define LAST_BUILTIN_TYPE(Id) LastKind = Id +#include "clang/AST/BuiltinTypes.def" + }; + +private: + friend class ASTContext; // ASTContext creates these. + + BuiltinType(Kind K) + : Type(Builtin, QualType(), + K == Dependent ? TypeDependence::DependentInstantiation + : TypeDependence::None) { + static_assert(Kind::LastKind < + (1 << BuiltinTypeBitfields::NumOfBuiltinTypeBits) && + "Defined builtin type exceeds the allocated space for serial " + "numbering"); + BuiltinTypeBits.Kind = K; + } + +public: + Kind getKind() const { return static_cast(BuiltinTypeBits.Kind); } + StringRef getName(const PrintingPolicy &Policy) const; + + const char *getNameAsCString(const PrintingPolicy &Policy) const { + // The StringRef is null-terminated. + StringRef str = getName(Policy); + assert(!str.empty() && str.data()[str.size()] == '\0'); + return str.data(); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + bool isInteger() const { + return getKind() >= Bool && getKind() <= Int128; + } + + bool isSignedInteger() const { + return getKind() >= Char_S && getKind() <= Int128; + } + + bool isUnsignedInteger() const { + return getKind() >= Bool && getKind() <= UInt128; + } + + bool isFloatingPoint() const { + return getKind() >= Half && getKind() <= Ibm128; + } + + bool isSVEBool() const { return getKind() == Kind::SveBool; } + + bool isSVECount() const { return getKind() == Kind::SveCount; } + + /// Determines whether the given kind corresponds to a placeholder type. + static bool isPlaceholderTypeKind(Kind K) { + return K >= Overload; + } + + /// Determines whether this type is a placeholder type, i.e. a type + /// which cannot appear in arbitrary positions in a fully-formed + /// expression. + bool isPlaceholderType() const { + return isPlaceholderTypeKind(getKind()); + } + + /// Determines whether this type is a placeholder type other than + /// Overload. Most placeholder types require only syntactic + /// information about their context in order to be resolved (e.g. + /// whether it is a call expression), which means they can (and + /// should) be resolved in an earlier "phase" of analysis. + /// Overload expressions sometimes pick up further information + /// from their context, like whether the context expects a + /// specific function-pointer type, and so frequently need + /// special treatment. + bool isNonOverloadPlaceholderType() const { + return getKind() > Overload; + } + + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } +}; + +/// Complex values, per C99 6.2.5p11. This supports the C99 complex +/// types (_Complex float etc) as well as the GCC integer complex extensions. +class ComplexType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType ElementType; + + ComplexType(QualType Element, QualType CanonicalPtr) + : Type(Complex, CanonicalPtr, Element->getDependence()), + ElementType(Element) {} + +public: + QualType getElementType() const { return ElementType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { + ID.AddPointer(Element.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Complex; } +}; + +/// Sugar for parentheses used when specifying types. +class ParenType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType Inner; + + ParenType(QualType InnerType, QualType CanonType) + : Type(Paren, CanonType, InnerType->getDependence()), Inner(InnerType) {} + +public: + QualType getInnerType() const { return Inner; } + + bool isSugared() const { return true; } + QualType desugar() const { return getInnerType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getInnerType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { + Inner.Profile(ID); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Paren; } +}; + +/// PointerType - C99 6.7.5.1 - Pointer Declarators. +class PointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType PointeeType; + + PointerType(QualType Pointee, QualType CanonicalPtr) + : Type(Pointer, CanonicalPtr, Pointee->getDependence()), + PointeeType(Pointee) {} + +public: + QualType getPointeeType() const { return PointeeType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } +}; + +/// [BoundsSafety] Represents information of declarations referenced by the +/// arguments of the `counted_by` attribute and the likes. +class TypeCoupledDeclRefInfo { +public: + using BaseTy = llvm::PointerIntPair; + +private: + enum { + DerefShift = 0, + DerefMask = 1, + }; + BaseTy Data; + +public: + /// \p D is to a declaration referenced by the argument of attribute. \p Deref + /// indicates whether \p D is referenced as a dereferenced form, e.g., \p + /// Deref is true for `*n` in `int *__counted_by(*n)`. + TypeCoupledDeclRefInfo(ValueDecl *D = nullptr, bool Deref = false); + + bool isDeref() const; + ValueDecl *getDecl() const; + unsigned getInt() const; + void *getOpaqueValue() const; + bool operator==(const TypeCoupledDeclRefInfo &Other) const; + void setFromOpaqueValue(void *V); +}; + +/// [BoundsSafety] Represents a parent type class for CountAttributedType and +/// similar sugar types that will be introduced to represent a type with a +/// bounds attribute. +/// +/// Provides a common interface to navigate declarations referred to by the +/// bounds expression. + +class BoundsAttributedType : public Type, public llvm::FoldingSetNode { + QualType WrappedTy; + +protected: + ArrayRef Decls; // stored in trailing objects + + BoundsAttributedType(TypeClass TC, QualType Wrapped, QualType Canon); + +public: + bool isSugared() const { return true; } + QualType desugar() const { return WrappedTy; } + + using decl_iterator = const TypeCoupledDeclRefInfo *; + using decl_range = llvm::iterator_range; + + decl_iterator dependent_decl_begin() const { return Decls.begin(); } + decl_iterator dependent_decl_end() const { return Decls.end(); } + + unsigned getNumCoupledDecls() const { return Decls.size(); } + + decl_range dependent_decls() const { + return decl_range(dependent_decl_begin(), dependent_decl_end()); + } + + ArrayRef getCoupledDecls() const { + return {dependent_decl_begin(), dependent_decl_end()}; + } + + bool referencesFieldDecls() const; + + static bool classof(const Type *T) { + // Currently, only `class CountAttributedType` inherits + // `BoundsAttributedType` but the subclass will grow as we add more bounds + // annotations. + switch (T->getTypeClass()) { + case CountAttributed: + return true; + default: + return false; + } + } +}; + +/// Represents a sugar type with `__counted_by` or `__sized_by` annotations, +/// including their `_or_null` variants. +class CountAttributedType final + : public BoundsAttributedType, + public llvm::TrailingObjects { + friend class ASTContext; + + Expr *CountExpr; + /// \p CountExpr represents the argument of __counted_by or the likes. \p + /// CountInBytes indicates that \p CountExpr is a byte count (i.e., + /// __sized_by(_or_null)) \p OrNull means it's an or_null variant (i.e., + /// __counted_by_or_null or __sized_by_or_null) \p CoupledDecls contains the + /// list of declarations referenced by \p CountExpr, which the type depends on + /// for the bounds information. + CountAttributedType(QualType Wrapped, QualType Canon, Expr *CountExpr, + bool CountInBytes, bool OrNull, + ArrayRef CoupledDecls); + + unsigned numTrailingObjects(OverloadToken) const { + return CountAttributedTypeBits.NumCoupledDecls; + } + +public: + enum DynamicCountPointerKind { + CountedBy = 0, + SizedBy, + CountedByOrNull, + SizedByOrNull, + }; + + Expr *getCountExpr() const { return CountExpr; } + bool isCountInBytes() const { return CountAttributedTypeBits.CountInBytes; } + bool isOrNull() const { return CountAttributedTypeBits.OrNull; } + + DynamicCountPointerKind getKind() const { + if (isOrNull()) + return isCountInBytes() ? SizedByOrNull : CountedByOrNull; + return isCountInBytes() ? SizedBy : CountedBy; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, desugar(), CountExpr, isCountInBytes(), isOrNull()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType WrappedTy, + Expr *CountExpr, bool CountInBytes, bool Nullable); + + static bool classof(const Type *T) { + return T->getTypeClass() == CountAttributed; + } + + StringRef getAttributeName(bool WithMacroPrefix) const; +}; + +/// Represents a type which was implicitly adjusted by the semantic +/// engine for arbitrary reasons. For example, array and function types can +/// decay, and function types can have their calling conventions adjusted. +class AdjustedType : public Type, public llvm::FoldingSetNode { + QualType OriginalTy; + QualType AdjustedTy; + +protected: + friend class ASTContext; // ASTContext creates these. + + AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, + QualType CanonicalPtr) + : Type(TC, CanonicalPtr, OriginalTy->getDependence()), + OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} + +public: + QualType getOriginalType() const { return OriginalTy; } + QualType getAdjustedType() const { return AdjustedTy; } + + bool isSugared() const { return true; } + QualType desugar() const { return AdjustedTy; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, OriginalTy, AdjustedTy); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { + ID.AddPointer(Orig.getAsOpaquePtr()); + ID.AddPointer(New.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed; + } +}; + +/// Represents a pointer type decayed from an array or function type. +class DecayedType : public AdjustedType { + friend class ASTContext; // ASTContext creates these. + + inline + DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); + +public: + QualType getDecayedType() const { return getAdjustedType(); } + + inline QualType getPointeeType() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } +}; + +/// Pointer to a block type. +/// This type is to represent types syntactically represented as +/// "void (^)(int)", etc. Pointee is required to always be a function type. +class BlockPointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + // Block is some kind of pointer type + QualType PointeeType; + + BlockPointerType(QualType Pointee, QualType CanonicalCls) + : Type(BlockPointer, CanonicalCls, Pointee->getDependence()), + PointeeType(Pointee) {} + +public: + // Get the pointee type. Pointee is required to always be a function type. + QualType getPointeeType() const { return PointeeType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == BlockPointer; + } +}; + +/// Base for LValueReferenceType and RValueReferenceType +class ReferenceType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + +protected: + ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) + : Type(tc, CanonicalRef, Referencee->getDependence()), + PointeeType(Referencee) { + ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; + ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); + } + +public: + bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } + bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } + + QualType getPointeeTypeAsWritten() const { return PointeeType; } + + QualType getPointeeType() const { + // FIXME: this might strip inner qualifiers; okay? + const ReferenceType *T = this; + while (T->isInnerRef()) + T = T->PointeeType->castAs(); + return T->PointeeType; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, PointeeType, isSpelledAsLValue()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Referencee, + bool SpelledAsLValue) { + ID.AddPointer(Referencee.getAsOpaquePtr()); + ID.AddBoolean(SpelledAsLValue); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference || + T->getTypeClass() == RValueReference; + } +}; + +/// An lvalue reference type, per C++11 [dcl.ref]. +class LValueReferenceType : public ReferenceType { + friend class ASTContext; // ASTContext creates these + + LValueReferenceType(QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) + : ReferenceType(LValueReference, Referencee, CanonicalRef, + SpelledAsLValue) {} + +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference; + } +}; + +/// An rvalue reference type, per C++11 [dcl.ref]. +class RValueReferenceType : public ReferenceType { + friend class ASTContext; // ASTContext creates these + + RValueReferenceType(QualType Referencee, QualType CanonicalRef) + : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {} + +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == RValueReference; + } +}; + +/// A pointer to member type per C++ 8.3.3 - Pointers to members. +/// +/// This includes both pointers to data members and pointer to member functions. +class MemberPointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType PointeeType; + + /// The class of which the pointee is a member. Must ultimately be a + /// CXXRecordType, but could be a typedef or a template parameter too. + NestedNameSpecifier Qualifier; + + MemberPointerType(QualType Pointee, NestedNameSpecifier Qualifier, + QualType CanonicalPtr) + : Type(MemberPointer, CanonicalPtr, + (toTypeDependence(Qualifier.getDependence()) & + ~TypeDependence::VariablyModified) | + Pointee->getDependence()), + PointeeType(Pointee), Qualifier(Qualifier) {} + +public: + QualType getPointeeType() const { return PointeeType; } + + /// Returns true if the member type (i.e. the pointee type) is a + /// function type rather than a data-member type. + bool isMemberFunctionPointer() const { + return PointeeType->isFunctionProtoType(); + } + + /// Returns true if the member type (i.e. the pointee type) is a + /// data type rather than a function type. + bool isMemberDataPointer() const { + return !PointeeType->isFunctionProtoType(); + } + + NestedNameSpecifier getQualifier() const { return Qualifier; } + /// Note: this can trigger extra deserialization when external AST sources are + /// used. Prefer `getCXXRecordDecl()` unless you really need the most recent + /// decl. + CXXRecordDecl *getMostRecentCXXRecordDecl() const; + + bool isSugared() const; + QualType desugar() const { + return isSugared() ? getCanonicalTypeInternal() : QualType(this, 0); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + // FIXME: `getMostRecentCXXRecordDecl()` should be possible to use here, + // however when external AST sources are used it causes nondeterminism + // issues (see https://github.com/llvm/llvm-project/pull/137910). + Profile(ID, getPointeeType(), getQualifier(), getCXXRecordDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, + const NestedNameSpecifier Qualifier, + const CXXRecordDecl *Cls); + + static bool classof(const Type *T) { + return T->getTypeClass() == MemberPointer; + } + +private: + CXXRecordDecl *getCXXRecordDecl() const; +}; + +/// Capture whether this is a normal array (e.g. int X[4]) +/// an array with a static size (e.g. int X[static 4]), or an array +/// with a star size (e.g. int X[*]). +/// 'static' is only allowed on function parameters. +enum class ArraySizeModifier { Normal, Static, Star }; + +/// Represents an array type, per C99 6.7.5.2 - Array Declarators. +class ArrayType : public Type, public llvm::FoldingSetNode { +private: + /// The element type of the array. + QualType ElementType; + +protected: + friend class ASTContext; // ASTContext creates these. + + ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, + unsigned tq, const Expr *sz = nullptr); + +public: + QualType getElementType() const { return ElementType; } + + ArraySizeModifier getSizeModifier() const { + return ArraySizeModifier(ArrayTypeBits.SizeModifier); + } + + Qualifiers getIndexTypeQualifiers() const { + return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); + } + + unsigned getIndexTypeCVRQualifiers() const { + return ArrayTypeBits.IndexTypeQuals; + } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == VariableArray || + T->getTypeClass() == IncompleteArray || + T->getTypeClass() == DependentSizedArray || + T->getTypeClass() == ArrayParameter; + } +}; + +/// Represents the canonical version of C arrays with a specified constant size. +/// For example, the canonical type for 'int A[4 + 4*100]' is a +/// ConstantArrayType where the element type is 'int' and the size is 404. +class ConstantArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. + + struct ExternalSize { + ExternalSize(const llvm::APInt &Sz, const Expr *SE) + : Size(Sz), SizeExpr(SE) {} + llvm::APInt Size; // Allows us to unique the type. + const Expr *SizeExpr; + }; + + union { + uint64_t Size; + ExternalSize *SizePtr; + }; + + ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz, + ArraySizeModifier SM, unsigned TQ) + : ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) { + ConstantArrayTypeBits.HasExternalSize = false; + ConstantArrayTypeBits.SizeWidth = Width / 8; + // The in-structure size stores the size in bytes rather than bits so we + // drop the three least significant bits since they're always zero anyways. + assert(Width < 0xFF && "Type width in bits must be less than 8 bits"); + } + + ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr, + ArraySizeModifier SM, unsigned TQ) + : ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr), + SizePtr(SzPtr) { + ConstantArrayTypeBits.HasExternalSize = true; + ConstantArrayTypeBits.SizeWidth = 0; + + assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) && + "canonical constant array should not have size expression"); + } + + static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET, + QualType Can, const llvm::APInt &Sz, + const Expr *SzExpr, ArraySizeModifier SzMod, + unsigned Qual); + +protected: + ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can) + : ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(), + ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) { + ConstantArrayTypeBits.HasExternalSize = + ATy->ConstantArrayTypeBits.HasExternalSize; + if (!ConstantArrayTypeBits.HasExternalSize) { + ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth; + Size = ATy->Size; + } else + SizePtr = ATy->SizePtr; + } + +public: + /// Return the constant array size as an APInt. + llvm::APInt getSize() const { + return ConstantArrayTypeBits.HasExternalSize + ? SizePtr->Size + : llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size); + } + + /// Return the bit width of the size type. + unsigned getSizeBitWidth() const { + return ConstantArrayTypeBits.HasExternalSize + ? SizePtr->Size.getBitWidth() + : static_cast(ConstantArrayTypeBits.SizeWidth * 8); + } + + /// Return true if the size is zero. + bool isZeroSize() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero() + : 0 == Size; + } + + /// Return the size zero-extended as a uint64_t. + uint64_t getZExtSize() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue() + : Size; + } + + /// Return the size sign-extended as a uint64_t. + int64_t getSExtSize() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue() + : static_cast(Size); + } + + /// Return the size zero-extended to uint64_t or UINT64_MAX if the value is + /// larger than UINT64_MAX. + uint64_t getLimitedSize() const { + return ConstantArrayTypeBits.HasExternalSize + ? SizePtr->Size.getLimitedValue() + : Size; + } + + /// Return a pointer to the size expression. + const Expr *getSizeExpr() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + /// Determine the number of bits required to address a member of + // an array with the given element type and number of elements. + static unsigned getNumAddressingBits(const ASTContext &Context, + QualType ElementType, + const llvm::APInt &NumElements); + + unsigned getNumAddressingBits(const ASTContext &Context) const; + + /// Determine the maximum number of active bits that an array's size + /// can require, which limits the maximum size of the array. + static unsigned getMaxSizeBits(const ASTContext &Context); + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { + Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(), + getSizeModifier(), getIndexTypeCVRQualifiers()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, + QualType ET, uint64_t ArraySize, const Expr *SizeExpr, + ArraySizeModifier SizeMod, unsigned TypeQuals); + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == ArrayParameter; + } +}; + +/// Represents a constant array type that does not decay to a pointer when used +/// as a function parameter. +class ArrayParameterType : public ConstantArrayType { + friend class ASTContext; // ASTContext creates these. + + ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy) + : ConstantArrayType(ArrayParameter, ATy, CanTy) {} + +public: + static bool classof(const Type *T) { + return T->getTypeClass() == ArrayParameter; + } + + QualType getConstantArrayType(const ASTContext &Ctx) const; +}; + +/// Represents a C array with an unspecified size. For example 'int A[]' has +/// an IncompleteArrayType where the element type is 'int' and the size is +/// unspecified. +class IncompleteArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. + + IncompleteArrayType(QualType et, QualType can, + ArraySizeModifier sm, unsigned tq) + : ArrayType(IncompleteArray, et, can, sm, tq) {} + +public: + friend class StmtIteratorBase; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == IncompleteArray; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSizeModifier(), + getIndexTypeCVRQualifiers()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + ArraySizeModifier SizeMod, unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(llvm::to_underlying(SizeMod)); + ID.AddInteger(TypeQuals); + } +}; + +/// Represents a C array with a specified size that is not an +/// integer-constant-expression. For example, 'int s[x+foo()]'. +/// Since the size expression is an arbitrary expression, we store it as such. +/// +/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and +/// should not be: two lexically equivalent variable array types could mean +/// different things, for example, these variables do not have the same type +/// dynamically: +/// +/// void foo(int x) { +/// int Y[x]; +/// ++x; +/// int Z[x]; +/// } +/// +/// FIXME: Even constant array types might be represented by a +/// VariableArrayType, as in: +/// +/// void func(int n) { +/// int array[7][n]; +/// } +/// +/// Even though 'array' is a constant-size array of seven elements of type +/// variable-length array of size 'n', it will be represented as a +/// VariableArrayType whose 'SizeExpr' is an IntegerLiteral whose value is 7. +/// Instead, this should be a ConstantArrayType whose element is a +/// VariableArrayType, which models the type better. +class VariableArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. + + /// An assignment-expression. VLA's are only permitted within + /// a function block. + Stmt *SizeExpr; + + VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, + unsigned tq) + : ArrayType(VariableArray, et, can, sm, tq, e), SizeExpr((Stmt *)e) {} + +public: + friend class StmtIteratorBase; + + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == VariableArray; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + llvm_unreachable("Cannot unique VariableArrayTypes."); + } +}; + +/// Represents an array type in C++ whose size is a value-dependent expression. +/// +/// For example: +/// \code +/// template +/// class array { +/// T data[Size]; +/// }; +/// \endcode +/// +/// For these types, we won't actually know what the array bound is +/// until template instantiation occurs, at which point this will +/// become either a ConstantArrayType or a VariableArrayType. +class DependentSizedArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. + + /// An assignment expression that will instantiate to the + /// size of the array. + /// + /// The expression itself might be null, in which case the array + /// type will have its size deduced from an initializer. + Stmt *SizeExpr; + + DependentSizedArrayType(QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq); + +public: + friend class StmtIteratorBase; + + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedArray; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getElementType(), + getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ET, ArraySizeModifier SizeMod, + unsigned TypeQuals, Expr *E); +}; + +/// Represents an extended address space qualifier where the input address space +/// value is dependent. Non-dependent address spaces are not represented with a +/// special Type subclass; they are stored on an ExtQuals node as part of a QualType. +/// +/// For example: +/// \code +/// template +/// class AddressSpace { +/// typedef T __attribute__((address_space(AddrSpace))) type; +/// } +/// \endcode +class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + + Expr *AddrSpaceExpr; + QualType PointeeType; + SourceLocation loc; + + DependentAddressSpaceType(QualType PointeeType, QualType can, + Expr *AddrSpaceExpr, SourceLocation loc); + +public: + Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } + QualType getPointeeType() const { return PointeeType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentAddressSpace; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType PointeeType, Expr *AddrSpaceExpr); +}; + +/// Represents an extended vector type where either the type or size is +/// dependent. +/// +/// For example: +/// \code +/// template +/// class vector { +/// typedef T __attribute__((ext_vector_type(Size))) type; +/// } +/// \endcode +class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + + Expr *SizeExpr; + + /// The element type of the array. + QualType ElementType; + + SourceLocation loc; + + DependentSizedExtVectorType(QualType ElementType, QualType can, + Expr *SizeExpr, SourceLocation loc); + +public: + Expr *getSizeExpr() const { return SizeExpr; } + QualType getElementType() const { return ElementType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedExtVector; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getElementType(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ElementType, Expr *SizeExpr); +}; + +enum class VectorKind { + /// not a target-specific vector type + Generic, + + /// is AltiVec vector + AltiVecVector, + + /// is AltiVec 'vector Pixel' + AltiVecPixel, + + /// is AltiVec 'vector bool ...' + AltiVecBool, + + /// is ARM Neon vector + Neon, + + /// is ARM Neon polynomial vector + NeonPoly, + + /// is AArch64 SVE fixed-length data vector + SveFixedLengthData, + + /// is AArch64 SVE fixed-length predicate vector + SveFixedLengthPredicate, + + /// is RISC-V RVV fixed-length data vector + RVVFixedLengthData, + + /// is RISC-V RVV fixed-length mask vector + RVVFixedLengthMask, + + RVVFixedLengthMask_1, + RVVFixedLengthMask_2, + RVVFixedLengthMask_4 +}; + +/// Represents a GCC generic vector type. This type is created using +/// __attribute__((vector_size(n)), where "n" specifies the vector size in +/// bytes; or from an Altivec __vector or vector declaration. +/// Since the constructor takes the number of vector elements, the +/// client is responsible for converting the size into the number of elements. +class VectorType : public Type, public llvm::FoldingSetNode { +protected: + friend class ASTContext; // ASTContext creates these. + + /// The element type of the vector. + QualType ElementType; + + VectorType(QualType vecType, unsigned nElements, QualType canonType, + VectorKind vecKind); + + VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType, VectorKind vecKind); + +public: + QualType getElementType() const { return ElementType; } + unsigned getNumElements() const { return VectorTypeBits.NumElements; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + VectorKind getVectorKind() const { + return VectorKind(VectorTypeBits.VecKind); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getNumElements(), + getTypeClass(), getVectorKind()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, + unsigned NumElements, TypeClass TypeClass, + VectorKind VecKind) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + ID.AddInteger(NumElements); + ID.AddInteger(TypeClass); + ID.AddInteger(llvm::to_underlying(VecKind)); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; + } +}; + +/// Represents a vector type where either the type or size is dependent. +//// +/// For example: +/// \code +/// template +/// class vector { +/// typedef T __attribute__((vector_size(Size))) type; +/// } +/// \endcode +class DependentVectorType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + + QualType ElementType; + Expr *SizeExpr; + SourceLocation Loc; + + DependentVectorType(QualType ElementType, QualType CanonType, Expr *SizeExpr, + SourceLocation Loc, VectorKind vecKind); + +public: + Expr *getSizeExpr() const { return SizeExpr; } + QualType getElementType() const { return ElementType; } + SourceLocation getAttributeLoc() const { return Loc; } + VectorKind getVectorKind() const { + return VectorKind(VectorTypeBits.VecKind); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentVector; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ElementType, const Expr *SizeExpr, + VectorKind VecKind); +}; + +/// ExtVectorType - Extended vector type. This type is created using +/// __attribute__((ext_vector_type(n)), where "n" is the number of elements. +/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This +/// class enables syntactic extensions, like Vector Components for accessing +/// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL +/// Shading Language). +class ExtVectorType : public VectorType { + friend class ASTContext; // ASTContext creates these. + + ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) + : VectorType(ExtVector, vecType, nElements, canonType, + VectorKind::Generic) {} + +public: + static int getPointAccessorIdx(char c) { + switch (c) { + default: return -1; + case 'x': case 'r': return 0; + case 'y': case 'g': return 1; + case 'z': case 'b': return 2; + case 'w': case 'a': return 3; + } + } + + static int getNumericAccessorIdx(char c) { + switch (c) { + default: return -1; + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': + case 'a': return 10; + case 'B': + case 'b': return 11; + case 'C': + case 'c': return 12; + case 'D': + case 'd': return 13; + case 'E': + case 'e': return 14; + case 'F': + case 'f': return 15; + } + } + + static int getAccessorIdx(char c, bool isNumericAccessor) { + if (isNumericAccessor) + return getNumericAccessorIdx(c); + else + return getPointAccessorIdx(c); + } + + bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const { + if (int idx = getAccessorIdx(c, isNumericAccessor)+1) + return unsigned(idx-1) < getNumElements(); + return false; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ExtVector; + } +}; + +/// Represents a matrix type, as defined in the Matrix Types clang extensions. +/// __attribute__((matrix_type(rows, columns))), where "rows" specifies +/// number of rows and "columns" specifies the number of columns. +class MatrixType : public Type, public llvm::FoldingSetNode { +protected: + friend class ASTContext; + + /// The element type of the matrix. + QualType ElementType; + + MatrixType(QualType ElementTy, QualType CanonElementTy); + + MatrixType(TypeClass TypeClass, QualType ElementTy, QualType CanonElementTy, + const Expr *RowExpr = nullptr, const Expr *ColumnExpr = nullptr); + +public: + /// Returns type of the elements being stored in the matrix + QualType getElementType() const { return ElementType; } + + /// Valid elements types are the following: + /// * an integer type (as in C23 6.2.5p22), but excluding enumerated types + /// and _Bool + /// * the standard floating types float or double + /// * a half-precision floating point type, if one is supported on the target + static bool isValidElementType(QualType T) { + return T->isDependentType() || + (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType()); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantMatrix || + T->getTypeClass() == DependentSizedMatrix; + } +}; + +/// Represents a concrete matrix type with constant number of rows and columns +class ConstantMatrixType final : public MatrixType { +protected: + friend class ASTContext; + + /// Number of rows and columns. + unsigned NumRows; + unsigned NumColumns; + + static constexpr unsigned MaxElementsPerDimension = (1 << 20) - 1; + + ConstantMatrixType(QualType MatrixElementType, unsigned NRows, + unsigned NColumns, QualType CanonElementType); + + ConstantMatrixType(TypeClass typeClass, QualType MatrixType, unsigned NRows, + unsigned NColumns, QualType CanonElementType); + +public: + /// Returns the number of rows in the matrix. + unsigned getNumRows() const { return NumRows; } + + /// Returns the number of columns in the matrix. + unsigned getNumColumns() const { return NumColumns; } + + /// Returns the number of elements required to embed the matrix into a vector. + unsigned getNumElementsFlattened() const { + return getNumRows() * getNumColumns(); + } + + /// Returns true if \p NumElements is a valid matrix dimension. + static constexpr bool isDimensionValid(size_t NumElements) { + return NumElements > 0 && NumElements <= MaxElementsPerDimension; + } + + /// Returns the maximum number of elements per dimension. + static constexpr unsigned getMaxElementsPerDimension() { + return MaxElementsPerDimension; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getNumRows(), getNumColumns(), + getTypeClass()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, + unsigned NumRows, unsigned NumColumns, + TypeClass TypeClass) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + ID.AddInteger(NumRows); + ID.AddInteger(NumColumns); + ID.AddInteger(TypeClass); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantMatrix; + } +}; + +/// Represents a matrix type where the type and the number of rows and columns +/// is dependent on a template. +class DependentSizedMatrixType final : public MatrixType { + friend class ASTContext; + + Expr *RowExpr; + Expr *ColumnExpr; + + SourceLocation loc; + + DependentSizedMatrixType(QualType ElementType, QualType CanonicalType, + Expr *RowExpr, Expr *ColumnExpr, SourceLocation loc); + +public: + Expr *getRowExpr() const { return RowExpr; } + Expr *getColumnExpr() const { return ColumnExpr; } + SourceLocation getAttributeLoc() const { return loc; } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedMatrix; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getElementType(), getRowExpr(), getColumnExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ElementType, Expr *RowExpr, Expr *ColumnExpr); +}; + +/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base +/// class of FunctionNoProtoType and FunctionProtoType. +class FunctionType : public Type { + // The type returned by the function. + QualType ResultType; + +public: + /// Interesting information about a specific parameter that can't simply + /// be reflected in parameter's type. This is only used by FunctionProtoType + /// but is in FunctionType to make this class available during the + /// specification of the bases of FunctionProtoType. + /// + /// It makes sense to model language features this way when there's some + /// sort of parameter-specific override (such as an attribute) that + /// affects how the function is called. For example, the ARC ns_consumed + /// attribute changes whether a parameter is passed at +0 (the default) + /// or +1 (ns_consumed). This must be reflected in the function type, + /// but isn't really a change to the parameter type. + /// + /// One serious disadvantage of modelling language features this way is + /// that they generally do not work with language features that attempt + /// to destructure types. For example, template argument deduction will + /// not be able to match a parameter declared as + /// T (*)(U) + /// against an argument of type + /// void (*)(__attribute__((ns_consumed)) id) + /// because the substitution of T=void, U=id into the former will + /// not produce the latter. + class ExtParameterInfo { + enum { + ABIMask = 0x0F, + IsConsumed = 0x10, + HasPassObjSize = 0x20, + IsNoEscape = 0x40, + }; + unsigned char Data = 0; + + public: + ExtParameterInfo() = default; + + /// Return the ABI treatment of this parameter. + ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } + ExtParameterInfo withABI(ParameterABI kind) const { + ExtParameterInfo copy = *this; + copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); + return copy; + } + + /// Is this parameter considered "consumed" by Objective-C ARC? + /// Consumed parameters must have retainable object type. + bool isConsumed() const { return (Data & IsConsumed); } + ExtParameterInfo withIsConsumed(bool consumed) const { + ExtParameterInfo copy = *this; + if (consumed) + copy.Data |= IsConsumed; + else + copy.Data &= ~IsConsumed; + return copy; + } + + bool hasPassObjectSize() const { return Data & HasPassObjSize; } + ExtParameterInfo withHasPassObjectSize() const { + ExtParameterInfo Copy = *this; + Copy.Data |= HasPassObjSize; + return Copy; + } + + bool isNoEscape() const { return Data & IsNoEscape; } + ExtParameterInfo withIsNoEscape(bool NoEscape) const { + ExtParameterInfo Copy = *this; + if (NoEscape) + Copy.Data |= IsNoEscape; + else + Copy.Data &= ~IsNoEscape; + return Copy; + } + + unsigned char getOpaqueValue() const { return Data; } + static ExtParameterInfo getFromOpaqueValue(unsigned char data) { + ExtParameterInfo result; + result.Data = data; + return result; + } + + friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { + return lhs.Data == rhs.Data; + } + + friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { + return lhs.Data != rhs.Data; + } + }; + + /// A class which abstracts out some details necessary for + /// making a call. + /// + /// It is not actually used directly for storing this information in + /// a FunctionType, although FunctionType does currently use the + /// same bit-pattern. + /// + // If you add a field (say Foo), other than the obvious places (both, + // constructors, compile failures), what you need to update is + // * Operator== + // * getFoo + // * withFoo + // * functionType. Add Foo, getFoo. + // * ASTContext::getFooType + // * ASTContext::mergeFunctionTypes + // * FunctionNoProtoType::Profile + // * FunctionProtoType::Profile + // * TypePrinter::PrintFunctionProto + // * AST read and write + // * Codegen + class ExtInfo { + friend class FunctionType; + + // Feel free to rearrange or add bits, but if you go over 16, you'll need to + // adjust the Bits field below, and if you add bits, you'll need to adjust + // Type::FunctionTypeBitfields::ExtInfo as well. + + // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|cmsenscall| + // |0 .. 5| 6 | 7 | 8 |9 .. 11| 12 | 13 | + // + // regparm is either 0 (no regparm attribute) or the regparm value+1. + enum { CallConvMask = 0x3F }; + enum { NoReturnMask = 0x40 }; + enum { ProducesResultMask = 0x80 }; + enum { NoCallerSavedRegsMask = 0x100 }; + enum { RegParmMask = 0xe00, RegParmOffset = 9 }; + enum { NoCfCheckMask = 0x1000 }; + enum { CmseNSCallMask = 0x2000 }; + uint16_t Bits = CC_C; + + ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} + + public: + // Constructor with no defaults. Use this when you know that you + // have all the elements (when reading an AST file for example). + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult, bool noCallerSavedRegs, bool NoCfCheck, + bool cmseNSCall) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); + Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | + (producesResult ? ProducesResultMask : 0) | + (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | + (NoCfCheck ? NoCfCheckMask : 0) | + (cmseNSCall ? CmseNSCallMask : 0); + } + + // Constructor with all defaults. Use when for example creating a + // function known to use defaults. + ExtInfo() = default; + + // Constructor with just the calling convention, which is an important part + // of the canonical type. + ExtInfo(CallingConv CC) : Bits(CC) {} + + bool getNoReturn() const { return Bits & NoReturnMask; } + bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getCmseNSCall() const { return Bits & CmseNSCallMask; } + bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } + bool getNoCfCheck() const { return Bits & NoCfCheckMask; } + bool getHasRegParm() const { return ((Bits & RegParmMask) >> RegParmOffset) != 0; } + + unsigned getRegParm() const { + unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset; + if (RegParm > 0) + --RegParm; + return RegParm; + } + + CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } + + bool operator==(ExtInfo Other) const { + return Bits == Other.Bits; + } + bool operator!=(ExtInfo Other) const { + return Bits != Other.Bits; + } + + // Note that we don't have setters. That is by design, use + // the following with methods instead of mutating these objects. + + ExtInfo withNoReturn(bool noReturn) const { + if (noReturn) + return ExtInfo(Bits | NoReturnMask); + else + return ExtInfo(Bits & ~NoReturnMask); + } + + ExtInfo withProducesResult(bool producesResult) const { + if (producesResult) + return ExtInfo(Bits | ProducesResultMask); + else + return ExtInfo(Bits & ~ProducesResultMask); + } + + ExtInfo withCmseNSCall(bool cmseNSCall) const { + if (cmseNSCall) + return ExtInfo(Bits | CmseNSCallMask); + else + return ExtInfo(Bits & ~CmseNSCallMask); + } + + ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { + if (noCallerSavedRegs) + return ExtInfo(Bits | NoCallerSavedRegsMask); + else + return ExtInfo(Bits & ~NoCallerSavedRegsMask); + } + + ExtInfo withNoCfCheck(bool noCfCheck) const { + if (noCfCheck) + return ExtInfo(Bits | NoCfCheckMask); + else + return ExtInfo(Bits & ~NoCfCheckMask); + } + + ExtInfo withRegParm(unsigned RegParm) const { + assert(RegParm < 7 && "Invalid regparm value"); + return ExtInfo((Bits & ~RegParmMask) | + ((RegParm + 1) << RegParmOffset)); + } + + ExtInfo withCallingConv(CallingConv cc) const { + return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Bits); + } + }; + + /// A simple holder for a QualType representing a type in an + /// exception specification. Unfortunately needed by FunctionProtoType + /// because TrailingObjects cannot handle repeated types. + struct ExceptionType { QualType Type; }; + + /// A simple holder for various uncommon bits which do not fit in + /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the + /// alignment of subsequent objects in TrailingObjects. + struct alignas(void *) FunctionTypeExtraBitfields { + /// The number of types in the exception specification. + /// A whole unsigned is not needed here and according to + /// [implimits] 8 bits would be enough here. + unsigned NumExceptionType : 10; + + LLVM_PREFERRED_TYPE(bool) + unsigned HasExtraAttributeInfo : 1; + + LLVM_PREFERRED_TYPE(bool) + unsigned HasArmTypeAttributes : 1; + + LLVM_PREFERRED_TYPE(bool) + unsigned EffectsHaveConditions : 1; + unsigned NumFunctionEffects : 4; + + FunctionTypeExtraBitfields() + : NumExceptionType(0), HasExtraAttributeInfo(false), + HasArmTypeAttributes(false), EffectsHaveConditions(false), + NumFunctionEffects(0) {} + }; + + /// A holder for extra information from attributes which aren't part of an + /// \p AttributedType. + struct alignas(void *) FunctionTypeExtraAttributeInfo { + /// A CFI "salt" that differentiates functions with the same prototype. + StringRef CFISalt; + + operator bool() const { return !CFISalt.empty(); } + + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddString(CFISalt); } + }; + + /// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number + /// of function type attributes that can be set on function types, including + /// function pointers. + enum AArch64SMETypeAttributes : uint16_t { + SME_NormalFunction = 0, + SME_PStateSMEnabledMask = 1 << 0, + SME_PStateSMCompatibleMask = 1 << 1, + + // Describes the value of the state using ArmStateValue. + SME_ZAShift = 2, + SME_ZAMask = 0b111 << SME_ZAShift, + SME_ZT0Shift = 5, + SME_ZT0Mask = 0b111 << SME_ZT0Shift, + + // A bit to tell whether a function is agnostic about sme ZA state. + SME_AgnosticZAStateShift = 8, + SME_AgnosticZAStateMask = 1 << SME_AgnosticZAStateShift, + + SME_AttributeMask = + 0b1'111'111'11 // We can't support more than 9 bits because of + // the bitmask in FunctionTypeArmAttributes + // and ExtProtoInfo. + }; + + enum ArmStateValue : unsigned { + ARM_None = 0, + ARM_Preserves = 1, + ARM_In = 2, + ARM_Out = 3, + ARM_InOut = 4, + }; + + static ArmStateValue getArmZAState(unsigned AttrBits) { + return static_cast((AttrBits & SME_ZAMask) >> SME_ZAShift); + } + + static ArmStateValue getArmZT0State(unsigned AttrBits) { + return static_cast((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift); + } + + /// A holder for Arm type attributes as described in the Arm C/C++ + /// Language extensions which are not particularly common to all + /// types and therefore accounted separately from FunctionTypeBitfields. + struct alignas(void *) FunctionTypeArmAttributes { + /// Any AArch64 SME ACLE type attributes that need to be propagated + /// on declarations and function pointers. + LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes) + unsigned AArch64SMEAttributes : 9; + + FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {} + }; + +protected: + FunctionType(TypeClass tc, QualType res, QualType Canonical, + TypeDependence Dependence, ExtInfo Info) + : Type(tc, Canonical, Dependence), ResultType(res) { + FunctionTypeBits.ExtInfo = Info.Bits; + } + + Qualifiers getFastTypeQuals() const { + if (isFunctionProtoType()) + return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals); + + return Qualifiers(); + } + +public: + QualType getReturnType() const { return ResultType; } + + bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } + unsigned getRegParmType() const { return getExtInfo().getRegParm(); } + + /// Determine whether this function type includes the GNU noreturn + /// attribute. The C++11 [[noreturn]] attribute does not affect the function + /// type. + bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } + + /// Determine whether this is a function prototype that includes the + /// cfi_unchecked_callee attribute. + bool getCFIUncheckedCalleeAttr() const; + + bool getCmseNSCallAttr() const { return getExtInfo().getCmseNSCall(); } + CallingConv getCallConv() const { return getExtInfo().getCC(); } + ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } + + static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, + "Const, volatile and restrict are assumed to be a subset of " + "the fast qualifiers."); + + bool isConst() const { return getFastTypeQuals().hasConst(); } + bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } + bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } + + /// Determine the type of an expression that calls a function of + /// this type. + QualType getCallResultType(const ASTContext &Context) const { + return getReturnType().getNonLValueExprType(Context); + } + + static StringRef getNameForCallConv(CallingConv CC); + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto || + T->getTypeClass() == FunctionProto; + } +}; + +/// Represents a K&R-style 'int foo()' function, which has +/// no information available about its arguments. +class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) + : FunctionType(FunctionNoProto, Result, Canonical, + Result->getDependence() & + ~(TypeDependence::DependentInstantiation | + TypeDependence::UnexpandedPack), + Info) {} + +public: + // No additional state past what FunctionType provides. + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReturnType(), getExtInfo()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, + ExtInfo Info) { + Info.Profile(ID); + ID.AddPointer(ResultType.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto; + } +}; + +// ------------------------------------------------------------------------------ + +/// Represents an abstract function effect, using just an enumeration describing +/// its kind. +class FunctionEffect { +public: + /// Identifies the particular effect. + enum class Kind : uint8_t { + NonBlocking, + NonAllocating, + Blocking, + Allocating, + Last = Allocating + }; + constexpr static size_t KindCount = static_cast(Kind::Last) + 1; + + /// Flags describing some behaviors of the effect. + using Flags = unsigned; + enum FlagBit : Flags { + // Can verification inspect callees' implementations? (e.g. nonblocking: + // yes, tcb+types: no). This also implies the need for 2nd-pass + // verification. + FE_InferrableOnCallees = 0x1, + + // Language constructs which effects can diagnose as disallowed. + FE_ExcludeThrow = 0x2, + FE_ExcludeCatch = 0x4, + FE_ExcludeObjCMessageSend = 0x8, + FE_ExcludeStaticLocalVars = 0x10, + FE_ExcludeThreadLocalVars = 0x20 + }; + +private: + Kind FKind; + + // Expansion: for hypothetical TCB+types, there could be one Kind for TCB, + // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would + // be considered for uniqueness. + +public: + explicit FunctionEffect(Kind K) : FKind(K) {} + + /// The kind of the effect. + Kind kind() const { return FKind; } + + /// Return the opposite kind, for effects which have opposites. + Kind oppositeKind() const; + + /// For serialization. + uint32_t toOpaqueInt32() const { return uint32_t(FKind); } + static FunctionEffect fromOpaqueInt32(uint32_t Value) { + return FunctionEffect(Kind(Value)); + } + + /// Flags describing some behaviors of the effect. + Flags flags() const { + switch (kind()) { + case Kind::NonBlocking: + return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | + FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars | + FE_ExcludeThreadLocalVars; + case Kind::NonAllocating: + // Same as NonBlocking, except without FE_ExcludeStaticLocalVars. + return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | + FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars; + case Kind::Blocking: + case Kind::Allocating: + return 0; + } + llvm_unreachable("unknown effect kind"); + } + + /// The description printed in diagnostics, e.g. 'nonblocking'. + StringRef name() const; + + friend raw_ostream &operator<<(raw_ostream &OS, + const FunctionEffect &Effect) { + OS << Effect.name(); + return OS; + } + + /// Determine whether the effect is allowed to be inferred on the callee, + /// which is either a FunctionDecl or BlockDecl. If the returned optional + /// is empty, inference is permitted; otherwise it holds the effect which + /// blocked inference. + /// Example: This allows nonblocking(false) to prevent inference for the + /// function. + std::optional + effectProhibitingInference(const Decl &Callee, + FunctionEffectKindSet CalleeFX) const; + + // Return false for success. When true is returned for a direct call, then the + // FE_InferrableOnCallees flag may trigger inference rather than an immediate + // diagnostic. Caller should be assumed to have the effect (it may not have it + // explicitly when inferring). + bool shouldDiagnoseFunctionCall(bool Direct, + FunctionEffectKindSet CalleeFX) const; + + friend bool operator==(FunctionEffect LHS, FunctionEffect RHS) { + return LHS.FKind == RHS.FKind; + } + friend bool operator!=(FunctionEffect LHS, FunctionEffect RHS) { + return !(LHS == RHS); + } + friend bool operator<(FunctionEffect LHS, FunctionEffect RHS) { + return LHS.FKind < RHS.FKind; + } +}; + +/// Wrap a function effect's condition expression in another struct so +/// that FunctionProtoType's TrailingObjects can treat it separately. +class EffectConditionExpr { + Expr *Cond = nullptr; // if null, unconditional. + +public: + EffectConditionExpr() = default; + EffectConditionExpr(Expr *E) : Cond(E) {} + + Expr *getCondition() const { return Cond; } + + bool operator==(const EffectConditionExpr &RHS) const { + return Cond == RHS.Cond; + } +}; + +/// A FunctionEffect plus a potential boolean expression determining whether +/// the effect is declared (e.g. nonblocking(expr)). Generally the condition +/// expression when present, is dependent. +struct FunctionEffectWithCondition { + FunctionEffect Effect; + EffectConditionExpr Cond; + + FunctionEffectWithCondition(FunctionEffect E, const EffectConditionExpr &C) + : Effect(E), Cond(C) {} + + /// Return a textual description of the effect, and its condition, if any. + std::string description() const; + + friend raw_ostream &operator<<(raw_ostream &OS, + const FunctionEffectWithCondition &CFE); +}; + +/// Support iteration in parallel through a pair of FunctionEffect and +/// EffectConditionExpr containers. +template class FunctionEffectIterator { + friend Container; + + const Container *Outer = nullptr; + size_t Idx = 0; + +public: + FunctionEffectIterator(); + FunctionEffectIterator(const Container &O, size_t I) : Outer(&O), Idx(I) {} + bool operator==(const FunctionEffectIterator &Other) const { + return Idx == Other.Idx; + } + bool operator!=(const FunctionEffectIterator &Other) const { + return Idx != Other.Idx; + } + + FunctionEffectIterator operator++() { + ++Idx; + return *this; + } + + FunctionEffectWithCondition operator*() const { + assert(Outer != nullptr && "invalid FunctionEffectIterator"); + bool HasConds = !Outer->Conditions.empty(); + return FunctionEffectWithCondition{Outer->Effects[Idx], + HasConds ? Outer->Conditions[Idx] + : EffectConditionExpr()}; + } +}; + +/// An immutable set of FunctionEffects and possibly conditions attached to +/// them. The effects and conditions reside in memory not managed by this object +/// (typically, trailing objects in FunctionProtoType, or borrowed references +/// from a FunctionEffectSet). +/// +/// Invariants: +/// - there is never more than one instance of any given effect. +/// - the array of conditions is either empty or has the same size as the +/// array of effects. +/// - some conditions may be null expressions; each condition pertains to +/// the effect at the same array index. +/// +/// Also, if there are any conditions, at least one of those expressions will be +/// dependent, but this is only asserted in the constructor of +/// FunctionProtoType. +/// +/// See also FunctionEffectSet, in Sema, which provides a mutable set. +class FunctionEffectsRef { + // Restrict classes which can call the private constructor -- these friends + // all maintain the required invariants. FunctionEffectSet is generally the + // only way in which the arrays are created; FunctionProtoType will not + // reorder them. + friend FunctionProtoType; + friend FunctionEffectSet; + + ArrayRef Effects; + ArrayRef Conditions; + + // The arrays are expected to have been sorted by the caller, with the + // effects in order. The conditions array must be empty or the same size + // as the effects array, since the conditions are associated with the effects + // at the same array indices. + FunctionEffectsRef(ArrayRef FX, + ArrayRef Conds) + : Effects(FX), Conditions(Conds) {} + +public: + /// Extract the effects from a Type if it is a function, block, or member + /// function pointer, or a reference or pointer to one. + static FunctionEffectsRef get(QualType QT); + + /// Asserts invariants. + static FunctionEffectsRef create(ArrayRef FX, + ArrayRef Conds); + + FunctionEffectsRef() = default; + + bool empty() const { return Effects.empty(); } + size_t size() const { return Effects.size(); } + + ArrayRef effects() const { return Effects; } + ArrayRef conditions() const { return Conditions; } + + using iterator = FunctionEffectIterator; + friend iterator; + iterator begin() const { return iterator(*this, 0); } + iterator end() const { return iterator(*this, size()); } + + friend bool operator==(const FunctionEffectsRef &LHS, + const FunctionEffectsRef &RHS) { + return LHS.Effects == RHS.Effects && LHS.Conditions == RHS.Conditions; + } + friend bool operator!=(const FunctionEffectsRef &LHS, + const FunctionEffectsRef &RHS) { + return !(LHS == RHS); + } + + void dump(llvm::raw_ostream &OS) const; +}; + +/// A mutable set of FunctionEffect::Kind. +class FunctionEffectKindSet { + // For now this only needs to be a bitmap. + constexpr static size_t EndBitPos = FunctionEffect::KindCount; + using KindBitsT = std::bitset; + + KindBitsT KindBits{}; + + explicit FunctionEffectKindSet(KindBitsT KB) : KindBits(KB) {} + + // Functions to translate between an effect kind, starting at 1, and a + // position in the bitset. + + constexpr static size_t kindToPos(FunctionEffect::Kind K) { + return static_cast(K); + } + + constexpr static FunctionEffect::Kind posToKind(size_t Pos) { + return static_cast(Pos); + } + + // Iterates through the bits which are set. + class iterator { + const FunctionEffectKindSet *Outer = nullptr; + size_t Idx = 0; + + // If Idx does not reference a set bit, advance it until it does, + // or until it reaches EndBitPos. + void advanceToNextSetBit() { + while (Idx < EndBitPos && !Outer->KindBits.test(Idx)) + ++Idx; + } + + public: + iterator(); + iterator(const FunctionEffectKindSet &O, size_t I) : Outer(&O), Idx(I) { + advanceToNextSetBit(); + } + bool operator==(const iterator &Other) const { return Idx == Other.Idx; } + bool operator!=(const iterator &Other) const { return Idx != Other.Idx; } + + iterator operator++() { + ++Idx; + advanceToNextSetBit(); + return *this; + } + + FunctionEffect operator*() const { + assert(Idx < EndBitPos && "Dereference of end iterator"); + return FunctionEffect(posToKind(Idx)); + } + }; + +public: + FunctionEffectKindSet() = default; + explicit FunctionEffectKindSet(FunctionEffectsRef FX) { insert(FX); } + + iterator begin() const { return iterator(*this, 0); } + iterator end() const { return iterator(*this, EndBitPos); } + + void insert(FunctionEffect Effect) { KindBits.set(kindToPos(Effect.kind())); } + void insert(FunctionEffectsRef FX) { + for (FunctionEffect Item : FX.effects()) + insert(Item); + } + void insert(FunctionEffectKindSet Set) { KindBits |= Set.KindBits; } + + bool empty() const { return KindBits.none(); } + bool contains(const FunctionEffect::Kind EK) const { + return KindBits.test(kindToPos(EK)); + } + void dump(llvm::raw_ostream &OS) const; + + static FunctionEffectKindSet difference(FunctionEffectKindSet LHS, + FunctionEffectKindSet RHS) { + return FunctionEffectKindSet(LHS.KindBits & ~RHS.KindBits); + } +}; + +/// A mutable set of FunctionEffects and possibly conditions attached to them. +/// Used to compare and merge effects on declarations. +/// +/// Has the same invariants as FunctionEffectsRef. +class FunctionEffectSet { + SmallVector Effects; + SmallVector Conditions; + +public: + FunctionEffectSet() = default; + + explicit FunctionEffectSet(const FunctionEffectsRef &FX) + : Effects(FX.effects()), Conditions(FX.conditions()) {} + + bool empty() const { return Effects.empty(); } + size_t size() const { return Effects.size(); } + + using iterator = FunctionEffectIterator; + friend iterator; + iterator begin() const { return iterator(*this, 0); } + iterator end() const { return iterator(*this, size()); } + + operator FunctionEffectsRef() const { return {Effects, Conditions}; } + + void dump(llvm::raw_ostream &OS) const; + + // Mutators + + // On insertion, a conflict occurs when attempting to insert an + // effect which is opposite an effect already in the set, or attempting + // to insert an effect which is already in the set but with a condition + // which is not identical. + struct Conflict { + FunctionEffectWithCondition Kept; + FunctionEffectWithCondition Rejected; + }; + using Conflicts = SmallVector; + + // Returns true for success (obviating a check of Errs.empty()). + bool insert(const FunctionEffectWithCondition &NewEC, Conflicts &Errs); + + // Returns true for success (obviating a check of Errs.empty()). + bool insert(const FunctionEffectsRef &Set, Conflicts &Errs); + + // Set operations + + static FunctionEffectSet getUnion(FunctionEffectsRef LHS, + FunctionEffectsRef RHS, Conflicts &Errs); + static FunctionEffectSet getIntersection(FunctionEffectsRef LHS, + FunctionEffectsRef RHS); +}; + +/// Represents a prototype with parameter type info, e.g. +/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no +/// parameters, not as having a single void parameter. Such a type can have +/// an exception specification, but this specification is not part of the +/// canonical type. FunctionProtoType has several trailing objects, some of +/// which optional. For more information about the trailing objects see +/// the first comment inside FunctionProtoType. +class FunctionProtoType final + : public FunctionType, + public llvm::FoldingSetNode, + private llvm::TrailingObjects< + FunctionProtoType, QualType, SourceLocation, + FunctionType::FunctionTypeExtraBitfields, + FunctionType::FunctionTypeExtraAttributeInfo, + FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType, + Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers, + FunctionEffect, EffectConditionExpr> { + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; + + // FunctionProtoType is followed by several trailing objects, some of + // which optional. They are in order: + // + // * An array of getNumParams() QualType holding the parameter types. + // Always present. Note that for the vast majority of FunctionProtoType, + // these will be the only trailing objects. + // + // * Optionally if the function is variadic, the SourceLocation of the + // ellipsis. + // + // * Optionally if some extra data is stored in FunctionTypeExtraBitfields + // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): + // a single FunctionTypeExtraBitfields. Present if and only if + // hasExtraBitfields() is true. + // + // * Optionally exactly one of: + // * an array of getNumExceptions() ExceptionType, + // * a single Expr *, + // * a pair of FunctionDecl *, + // * a single FunctionDecl * + // used to store information about the various types of exception + // specification. See getExceptionSpecSize for the details. + // + // * Optionally an array of getNumParams() ExtParameterInfo holding + // an ExtParameterInfo for each of the parameters. Present if and + // only if hasExtParameterInfos() is true. + // + // * Optionally a Qualifiers object to represent extra qualifiers that can't + // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and + // only if hasExtQualifiers() is true. + // + // * Optionally, an array of getNumFunctionEffects() FunctionEffect. + // Present only when getNumFunctionEffects() > 0 + // + // * Optionally, an array of getNumFunctionEffects() EffectConditionExpr. + // Present only when getNumFunctionEffectConditions() > 0. + // + // The optional FunctionTypeExtraBitfields has to be before the data + // related to the exception specification since it contains the number + // of exception types. + // + // We put the ExtParameterInfos later. If all were equal, it would make + // more sense to put these before the exception specification, because + // it's much easier to skip past them compared to the elaborate switch + // required to skip the exception specification. However, all is not + // equal; ExtParameterInfos are used to model very uncommon features, + // and it's better not to burden the more common paths. + +public: + /// Holds information about the various types of exception specification. + /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is + /// used to group together the various bits of information about the + /// exception specification. + struct ExceptionSpecInfo { + /// The kind of exception specification this is. + ExceptionSpecificationType Type = EST_None; + + /// Explicitly-specified list of exception types. + ArrayRef Exceptions; + + /// Noexcept expression, if this is a computed noexcept specification. + Expr *NoexceptExpr = nullptr; + + /// The function whose exception specification this is, for + /// EST_Unevaluated and EST_Uninstantiated. + FunctionDecl *SourceDecl = nullptr; + + /// The function template whose exception specification this is instantiated + /// from, for EST_Uninstantiated. + FunctionDecl *SourceTemplate = nullptr; + + ExceptionSpecInfo() = default; + + ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} + + void instantiate(); + }; + + /// Extra information about a function prototype. ExtProtoInfo is not + /// stored as such in FunctionProtoType but is used to group together + /// the various bits of extra information about a function prototype. + struct ExtProtoInfo { + FunctionType::ExtInfo ExtInfo; + Qualifiers TypeQuals; + RefQualifierKind RefQualifier = RQ_None; + ExceptionSpecInfo ExceptionSpec; + const ExtParameterInfo *ExtParameterInfos = nullptr; + SourceLocation EllipsisLoc; + FunctionEffectsRef FunctionEffects; + FunctionTypeExtraAttributeInfo ExtraAttributeInfo; + + LLVM_PREFERRED_TYPE(bool) + unsigned Variadic : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned HasTrailingReturn : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned CFIUncheckedCallee : 1; + LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes) + unsigned AArch64SMEAttributes : 9; + + ExtProtoInfo() + : Variadic(false), HasTrailingReturn(false), CFIUncheckedCallee(false), + AArch64SMEAttributes(SME_NormalFunction) {} + + ExtProtoInfo(CallingConv CC) + : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), + CFIUncheckedCallee(false), AArch64SMEAttributes(SME_NormalFunction) {} + + ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { + ExtProtoInfo Result(*this); + Result.ExceptionSpec = ESI; + return Result; + } + + ExtProtoInfo withCFIUncheckedCallee(bool CFIUncheckedCallee) { + ExtProtoInfo Result(*this); + Result.CFIUncheckedCallee = CFIUncheckedCallee; + return Result; + } + + bool requiresFunctionProtoTypeExtraBitfields() const { + return ExceptionSpec.Type == EST_Dynamic || + requiresFunctionProtoTypeArmAttributes() || + requiresFunctionProtoTypeExtraAttributeInfo() || + !FunctionEffects.empty(); + } + + bool requiresFunctionProtoTypeArmAttributes() const { + return AArch64SMEAttributes != SME_NormalFunction; + } + + bool requiresFunctionProtoTypeExtraAttributeInfo() const { + return static_cast(ExtraAttributeInfo); + } + + void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) { + if (Enable) + AArch64SMEAttributes |= Kind; + else + AArch64SMEAttributes &= ~Kind; + } + }; + +private: + unsigned numTrailingObjects(OverloadToken) const { + return getNumParams(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return isVariadic(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasArmTypeAttributes(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasExtraBitfields(); + } + + unsigned + numTrailingObjects(OverloadToken) const { + return hasExtraAttributeInfo(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return getExceptionSpecSize().NumExceptionType; + } + + unsigned numTrailingObjects(OverloadToken) const { + return getExceptionSpecSize().NumExprPtr; + } + + unsigned numTrailingObjects(OverloadToken) const { + return getExceptionSpecSize().NumFunctionDeclPtr; + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasExtParameterInfos() ? getNumParams() : 0; + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasExtQualifiers() ? 1 : 0; + } + + unsigned numTrailingObjects(OverloadToken) const { + return getNumFunctionEffects(); + } + + /// Determine whether there are any argument types that + /// contain an unexpanded parameter pack. + static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, + unsigned numArgs) { + for (unsigned Idx = 0; Idx < numArgs; ++Idx) + if (ArgArray[Idx]->containsUnexpandedParameterPack()) + return true; + + return false; + } + + FunctionProtoType(QualType result, ArrayRef params, + QualType canonical, const ExtProtoInfo &epi); + + /// This struct is returned by getExceptionSpecSize and is used to + /// translate an ExceptionSpecificationType to the number and kind + /// of trailing objects related to the exception specification. + struct ExceptionSpecSizeHolder { + unsigned NumExceptionType; + unsigned NumExprPtr; + unsigned NumFunctionDeclPtr; + }; + + /// Return the number and kind of trailing objects + /// related to the exception specification. + static ExceptionSpecSizeHolder + getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { + switch (EST) { + case EST_None: + case EST_DynamicNone: + case EST_MSAny: + case EST_BasicNoexcept: + case EST_Unparsed: + case EST_NoThrow: + return {0, 0, 0}; + + case EST_Dynamic: + return {NumExceptions, 0, 0}; + + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: + return {0, 1, 0}; + + case EST_Uninstantiated: + return {0, 0, 2}; + + case EST_Unevaluated: + return {0, 0, 1}; + } + llvm_unreachable("bad exception specification kind"); + } + + /// Return the number and kind of trailing objects + /// related to the exception specification. + ExceptionSpecSizeHolder getExceptionSpecSize() const { + return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); + } + + /// Whether the trailing FunctionTypeExtraBitfields is present. + bool hasExtraBitfields() const { + assert((getExceptionSpecType() != EST_Dynamic || + FunctionTypeBits.HasExtraBitfields) && + "ExtraBitfields are required for given ExceptionSpecType"); + return FunctionTypeBits.HasExtraBitfields; + + } + + bool hasExtraAttributeInfo() const { + return FunctionTypeBits.HasExtraBitfields && + getTrailingObjects() + ->HasExtraAttributeInfo; + } + + bool hasArmTypeAttributes() const { + return FunctionTypeBits.HasExtraBitfields && + getTrailingObjects() + ->HasArmTypeAttributes; + } + + bool hasExtQualifiers() const { + return FunctionTypeBits.HasExtQuals; + } + +public: + unsigned getNumParams() const { return FunctionTypeBits.NumParams; } + + QualType getParamType(unsigned i) const { + assert(i < getNumParams() && "invalid parameter index"); + return param_type_begin()[i]; + } + + ArrayRef getParamTypes() const { + return {param_type_begin(), param_type_end()}; + } + + ExtProtoInfo getExtProtoInfo() const { + ExtProtoInfo EPI; + EPI.ExtInfo = getExtInfo(); + EPI.Variadic = isVariadic(); + EPI.EllipsisLoc = getEllipsisLoc(); + EPI.HasTrailingReturn = hasTrailingReturn(); + EPI.CFIUncheckedCallee = hasCFIUncheckedCallee(); + EPI.ExceptionSpec = getExceptionSpecInfo(); + EPI.TypeQuals = getMethodQuals(); + EPI.RefQualifier = getRefQualifier(); + EPI.ExtParameterInfos = getExtParameterInfosOrNull(); + EPI.ExtraAttributeInfo = getExtraAttributeInfo(); + EPI.AArch64SMEAttributes = getAArch64SMEAttributes(); + EPI.FunctionEffects = getFunctionEffects(); + return EPI; + } + + /// Get the kind of exception specification on this function. + ExceptionSpecificationType getExceptionSpecType() const { + return static_cast( + FunctionTypeBits.ExceptionSpecType); + } + + /// Return whether this function has any kind of exception spec. + bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } + + /// Return whether this function has a dynamic (throw) exception spec. + bool hasDynamicExceptionSpec() const { + return isDynamicExceptionSpec(getExceptionSpecType()); + } + + /// Return whether this function has a noexcept exception spec. + bool hasNoexceptExceptionSpec() const { + return isNoexceptExceptionSpec(getExceptionSpecType()); + } + + /// Return whether this function has a dependent exception spec. + bool hasDependentExceptionSpec() const; + + /// Return whether this function has an instantiation-dependent exception + /// spec. + bool hasInstantiationDependentExceptionSpec() const; + + /// Return all the available information about this type's exception spec. + ExceptionSpecInfo getExceptionSpecInfo() const { + ExceptionSpecInfo Result; + Result.Type = getExceptionSpecType(); + if (Result.Type == EST_Dynamic) { + Result.Exceptions = exceptions(); + } else if (isComputedNoexcept(Result.Type)) { + Result.NoexceptExpr = getNoexceptExpr(); + } else if (Result.Type == EST_Uninstantiated) { + Result.SourceDecl = getExceptionSpecDecl(); + Result.SourceTemplate = getExceptionSpecTemplate(); + } else if (Result.Type == EST_Unevaluated) { + Result.SourceDecl = getExceptionSpecDecl(); + } + return Result; + } + + /// Return the number of types in the exception specification. + unsigned getNumExceptions() const { + return getExceptionSpecType() == EST_Dynamic + ? getTrailingObjects() + ->NumExceptionType + : 0; + } + + /// Return the ith exception type, where 0 <= i < getNumExceptions(). + QualType getExceptionType(unsigned i) const { + assert(i < getNumExceptions() && "Invalid exception number!"); + return exception_begin()[i]; + } + + /// Return the expression inside noexcept(expression), or a null pointer + /// if there is none (because the exception spec is not of this form). + Expr *getNoexceptExpr() const { + if (!isComputedNoexcept(getExceptionSpecType())) + return nullptr; + return *getTrailingObjects(); + } + + /// If this function type has an exception specification which hasn't + /// been determined yet (either because it has not been evaluated or because + /// it has not been instantiated), this is the function whose exception + /// specification is represented by this type. + FunctionDecl *getExceptionSpecDecl() const { + if (getExceptionSpecType() != EST_Uninstantiated && + getExceptionSpecType() != EST_Unevaluated) + return nullptr; + return getTrailingObjects()[0]; + } + + /// If this function type has an uninstantiated exception + /// specification, this is the function whose exception specification + /// should be instantiated to find the exception specification for + /// this type. + FunctionDecl *getExceptionSpecTemplate() const { + if (getExceptionSpecType() != EST_Uninstantiated) + return nullptr; + return getTrailingObjects()[1]; + } + + /// Determine whether this function type has a non-throwing exception + /// specification. + CanThrowResult canThrow() const; + + /// Determine whether this function type has a non-throwing exception + /// specification. If this depends on template arguments, returns + /// \c ResultIfDependent. + bool isNothrow(bool ResultIfDependent = false) const { + return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; + } + + /// Whether this function prototype is variadic. + bool isVariadic() const { return FunctionTypeBits.Variadic; } + + SourceLocation getEllipsisLoc() const { + return isVariadic() ? *getTrailingObjects() + : SourceLocation(); + } + + /// Determines whether this function prototype contains a + /// parameter pack at the end. + /// + /// A function template whose last parameter is a parameter pack can be + /// called with an arbitrary number of arguments, much like a variadic + /// function. + bool isTemplateVariadic() const; + + /// Whether this function prototype has a trailing return type. + bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } + + bool hasCFIUncheckedCallee() const { + return FunctionTypeBits.CFIUncheckedCallee; + } + + Qualifiers getMethodQuals() const { + if (hasExtQualifiers()) + return *getTrailingObjects(); + else + return getFastTypeQuals(); + } + + /// Retrieve the ref-qualifier associated with this function type. + RefQualifierKind getRefQualifier() const { + return static_cast(FunctionTypeBits.RefQualifier); + } + + using param_type_iterator = const QualType *; + + ArrayRef param_types() const { + return {param_type_begin(), param_type_end()}; + } + + param_type_iterator param_type_begin() const { + return getTrailingObjects(); + } + + param_type_iterator param_type_end() const { + return param_type_begin() + getNumParams(); + } + + using exception_iterator = const QualType *; + + ArrayRef exceptions() const { + return {exception_begin(), exception_end()}; + } + + exception_iterator exception_begin() const { + return reinterpret_cast( + getTrailingObjects()); + } + + exception_iterator exception_end() const { + return exception_begin() + getNumExceptions(); + } + + /// Is there any interesting extra information for any of the parameters + /// of this function type? + bool hasExtParameterInfos() const { + return FunctionTypeBits.HasExtParameterInfos; + } + + ArrayRef getExtParameterInfos() const { + assert(hasExtParameterInfos()); + return ArrayRef(getTrailingObjects(), + getNumParams()); + } + + /// Return a pointer to the beginning of the array of extra parameter + /// information, if present, or else null if none of the parameters + /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos. + const ExtParameterInfo *getExtParameterInfosOrNull() const { + if (!hasExtParameterInfos()) + return nullptr; + return getTrailingObjects(); + } + + /// Return the extra attribute information. + FunctionTypeExtraAttributeInfo getExtraAttributeInfo() const { + if (hasExtraAttributeInfo()) + return *getTrailingObjects(); + return FunctionTypeExtraAttributeInfo(); + } + + /// Return a bitmask describing the SME attributes on the function type, see + /// AArch64SMETypeAttributes for their values. + unsigned getAArch64SMEAttributes() const { + if (!hasArmTypeAttributes()) + return SME_NormalFunction; + return getTrailingObjects() + ->AArch64SMEAttributes; + } + + ExtParameterInfo getExtParameterInfo(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasExtParameterInfos()) + return getTrailingObjects()[I]; + return ExtParameterInfo(); + } + + ParameterABI getParameterABI(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasExtParameterInfos()) + return getTrailingObjects()[I].getABI(); + return ParameterABI::Ordinary; + } + + bool isParamConsumed(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasExtParameterInfos()) + return getTrailingObjects()[I].isConsumed(); + return false; + } + + unsigned getNumFunctionEffects() const { + return hasExtraBitfields() + ? getTrailingObjects() + ->NumFunctionEffects + : 0; + } + + // For serialization. + ArrayRef getFunctionEffectsWithoutConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->NumFunctionEffects > 0) + return getTrailingObjects( + Bitfields->NumFunctionEffects); + } + return {}; + } + + unsigned getNumFunctionEffectConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->EffectsHaveConditions) + return Bitfields->NumFunctionEffects; + } + return 0; + } + + // For serialization. + ArrayRef getFunctionEffectConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->EffectsHaveConditions) + return getTrailingObjects( + Bitfields->NumFunctionEffects); + } + return {}; + } + + // Combines effects with their conditions. + FunctionEffectsRef getFunctionEffects() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->NumFunctionEffects > 0) { + const size_t NumConds = Bitfields->EffectsHaveConditions + ? Bitfields->NumFunctionEffects + : 0; + return FunctionEffectsRef( + getTrailingObjects(Bitfields->NumFunctionEffects), + {NumConds ? getTrailingObjects() : nullptr, + NumConds}); + } + } + return {}; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void printExceptionSpecification(raw_ostream &OS, + const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionProto; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); + static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, + param_type_iterator ArgTys, unsigned NumArgs, + const ExtProtoInfo &EPI, const ASTContext &Context, + bool Canonical); +}; + +/// The elaboration keyword that precedes a qualified type name or +/// introduces an elaborated-type-specifier. +enum class ElaboratedTypeKeyword { + /// The "struct" keyword introduces the elaborated-type-specifier. + Struct, + + /// The "__interface" keyword introduces the elaborated-type-specifier. + Interface, + + /// The "union" keyword introduces the elaborated-type-specifier. + Union, + + /// The "class" keyword introduces the elaborated-type-specifier. + Class, + + /// The "enum" keyword introduces the elaborated-type-specifier. + Enum, + + /// The "typename" keyword precedes the qualified type name, e.g., + /// \c typename T::type. + Typename, + + /// No keyword precedes the qualified type name. + None +}; + +/// The kind of a tag type. +enum class TagTypeKind { + /// The "struct" keyword. + Struct, + + /// The "__interface" keyword. + Interface, + + /// The "union" keyword. + Union, + + /// The "class" keyword. + Class, + + /// The "enum" keyword. + Enum +}; + +/// Provides a few static helpers for converting and printing +/// elaborated type keyword and tag type kind enumerations. +struct KeywordHelpers { + /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); + + /// Converts a type specifier (DeclSpec::TST) into a tag type kind. + /// It is an error to provide a type specifier which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); + + /// Converts a TagTypeKind into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); + + /// Converts an elaborated type keyword into a TagTypeKind. + /// It is an error to provide an elaborated type keyword + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); + + static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); + + static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); + + static StringRef getTagTypeKindName(TagTypeKind Kind) { + return getKeywordName(getKeywordForTagTypeKind(Kind)); + } +}; + +template class KeywordWrapper : public T, public KeywordHelpers { +protected: + template + KeywordWrapper(ElaboratedTypeKeyword Keyword, As &&...as) + : T(std::forward(as)...) { + this->KeywordWrapperBits.Keyword = llvm::to_underlying(Keyword); + } + +public: + ElaboratedTypeKeyword getKeyword() const { + return static_cast(this->KeywordWrapperBits.Keyword); + } + + class CannotCastToThisType {}; + static CannotCastToThisType classof(const T *); +}; + +/// A helper class for Type nodes having an ElaboratedTypeKeyword. +/// The keyword in stored in the free bits of the base class. +class TypeWithKeyword : public KeywordWrapper { +protected: + TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, + QualType Canonical, TypeDependence Dependence) + : KeywordWrapper(Keyword, tc, Canonical, Dependence) {} +}; + +template struct FoldingSetPlaceholder : llvm::FoldingSetNode { + void Profile(llvm::FoldingSetNodeID &ID) { getType()->Profile(ID); } + + inline const T *getType() const { + constexpr unsigned long Offset = + llvm::alignTo(sizeof(T), alignof(FoldingSetPlaceholder)); + const auto *Addr = reinterpret_cast( + reinterpret_cast(this) - Offset); + assert(llvm::isAddrAligned(llvm::Align(alignof(T)), Addr)); + return Addr; + } +}; + +/// Represents the dependent type named by a dependently-scoped +/// typename using declaration, e.g. +/// using typename Base::foo; +/// +/// Template instantiation turns these into the underlying type. +class UnresolvedUsingType final + : public TypeWithKeyword, + private llvm::TrailingObjects, + NestedNameSpecifier> { + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; + + UnresolvedUsingTypenameDecl *Decl; + + unsigned numTrailingObjects( + OverloadToken>) const { + assert(UnresolvedUsingBits.hasQualifier || + getKeyword() != ElaboratedTypeKeyword::None); + return 1; + } + + FoldingSetPlaceholder *getFoldingSetPlaceholder() { + assert(numTrailingObjects( + OverloadToken>{}) == + 1); + return getTrailingObjects>(); + } + + UnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, + const Type *CanonicalType); + +public: + NestedNameSpecifier getQualifier() const { + return UnresolvedUsingBits.hasQualifier + ? *getTrailingObjects() + : std::nullopt; + } + + UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D) { + static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7); + ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword)); + if (Qualifier) + Qualifier.Profile(ID); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getQualifier(), getDecl()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnresolvedUsing; + } +}; + +class UsingType final : public TypeWithKeyword, + public llvm::FoldingSetNode, + llvm::TrailingObjects { + UsingShadowDecl *D; + QualType UnderlyingType; + + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; + + UsingType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const UsingShadowDecl *D, QualType UnderlyingType); + +public: + NestedNameSpecifier getQualifier() const { + return UsingBits.hasQualifier ? *getTrailingObjects() : std::nullopt; + } + + UsingShadowDecl *getDecl() const { return D; } + + QualType desugar() const { return UnderlyingType; } + bool isSugared() const { return true; } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const UsingShadowDecl *D, + QualType UnderlyingType) { + static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7); + ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword)); + UnderlyingType.Profile(ID); + if (Qualifier) + Qualifier.Profile(ID); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getQualifier(), D, desugar()); + } + static bool classof(const Type *T) { return T->getTypeClass() == Using; } +}; + +class TypedefType final + : public TypeWithKeyword, + private llvm::TrailingObjects, + NestedNameSpecifier, QualType> { + TypedefNameDecl *Decl; + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; + + unsigned + numTrailingObjects(OverloadToken>) const { + assert(TypedefBits.hasQualifier || TypedefBits.hasTypeDifferentFromDecl || + getKeyword() != ElaboratedTypeKeyword::None); + return 1; + } + + unsigned numTrailingObjects(OverloadToken) const { + return TypedefBits.hasQualifier; + } + + TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TypedefNameDecl *D, + QualType UnderlyingType, bool HasTypeDifferentFromDecl); + + FoldingSetPlaceholder *getFoldingSetPlaceholder() { + assert(numTrailingObjects( + OverloadToken>{}) == 1); + return getTrailingObjects>(); + } + +public: + NestedNameSpecifier getQualifier() const { + return TypedefBits.hasQualifier ? *getTrailingObjects() + : std::nullopt; + } + + TypedefNameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return true; } + + // This always has the 'same' type as declared, but not necessarily identical. + QualType desugar() const; + + // Internal helper, for debugging purposes. + bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypedefNameDecl *Decl, QualType Underlying) { + + ID.AddInteger(uintptr_t(Decl) | (Keyword != ElaboratedTypeKeyword::None) | + (!Qualifier << 1)); + if (Keyword != ElaboratedTypeKeyword::None) + ID.AddInteger(llvm::to_underlying(Keyword)); + if (Qualifier) + Qualifier.Profile(ID); + if (!Underlying.isNull()) + Underlying.Profile(ID); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getQualifier(), getDecl(), + typeMatchesDecl() ? QualType() : desugar()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } +}; + +/// Sugar type that represents a type that was qualified by a qualifier written +/// as a macro invocation. +class MacroQualifiedType : public Type { + friend class ASTContext; // ASTContext creates these. + + QualType UnderlyingTy; + const IdentifierInfo *MacroII; + + MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy, + const IdentifierInfo *MacroII) + : Type(MacroQualified, CanonTy, UnderlyingTy->getDependence()), + UnderlyingTy(UnderlyingTy), MacroII(MacroII) { + assert(isa(UnderlyingTy) && + "Expected a macro qualified type to only wrap attributed types."); + } + +public: + const IdentifierInfo *getMacroIdentifier() const { return MacroII; } + QualType getUnderlyingType() const { return UnderlyingTy; } + + /// Return this attributed type's modified type with no qualifiers attached to + /// it. + QualType getModifiedType() const; + + bool isSugared() const { return true; } + QualType desugar() const; + + static bool classof(const Type *T) { + return T->getTypeClass() == MacroQualified; + } +}; + +/// Represents a `typeof` (or __typeof__) expression (a C23 feature and GCC +/// extension) or a `typeof_unqual` expression (a C23 feature). +class TypeOfExprType : public Type { + Expr *TOExpr; + const ASTContext &Context; + +protected: + friend class ASTContext; // ASTContext creates these. + + TypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind, + QualType Can = QualType()); + +public: + Expr *getUnderlyingExpr() const { return TOExpr; } + + /// Returns the kind of 'typeof' type this is. + TypeOfKind getKind() const { + return static_cast(TypeOfBits.Kind); + } + + /// Remove a single level of sugar. + QualType desugar() const; + + /// Returns whether this type directly provides sugar. + bool isSugared() const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } +}; + +/// Internal representation of canonical, dependent +/// `typeof(expr)` types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via TypeOfExprType nodes. +class DependentTypeOfExprType : public TypeOfExprType, + public llvm::FoldingSetNode { +public: + DependentTypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind) + : TypeOfExprType(Context, E, Kind) {} + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getUnderlyingExpr(), + getKind() == TypeOfKind::Unqualified); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E, bool IsUnqual); +}; + +/// Represents `typeof(type)`, a C23 feature and GCC extension, or +/// `typeof_unqual(type), a C23 feature. +class TypeOfType : public Type { + friend class ASTContext; // ASTContext creates these. + + QualType TOType; + const ASTContext &Context; + + TypeOfType(const ASTContext &Context, QualType T, QualType Can, + TypeOfKind Kind); + +public: + QualType getUnmodifiedType() const { return TOType; } + + /// Remove a single level of sugar. + QualType desugar() const; + + /// Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + /// Returns the kind of 'typeof' type this is. + TypeOfKind getKind() const { + return static_cast(TypeOfBits.Kind); + } + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } +}; + +/// Represents the type `decltype(expr)` (C++11). +class DecltypeType : public Type { + Expr *E; + QualType UnderlyingType; + +protected: + friend class ASTContext; // ASTContext creates these. + + DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); + +public: + Expr *getUnderlyingExpr() const { return E; } + QualType getUnderlyingType() const { return UnderlyingType; } + + /// Remove a single level of sugar. + QualType desugar() const; + + /// Returns whether this type directly provides sugar. + bool isSugared() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } +}; + +/// Internal representation of canonical, dependent +/// decltype(expr) types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via DecltypeType nodes. +class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { +public: + DependentDecltypeType(Expr *E); + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E); +}; + +class PackIndexingType final + : public Type, + public llvm::FoldingSetNode, + private llvm::TrailingObjects { + friend TrailingObjects; + + QualType Pattern; + Expr *IndexExpr; + + unsigned Size : 31; + + LLVM_PREFERRED_TYPE(bool) + unsigned FullySubstituted : 1; + +protected: + friend class ASTContext; // ASTContext creates these. + PackIndexingType(QualType Canonical, QualType Pattern, Expr *IndexExpr, + bool FullySubstituted, ArrayRef Expansions = {}); + +public: + Expr *getIndexExpr() const { return IndexExpr; } + QualType getPattern() const { return Pattern; } + + bool isSugared() const { return hasSelectedType(); } + + QualType desugar() const { + if (hasSelectedType()) + return getSelectedType(); + return QualType(this, 0); + } + + QualType getSelectedType() const { + assert(hasSelectedType() && "Type is dependant"); + return *(getExpansionsPtr() + *getSelectedIndex()); + } + + UnsignedOrNone getSelectedIndex() const; + + bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; } + + bool isFullySubstituted() const { return FullySubstituted; } + + bool expandsToEmptyPack() const { return isFullySubstituted() && Size == 0; } + + ArrayRef getExpansions() const { + return {getExpansionsPtr(), Size}; + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PackIndexing; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context); + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType Pattern, Expr *E, bool FullySubstituted, + ArrayRef Expansions); + +private: + const QualType *getExpansionsPtr() const { return getTrailingObjects(); } + + static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr, + ArrayRef Expansions = {}); +}; + +/// A unary type transform, which is a type constructed from another. +class UnaryTransformType : public Type, public llvm::FoldingSetNode { +public: + enum UTTKind { +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum, +#include "clang/Basic/TransformTypeTraits.def" + }; + +private: + /// The untransformed type. + QualType BaseType; + + /// The transformed type if not dependent, otherwise the same as BaseType. + QualType UnderlyingType; + + UTTKind UKind; + +protected: + friend class ASTContext; + + UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, + QualType CanonicalTy); + +public: + bool isSugared() const { return !isDependentType(); } + QualType desugar() const { return UnderlyingType; } + + QualType getUnderlyingType() const { return UnderlyingType; } + QualType getBaseType() const { return BaseType; } + + UTTKind getUTTKind() const { return UKind; } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnaryTransform; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, + QualType UnderlyingType, UTTKind UKind) { + BaseType.Profile(ID); + UnderlyingType.Profile(ID); + ID.AddInteger(UKind); + } +}; + +class TagType : public TypeWithKeyword { + friend class ASTContext; // ASTContext creates these. + + /// Stores the TagDecl associated with this type. The decl may point to any + /// TagDecl that declares the entity. + TagDecl *decl; + + void *getTrailingPointer() const; + NestedNameSpecifier &getTrailingQualifier() const; + +protected: + TagType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag, + bool IsInjected, const Type *CanonicalType); + +public: + // FIXME: Temporarily renamed from `getDecl` in order to facilitate + // rebasing, due to change in behaviour. This should be renamed back + // to `getDecl` once the change is settled. + TagDecl *getOriginalDecl() const { return decl; } + + NestedNameSpecifier getQualifier() const; + + /// Does the TagType own this declaration of the Tag? + bool isTagOwned() const { return TagTypeBits.OwnsTag; } + + bool isInjected() const { return TagTypeBits.IsInjected; } + + ClassTemplateDecl *getTemplateDecl() const; + TemplateName getTemplateName(const ASTContext &Ctx) const; + ArrayRef getTemplateArgs(const ASTContext &Ctx) const; + + bool isSugared() const { return false; } + QualType desugar() const { return getCanonicalTypeInternal(); } + + static bool classof(const Type *T) { + return T->getTypeClass() == Enum || T->getTypeClass() == Record || + T->getTypeClass() == InjectedClassName; + } +}; + +struct TagTypeFoldingSetPlaceholder : public llvm::FoldingSetNode { + static constexpr size_t getOffset() { + return alignof(TagType) - + (sizeof(TagTypeFoldingSetPlaceholder) % alignof(TagType)); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *Tag, + bool OwnsTag, bool IsInjected) { + ID.AddInteger(uintptr_t(Tag) | OwnsTag | (IsInjected << 1) | + ((Keyword != ElaboratedTypeKeyword::None) << 2)); + if (Keyword != ElaboratedTypeKeyword::None) + ID.AddInteger(llvm::to_underlying(Keyword)); + if (Qualifier) + Qualifier.Profile(ID); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + const TagType *T = getTagType(); + Profile(ID, T->getKeyword(), T->getQualifier(), T->getOriginalDecl(), + T->isTagOwned(), T->isInjected()); + } + + TagType *getTagType() { + return reinterpret_cast(reinterpret_cast(this + 1) + + getOffset()); + } + const TagType *getTagType() const { + return const_cast(this)->getTagType(); + } + static TagTypeFoldingSetPlaceholder *fromTagType(TagType *T) { + return reinterpret_cast( + reinterpret_cast(T) - getOffset()) - + 1; + } +}; + +/// A helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of structs/unions/classes. +class RecordType final : public TagType { + using TagType::TagType; + +public: + // FIXME: Temporarily renamed from `getDecl` in order to facilitate + // rebasing, due to change in behaviour. This should be renamed back + // to `getDecl` once the change is settled. + RecordDecl *getOriginalDecl() const { + return reinterpret_cast(TagType::getOriginalDecl()); + } + + /// Recursively check all fields in the record for const-ness. If any field + /// is declared const, return true. Otherwise, return false. + bool hasConstFields() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Record; } +}; + +/// A helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of enums. +class EnumType final : public TagType { + using TagType::TagType; + +public: + // FIXME: Temporarily renamed from `getDecl` in order to facilitate + // rebasing, due to change in behaviour. This should be renamed back + // to `getDecl` once the change is settled. + EnumDecl *getOriginalDecl() const { + return reinterpret_cast(TagType::getOriginalDecl()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Enum; } +}; + +/// The injected class name of a C++ class template or class +/// template partial specialization. Used to record that a type was +/// spelled with a bare identifier rather than as a template-id; the +/// equivalent for non-templated classes is just RecordType. +/// +/// Injected class name types are always dependent. Template +/// instantiation turns these into RecordTypes. +/// +/// Injected class name types are always canonical. This works +/// because it is impossible to compare an injected class name type +/// with the corresponding non-injected template type, for the same +/// reason that it is impossible to directly compare template +/// parameters from different dependent contexts: injected class name +/// types can only occur within the scope of a particular templated +/// declaration, and within that scope every template specialization +/// will canonicalize to the injected class name (when appropriate +/// according to the rules of the language). +class InjectedClassNameType final : public TagType { + friend class ASTContext; // ASTContext creates these. + + InjectedClassNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *TD, + bool IsInjected, const Type *CanonicalType); + +public: + // FIXME: Temporarily renamed from `getDecl` in order to facilitate + // rebasing, due to change in behaviour. This should be renamed back + // to `getDecl` once the change is settled. + CXXRecordDecl *getOriginalDecl() const { + return reinterpret_cast(TagType::getOriginalDecl()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == InjectedClassName; + } +}; + +/// An attributed type is a type to which a type attribute has been applied. +/// +/// The "modified type" is the fully-sugared type to which the attributed +/// type was applied; generally it is not canonically equivalent to the +/// attributed type. The "equivalent type" is the minimally-desugared type +/// which the type is canonically equivalent to. +/// +/// For example, in the following attributed type: +/// int32_t __attribute__((vector_size(16))) +/// - the modified type is the TypedefType for int32_t +/// - the equivalent type is VectorType(16, int32_t) +/// - the canonical type is VectorType(16, int) +class AttributedType : public Type, public llvm::FoldingSetNode { +public: + using Kind = attr::Kind; + +private: + friend class ASTContext; // ASTContext creates these + + const Attr *Attribute; + + QualType ModifiedType; + QualType EquivalentType; + + AttributedType(QualType canon, attr::Kind attrKind, QualType modified, + QualType equivalent) + : AttributedType(canon, attrKind, nullptr, modified, equivalent) {} + + AttributedType(QualType canon, const Attr *attr, QualType modified, + QualType equivalent); + +private: + AttributedType(QualType canon, attr::Kind attrKind, const Attr *attr, + QualType modified, QualType equivalent); + +public: + Kind getAttrKind() const { + return static_cast(AttributedTypeBits.AttrKind); + } + + const Attr *getAttr() const { return Attribute; } + + QualType getModifiedType() const { return ModifiedType; } + QualType getEquivalentType() const { return EquivalentType; } + + bool isSugared() const { return true; } + QualType desugar() const { return getEquivalentType(); } + + /// Does this attribute behave like a type qualifier? + /// + /// A type qualifier adjusts a type to provide specialized rules for + /// a specific object, like the standard const and volatile qualifiers. + /// This includes attributes controlling things like nullability, + /// address spaces, and ARC ownership. The value of the object is still + /// largely described by the modified type. + /// + /// In contrast, many type attributes "rewrite" their modified type to + /// produce a fundamentally different type, not necessarily related in any + /// formalizable way to the original type. For example, calling convention + /// and vector attributes are not simple type qualifiers. + /// + /// Type qualifiers are often, but not always, reflected in the canonical + /// type. + bool isQualifier() const; + + bool isMSTypeSpec() const; + + bool isWebAssemblyFuncrefSpec() const; + + bool isCallingConv() const; + + std::optional getImmediateNullability() const; + + /// Strip off the top-level nullability annotation on the given + /// type, if it's there. + /// + /// \param T The type to strip. If the type is exactly an + /// AttributedType specifying nullability (without looking through + /// type sugar), the nullability is returned and this type changed + /// to the underlying modified type. + /// + /// \returns the top-level nullability, if present. + static std::optional stripOuterNullability(QualType &T); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, + QualType modified, QualType equivalent, + const Attr *attr) { + ID.AddInteger(attrKind); + ID.AddPointer(modified.getAsOpaquePtr()); + ID.AddPointer(equivalent.getAsOpaquePtr()); + ID.AddPointer(attr); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Attributed; + } +}; + +class BTFTagAttributedType : public Type, public llvm::FoldingSetNode { +private: + friend class ASTContext; // ASTContext creates these + + QualType WrappedType; + const BTFTypeTagAttr *BTFAttr; + + BTFTagAttributedType(QualType Canon, QualType Wrapped, + const BTFTypeTagAttr *BTFAttr) + : Type(BTFTagAttributed, Canon, Wrapped->getDependence()), + WrappedType(Wrapped), BTFAttr(BTFAttr) {} + +public: + QualType getWrappedType() const { return WrappedType; } + const BTFTypeTagAttr *getAttr() const { return BTFAttr; } + + bool isSugared() const { return true; } + QualType desugar() const { return getWrappedType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, WrappedType, BTFAttr); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped, + const BTFTypeTagAttr *BTFAttr) { + ID.AddPointer(Wrapped.getAsOpaquePtr()); + ID.AddPointer(BTFAttr); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == BTFTagAttributed; + } +}; + +class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode { +public: + struct Attributes { + // Data gathered from HLSL resource attributes + llvm::dxil::ResourceClass ResourceClass; + + LLVM_PREFERRED_TYPE(bool) + uint8_t IsROV : 1; + + LLVM_PREFERRED_TYPE(bool) + uint8_t RawBuffer : 1; + + Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false, + bool RawBuffer = false) + : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {} + + Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {} + + friend bool operator==(const Attributes &LHS, const Attributes &RHS) { + return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) == + std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer); + } + friend bool operator!=(const Attributes &LHS, const Attributes &RHS) { + return !(LHS == RHS); + } + }; + +private: + friend class ASTContext; // ASTContext creates these + + QualType WrappedType; + QualType ContainedType; + const Attributes Attrs; + + HLSLAttributedResourceType(QualType Wrapped, QualType Contained, + const Attributes &Attrs) + : Type(HLSLAttributedResource, QualType(), + Contained.isNull() ? TypeDependence::None + : Contained->getDependence()), + WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {} + +public: + QualType getWrappedType() const { return WrappedType; } + QualType getContainedType() const { return ContainedType; } + bool hasContainedType() const { return !ContainedType.isNull(); } + const Attributes &getAttrs() const { return Attrs; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, WrappedType, ContainedType, Attrs); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped, + QualType Contained, const Attributes &Attrs) { + ID.AddPointer(Wrapped.getAsOpaquePtr()); + ID.AddPointer(Contained.getAsOpaquePtr()); + ID.AddInteger(static_cast(Attrs.ResourceClass)); + ID.AddBoolean(Attrs.IsROV); + ID.AddBoolean(Attrs.RawBuffer); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == HLSLAttributedResource; + } + + // Returns handle type from HLSL resource, if the type is a resource + static const HLSLAttributedResourceType * + findHandleTypeOnResource(const Type *RT); +}; + +/// Instances of this class represent operands to a SPIR-V type instruction. +class SpirvOperand { +public: + enum SpirvOperandKind : unsigned char { + Invalid, ///< Uninitialized. + ConstantId, ///< Integral value to represent as a SPIR-V OpConstant + ///< instruction ID. + Literal, ///< Integral value to represent as an immediate literal. + TypeId, ///< Type to represent as a SPIR-V type ID. + + Max, + }; + +private: + SpirvOperandKind Kind = Invalid; + + QualType ResultType; + llvm::APInt Value; // Signedness of constants is represented by ResultType. + +public: + SpirvOperand() : Kind(Invalid), ResultType(), Value() {} + + SpirvOperand(SpirvOperandKind Kind, QualType ResultType, llvm::APInt Value) + : Kind(Kind), ResultType(ResultType), Value(std::move(Value)) {} + + SpirvOperand(const SpirvOperand &Other) { *this = Other; } + ~SpirvOperand() {} + + SpirvOperand &operator=(const SpirvOperand &Other) = default; + + bool operator==(const SpirvOperand &Other) const { + return Kind == Other.Kind && ResultType == Other.ResultType && + Value == Other.Value; + } + + bool operator!=(const SpirvOperand &Other) const { return !(*this == Other); } + + SpirvOperandKind getKind() const { return Kind; } + + bool isValid() const { return Kind != Invalid && Kind < Max; } + bool isConstant() const { return Kind == ConstantId; } + bool isLiteral() const { return Kind == Literal; } + bool isType() const { return Kind == TypeId; } + + llvm::APInt getValue() const { + assert((isConstant() || isLiteral()) && + "This is not an operand with a value!"); + return Value; + } + + QualType getResultType() const { + assert((isConstant() || isType()) && + "This is not an operand with a result type!"); + return ResultType; + } + + static SpirvOperand createConstant(QualType ResultType, llvm::APInt Val) { + return SpirvOperand(ConstantId, ResultType, std::move(Val)); + } + + static SpirvOperand createLiteral(llvm::APInt Val) { + return SpirvOperand(Literal, QualType(), std::move(Val)); + } + + static SpirvOperand createType(QualType T) { + return SpirvOperand(TypeId, T, llvm::APSInt()); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Kind); + ID.AddPointer(ResultType.getAsOpaquePtr()); + Value.Profile(ID); + } +}; + +/// Represents an arbitrary, user-specified SPIR-V type instruction. +class HLSLInlineSpirvType final + : public Type, + public llvm::FoldingSetNode, + private llvm::TrailingObjects { + friend class ASTContext; // ASTContext creates these + friend TrailingObjects; + +private: + uint32_t Opcode; + uint32_t Size; + uint32_t Alignment; + size_t NumOperands; + + HLSLInlineSpirvType(uint32_t Opcode, uint32_t Size, uint32_t Alignment, + ArrayRef Operands) + : Type(HLSLInlineSpirv, QualType(), TypeDependence::None), Opcode(Opcode), + Size(Size), Alignment(Alignment), NumOperands(Operands.size()) { + for (size_t I = 0; I < NumOperands; I++) { + // Since Operands are stored as a trailing object, they have not been + // initialized yet. Call the constructor manually. + auto *Operand = new (&getTrailingObjects()[I]) SpirvOperand(); + *Operand = Operands[I]; + } + } + +public: + uint32_t getOpcode() const { return Opcode; } + uint32_t getSize() const { return Size; } + uint32_t getAlignment() const { return Alignment; } + ArrayRef getOperands() const { + return getTrailingObjects(NumOperands); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Opcode, Size, Alignment, getOperands()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, uint32_t Opcode, + uint32_t Size, uint32_t Alignment, + ArrayRef Operands) { + ID.AddInteger(Opcode); + ID.AddInteger(Size); + ID.AddInteger(Alignment); + for (auto &Operand : Operands) + Operand.Profile(ID); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == HLSLInlineSpirv; + } +}; + +class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + + // The associated TemplateTypeParmDecl for the non-canonical type. + TemplateTypeParmDecl *TTPDecl; + + TemplateTypeParmType(unsigned D, unsigned I, bool PP, + TemplateTypeParmDecl *TTPDecl, QualType Canon) + : Type(TemplateTypeParm, Canon, + TypeDependence::DependentInstantiation | + (PP ? TypeDependence::UnexpandedPack : TypeDependence::None)), + TTPDecl(TTPDecl) { + assert(!TTPDecl == Canon.isNull()); + TemplateTypeParmTypeBits.Depth = D; + TemplateTypeParmTypeBits.Index = I; + TemplateTypeParmTypeBits.ParameterPack = PP; + } + +public: + unsigned getDepth() const { return TemplateTypeParmTypeBits.Depth; } + unsigned getIndex() const { return TemplateTypeParmTypeBits.Index; } + bool isParameterPack() const { + return TemplateTypeParmTypeBits.ParameterPack; + } + + TemplateTypeParmDecl *getDecl() const { return TTPDecl; } + + IdentifierInfo *getIdentifier() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, + unsigned Index, bool ParameterPack, + TemplateTypeParmDecl *TTPDecl) { + ID.AddInteger(Depth); + ID.AddInteger(Index); + ID.AddBoolean(ParameterPack); + ID.AddPointer(TTPDecl); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateTypeParm; + } +}; + +/// Represents the result of substituting a type for a template +/// type parameter. +/// +/// Within an instantiated template, all template type parameters have +/// been replaced with these. They are used solely to record that a +/// type was originally written as a template type parameter; +/// therefore they are never canonical. +class SubstTemplateTypeParmType final + : public Type, + public llvm::FoldingSetNode, + private llvm::TrailingObjects { + friend class ASTContext; + friend class llvm::TrailingObjects; + + Decl *AssociatedDecl; + + SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl, + unsigned Index, UnsignedOrNone PackIndex, + bool Final); + +public: + /// Gets the type that was substituted for the template + /// parameter. + QualType getReplacementType() const { + return SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType + ? *getTrailingObjects() + : getCanonicalTypeInternal(); + } + + /// A template-like entity which owns the whole pattern being substituted. + /// This will usually own a set of template parameters, or in some + /// cases might even be a template parameter itself. + Decl *getAssociatedDecl() const { return AssociatedDecl; } + + /// Gets the template parameter declaration that was substituted for. + const TemplateTypeParmDecl *getReplacedParameter() const; + + /// Returns the index of the replaced parameter in the associated declaration. + /// This should match the result of `getReplacedParameter()->getIndex()`. + unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; } + + // This substitution is Final, which means the substitution is fully + // sugared: it doesn't need to be resugared later. + unsigned getFinal() const { return SubstTemplateTypeParmTypeBits.Final; } + + UnsignedOrNone getPackIndex() const { + return UnsignedOrNone::fromInternalRepresentation( + SubstTemplateTypeParmTypeBits.PackIndex); + } + + bool isSugared() const { return true; } + QualType desugar() const { return getReplacementType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(), + getPackIndex(), getFinal()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement, + const Decl *AssociatedDecl, unsigned Index, + UnsignedOrNone PackIndex, bool Final); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParm; + } +}; + +/// Represents the result of substituting a set of types as a template argument +/// that needs to be expanded later. +/// +/// These types are always dependent and produced depending on the situations: +/// - SubstTemplateTypeParmPack is an expansion that had to be delayed, +/// - SubstBuiltinTemplatePackType is an expansion from a builtin. +class SubstPackType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + + /// A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + +protected: + SubstPackType(TypeClass Derived, QualType Canon, + const TemplateArgument &ArgPack); + +public: + unsigned getNumArgs() const { return SubstPackTypeBits.NumArgs; } + + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateArgument &ArgPack); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParmPack || + T->getTypeClass() == SubstBuiltinTemplatePack; + } +}; + +/// Represents the result of substituting a builtin template as a pack. +class SubstBuiltinTemplatePackType : public SubstPackType { + friend class ASTContext; + + SubstBuiltinTemplatePackType(QualType Canon, const TemplateArgument &ArgPack); + +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + /// Mark that we reuse the Profile. We do not introduce new fields. + using SubstPackType::Profile; + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstBuiltinTemplatePack; + } +}; + +/// Represents the result of substituting a set of types for a template +/// type parameter pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this type node is used to represent a template type +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType +/// at the current pack substitution index. +class SubstTemplateTypeParmPackType : public SubstPackType { + friend class ASTContext; + + /// A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + llvm::PointerIntPair AssociatedDeclAndFinal; + + SubstTemplateTypeParmPackType(QualType Canon, Decl *AssociatedDecl, + unsigned Index, bool Final, + const TemplateArgument &ArgPack); + +public: + IdentifierInfo *getIdentifier() const; + + /// A template-like entity which owns the whole pattern being substituted. + /// This will usually own a set of template parameters, or in some + /// cases might even be a template parameter itself. + Decl *getAssociatedDecl() const; + + /// Gets the template parameter declaration that was substituted for. + const TemplateTypeParmDecl *getReplacedParameter() const; + + /// Returns the index of the replaced parameter in the associated declaration. + /// This should match the result of `getReplacedParameter()->getIndex()`. + unsigned getIndex() const { + return SubstPackTypeBits.SubstTemplTypeParmPackIndex; + } + + // This substitution will be Final, which means the substitution will be fully + // sugared: it doesn't need to be resugared later. + bool getFinal() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl, + unsigned Index, bool Final, + const TemplateArgument &ArgPack); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParmPack; + } +}; + +/// Common base class for placeholders for types that get replaced by +/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced +/// class template types, and constrained type names. +/// +/// These types are usually a placeholder for a deduced type. However, before +/// the initializer is attached, or (usually) if the initializer is +/// type-dependent, there is no deduced type and the type is canonical. In +/// the latter case, it is also a dependent type. +class DeducedType : public Type { + QualType DeducedAsType; + +protected: + DeducedType(TypeClass TC, QualType DeducedAsType, + TypeDependence ExtraDependence, QualType Canon) + : Type(TC, Canon, + ExtraDependence | (DeducedAsType.isNull() + ? TypeDependence::None + : DeducedAsType->getDependence() & + ~TypeDependence::VariablyModified)), + DeducedAsType(DeducedAsType) {} + +public: + bool isSugared() const { return !DeducedAsType.isNull(); } + QualType desugar() const { + return isSugared() ? DeducedAsType : QualType(this, 0); + } + + /// Get the type deduced for this placeholder type, or null if it + /// has not been deduced. + QualType getDeducedType() const { return DeducedAsType; } + bool isDeduced() const { + return !DeducedAsType.isNull() || isDependentType(); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Auto || + T->getTypeClass() == DeducedTemplateSpecialization; + } +}; + +/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained +/// by a type-constraint. +class AutoType : public DeducedType { + friend class ASTContext; // ASTContext creates these + + TemplateDecl *TypeConstraintConcept; + + AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, + TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD, + ArrayRef TypeConstraintArgs); + +public: + ArrayRef getTypeConstraintArguments() const { + return {reinterpret_cast(this + 1), + AutoTypeBits.NumArgs}; + } + + TemplateDecl *getTypeConstraintConcept() const { + return TypeConstraintConcept; + } + + bool isConstrained() const { + return TypeConstraintConcept != nullptr; + } + + bool isDecltypeAuto() const { + return getKeyword() == AutoTypeKeyword::DecltypeAuto; + } + + bool isGNUAutoType() const { + return getKeyword() == AutoTypeKeyword::GNUAutoType; + } + + AutoTypeKeyword getKeyword() const { + return (AutoTypeKeyword)AutoTypeBits.Keyword; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context); + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType Deduced, AutoTypeKeyword Keyword, + bool IsDependent, TemplateDecl *CD, + ArrayRef Arguments); + + static bool classof(const Type *T) { + return T->getTypeClass() == Auto; + } +}; + +/// Represents a C++17 deduced template specialization type. +class DeducedTemplateSpecializationType : public KeywordWrapper, + public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + + /// The name of the template whose arguments will be deduced. + TemplateName Template; + + DeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + TemplateName Template, + QualType DeducedAsType, + bool IsDeducedAsDependent, QualType Canon) + : KeywordWrapper(Keyword, DeducedTemplateSpecialization, DeducedAsType, + toTypeDependence(Template.getDependence()) | + (IsDeducedAsDependent + ? TypeDependence::DependentInstantiation + : TypeDependence::None), + Canon), + Template(Template) {} + +public: + /// Retrieve the name of the template that we are deducing. + TemplateName getTemplateName() const { return Template; } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getTemplateName(), getDeducedType(), + isDependentType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + TemplateName Template, QualType Deduced, + bool IsDependent) { + ID.AddInteger(llvm::to_underlying(Keyword)); + Template.Profile(ID); + Deduced.Profile(ID); + ID.AddBoolean(IsDependent || Template.isDependent()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == DeducedTemplateSpecialization; + } +}; + +/// Represents a type template specialization; the template +/// must be a class template, a type alias template, or a template +/// template parameter. A template which cannot be resolved to one of +/// these, e.g. because it is written with a dependent scope +/// specifier, is instead represented as a +/// @c DependentTemplateSpecializationType. +/// +/// A non-dependent template specialization type is always "sugar", +/// typically for a \c RecordType. For example, a class template +/// specialization type of \c vector will refer to a tag type for +/// the instantiation \c std::vector> +/// +/// Template specializations are dependent if either the template or +/// any of the template arguments are dependent, in which case the +/// type may also be canonical. +/// +/// Instances of this type are allocated with a trailing array of +/// TemplateArguments, followed by a QualType representing the +/// non-canonical aliased type when the template is a type alias +/// template. +class TemplateSpecializationType : public TypeWithKeyword, + public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + + /// The name of the template being specialized. This is + /// either a TemplateName::Template (in which case it is a + /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a + /// TypeAliasTemplateDecl*), a + /// TemplateName::SubstTemplateTemplateParmPack, or a + /// TemplateName::SubstTemplateTemplateParm (in which case the + /// replacement must, recursively, be one of these). + TemplateName Template; + + TemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, + bool IsAlias, ArrayRef Args, + QualType Underlying); + +public: + /// Determine whether any of the given template arguments are dependent. + /// + /// The converted arguments should be supplied when known; whether an + /// argument is dependent can depend on the conversions performed on it + /// (for example, a 'const int' passed as a template argument might be + /// dependent if the parameter is a reference but non-dependent if the + /// parameter is an int). + /// + /// Note that the \p Args parameter is unused: this is intentional, to remind + /// the caller that they need to pass in the converted arguments, not the + /// specified arguments. + static bool + anyDependentTemplateArguments(ArrayRef Args, + ArrayRef Converted); + static bool + anyDependentTemplateArguments(const TemplateArgumentListInfo &, + ArrayRef Converted); + static bool anyInstantiationDependentTemplateArguments( + ArrayRef Args); + + /// True if this template specialization type matches a current + /// instantiation in the context in which it is found. + bool isCurrentInstantiation() const { + return isa(getCanonicalTypeInternal()); + } + + /// Determine if this template specialization type is for a type alias + /// template that has been substituted. + /// + /// Nearly every template specialization type whose template is an alias + /// template will be substituted. However, this is not the case when + /// the specialization contains a pack expansion but the template alias + /// does not have a corresponding parameter pack, e.g., + /// + /// \code + /// template struct S; + /// template using A = S; + /// template struct X { + /// typedef A type; // not a type alias + /// }; + /// \endcode + bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } + + /// Get the aliased type, if this is a specialization of a type alias + /// template. + QualType getAliasedType() const; + + /// Retrieve the name of the template that we are specializing. + TemplateName getTemplateName() const { return Template; } + + ArrayRef template_arguments() const { + return {reinterpret_cast(this + 1), + TemplateSpecializationTypeBits.NumArgs}; + } + + bool isSugared() const; + + QualType desugar() const { + return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + ArrayRef Args, QualType Underlying, + const ASTContext &Context); + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateSpecialization; + } +}; + +/// Print a template argument list, including the '<' and '>' +/// enclosing the template arguments. +void printTemplateArgumentList(raw_ostream &OS, + ArrayRef Args, + const PrintingPolicy &Policy, + const TemplateParameterList *TPL = nullptr); + +void printTemplateArgumentList(raw_ostream &OS, + ArrayRef Args, + const PrintingPolicy &Policy, + const TemplateParameterList *TPL = nullptr); + +void printTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy, + const TemplateParameterList *TPL = nullptr); + +/// Make a best-effort determination of whether the type T can be produced by +/// substituting Args into the default argument of Param. +bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg, + const NamedDecl *Param, + ArrayRef Args, + unsigned Depth); + +/// Represents a qualified type name for which the type name is +/// dependent. +/// +/// DependentNameType represents a class of dependent types that involve a +/// possibly dependent nested-name-specifier (e.g., "T::") followed by a +/// name of a type. The DependentNameType may start with a "typename" (for a +/// typename-specifier), "class", "struct", "union", or "enum" (for a +/// dependent elaborated-type-specifier), or nothing (in contexts where we +/// know that we must be referring to a type, e.g., in a base class specifier). +/// Typically the nested-name-specifier is dependent, but in MSVC compatibility +/// mode, this type is used with non-dependent names to delay name lookup until +/// instantiation. +class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + + /// The nested name specifier containing the qualifier. + NestedNameSpecifier NNS; + + /// The type that this typename specifier refers to. + const IdentifierInfo *Name; + + DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier NNS, + const IdentifierInfo *Name, QualType CanonType) + : TypeWithKeyword(Keyword, DependentName, CanonType, + TypeDependence::DependentInstantiation | + (NNS ? toTypeDependence(NNS.getDependence()) + : TypeDependence::Dependent)), + NNS(NNS), Name(Name) { + assert(Name); + } + +public: + /// Retrieve the qualification on this type. + NestedNameSpecifier getQualifier() const { return NNS; } + + /// Retrieve the identifier that terminates this type name. + /// For example, "type" in "typename T::type". + const IdentifierInfo *getIdentifier() const { + return Name; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getKeyword(), NNS, Name); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier NNS, const IdentifierInfo *Name) { + ID.AddInteger(llvm::to_underlying(Keyword)); + NNS.Profile(ID); + ID.AddPointer(Name); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentName; + } +}; + +/// Represents a template specialization type whose template cannot be +/// resolved, e.g. +/// A::template B +class DependentTemplateSpecializationType : public TypeWithKeyword { + friend class ASTContext; // ASTContext creates these + + DependentTemplateStorage Name; + + DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + const DependentTemplateStorage &Name, + ArrayRef Args, + QualType Canon); + +public: + const DependentTemplateStorage &getDependentTemplateName() const { + return Name; + } + + ArrayRef template_arguments() const { + return {reinterpret_cast(this + 1), + DependentTemplateSpecializationTypeBits.NumArgs}; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getKeyword(), Name, template_arguments()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + ElaboratedTypeKeyword Keyword, + const DependentTemplateStorage &Name, + ArrayRef Args); + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentTemplateSpecialization; + } +}; + +/// Represents a pack expansion of types. +/// +/// Pack expansions are part of C++11 variadic templates. A pack +/// expansion contains a pattern, which itself contains one or more +/// "unexpanded" parameter packs. When instantiated, a pack expansion +/// produces a series of types, each instantiated from the pattern of +/// the expansion, where the Ith instantiation of the pattern uses the +/// Ith arguments bound to each of the unexpanded parameter packs. The +/// pack expansion is considered to "expand" these unexpanded +/// parameter packs. +/// +/// \code +/// template struct tuple; +/// +/// template +/// struct tuple_of_references { +/// typedef tuple type; +/// }; +/// \endcode +/// +/// Here, the pack expansion \c Types&... is represented via a +/// PackExpansionType whose pattern is Types&. +class PackExpansionType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + + /// The pattern of the pack expansion. + QualType Pattern; + + PackExpansionType(QualType Pattern, QualType Canon, + UnsignedOrNone NumExpansions) + : Type(PackExpansion, Canon, + (Pattern->getDependence() | TypeDependence::Dependent | + TypeDependence::Instantiation) & + ~TypeDependence::UnexpandedPack), + Pattern(Pattern) { + PackExpansionTypeBits.NumExpansions = + NumExpansions ? *NumExpansions + 1 : 0; + } + +public: + /// Retrieve the pattern of this pack expansion, which is the + /// type that will be repeatedly instantiated when instantiating the + /// pack expansion itself. + QualType getPattern() const { return Pattern; } + + /// Retrieve the number of expansions that this pack expansion will + /// generate, if known. + UnsignedOrNone getNumExpansions() const { + if (PackExpansionTypeBits.NumExpansions) + return PackExpansionTypeBits.NumExpansions - 1; + return std::nullopt; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPattern(), getNumExpansions()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, + UnsignedOrNone NumExpansions) { + ID.AddPointer(Pattern.getAsOpaquePtr()); + ID.AddInteger(NumExpansions.toInternalRepresentation()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PackExpansion; + } +}; + +/// This class wraps the list of protocol qualifiers. For types that can +/// take ObjC protocol qualifers, they can subclass this class. +template +class ObjCProtocolQualifiers { +protected: + ObjCProtocolQualifiers() = default; + + ObjCProtocolDecl * const *getProtocolStorage() const { + return const_cast(this)->getProtocolStorage(); + } + + ObjCProtocolDecl **getProtocolStorage() { + return static_cast(this)->getProtocolStorageImpl(); + } + + void setNumProtocols(unsigned N) { + static_cast(this)->setNumProtocolsImpl(N); + } + + void initialize(ArrayRef protocols) { + setNumProtocols(protocols.size()); + assert(getNumProtocols() == protocols.size() && + "bitfield overflow in protocol count"); + if (!protocols.empty()) + memcpy(getProtocolStorage(), protocols.data(), + protocols.size() * sizeof(ObjCProtocolDecl*)); + } + +public: + using qual_iterator = ObjCProtocolDecl * const *; + using qual_range = llvm::iterator_range; + + qual_range quals() const { return qual_range(qual_begin(), qual_end()); } + qual_iterator qual_begin() const { return getProtocolStorage(); } + qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } + + bool qual_empty() const { return getNumProtocols() == 0; } + + /// Return the number of qualifying protocols in this type, or 0 if + /// there are none. + unsigned getNumProtocols() const { + return static_cast(this)->getNumProtocolsImpl(); + } + + /// Fetch a protocol by index. + ObjCProtocolDecl *getProtocol(unsigned I) const { + assert(I < getNumProtocols() && "Out-of-range protocol access"); + return qual_begin()[I]; + } + + /// Retrieve all of the protocol qualifiers. + ArrayRef getProtocols() const { + return ArrayRef(qual_begin(), getNumProtocols()); + } +}; + +/// Represents a type parameter type in Objective C. It can take +/// a list of protocols. +class ObjCTypeParamType : public Type, + public ObjCProtocolQualifiers, + public llvm::FoldingSetNode { + friend class ASTContext; + friend class ObjCProtocolQualifiers; + + /// The number of protocols stored on this type. + unsigned NumProtocols : 6; + + ObjCTypeParamDecl *OTPDecl; + + /// The protocols are stored after the ObjCTypeParamType node. In the + /// canonical type, the list of protocols are sorted alphabetically + /// and uniqued. + ObjCProtocolDecl **getProtocolStorageImpl(); + + /// Return the number of qualifying protocols in this interface type, + /// or 0 if there are none. + unsigned getNumProtocolsImpl() const { + return NumProtocols; + } + + void setNumProtocolsImpl(unsigned N) { + NumProtocols = N; + } + + ObjCTypeParamType(const ObjCTypeParamDecl *D, + QualType can, + ArrayRef protocols); + +public: + bool isSugared() const { return true; } + QualType desugar() const { return getCanonicalTypeInternal(); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCTypeParam; + } + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const ObjCTypeParamDecl *OTPDecl, + QualType CanonicalType, + ArrayRef protocols); + + ObjCTypeParamDecl *getDecl() const { return OTPDecl; } +}; + +/// Represents a class type in Objective C. +/// +/// Every Objective C type is a combination of a base type, a set of +/// type arguments (optional, for parameterized classes) and a list of +/// protocols. +/// +/// Given the following declarations: +/// \code +/// \@class C; +/// \@protocol P; +/// \endcode +/// +/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType +/// with base C and no protocols. +/// +/// 'C

' is an unspecialized ObjCObjectType with base C and protocol list [P]. +/// 'C' is a specialized ObjCObjectType with type arguments 'C*' and no +/// protocol list. +/// 'C

' is a specialized ObjCObjectType with base C, type arguments 'C*', +/// and protocol list [P]. +/// +/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose +/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType +/// and no protocols. +/// +/// 'id

' is an ObjCObjectPointerType whose pointee is an ObjCObjectType +/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually +/// this should get its own sugar class to better represent the source. +class ObjCObjectType : public Type, + public ObjCProtocolQualifiers { + friend class ObjCProtocolQualifiers; + + // ObjCObjectType.NumTypeArgs - the number of type arguments stored + // after the ObjCObjectPointerType node. + // ObjCObjectType.NumProtocols - the number of protocols stored + // after the type arguments of ObjCObjectPointerType node. + // + // These protocols are those written directly on the type. If + // protocol qualifiers ever become additive, the iterators will need + // to get kindof complicated. + // + // In the canonical object type, these are sorted alphabetically + // and uniqued. + + /// Either a BuiltinType or an InterfaceType or sugar for either. + QualType BaseType; + + /// Cached superclass type. + mutable llvm::PointerIntPair + CachedSuperClassType; + + QualType *getTypeArgStorage(); + const QualType *getTypeArgStorage() const { + return const_cast(this)->getTypeArgStorage(); + } + + ObjCProtocolDecl **getProtocolStorageImpl(); + /// Return the number of qualifying protocols in this interface type, + /// or 0 if there are none. + unsigned getNumProtocolsImpl() const { + return ObjCObjectTypeBits.NumProtocols; + } + void setNumProtocolsImpl(unsigned N) { + ObjCObjectTypeBits.NumProtocols = N; + } + +protected: + enum Nonce_ObjCInterface { Nonce_ObjCInterface }; + + ObjCObjectType(QualType Canonical, QualType Base, + ArrayRef typeArgs, + ArrayRef protocols, + bool isKindOf); + + ObjCObjectType(enum Nonce_ObjCInterface) + : Type(ObjCInterface, QualType(), TypeDependence::None), + BaseType(QualType(this_(), 0)) { + ObjCObjectTypeBits.NumProtocols = 0; + ObjCObjectTypeBits.NumTypeArgs = 0; + ObjCObjectTypeBits.IsKindOf = 0; + } + + void computeSuperClassTypeSlow() const; + +public: + /// Gets the base type of this object type. This is always (possibly + /// sugar for) one of: + /// - the 'id' builtin type (as opposed to the 'id' type visible to the + /// user, which is a typedef for an ObjCObjectPointerType) + /// - the 'Class' builtin type (same caveat) + /// - an ObjCObjectType (currently always an ObjCInterfaceType) + QualType getBaseType() const { return BaseType; } + + bool isObjCId() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); + } + + bool isObjCClass() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); + } + + bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } + bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } + bool isObjCUnqualifiedIdOrClass() const { + if (!qual_empty()) return false; + if (const BuiltinType *T = getBaseType()->getAs()) + return T->getKind() == BuiltinType::ObjCId || + T->getKind() == BuiltinType::ObjCClass; + return false; + } + bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } + bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } + + /// Gets the interface declaration for this object type, if the base type + /// really is an interface. + ObjCInterfaceDecl *getInterface() const; + + /// Determine whether this object type is "specialized", meaning + /// that it has type arguments. + bool isSpecialized() const; + + /// Determine whether this object type was written with type arguments. + bool isSpecializedAsWritten() const { + return ObjCObjectTypeBits.NumTypeArgs > 0; + } + + /// Determine whether this object type is "unspecialized", meaning + /// that it has no type arguments. + bool isUnspecialized() const { return !isSpecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments of this object type (semantically). + ArrayRef getTypeArgs() const; + + /// Retrieve the type arguments of this object type as they were + /// written. + ArrayRef getTypeArgsAsWritten() const { + return {getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs}; + } + + /// Whether this is a "__kindof" type as written. + bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } + + /// Whether this ia a "__kindof" type (semantically). + bool isKindOfType() const; + + /// Retrieve the type of the superclass of this object type. + /// + /// This operation substitutes any type arguments into the + /// superclass of the current class type, potentially producing a + /// specialization of the superclass type. Produces a null type if + /// there is no superclass. + QualType getSuperClassType() const { + if (!CachedSuperClassType.getInt()) + computeSuperClassTypeSlow(); + + assert(CachedSuperClassType.getInt() && "Superclass not set?"); + return QualType(CachedSuperClassType.getPointer(), 0); + } + + /// Strip off the Objective-C "kindof" type and (with it) any + /// protocol qualifiers. + QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObject || + T->getTypeClass() == ObjCInterface; + } +}; + +/// A class providing a concrete implementation +/// of ObjCObjectType, so as to not increase the footprint of +/// ObjCInterfaceType. Code outside of ASTContext and the core type +/// system should not reference this type. +class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { + friend class ASTContext; + + // If anyone adds fields here, ObjCObjectType::getProtocolStorage() + // will need to be modified. + + ObjCObjectTypeImpl(QualType Canonical, QualType Base, + ArrayRef typeArgs, + ArrayRef protocols, + bool isKindOf) + : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Base, + ArrayRef typeArgs, + ArrayRef protocols, + bool isKindOf); +}; + +inline QualType *ObjCObjectType::getTypeArgStorage() { + return reinterpret_cast(static_cast(this)+1); +} + +inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { + return reinterpret_cast( + getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); +} + +inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { + return reinterpret_cast( + static_cast(this)+1); +} + +/// Interfaces are the core concept in Objective-C for object oriented design. +/// They basically correspond to C++ classes. There are two kinds of interface +/// types: normal interfaces like `NSString`, and qualified interfaces, which +/// are qualified with a protocol list like `NSString`. +/// +/// ObjCInterfaceType guarantees the following properties when considered +/// as a subtype of its superclass, ObjCObjectType: +/// - There are no protocol qualifiers. To reinforce this, code which +/// tries to invoke the protocol methods via an ObjCInterfaceType will +/// fail to compile. +/// - It is its own base type. That is, if T is an ObjCInterfaceType*, +/// T->getBaseType() == QualType(T, 0). +class ObjCInterfaceType : public ObjCObjectType { + friend class ASTContext; // ASTContext creates these. + friend class ASTReader; + template friend class serialization::AbstractTypeReader; + + ObjCInterfaceDecl *Decl; + + ObjCInterfaceType(const ObjCInterfaceDecl *D) + : ObjCObjectType(Nonce_ObjCInterface), + Decl(const_cast(D)) {} + +public: + /// Get the declaration of this interface. + ObjCInterfaceDecl *getDecl() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCInterface; + } + + // Nonsense to "hide" certain members of ObjCObjectType within this + // class. People asking for protocols on an ObjCInterfaceType are + // not going to get what they want: ObjCInterfaceTypes are + // guaranteed to have no protocols. + enum { + qual_iterator, + qual_begin, + qual_end, + getNumProtocols, + getProtocol + }; +}; + +inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { + QualType baseType = getBaseType(); + while (const auto *ObjT = baseType->getAs()) { + if (const auto *T = dyn_cast(ObjT)) + return T->getDecl(); + + baseType = ObjT->getBaseType(); + } + + return nullptr; +} + +/// Represents a pointer to an Objective C object. +/// +/// These are constructed from pointer declarators when the pointee type is +/// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class' +/// types are typedefs for these, and the protocol-qualified types 'id

' +/// and 'Class

' are translated into these. +/// +/// Pointers to pointers to Objective C objects are still PointerTypes; +/// only the first level of pointer gets it own type implementation. +class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType PointeeType; + + ObjCObjectPointerType(QualType Canonical, QualType Pointee) + : Type(ObjCObjectPointer, Canonical, Pointee->getDependence()), + PointeeType(Pointee) {} + +public: + /// Gets the type pointed to by this ObjC pointer. + /// The result will always be an ObjCObjectType or sugar thereof. + QualType getPointeeType() const { return PointeeType; } + + /// Gets the type pointed to by this ObjC pointer. Always returns non-null. + /// + /// This method is equivalent to getPointeeType() except that + /// it discards any typedefs (or other sugar) between this + /// type and the "outermost" object type. So for: + /// \code + /// \@class A; \@protocol P; \@protocol Q; + /// typedef A

AP; + /// typedef A A1; + /// typedef A1

A1P; + /// typedef A1P A1PQ; + /// \endcode + /// For 'A*', getObjectType() will return 'A'. + /// For 'A

*', getObjectType() will return 'A

'. + /// For 'AP*', getObjectType() will return 'A

'. + /// For 'A1*', getObjectType() will return 'A'. + /// For 'A1

*', getObjectType() will return 'A1

'. + /// For 'A1P*', getObjectType() will return 'A1

'. + /// For 'A1PQ*', getObjectType() will return 'A1', because + /// adding protocols to a protocol-qualified base discards the + /// old qualifiers (for now). But if it didn't, getObjectType() + /// would return 'A1P' (and we'd have to make iterating over + /// qualifiers more complicated). + const ObjCObjectType *getObjectType() const { + return PointeeType->castAs(); + } + + /// If this pointer points to an Objective C + /// \@interface type, gets the type for that interface. Any protocol + /// qualifiers on the interface are ignored. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' + const ObjCInterfaceType *getInterfaceType() const; + + /// If this pointer points to an Objective \@interface + /// type, gets the declaration for that interface. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' + ObjCInterfaceDecl *getInterfaceDecl() const { + return getObjectType()->getInterface(); + } + + /// True if this is equivalent to the 'id' type, i.e. if + /// its object type is the primitive 'id' type with no protocols. + bool isObjCIdType() const { + return getObjectType()->isObjCUnqualifiedId(); + } + + /// True if this is equivalent to the 'Class' type, + /// i.e. if its object tive is the primitive 'Class' type with no protocols. + bool isObjCClassType() const { + return getObjectType()->isObjCUnqualifiedClass(); + } + + /// True if this is equivalent to the 'id' or 'Class' type, + bool isObjCIdOrClassType() const { + return getObjectType()->isObjCUnqualifiedIdOrClass(); + } + + /// True if this is equivalent to 'id

' for some non-empty set of + /// protocols. + bool isObjCQualifiedIdType() const { + return getObjectType()->isObjCQualifiedId(); + } + + /// True if this is equivalent to 'Class

' for some non-empty set of + /// protocols. + bool isObjCQualifiedClassType() const { + return getObjectType()->isObjCQualifiedClass(); + } + + /// Whether this is a "__kindof" type. + bool isKindOfType() const { return getObjectType()->isKindOfType(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecialized() const { return getObjectType()->isSpecialized(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecializedAsWritten() const { + return getObjectType()->isSpecializedAsWritten(); + } + + /// Whether this type is unspecialized, meaning that is has no type arguments. + bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments for this type. + ArrayRef getTypeArgs() const { + return getObjectType()->getTypeArgs(); + } + + /// Retrieve the type arguments for this type. + ArrayRef getTypeArgsAsWritten() const { + return getObjectType()->getTypeArgsAsWritten(); + } + + /// An iterator over the qualifiers on the object type. Provided + /// for convenience. This will always iterate over the full set of + /// protocols on a type, not just those provided directly. + using qual_iterator = ObjCObjectType::qual_iterator; + using qual_range = llvm::iterator_range; + + qual_range quals() const { return qual_range(qual_begin(), qual_end()); } + + qual_iterator qual_begin() const { + return getObjectType()->qual_begin(); + } + + qual_iterator qual_end() const { + return getObjectType()->qual_end(); + } + + bool qual_empty() const { return getObjectType()->qual_empty(); } + + /// Return the number of qualifying protocols on the object type. + unsigned getNumProtocols() const { + return getObjectType()->getNumProtocols(); + } + + /// Retrieve a qualifying protocol by index on the object type. + ObjCProtocolDecl *getProtocol(unsigned I) const { + return getObjectType()->getProtocol(I); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + /// Retrieve the type of the superclass of this object pointer type. + /// + /// This operation substitutes any type arguments into the + /// superclass of the current class type, potentially producing a + /// pointer to a specialization of the superclass type. Produces a + /// null type if there is no superclass. + QualType getSuperClassType() const; + + /// Strip off the Objective-C "kindof" type and (with it) any + /// protocol qualifiers. + const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( + const ASTContext &ctx) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObjectPointer; + } +}; + +class AtomicType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType ValueType; + + AtomicType(QualType ValTy, QualType Canonical) + : Type(Atomic, Canonical, ValTy->getDependence()), ValueType(ValTy) {} + +public: + /// Gets the type contained by this atomic type, i.e. + /// the type returned by performing an atomic load of this atomic type. + QualType getValueType() const { return ValueType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getValueType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Atomic; + } +}; + +/// PipeType - OpenCL20. +class PipeType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + + QualType ElementType; + bool isRead; + + PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) + : Type(Pipe, CanonicalPtr, elemType->getDependence()), + ElementType(elemType), isRead(isRead) {} + +public: + QualType getElementType() const { return ElementType; } + + bool isSugared() const { return false; } + + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), isReadOnly()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) { + ID.AddPointer(T.getAsOpaquePtr()); + ID.AddBoolean(isRead); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Pipe; + } + + bool isReadOnly() const { return isRead; } +}; + +/// A fixed int type of a specified bitwidth. +class BitIntType final : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + LLVM_PREFERRED_TYPE(bool) + unsigned IsUnsigned : 1; + unsigned NumBits : 24; + +protected: + BitIntType(bool isUnsigned, unsigned NumBits); + +public: + bool isUnsigned() const { return IsUnsigned; } + bool isSigned() const { return !IsUnsigned; } + unsigned getNumBits() const { return NumBits; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, isUnsigned(), getNumBits()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, bool IsUnsigned, + unsigned NumBits) { + ID.AddBoolean(IsUnsigned); + ID.AddInteger(NumBits); + } + + static bool classof(const Type *T) { return T->getTypeClass() == BitInt; } +}; + +class DependentBitIntType final : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + llvm::PointerIntPair ExprAndUnsigned; + +protected: + DependentBitIntType(bool IsUnsigned, Expr *NumBits); + +public: + bool isUnsigned() const; + bool isSigned() const { return !isUnsigned(); } + Expr *getNumBitsExpr() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, isUnsigned(), getNumBitsExpr()); + } + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool IsUnsigned, Expr *NumBitsExpr); + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentBitInt; + } +}; + +class PredefinedSugarType final : public Type { +public: + friend class ASTContext; + using Kind = PredefinedSugarKind; + +private: + PredefinedSugarType(Kind KD, const IdentifierInfo *IdentName, + QualType CanonicalType) + : Type(PredefinedSugar, CanonicalType, TypeDependence::None), + Name(IdentName) { + PredefinedSugarTypeBits.Kind = llvm::to_underlying(KD); + } + + static StringRef getName(Kind KD); + + const IdentifierInfo *Name; + +public: + bool isSugared() const { return true; } + + QualType desugar() const { return getCanonicalTypeInternal(); } + + Kind getKind() const { return Kind(PredefinedSugarTypeBits.Kind); } + + const IdentifierInfo *getIdentifier() const { return Name; } + + static bool classof(const Type *T) { + return T->getTypeClass() == PredefinedSugar; + } +}; + +/// A qualifier set is used to build a set of qualifiers. +class QualifierCollector : public Qualifiers { +public: + QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} + + /// Collect any qualifiers on the given type and return an + /// unqualified type. The qualifiers are assumed to be consistent + /// with those already in the type. + const Type *strip(QualType type) { + addFastQualifiers(type.getLocalFastQualifiers()); + if (!type.hasLocalNonFastQualifiers()) + return type.getTypePtrUnsafe(); + + const ExtQuals *extQuals = type.getExtQualsUnsafe(); + addConsistentQualifiers(extQuals->getQualifiers()); + return extQuals->getBaseType(); + } + + /// Apply the collected qualifiers to the given type. + QualType apply(const ASTContext &Context, QualType QT) const; + + /// Apply the collected qualifiers to the given type. + QualType apply(const ASTContext &Context, const Type* T) const; +}; + +/// A container of type source information. +/// +/// A client can read the relevant info using TypeLoc wrappers, e.g: +/// @code +/// TypeLoc TL = TypeSourceInfo->getTypeLoc(); +/// TL.getBeginLoc().print(OS, SrcMgr); +/// @endcode +class alignas(8) TypeSourceInfo { + // Contains a memory block after the class, used for type source information, + // allocated by ASTContext. + friend class ASTContext; + + QualType Ty; + + TypeSourceInfo(QualType ty, size_t DataSize); // implemented in TypeLoc.h + +public: + /// Return the type wrapped by this type source info. + QualType getType() const { return Ty; } + + /// Return the TypeLoc wrapper for the type source info. + TypeLoc getTypeLoc() const; // implemented in TypeLoc.h + + /// Override the type stored in this TypeSourceInfo. Use with caution! + void overrideType(QualType T) { Ty = T; } +}; + +// Inline function definitions. + +inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { + SplitQualType desugar = + Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); + desugar.Quals.addConsistentQualifiers(Quals); + return desugar; +} + +inline const Type *QualType::getTypePtr() const { + return getCommonPtr()->BaseType; +} + +inline const Type *QualType::getTypePtrOrNull() const { + return (isNull() ? nullptr : getCommonPtr()->BaseType); +} + +inline bool QualType::isReferenceable() const { + // C++ [defns.referenceable] + // type that is either an object type, a function type that does not have + // cv-qualifiers or a ref-qualifier, or a reference type. + const Type &Self = **this; + if (Self.isObjectType() || Self.isReferenceType()) + return true; + if (const auto *F = Self.getAs()) + return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None; + + return false; +} + +inline SplitQualType QualType::split() const { + if (!hasLocalNonFastQualifiers()) + return SplitQualType(getTypePtrUnsafe(), + Qualifiers::fromFastMask(getLocalFastQualifiers())); + + const ExtQuals *eq = getExtQualsUnsafe(); + Qualifiers qs = eq->getQualifiers(); + qs.addFastQualifiers(getLocalFastQualifiers()); + return SplitQualType(eq->getBaseType(), qs); +} + +inline Qualifiers QualType::getLocalQualifiers() const { + Qualifiers Quals; + if (hasLocalNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getLocalFastQualifiers()); + return Quals; +} + +inline Qualifiers QualType::getQualifiers() const { + Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); + quals.addFastQualifiers(getLocalFastQualifiers()); + return quals; +} + +inline unsigned QualType::getCVRQualifiers() const { + unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); + cvr |= getLocalCVRQualifiers(); + return cvr; +} + +inline QualType QualType::getCanonicalType() const { + QualType canon = getCommonPtr()->CanonicalType; + return canon.withFastQualifiers(getLocalFastQualifiers()); +} + +inline bool QualType::isCanonical() const { + return getTypePtr()->isCanonicalUnqualified(); +} + +inline bool QualType::isCanonicalAsParam() const { + if (!isCanonical()) return false; + if (hasLocalQualifiers()) return false; + + const Type *T = getTypePtr(); + if (T->isVariablyModifiedType() && T->hasSizedVLAType()) + return false; + + return !isa(T) && + (!isa(T) || isa(T)); +} + +inline bool QualType::isConstQualified() const { + return isLocalConstQualified() || + getCommonPtr()->CanonicalType.isLocalConstQualified(); +} + +inline bool QualType::isRestrictQualified() const { + return isLocalRestrictQualified() || + getCommonPtr()->CanonicalType.isLocalRestrictQualified(); +} + + +inline bool QualType::isVolatileQualified() const { + return isLocalVolatileQualified() || + getCommonPtr()->CanonicalType.isLocalVolatileQualified(); +} + +inline bool QualType::hasQualifiers() const { + return hasLocalQualifiers() || + getCommonPtr()->CanonicalType.hasLocalQualifiers(); +} + +inline QualType QualType::getUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return QualType(getTypePtr(), 0); + + return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); +} + +inline SplitQualType QualType::getSplitUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return split(); + + return getSplitUnqualifiedTypeImpl(*this); +} + +inline void QualType::removeLocalConst() { + removeLocalFastQualifiers(Qualifiers::Const); +} + +inline void QualType::removeLocalRestrict() { + removeLocalFastQualifiers(Qualifiers::Restrict); +} + +inline void QualType::removeLocalVolatile() { + removeLocalFastQualifiers(Qualifiers::Volatile); +} + +/// Check if this type has any address space qualifier. +inline bool QualType::hasAddressSpace() const { + return getQualifiers().hasAddressSpace(); +} + +/// Return the address space of this type. +inline LangAS QualType::getAddressSpace() const { + return getQualifiers().getAddressSpace(); +} + +/// Return the gc attribute of this type. +inline Qualifiers::GC QualType::getObjCGCAttr() const { + return getQualifiers().getObjCGCAttr(); +} + +inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { + if (const auto *PT = t.getAs()) { + if (const auto *FT = PT->getPointeeType()->getAs()) + return FT->getExtInfo(); + } else if (const auto *FT = t.getAs()) + return FT->getExtInfo(); + + return FunctionType::ExtInfo(); +} + +inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { + return getFunctionExtInfo(*t); +} + +/// Determine whether this type is more +/// qualified than the Other type. For example, "const volatile int" +/// is more qualified than "const int", "volatile int", and +/// "int". However, it is not more qualified than "const volatile +/// int". +inline bool QualType::isMoreQualifiedThan(QualType other, + const ASTContext &Ctx) const { + Qualifiers MyQuals = getQualifiers(); + Qualifiers OtherQuals = other.getQualifiers(); + return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, Ctx)); +} + +/// Determine whether this type is at last +/// as qualified as the Other type. For example, "const volatile +/// int" is at least as qualified as "const int", "volatile int", +/// "int", and "const volatile int". +inline bool QualType::isAtLeastAsQualifiedAs(QualType other, + const ASTContext &Ctx) const { + Qualifiers OtherQuals = other.getQualifiers(); + + // Ignore __unaligned qualifier if this type is a void. + if (getUnqualifiedType()->isVoidType()) + OtherQuals.removeUnaligned(); + + return getQualifiers().compatiblyIncludes(OtherQuals, Ctx); +} + +/// If Type is a reference type (e.g., const +/// int&), returns the type that the reference refers to ("const +/// int"). Otherwise, returns the type itself. This routine is used +/// throughout Sema to implement C++ 5p6: +/// +/// If an expression initially has the type "reference to T" (8.3.2, +/// 8.5.3), the type is adjusted to "T" prior to any further +/// analysis, the expression designates the object or function +/// denoted by the reference, and the expression is an lvalue. +inline QualType QualType::getNonReferenceType() const { + if (const auto *RefType = (*this)->getAs()) + return RefType->getPointeeType(); + else + return *this; +} + +inline bool QualType::isCForbiddenLValueType() const { + return ((getTypePtr()->isVoidType() && !hasQualifiers()) || + getTypePtr()->isFunctionType()); +} + +/// Tests whether the type is categorized as a fundamental type. +/// +/// \returns True for types specified in C++0x [basic.fundamental]. +inline bool Type::isFundamentalType() const { + return isVoidType() || + isNullPtrType() || + // FIXME: It's really annoying that we don't have an + // 'isArithmeticType()' which agrees with the standard definition. + (isArithmeticType() && !isEnumeralType()); +} + +/// Tests whether the type is categorized as a compound type. +/// +/// \returns True for types specified in C++0x [basic.compound]. +inline bool Type::isCompoundType() const { + // C++0x [basic.compound]p1: + // Compound types can be constructed in the following ways: + // -- arrays of objects of a given type [...]; + return isArrayType() || + // -- functions, which have parameters of given types [...]; + isFunctionType() || + // -- pointers to void or objects or functions [...]; + isPointerType() || + // -- references to objects or functions of a given type. [...] + isReferenceType() || + // -- classes containing a sequence of objects of various types, [...]; + isRecordType() || + // -- unions, which are classes capable of containing objects of different + // types at different times; + isUnionType() || + // -- enumerations, which comprise a set of named constant values. [...]; + isEnumeralType() || + // -- pointers to non-static class members, [...]. + isMemberPointerType(); +} + +inline bool Type::isFunctionType() const { + return isa(CanonicalType); +} + +inline bool Type::isPointerType() const { + return isa(CanonicalType); +} + +inline bool Type::isPointerOrReferenceType() const { + return isPointerType() || isReferenceType(); +} + +inline bool Type::isAnyPointerType() const { + return isPointerType() || isObjCObjectPointerType(); +} + +inline bool Type::isSignableType(const ASTContext &Ctx) const { + return isSignablePointerType() || isSignableIntegerType(Ctx); +} + +inline bool Type::isSignablePointerType() const { + return isPointerType() || isObjCClassType() || isObjCQualifiedClassType(); +} + +inline bool Type::isBlockPointerType() const { + return isa(CanonicalType); +} + +inline bool Type::isReferenceType() const { + return isa(CanonicalType); +} + +inline bool Type::isLValueReferenceType() const { + return isa(CanonicalType); +} + +inline bool Type::isRValueReferenceType() const { + return isa(CanonicalType); +} + +inline bool Type::isObjectPointerType() const { + // Note: an "object pointer type" is not the same thing as a pointer to an + // object type; rather, it is a pointer to an object type or a pointer to cv + // void. + if (const auto *T = getAs()) + return !T->getPointeeType()->isFunctionType(); + else + return false; +} + +inline bool Type::isCFIUncheckedCalleeFunctionType() const { + if (const auto *Fn = getAs()) + return Fn->hasCFIUncheckedCallee(); + return false; +} + +inline bool Type::hasPointeeToToCFIUncheckedCalleeFunctionType() const { + QualType Pointee; + if (const auto *PT = getAs()) + Pointee = PT->getPointeeType(); + else if (const auto *RT = getAs()) + Pointee = RT->getPointeeType(); + else if (const auto *MPT = getAs()) + Pointee = MPT->getPointeeType(); + else if (const auto *DT = getAs()) + Pointee = DT->getPointeeType(); + else + return false; + return Pointee->isCFIUncheckedCalleeFunctionType(); +} + +inline bool Type::isFunctionPointerType() const { + if (const auto *T = getAs()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} + +inline bool Type::isFunctionReferenceType() const { + if (const auto *T = getAs()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} + +inline bool Type::isMemberPointerType() const { + return isa(CanonicalType); +} + +inline bool Type::isMemberFunctionPointerType() const { + if (const auto *T = getAs()) + return T->isMemberFunctionPointer(); + else + return false; +} + +inline bool Type::isMemberDataPointerType() const { + if (const auto *T = getAs()) + return T->isMemberDataPointer(); + else + return false; +} + +inline bool Type::isArrayType() const { + return isa(CanonicalType); +} + +inline bool Type::isConstantArrayType() const { + return isa(CanonicalType); +} + +inline bool Type::isIncompleteArrayType() const { + return isa(CanonicalType); +} + +inline bool Type::isVariableArrayType() const { + return isa(CanonicalType); +} + +inline bool Type::isArrayParameterType() const { + return isa(CanonicalType); +} + +inline bool Type::isDependentSizedArrayType() const { + return isa(CanonicalType); +} + +inline bool Type::isBuiltinType() const { + return isa(CanonicalType); +} + +inline bool Type::isRecordType() const { + return isa(CanonicalType); +} + +inline bool Type::isEnumeralType() const { + return isa(CanonicalType); +} + +inline bool Type::isAnyComplexType() const { + return isa(CanonicalType); +} + +inline bool Type::isVectorType() const { + return isa(CanonicalType); +} + +inline bool Type::isExtVectorType() const { + return isa(CanonicalType); +} + +inline bool Type::isExtVectorBoolType() const { + if (!isExtVectorType()) + return false; + return cast(CanonicalType)->getElementType()->isBooleanType(); +} + +inline bool Type::isSubscriptableVectorType() const { + return isVectorType() || isSveVLSBuiltinType(); +} + +inline bool Type::isMatrixType() const { + return isa(CanonicalType); +} + +inline bool Type::isConstantMatrixType() const { + return isa(CanonicalType); +} + +inline bool Type::isDependentAddressSpaceType() const { + return isa(CanonicalType); +} + +inline bool Type::isObjCObjectPointerType() const { + return isa(CanonicalType); +} + +inline bool Type::isObjCObjectType() const { + return isa(CanonicalType); +} + +inline bool Type::isObjCObjectOrInterfaceType() const { + return isa(CanonicalType) || + isa(CanonicalType); +} + +inline bool Type::isAtomicType() const { + return isa(CanonicalType); +} + +inline bool Type::isUndeducedAutoType() const { + return isa(CanonicalType); +} + +inline bool Type::isObjCQualifiedIdType() const { + if (const auto *OPT = getAs()) + return OPT->isObjCQualifiedIdType(); + return false; +} + +inline bool Type::isObjCQualifiedClassType() const { + if (const auto *OPT = getAs()) + return OPT->isObjCQualifiedClassType(); + return false; +} + +inline bool Type::isObjCIdType() const { + if (const auto *OPT = getAs()) + return OPT->isObjCIdType(); + return false; +} + +inline bool Type::isObjCClassType() const { + if (const auto *OPT = getAs()) + return OPT->isObjCClassType(); + return false; +} + +inline bool Type::isObjCSelType() const { + if (const auto *OPT = getAs()) + return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); + return false; +} + +inline bool Type::isObjCBuiltinType() const { + return isObjCIdType() || isObjCClassType() || isObjCSelType(); +} + +inline bool Type::isDecltypeType() const { + return isa(this); +} + +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + inline bool Type::is##Id##Type() const { \ + return isSpecificBuiltinType(BuiltinType::Id); \ + } +#include "clang/Basic/OpenCLImageTypes.def" + +inline bool Type::isSamplerT() const { + return isSpecificBuiltinType(BuiltinType::OCLSampler); +} + +inline bool Type::isEventT() const { + return isSpecificBuiltinType(BuiltinType::OCLEvent); +} + +inline bool Type::isClkEventT() const { + return isSpecificBuiltinType(BuiltinType::OCLClkEvent); +} + +inline bool Type::isQueueT() const { + return isSpecificBuiltinType(BuiltinType::OCLQueue); +} + +inline bool Type::isReserveIDT() const { + return isSpecificBuiltinType(BuiltinType::OCLReserveID); +} + +inline bool Type::isImageType() const { +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() || + return +#include "clang/Basic/OpenCLImageTypes.def" + false; // end boolean or operation +} + +inline bool Type::isPipeType() const { + return isa(CanonicalType); +} + +inline bool Type::isBitIntType() const { + return isa(CanonicalType); +} + +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + inline bool Type::is##Id##Type() const { \ + return isSpecificBuiltinType(BuiltinType::Id); \ + } +#include "clang/Basic/OpenCLExtensionTypes.def" + +inline bool Type::isOCLIntelSubgroupAVCType() const { +#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \ + isOCLIntelSubgroupAVC##Id##Type() || + return +#include "clang/Basic/OpenCLExtensionTypes.def" + false; // end of boolean or operation +} + +inline bool Type::isOCLExtOpaqueType() const { +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() || + return +#include "clang/Basic/OpenCLExtensionTypes.def" + false; // end of boolean or operation +} + +inline bool Type::isOpenCLSpecificType() const { + return isSamplerT() || isEventT() || isImageType() || isClkEventT() || + isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType(); +} + +#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \ + inline bool Type::is##Id##Type() const { \ + return isSpecificBuiltinType(BuiltinType::Id); \ + } +#include "clang/Basic/HLSLIntangibleTypes.def" + +inline bool Type::isHLSLBuiltinIntangibleType() const { +#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() || + return +#include "clang/Basic/HLSLIntangibleTypes.def" + false; +} + +inline bool Type::isHLSLSpecificType() const { + return isHLSLBuiltinIntangibleType() || isHLSLAttributedResourceType() || + isHLSLInlineSpirvType(); +} + +inline bool Type::isHLSLAttributedResourceType() const { + return isa(this); +} + +inline bool Type::isHLSLInlineSpirvType() const { + return isa(this); +} + +inline bool Type::isTemplateTypeParmType() const { + return isa(CanonicalType); +} + +inline bool Type::isSpecificBuiltinType(unsigned K) const { + if (const BuiltinType *BT = getAs()) { + return BT->getKind() == static_cast(K); + } + return false; +} + +inline bool Type::isPlaceholderType() const { + if (const auto *BT = dyn_cast(this)) + return BT->isPlaceholderType(); + return false; +} + +inline const BuiltinType *Type::getAsPlaceholderType() const { + if (const auto *BT = dyn_cast(this)) + if (BT->isPlaceholderType()) + return BT; + return nullptr; +} + +inline bool Type::isSpecificPlaceholderType(unsigned K) const { + assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); + return isSpecificBuiltinType(K); +} + +inline bool Type::isNonOverloadPlaceholderType() const { + if (const auto *BT = dyn_cast(this)) + return BT->isNonOverloadPlaceholderType(); + return false; +} + +inline bool Type::isVoidType() const { + return isSpecificBuiltinType(BuiltinType::Void); +} + +inline bool Type::isHalfType() const { + // FIXME: Should we allow complex __fp16? Probably not. + return isSpecificBuiltinType(BuiltinType::Half); +} + +inline bool Type::isFloat16Type() const { + return isSpecificBuiltinType(BuiltinType::Float16); +} + +inline bool Type::isFloat32Type() const { + return isSpecificBuiltinType(BuiltinType::Float); +} + +inline bool Type::isDoubleType() const { + return isSpecificBuiltinType(BuiltinType::Double); +} + +inline bool Type::isBFloat16Type() const { + return isSpecificBuiltinType(BuiltinType::BFloat16); +} + +inline bool Type::isMFloat8Type() const { + return isSpecificBuiltinType(BuiltinType::MFloat8); +} + +inline bool Type::isFloat128Type() const { + return isSpecificBuiltinType(BuiltinType::Float128); +} + +inline bool Type::isIbm128Type() const { + return isSpecificBuiltinType(BuiltinType::Ibm128); +} + +inline bool Type::isNullPtrType() const { + return isSpecificBuiltinType(BuiltinType::NullPtr); +} + +bool IsEnumDeclComplete(EnumDecl *); +bool IsEnumDeclScoped(EnumDecl *); + +inline bool Type::isIntegerType() const { + if (const auto *BT = dyn_cast(CanonicalType)) + return BT->isInteger(); + if (const EnumType *ET = dyn_cast(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + return IsEnumDeclComplete(ET->getOriginalDecl()) && + !IsEnumDeclScoped(ET->getOriginalDecl()); + } + return isBitIntType(); +} + +inline bool Type::isFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return BT->getKind() >= BuiltinType::ShortAccum && + BT->getKind() <= BuiltinType::SatULongFract; + } + return false; +} + +inline bool Type::isFixedPointOrIntegerType() const { + return isFixedPointType() || isIntegerType(); +} + +inline bool Type::isConvertibleToFixedPointType() const { + return isRealFloatingType() || isFixedPointOrIntegerType(); +} + +inline bool Type::isSaturatedFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return BT->getKind() >= BuiltinType::SatShortAccum && + BT->getKind() <= BuiltinType::SatULongFract; + } + return false; +} + +inline bool Type::isUnsaturatedFixedPointType() const { + return isFixedPointType() && !isSaturatedFixedPointType(); +} + +inline bool Type::isSignedFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return ((BT->getKind() >= BuiltinType::ShortAccum && + BT->getKind() <= BuiltinType::LongAccum) || + (BT->getKind() >= BuiltinType::ShortFract && + BT->getKind() <= BuiltinType::LongFract) || + (BT->getKind() >= BuiltinType::SatShortAccum && + BT->getKind() <= BuiltinType::SatLongAccum) || + (BT->getKind() >= BuiltinType::SatShortFract && + BT->getKind() <= BuiltinType::SatLongFract)); + } + return false; +} + +inline bool Type::isUnsignedFixedPointType() const { + return isFixedPointType() && !isSignedFixedPointType(); +} + +inline bool Type::isScalarType() const { + if (const auto *BT = dyn_cast(CanonicalType)) + return BT->getKind() > BuiltinType::Void && + BT->getKind() <= BuiltinType::NullPtr; + if (const EnumType *ET = dyn_cast(CanonicalType)) + // Enums are scalar types, but only if they are defined. Incomplete enums + // are not treated as scalar types. + return IsEnumDeclComplete(ET->getOriginalDecl()); + return isa(CanonicalType) || + isa(CanonicalType) || + isa(CanonicalType) || + isa(CanonicalType) || + isa(CanonicalType) || + isBitIntType(); +} + +inline bool Type::isIntegralOrEnumerationType() const { + if (const auto *BT = dyn_cast(CanonicalType)) + return BT->isInteger(); + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + if (const auto *ET = dyn_cast(CanonicalType)) + return IsEnumDeclComplete(ET->getOriginalDecl()); + + return isBitIntType(); +} + +inline bool Type::isBooleanType() const { + if (const auto *BT = dyn_cast(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + return false; +} + +inline bool Type::isUndeducedType() const { + auto *DT = getContainedDeducedType(); + return DT && !DT->isDeduced(); +} + +/// Determines whether this is a type for which one can define +/// an overloaded operator. +inline bool Type::isOverloadableType() const { + if (!isDependentType()) + return isRecordType() || isEnumeralType(); + return !isArrayType() && !isFunctionType() && !isAnyPointerType() && + !isMemberPointerType(); +} + +/// Determines whether this type is written as a typedef-name. +inline bool Type::isTypedefNameType() const { + if (getAs()) + return true; + if (auto *TST = getAs()) + return TST->isTypeAlias(); + return false; +} + +/// Determines whether this type can decay to a pointer type. +inline bool Type::canDecayToPointerType() const { + return isFunctionType() || (isArrayType() && !isArrayParameterType()); +} + +inline bool Type::hasPointerRepresentation() const { + return (isPointerType() || isReferenceType() || isBlockPointerType() || + isObjCObjectPointerType() || isNullPtrType()); +} + +inline bool Type::hasObjCPointerRepresentation() const { + return isObjCObjectPointerType(); +} + +inline const Type *Type::getBaseElementTypeUnsafe() const { + const Type *type = this; + while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) + type = arrayType->getElementType().getTypePtr(); + return type; +} + +inline const Type *Type::getPointeeOrArrayElementType() const { + const Type *type = this; + if (type->isAnyPointerType()) + return type->getPointeeType().getTypePtr(); + else if (type->isArrayType()) + return type->getBaseElementTypeUnsafe(); + return type; +} +/// Insertion operator for partial diagnostics. This allows sending adress +/// spaces into a diagnostic with <<. +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, + LangAS AS) { + PD.AddTaggedVal(llvm::to_underlying(AS), + DiagnosticsEngine::ArgumentKind::ak_addrspace); + return PD; +} + +/// Insertion operator for partial diagnostics. This allows sending Qualifiers +/// into a diagnostic with <<. +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, + Qualifiers Q) { + PD.AddTaggedVal(Q.getAsOpaqueValue(), + DiagnosticsEngine::ArgumentKind::ak_qual); + return PD; +} + +/// Insertion operator for partial diagnostics. This allows sending QualType's +/// into a diagnostic with <<. +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, + QualType T) { + PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), + DiagnosticsEngine::ak_qualtype); + return PD; +} + +// Helper class template that is used by Type::getAs to ensure that one does +// not try to look through a qualified type to get to an array type. +template +using TypeIsArrayType = + std::integral_constant::value || + std::is_base_of::value>; + +// Member-template getAs'. +template const T *Type::getAs() const { + static_assert(!TypeIsArrayType::value, + "ArrayType cannot be used with getAs!"); + + // If this is directly a T type, return it. + if (const auto *Ty = dyn_cast(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) + return nullptr; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast(getUnqualifiedDesugaredType()); +} + +template const T *Type::getAsAdjusted() const { + static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAsAdjusted!"); + + // If this is directly a T type, return it. + if (const auto *Ty = dyn_cast(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) + return nullptr; + + // Strip off type adjustments that do not modify the underlying nature of the + // type. + const Type *Ty = this; + while (Ty) { + if (const auto *A = dyn_cast(Ty)) + Ty = A->getModifiedType().getTypePtr(); + else if (const auto *A = dyn_cast(Ty)) + Ty = A->getWrappedType().getTypePtr(); + else if (const auto *A = dyn_cast(Ty)) + Ty = A->getWrappedType().getTypePtr(); + else if (const auto *P = dyn_cast(Ty)) + Ty = P->desugar().getTypePtr(); + else if (const auto *A = dyn_cast(Ty)) + Ty = A->desugar().getTypePtr(); + else if (const auto *M = dyn_cast(Ty)) + Ty = M->desugar().getTypePtr(); + else + break; + } + + // Just because the canonical type is correct does not mean we can use cast<>, + // since we may not have stripped off all the sugar down to the base type. + return dyn_cast(Ty); +} + +inline const ArrayType *Type::getAsArrayTypeUnsafe() const { + // If this is directly an array type, return it. + if (const auto *arr = dyn_cast(this)) + return arr; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) + return nullptr; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast(getUnqualifiedDesugaredType()); +} + +template const T *Type::castAs() const { + static_assert(!TypeIsArrayType::value, + "ArrayType cannot be used with castAs!"); + + if (const auto *ty = dyn_cast(this)) return ty; + assert(isa(CanonicalType)); + return cast(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::castAsArrayTypeUnsafe() const { + assert(isa(CanonicalType)); + if (const auto *arr = dyn_cast(this)) return arr; + return cast(getUnqualifiedDesugaredType()); +} + +DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr, + QualType CanonicalPtr) + : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { +#ifndef NDEBUG + QualType Adjusted = getAdjustedType(); + (void)AttributedType::stripOuterNullability(Adjusted); + assert(isa(Adjusted)); +#endif +} + +QualType DecayedType::getPointeeType() const { + QualType Decayed = getDecayedType(); + (void)AttributedType::stripOuterNullability(Decayed); + return cast(Decayed)->getPointeeType(); +} + +// Get the decimal string representation of a fixed point type, represented +// as a scaled integer. +// TODO: At some point, we should change the arguments to instead just accept an +// APFixedPoint instead of APSInt and scale. +void FixedPointValueToString(SmallVectorImpl &Str, llvm::APSInt Val, + unsigned Scale); + +inline FunctionEffectsRef FunctionEffectsRef::get(QualType QT) { + const Type *TypePtr = QT.getTypePtr(); + while (true) { + if (QualType Pointee = TypePtr->getPointeeType(); !Pointee.isNull()) + TypePtr = Pointee.getTypePtr(); + else if (TypePtr->isArrayType()) + TypePtr = TypePtr->getBaseElementTypeUnsafe(); + else + break; + } + if (const auto *FPT = TypePtr->getAs()) + return FPT->getFunctionEffects(); + return {}; +} + +} // namespace clang + +#endif // LLVM_CLANG_AST_TYPE_BASE_H diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 00835f1490eda..3099e81bbc8a9 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -18,7 +18,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateBase.h" -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" 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; -def BuiltinType : TypeNode, LeafType; +def BuiltinType : TypeNode, AlwaysCanonical; def ComplexType : TypeNode; def PointerType : TypeNode; def BlockPointerType : TypeNode; @@ -88,14 +79,14 @@ def TypeOfType : TypeNode, NeverCanonicalUnlessDependent; def DecltypeType : TypeNode, NeverCanonicalUnlessDependent; def UnaryTransformType : TypeNode, NeverCanonicalUnlessDependent; def TagType : TypeNode; -def RecordType : TypeNode, LeafType; -def EnumType : TypeNode, LeafType; -def InjectedClassNameType : TypeNode, AlwaysDependent, LeafType; +def RecordType : TypeNode; +def EnumType : TypeNode; +def InjectedClassNameType : TypeNode, AlwaysDependent; def AttributedType : TypeNode, NeverCanonical; def BTFTagAttributedType : TypeNode, NeverCanonical; def HLSLAttributedResourceType : TypeNode; def HLSLInlineSpirvType : TypeNode; -def TemplateTypeParmType : TypeNode, AlwaysDependent, LeafType; +def TemplateTypeParmType : TypeNode, AlwaysDependent; def SubstTemplateTypeParmType : TypeNode, NeverCanonical; def SubstPackType : TypeNode; def SubstTemplateTypeParmPackType : TypeNode, AlwaysDependent; @@ -110,7 +101,7 @@ def PackExpansionType : TypeNode, AlwaysDependent; def PackIndexingType : TypeNode, NeverCanonicalUnlessDependent; def ObjCTypeParamType : TypeNode, NeverCanonical; def ObjCObjectType : TypeNode; -def ObjCInterfaceType : TypeNode, LeafType; +def ObjCInterfaceType : TypeNode, AlwaysCanonical; def ObjCObjectPointerType : TypeNode; def BoundsAttributedType : TypeNode; def CountAttributedType : TypeNode, NeverCanonical; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 12112eb1ad225..2c9333491e930 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5404,7 +5404,7 @@ class Sema final : public SemaBase { /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. - void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); + void FinalizeVarWithDestructor(VarDecl *VD, CXXRecordDecl *DeclInit); /// Helper class that collects exception specifications for /// implicitly-declared special member functions. diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 2d62209bbc28c..7173c2a0e1a2a 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -903,8 +903,7 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, case APValue::Struct: { Out << '{'; bool First = true; - const RecordDecl *RD = - Ty->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = Ty->castAsRecordDecl(); if (unsigned N = getStructNumBases()) { const CXXRecordDecl *CD = cast(RD); CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index bbb957067c4c8..405ee15d65cb7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -654,9 +654,9 @@ comments::FullComment *ASTContext::getCommentForDecl( // does not have one of its own. QualType QT = TD->getUnderlyingType(); if (const auto *TT = QT->getAs()) - if (const Decl *TD = TT->getOriginalDecl()) - if (comments::FullComment *FC = getCommentForDecl(TD, PP)) - return cloneFullComment(FC, D); + if (comments::FullComment *FC = + getCommentForDecl(TT->getOriginalDecl(), PP)) + return cloneFullComment(FC, D); } else if (const auto *IC = dyn_cast(D)) { while (IC->getSuperClass()) { @@ -1933,12 +1933,9 @@ TypeInfoChars ASTContext::getTypeInfoDataSizeInChars(QualType T) const { // of a base-class subobject. We decide whether that's possible // during class layout, so here we can just trust the layout results. if (getLangOpts().CPlusPlus) { - if (const auto *RT = T->getAs()) { - const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (!RD->isInvalidDecl()) { - const ASTRecordLayout &layout = getASTRecordLayout(RD); - Info.Width = layout.getDataSize(); - } + if (const auto *RD = T->getAsCXXRecordDecl(); RD && !RD->isInvalidDecl()) { + const ASTRecordLayout &layout = getASTRecordLayout(RD); + Info.Width = layout.getDataSize(); } } @@ -2004,8 +2001,7 @@ bool ASTContext::isPromotableIntegerType(QualType T) const { // Enumerated types are promotable to their compatible integer types // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). - if (const auto *ET = T->getAs()) { - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *ED = T->getAsEnumDecl()) { if (T->isDependentType() || ED->getPromotionType().isNull() || ED->isScoped()) return false; @@ -2618,10 +2614,10 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { return I->second; unsigned UnadjustedAlign; - if (const auto *RT = T->getAs()) { + if (const auto *RT = T->getAsCanonical()) { const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); - } else if (const auto *ObjCI = T->getAs()) { + } else if (const auto *ObjCI = T->getAsCanonical()) { const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); } else { @@ -2694,9 +2690,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { if (!Target->allowsLargerPreferedTypeAlignment()) return ABIAlign; - if (const auto *RT = T->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - + if (const auto *RD = T->getAsRecordDecl()) { // When used as part of a typedef, or together with a 'packed' attribute, // the 'aligned' attribute can be used to decrease alignment. Note that the // 'packed' case is already taken into consideration when computing the @@ -2717,11 +2711,8 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { // possible. if (const auto *CT = T->getAs()) T = CT->getElementType().getTypePtr(); - if (const auto *ET = T->getAs()) - T = ET->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType() - .getTypePtr(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong) || @@ -2887,12 +2878,10 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, static std::optional getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context, bool CheckIfTriviallyCopyable) { - if (Field->getType()->isRecordType()) { - const RecordDecl *RD = Field->getType()->getAsRecordDecl(); - if (!RD->isUnion()) - return structHasUniqueObjectRepresentations(Context, RD, - CheckIfTriviallyCopyable); - } + if (const auto *RD = Field->getType()->getAsRecordDecl(); + RD && !RD->isUnion()) + return structHasUniqueObjectRepresentations(Context, RD, + CheckIfTriviallyCopyable); // A _BitInt type may not be unique if it has padding bits // but if it is a bitfield the padding bits are not used. @@ -3047,10 +3036,7 @@ bool ASTContext::hasUniqueObjectRepresentations( if (const auto *MPT = Ty->getAs()) return !ABI->getMemberPointerInfo(MPT).HasPadding; - if (Ty->isRecordType()) { - const RecordDecl *Record = - Ty->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - + if (const auto *Record = Ty->getAsRecordDecl()) { if (Record->isInvalidDecl()) return false; @@ -3422,10 +3408,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, // type, or an unsigned integer type. // // So we have to treat enum types as integers. - QualType UnderlyingType = cast(T) - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType(); + QualType UnderlyingType = T->castAsEnumDecl()->getIntegerType(); return encodeTypeForFunctionPointerAuth( Ctx, OS, UnderlyingType.isNull() ? Ctx.IntTy : UnderlyingType); } @@ -3569,8 +3552,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, llvm_unreachable("should never get here"); } case Type::Record: { - const RecordDecl *RD = - T->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const RecordDecl *RD = T->castAsCanonical()->getOriginalDecl(); const IdentifierInfo *II = RD->getIdentifier(); // In C++, an immediate typedef of an anonymous struct or union @@ -8362,8 +8344,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); assert(isPromotableIntegerType(Promotable)); - if (const auto *ET = Promotable->getAs()) - return ET->getOriginalDecl()->getDefinitionOrSelf()->getPromotionType(); + if (const auto *ED = Promotable->getAsEnumDecl()) + return ED->getPromotionType(); if (const auto *BT = Promotable->getAs()) { // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t @@ -8582,10 +8564,9 @@ QualType ASTContext::getObjCSuperType() const { } void ASTContext::setCFConstantStringType(QualType T) { - const auto *TD = T->castAs(); - CFConstantStringTypeDecl = cast(TD->getDecl()); - const auto *TagType = TD->castAs(); - CFConstantStringTagDecl = TagType->getOriginalDecl()->getDefinitionOrSelf(); + const auto *TT = T->castAs(); + CFConstantStringTypeDecl = cast(TT->getDecl()); + CFConstantStringTagDecl = TT->castAsRecordDecl(); } QualType ASTContext::getBlockDescriptorType() const { @@ -9296,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()) @@ -9340,8 +9321,8 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, S += llvm::utostr(Offset); - if (const auto *ET = T->getAs()) - S += ObjCEncodingForEnumType(Ctx, ET); + if (const auto *ET = T->getAsCanonical()) + S += ObjCEncodingForEnumDecl(Ctx, ET->getOriginalDecl()); else { const auto *BT = T->castAs(); S += getObjCEncodingForPrimitiveType(Ctx, BT); @@ -9398,7 +9379,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, if (const auto *BT = dyn_cast(CT)) S += getObjCEncodingForPrimitiveType(this, BT); else - S += ObjCEncodingForEnumType(this, cast(CT)); + S += ObjCEncodingForEnumDecl(this, cast(CT)->getOriginalDecl()); return; case Type::Complex: @@ -9465,7 +9446,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, S += '*'; return; } - } else if (const auto *RTy = PointeeTy->getAs()) { + } else if (const auto *RTy = PointeeTy->getAsCanonical()) { const IdentifierInfo *II = RTy->getOriginalDecl()->getIdentifier(); // GCC binary compat: Need to convert "struct objc_class *" to "#". if (II == &Idents.get("objc_class")) { @@ -11672,9 +11653,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, // Look at the converted type of enum types, since that is the type used // to pass enum values. - if (const auto *Enum = paramTy->getAs()) { - paramTy = - Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = paramTy->getAsEnumDecl()) { + paramTy = ED->getIntegerType(); if (paramTy.isNull()) return {}; } @@ -11832,10 +11812,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()) { + if (const auto *ETy = LHS->getAsCanonical()) { return mergeEnumWithInteger(*this, ETy, RHS, false); } - if (const EnumType* ETy = RHS->getAs()) { + if (const EnumType *ETy = RHS->getAsCanonical()) { return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType); } // allow block pointer type to match an 'id' type. @@ -12265,8 +12245,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { //===----------------------------------------------------------------------===// unsigned ASTContext::getIntWidth(QualType T) const { - if (const auto *ET = T->getAs()) - T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType(); if (T->isBooleanType()) return 1; if (const auto *EIT = T->getAs()) @@ -12291,8 +12271,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. - if (const auto *ETy = T->getAs()) - T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType(); switch (T->castAs()->getKind()) { case BuiltinType::Char_U: @@ -12365,8 +12345,8 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. - if (const auto *ETy = T->getAs()) - T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType(); switch (T->castAs()->getKind()) { case BuiltinType::Char_S: diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 6d83de384ee10..1292c30d47589 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -878,10 +878,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Treat the enumeration as its underlying type and use the builtin type // class comparison. if (T1->getTypeClass() == Type::Enum) { - T1 = T1->getAs()->getOriginalDecl()->getIntegerType(); + T1 = cast(T1)->getOriginalDecl()->getIntegerType(); assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check } else if (T2->getTypeClass() == Type::Enum) { - T2 = T2->getAs()->getOriginalDecl()->getIntegerType(); + T2 = cast(T2)->getOriginalDecl()->getIntegerType(); assert(T1->isBuiltinType() && !T2.isNull()); // Sanity check } TC = Type::Builtin; diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index e3235d34e230e..aee7421066180 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -559,8 +559,7 @@ bool Compiler::VisitCastExpr(const CastExpr *CE) { // Possibly diagnose casts to enum types if the target type does not // have a fixed size. if (Ctx.getLangOpts().CPlusPlus && CE->getType()->isEnumeralType()) { - const auto *ET = CE->getType().getCanonicalType()->castAs(); - const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = CE->getType()->castAsEnumDecl(); if (!ED->isFixed()) { if (!this->emitCheckEnumValue(*FromT, ED, CE)) return false; @@ -4608,8 +4607,8 @@ UnsignedOrNone Compiler::allocateTemporary(const Expr *E) { template const RecordType *Compiler::getRecordTy(QualType Ty) { if (const PointerType *PT = dyn_cast(Ty)) - return PT->getPointeeType()->getAs(); - return Ty->getAs(); + return PT->getPointeeType()->getAsCanonical(); + return Ty->getAsCanonical(); } template Record *Compiler::getRecord(QualType Ty) { diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 36eb7607e70bf..fbbb508ed226c 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -364,8 +364,7 @@ OptPrimType Context::classify(QualType T) const { return integralTypeToPrimTypeU(BT->getNumBits()); } - if (const auto *ET = T->getAs()) { - const auto *D = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *D = T->getAsEnumDecl()) { if (!D->isComplete()) return std::nullopt; return classify(D->getIntegerType()); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 2e28814abfddb..e245f24e614e5 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -3303,11 +3303,8 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, switch (Node.getKind()) { case OffsetOfNode::Field: { const FieldDecl *MemberDecl = Node.getField(); - const RecordType *RT = CurrentType->getAs(); - if (!RT) - return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->isInvalidDecl()) + const auto *RD = CurrentType->getAsRecordDecl(); + if (!RD || RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); unsigned FieldIndex = MemberDecl->getFieldIndex(); @@ -3336,23 +3333,19 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, return false; // Find the layout of the class whose base we are looking into. - const RecordType *RT = CurrentType->getAs(); - if (!RT) - return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->isInvalidDecl()) + const auto *RD = CurrentType->getAsCXXRecordDecl(); + if (!RD || RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); // Find the base class itself. CurrentType = BaseSpec->getType(); - const RecordType *BaseRT = CurrentType->getAs(); - if (!BaseRT) + const auto *BaseRD = CurrentType->getAsCXXRecordDecl(); + if (!BaseRD) return false; // Add the offset to the base. - Result += RL.getBaseClassOffset(cast( - BaseRT->getOriginalDecl()->getDefinitionOrSelf())); + Result += RL.getBaseClassOffset(BaseRD); break; } case OffsetOfNode::Identifier: diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 38856ad256a63..bd4d440e29347 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -700,7 +700,7 @@ std::optional Pointer::toRValue(const Context &Ctx, return true; } - if (const auto *RT = Ty->getAs()) { + if (const auto *RT = Ty->getAsCanonical()) { const auto *Record = Ptr.getRecord(); assert(Record && "Missing record descriptor"); diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 5d72044af969e..0892d1dc36595 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -332,10 +332,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { continue; // In error cases, the base might not be a RecordType. - const auto *RT = Spec.getType()->getAs(); - if (!RT) + const auto *BD = Spec.getType()->getAsCXXRecordDecl(); + if (!BD) return nullptr; - const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -348,11 +347,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { } for (const CXXBaseSpecifier &Spec : CD->vbases()) { - const auto *RT = Spec.getType()->getAs(); - if (!RT) - return nullptr; - - const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf(); + const auto *BD = Spec.getType()->castAsCXXRecordDecl(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -408,9 +403,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, const Expr *Init) { // Classes and structures. - if (const auto *RT = Ty->getAs()) { - if (const auto *Record = - getOrCreateRecord(RT->getOriginalDecl()->getDefinitionOrSelf())) + if (const auto *RD = Ty->getAsRecordDecl()) { + if (const auto *Record = getOrCreateRecord(RD)) return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, IsMutable, IsVolatile); return allocateDescriptor(D, MDSize); diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp index a7934ccb4e55e..c20ec184f34f4 100644 --- a/clang/lib/AST/ByteCode/Record.cpp +++ b/clang/lib/AST/ByteCode/Record.cpp @@ -50,10 +50,8 @@ const Record::Base *Record::getBase(const RecordDecl *FD) const { } const Record::Base *Record::getBase(QualType T) const { - if (auto *RT = T->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (auto *RD = T->getAsCXXRecordDecl()) return BaseMap.lookup(RD); - } return nullptr; } diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index e4b77edc063dc..b60d445ad3414 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -128,17 +128,11 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const { const CXXRecordDecl *Record = this; while (true) { for (const auto &I : Record->bases()) { - const RecordType *Ty = I.getType()->getAs(); - if (!Ty) + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base || !(Base->isBeingDefined() || Base->isCompleteDefinition())) return false; - - CXXRecordDecl *Base = cast_if_present( - Ty->getOriginalDecl()->getDefinition()); - if (!Base || - (Base->isDependentContext() && - !Base->isCurrentInstantiation(Record))) { + if (Base->isDependentContext() && !Base->isCurrentInstantiation(Record)) return false; - } Queue.push_back(Base); if (!BaseMatches(Base)) @@ -196,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(); + DetectedVirtual = BaseType->getAsCanonical(); SetVirtual = true; } } else { @@ -255,9 +249,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, const TemplateSpecializationType *TST = BaseSpec.getType()->getAs(); if (!TST) { - if (auto *RT = BaseSpec.getType()->getAs()) - BaseRecord = cast(RT->getOriginalDecl()) - ->getDefinitionOrSelf(); + BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl(); } else { TemplateName TN = TST->getTemplateName(); if (auto *TD = @@ -271,7 +263,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, BaseRecord = nullptr; } } else { - BaseRecord = cast(BaseSpec.getType()->getAsRecordDecl()); + BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl(); } if (BaseRecord && lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) { @@ -335,10 +327,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, if (!PE.Base->isVirtual()) continue; - CXXRecordDecl *VBase = nullptr; - if (const RecordType *Record = PE.Base->getType()->getAs()) - VBase = cast(Record->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *VBase = PE.Base->getType()->getAsCXXRecordDecl(); if (!VBase) break; @@ -347,11 +336,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, // base is a subobject of any other path; if so, then the // declaration in this path are hidden by that patch. for (const CXXBasePath &HidingP : Paths) { - CXXRecordDecl *HidingClass = nullptr; - if (const RecordType *Record = - HidingP.back().Base->getType()->getAs()) - HidingClass = cast(Record->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *HidingClass = + HidingP.back().Base->getType()->getAsCXXRecordDecl(); if (!HidingClass) break; @@ -407,7 +393,7 @@ bool CXXRecordDecl::hasMemberName(DeclarationName Name) const { CXXBasePaths Paths(false, false, false); return lookupInBases( [Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - return findOrdinaryMember(Specifier->getType()->getAsCXXRecordDecl(), + return findOrdinaryMember(Specifier->getType()->castAsCXXRecordDecl(), Path, Name); }, Paths); @@ -470,9 +456,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, = ++SubobjectCount[cast(RD->getCanonicalDecl())]; for (const auto &Base : RD->bases()) { - if (const RecordType *RT = Base.getType()->getAs()) { - const CXXRecordDecl *BaseDecl = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); + if (const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl()) { if (!BaseDecl->isPolymorphic()) continue; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4507f415ce606..343673069e15e 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2861,9 +2861,8 @@ VarDecl::needsDestruction(const ASTContext &Ctx) const { bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { assert(hasInit() && "Expect initializer to check for flexible array init"); - auto *Ty = getType()->getAs(); - if (!Ty || - !Ty->getOriginalDecl()->getDefinitionOrSelf()->hasFlexibleArrayMember()) + auto *D = getType()->getAsRecordDecl(); + if (!D || !D->hasFlexibleArrayMember()) return false; auto *List = dyn_cast(getInit()->IgnoreParens()); if (!List) @@ -2877,11 +2876,8 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const { assert(hasInit() && "Expect initializer to check for flexible array init"); - auto *Ty = getType()->getAs(); - if (!Ty) - return CharUnits::Zero(); - const RecordDecl *RD = Ty->getOriginalDecl()->getDefinitionOrSelf(); - if (!Ty || !RD->hasFlexibleArrayMember()) + auto *RD = getType()->getAsRecordDecl(); + if (!RD || !RD->hasFlexibleArrayMember()) return CharUnits::Zero(); auto *List = dyn_cast(getInit()->IgnoreParens()); if (!List || List->getNumInits() == 0) @@ -2992,7 +2988,7 @@ bool ParmVarDecl::isDestroyedInCallee() const { // FIXME: isParamDestroyedInCallee() should probably imply // isDestructedType() - const auto *RT = getType()->getAs(); + const auto *RT = getType()->getAsCanonical(); if (RT && RT->getOriginalDecl() ->getDefinitionOrSelf() @@ -3507,7 +3503,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation( while (const auto *TD = T->getAs()) T = TD->getDecl()->getUnderlyingType(); const IdentifierInfo *II = - T->castAs()->getOriginalDecl()->getIdentifier(); + T->castAsCanonical()->getOriginalDecl()->getIdentifier(); if (II && II->isStr("__hot_cold_t")) Consume(); } @@ -4657,7 +4653,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const { if (!isImplicit() || getDeclName()) return false; - if (const auto *Record = getType()->getAs()) + if (const auto *Record = getType()->getAsCanonical()) return Record->getOriginalDecl()->isAnonymousStructOrUnion(); return false; @@ -4715,7 +4711,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { return false; // -- is not of class type, or - const auto *RT = getType()->getAs(); + const auto *RT = getType()->getAsCanonical(); if (!RT) return false; const RecordDecl *RD = RT->getOriginalDecl()->getDefinition(); @@ -4738,7 +4734,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { // MS ABI: has nonzero size if it is a class type with class type fields, // whether or not they have nonzero size return !llvm::any_of(CXXRD->fields(), [](const FieldDecl *Field) { - return Field->getType()->getAs(); + return Field->getType()->isRecordType(); }); } @@ -5142,7 +5138,7 @@ bool RecordDecl::isOrContainsUnion() const { if (const RecordDecl *Def = getDefinition()) { for (const FieldDecl *FD : Def->fields()) { - const RecordType *RT = FD->getType()->getAs(); + const RecordType *RT = FD->getType()->getAsCanonical(); if (RT && RT->getOriginalDecl()->isOrContainsUnion()) return true; } @@ -5274,10 +5270,8 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const { if (I->getIdentifier()) return I; - if (const auto *RT = I->getType()->getAs()) - if (const FieldDecl *NamedDataMember = RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->findFirstNamedDataMember()) + if (const auto *RD = I->getType()->getAsRecordDecl()) + if (const FieldDecl *NamedDataMember = RD->findFirstNamedDataMember()) return NamedDataMember; } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 50b1a1d000090..97fdbe3c42bc8 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -216,9 +216,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; - auto *BaseClassDecl = - cast(BaseType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *BaseClassDecl = BaseType->castAsCXXRecordDecl(); // C++2a [class]p7: // A standard-layout class is a class that: @@ -1207,9 +1205,8 @@ void CXXRecordDecl::addedMember(Decl *D) { // those because they are always unnamed. bool IsZeroSize = Field->isZeroSize(Context); - if (const auto *RecordTy = T->getAs()) { - auto *FieldRec = cast(RecordTy->getOriginalDecl()); - if (FieldRec->getDefinition()) { + if (auto *FieldRec = T->getAsCXXRecordDecl()) { + if (FieldRec->isBeingDefined() || FieldRec->isCompleteDefinition()) { addedClassSubobject(FieldRec); // We may need to perform overload resolution to determine whether a @@ -1908,15 +1905,14 @@ static void CollectVisibleConversions( // Collect information recursively from any base classes. for (const auto &I : Record->bases()) { - const auto *RT = I.getType()->getAs(); - if (!RT) continue; + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) + continue; AccessSpecifier BaseAccess = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier()); bool BaseInVirtual = InVirtual || I.isVirtual(); - auto *Base = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } @@ -1951,14 +1947,13 @@ static void CollectVisibleConversions(ASTContext &Context, // Recursively collect conversions from base classes. for (const auto &I : Record->bases()) { - const auto *RT = I.getType()->getAs(); - if (!RT) continue; + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) + continue; - CollectVisibleConversions( - Context, - cast(RT->getOriginalDecl())->getDefinitionOrSelf(), - I.isVirtual(), I.getAccessSpecifier(), HiddenTypes, Output, VBaseCs, - HiddenVBaseCs); + CollectVisibleConversions(Context, Base, I.isVirtual(), + I.getAccessSpecifier(), HiddenTypes, Output, + VBaseCs, HiddenVBaseCs); } // Add any unhidden conversions provided by virtual bases. @@ -2312,7 +2307,7 @@ bool CXXRecordDecl::mayBeAbstract() const { for (const auto &B : bases()) { const auto *BaseDecl = cast( - B.getType()->castAs()->getOriginalDecl()); + B.getType()->castAsCanonical()->getOriginalDecl()); if (BaseDecl->isAbstract()) return true; } @@ -2472,11 +2467,9 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, }; for (const auto &I : RD->bases()) { - const RecordType *RT = I.getType()->getAs(); - if (!RT) + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) continue; - const auto *Base = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base)) AddFinalOverrider(D); } @@ -3437,13 +3430,12 @@ SourceRange UsingDecl::getSourceRange() const { void UsingEnumDecl::anchor() {} UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation UL, - SourceLocation EL, + SourceLocation UL, SourceLocation EL, SourceLocation NL, TypeSourceInfo *EnumType) { - assert(isa(EnumType->getType()->getAsTagDecl())); return new (C, DC) - UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType); + UsingEnumDecl(DC, EnumType->getType()->castAsEnumDecl()->getDeclName(), + UL, EL, NL, EnumType); } UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index b91b4670c63a3..3162857aac5d0 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -730,15 +730,15 @@ void TemplateTypeParmDecl::setDefaultArgument( } unsigned TemplateTypeParmDecl::getDepth() const { - return getTypeForDecl()->castAs()->getDepth(); + return dyn_cast(getTypeForDecl())->getDepth(); } unsigned TemplateTypeParmDecl::getIndex() const { - return getTypeForDecl()->castAs()->getIndex(); + return dyn_cast(getTypeForDecl())->getIndex(); } bool TemplateTypeParmDecl::isParameterPack() const { - return getTypeForDecl()->castAs()->isParameterPack(); + return dyn_cast(getTypeForDecl())->isParameterPack(); } void TemplateTypeParmDecl::setTypeConstraint( 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()) { + if (const RecordType *ClassRec = ClassType->getAsCanonical()) { ClassRec->getOriginalDecl()->printName(OS, Policy); return; } if (Policy.SuppressTemplateArgsInCXXConstructors) { - if (auto *InjTy = ClassType->getAs()) { + if (auto *InjTy = ClassType->getAsCanonical()) { InjTy->getOriginalDecl()->printName(OS, Policy); return; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 340de6d4be934..ba589ac3c0dfe 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -74,8 +74,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { if (DerivedType->isDependentType()) return nullptr; - const RecordType *Ty = DerivedType->castAs(); - return cast(Ty->getOriginalDecl())->getDefinitionOrSelf(); + return DerivedType->castAsCXXRecordDecl(); } const Expr *Expr::skipRValueSubobjectAdjustments( @@ -90,10 +89,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments( CE->getCastKind() == CK_UncheckedDerivedToBase) && E->getType()->isRecordType()) { E = CE->getSubExpr(); - const auto *Derived = - cast( - E->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *Derived = E->getType()->castAsCXXRecordDecl(); Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } @@ -2032,9 +2028,7 @@ CXXBaseSpecifier **CastExpr::path_buffer() { const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, QualType opType) { - auto RD = - unionType->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - return getTargetFieldForToUnionCast(RD, opType); + return getTargetFieldForToUnionCast(unionType->castAsRecordDecl(), opType); } const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD, @@ -3396,10 +3390,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; - RecordDecl *RD = ILE->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = ILE->getType()->castAsRecordDecl(); // In C++17, bases were added to the list of members used by aggregate // initialization. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9b934753bcc3c..5803931c4a424 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2623,8 +2623,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK, Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps); } if (Value.isStruct()) { - RecordDecl *RD = - Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + auto *RD = Type->castAsRecordDecl(); if (const CXXRecordDecl *CD = dyn_cast(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { @@ -4110,7 +4109,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } // Next subobject is a class, struct or union field. - RecordDecl *RD = ObjType->castAs()->getOriginalDecl(); + RecordDecl *RD = + ObjType->castAsCanonical()->getOriginalDecl(); if (RD->isUnion()) { const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || @@ -8591,10 +8591,9 @@ class ExprEvaluatorBase const FieldDecl *FD = dyn_cast(E->getMemberDecl()); if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); - assert( - BaseTy->castAs()->getOriginalDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && - "record / field mismatch"); + assert(BaseTy->castAsCanonical()->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 @@ -8821,10 +8820,9 @@ class LValueExprEvaluatorBase const ValueDecl *MD = E->getMemberDecl(); if (const FieldDecl *FD = dyn_cast(E->getMemberDecl())) { - assert( - BaseTy->castAs()->getOriginalDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && - "record / field mismatch"); + assert(BaseTy->castAsCanonical()->getOriginalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); (void)BaseTy; if (!HandleLValueMember(this->Info, E, Result, FD)) return false; @@ -10824,8 +10822,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, } bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) { - const RecordDecl *RD = - T->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = T->castAsRecordDecl(); if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the @@ -10894,10 +10891,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( const Expr *ExprToVisit, ArrayRef Args) { - const RecordDecl *RD = ExprToVisit->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + const auto *RD = ExprToVisit->getType()->castAsRecordDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); auto *CXXRD = dyn_cast(RD); @@ -11125,10 +11119,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( Result = APValue(APValue::UninitStruct(), 0, 2); Array.moveInto(Result.getStructField(0)); - RecordDecl *Record = E->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *Record = E->getType()->castAsRecordDecl(); RecordDecl::field_iterator Field = Record->field_begin(); assert(Field != Record->field_end() && Info.Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -13172,10 +13163,7 @@ static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int, static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T, const LValue &LV, CharUnits &Size) { if (!T.isNull() && T->isStructureType() && - T->getAsStructureType() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) + T->castAsRecordDecl()->hasFlexibleArrayMember()) if (const auto *V = LV.getLValueBase().dyn_cast()) if (const auto *VD = dyn_cast(V)) if (VD->hasInit()) @@ -15459,10 +15447,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { case OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); - const RecordType *RT = CurrentType->getAs(); - if (!RT) + const auto *RD = CurrentType->getAsRecordDecl(); + if (!RD) return Error(OOE); - RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); unsigned i = MemberDecl->getFieldIndex(); @@ -15481,22 +15468,20 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); // Find the layout of the class whose base we are looking into. - const RecordType *RT = CurrentType->getAs(); - if (!RT) + const auto *RD = CurrentType->getAsCXXRecordDecl(); + if (!RD) return Error(OOE); - RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); // Find the base class itself. CurrentType = BaseSpec->getType(); - const RecordType *BaseRT = CurrentType->getAs(); - if (!BaseRT) + const auto *BaseRD = CurrentType->getAsCXXRecordDecl(); + if (!BaseRD) return Error(OOE); // Add the offset to the base. - Result += RL.getBaseClassOffset(cast( - BaseRT->getOriginalDecl()->getDefinitionOrSelf())); + Result += RL.getBaseClassOffset(BaseRD); break; } } @@ -15674,8 +15659,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { } if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) { - const EnumType *ET = dyn_cast(DestType.getCanonicalType()); - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = DestType->getAsEnumDecl(); // Check that the value is within the range of the enumeration values. // // This corressponds to [expr.static.cast]p10 which says: diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 502a3e6b145e3..d4cb89b43ae87 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -413,14 +413,13 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return Match; case AnyCharTy: { - if (const auto *ETy = argTy->getAs()) { + if (const auto *ED = argTy->getAsEnumDecl()) { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped // enumeration. - const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); if (!ED->isComplete()) return NoMatch; - if (ETy->isUnscopedEnumerationType()) + if (!ED->isScoped()) argTy = ED->getIntegerType(); } @@ -463,14 +462,13 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return matchesSizeTPtrdiffT(C, argTy, T); } - if (const EnumType *ETy = argTy->getAs()) { + if (const auto *ED = argTy->getAsEnumDecl()) { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped // enumeration as that needs an exact match. - const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); if (!ED->isComplete()) argTy = C.IntTy; - else if (ETy->isUnscopedEnumerationType()) + else if (!ED->isScoped()) argTy = ED->getIntegerType(); } @@ -655,7 +653,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { // to Objective-C objects. Since the compiler doesn't know which // structs can be toll-free bridged, we just accept them all. QualType pointee = PT->getPointeeType(); - if (pointee->getAsStructureType() || pointee->isVoidType()) + if (pointee->isStructureType() || pointee->isVoidType()) return Match; } return NoMatch; 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( - Type->castAs()->getOriginalDecl()); + const auto *Decl = cast( + Type->castAsCanonical()->getOriginalDecl()); for (const auto &Base : Decl->bases()) { QualType CanonBaseType = Context.getCanonicalType(Base.getType()); diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 43a8bcd9443ff..adef1584fd9b6 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -42,8 +42,7 @@ namespace { /// /// Returns the name of anonymous union VarDecl or nullptr if it is not found. static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) { - const auto *RT = VD.getType()->castAs(); - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = VD.getType()->castAsRecordDecl(); assert(RD->isUnion() && "RecordType is expected to be a union."); if (const FieldDecl *FD = RD->findFirstNamedDataMember()) { return FD->getIdentifier(); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 112678fb2714a..ffadfce67d631 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1580,10 +1580,7 @@ void CXXNameMangler::mangleUnqualifiedName( if (const VarDecl *VD = dyn_cast(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = VD->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + const auto *RD = VD->getType()->castAsRecordDecl(); // Itanium C++ ABI 5.1.2: // @@ -4729,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()) { + while (const auto *RT = Base->getType()->getAsCanonical()) { if (!RT->getOriginalDecl()->isAnonymousStructOrUnion()) break; const auto *ME = dyn_cast(Base); @@ -6997,8 +6994,8 @@ static bool hasMangledSubstitutionQualifiers(QualType T) { bool CXXNameMangler::mangleSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs()) - return mangleSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf()); + if (const auto *RD = T->getAsCXXRecordDecl()) + return mangleSubstitution(RD); } uintptr_t TypePtr = reinterpret_cast(T.getAsOpaquePtr()); @@ -7034,7 +7031,7 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name, if (S.isNull()) return false; - const RecordType *RT = S->getAs(); + const RecordType *RT = S->getAsCanonical(); if (!RT) return false; @@ -7168,8 +7165,8 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { void CXXNameMangler::addSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs()) { - addSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf()); + if (const auto *RD = T->getAsCXXRecordDecl()) { + addSubstitution(RD); return; } } 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( - Base->getType()->castAs()->getOriginalDecl()); + Base->getType()->castAsCanonical()->getOriginalDecl()); llvm::json::Object Val{{"name", RD->getName()}}; if (Base->isVirtual()) diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index 687160c6116be..855550475721a 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -793,8 +793,8 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, } // If it's an enum, get its underlying type. - if (const EnumType *ETy = QT->getAs()) - QT = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = QT->getAsEnumDecl()) + QT = ED->getIntegerType(); const BuiltinType *BT = QT->getAs(); if (!BT) { diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index f1f21f426f944..4b312c559bf2a 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -204,15 +204,13 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { // Check the fields. for (const FieldDecl *FD : Class->fields()) { - const RecordType *RT = - Context.getBaseElementType(FD->getType())->getAs(); - - // We only care about record types. - if (!RT) + // We only care about records. + const auto *MemberDecl = + Context.getBaseElementType(FD->getType())->getAsCXXRecordDecl(); + if (!MemberDecl) continue; CharUnits EmptySize; - const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); if (MemberDecl->isEmpty()) { // If the class decl is empty, get its size. @@ -433,11 +431,10 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, // If we have an array type we need to look at every element. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { QualType ElemTy = Context.getBaseElementType(AT); - const RecordType *RT = ElemTy->getAs(); - if (!RT) + const auto *RD = ElemTy->getAsCXXRecordDecl(); + if (!RD) return true; - const CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); @@ -533,11 +530,10 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects( // If we have an array type we need to update every element. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { QualType ElemTy = Context.getBaseElementType(AT); - const RecordType *RT = ElemTy->getAs(); - if (!RT) + const auto *RD = ElemTy->getAsCXXRecordDecl(); + if (!RD) return; - const CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); @@ -2011,7 +2007,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, CTy->getElementType()->castAs()); } else if (const BuiltinType *BTy = BaseTy->getAs()) { performBuiltinTypeAlignmentUpgrade(BTy); - } else if (const RecordType *RT = BaseTy->getAs()) { + } else if (const RecordType *RT = BaseTy->getAsCanonical()) { const RecordDecl *RD = RT->getOriginalDecl(); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); PreferredAlign = FieldRecord.getPreferredAlignment(); @@ -2711,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()) { + if (const auto *RT = FD->getType() + ->getBaseElementTypeUnsafe() + ->getAsCanonical()) { auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl()); EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldRequiredAlignment = std::max(FieldRequiredAlignment, @@ -3695,9 +3692,9 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits); // Recursively dump fields of record type. - if (auto RT = Field->getType()->getAs()) { - DumpRecordLayout(OS, RT->getOriginalDecl()->getDefinitionOrSelf(), C, - FieldOffset, IndentLevel, Field->getName().data(), + if (const auto *RD = Field->getType()->getAsRecordDecl()) { + DumpRecordLayout(OS, RD, C, FieldOffset, IndentLevel, + Field->getName().data(), /*PrintSizeInfo=*/false, /*IncludeVirtualBases=*/true); continue; diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 31c001d025fea..41cf71a3e042d 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -430,9 +430,8 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT, QualType PT = QT->getPointeeType(); // If it's an enum, get its underlying type. - if (const EnumType *ETy = PT->getAs()) { + if (const auto *ED = PT->getAsEnumDecl()) { // Don't try to fix incomplete enums. - const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); if (!ED->isComplete()) return false; PT = ED->getIntegerType(); diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 76050ceeb35a7..76f96fb8c5dcc 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -56,8 +56,8 @@ static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, const llvm::APSInt &Val = TemplArg.getAsIntegral(); if (Policy.UseEnumerators) { - if (const EnumType *ET = T->getAs()) { - for (const EnumConstantDecl *ECD : ET->getOriginalDecl()->enumerators()) { + if (const auto *ED = T->getAsEnumDecl()) { + for (const EnumConstantDecl *ECD : ED->enumerators()) { // In Sema::CheckTemplateArugment, enum template arguments value are // extended to the size of the integer underlying the enum type. This // may create a size difference between the enum value and template 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( - Base->getType()->castAs()->getOriginalDecl()); + Base->getType()->castAsCanonical()->getOriginalDecl()); if (Base->isVirtual()) OS << "virtual "; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index a70bc5424009c..500c942bea039 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -113,10 +113,8 @@ const IdentifierInfo *QualType::getBaseTypeIdentifier() const { return DNT->getIdentifier(); if (ty->isPointerOrReferenceType()) return ty->getPointeeType().getBaseTypeIdentifier(); - if (ty->isRecordType()) - ND = ty->castAs()->getOriginalDecl(); - else if (ty->isEnumeralType()) - ND = ty->castAs()->getOriginalDecl(); + if (const auto *TT = ty->getAs()) + ND = TT->getOriginalDecl(); else if (ty->getTypeClass() == Type::Typedef) ND = ty->castAs()->getDecl(); else if (ty->isArrayType()) @@ -672,63 +670,59 @@ const Type *Type::getUnqualifiedDesugaredType() const { } bool Type::isClassType() const { - if (const auto *RT = getAs()) + if (const auto *RT = getAsCanonical()) return RT->getOriginalDecl()->isClass(); return false; } bool Type::isStructureType() const { - if (const auto *RT = getAs()) + if (const auto *RT = getAsCanonical()) return RT->getOriginalDecl()->isStruct(); return false; } bool Type::isStructureTypeWithFlexibleArrayMember() const { - const auto *RT = getAs(); + const auto *RT = getAsCanonical(); if (!RT) return false; - const auto *Decl = RT->getOriginalDecl()->getDefinitionOrSelf(); + const auto *Decl = RT->getOriginalDecl(); if (!Decl->isStruct()) return false; - return Decl->hasFlexibleArrayMember(); + return Decl->getDefinitionOrSelf()->hasFlexibleArrayMember(); } bool Type::isObjCBoxableRecordType() const { - if (const auto *RT = getAs()) - return RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasAttr(); + if (const auto *RD = getAsRecordDecl()) + return RD->hasAttr(); return false; } bool Type::isInterfaceType() const { - if (const auto *RT = getAs()) + if (const auto *RT = getAsCanonical()) return RT->getOriginalDecl()->isInterface(); return false; } bool Type::isStructureOrClassType() const { - if (const auto *RT = getAs()) { - RecordDecl *RD = RT->getOriginalDecl(); - return RD->isStruct() || RD->isClass() || RD->isInterface(); - } + if (const auto *RT = getAsCanonical()) + return RT->getOriginalDecl()->isStructureOrClass(); return false; } bool Type::isVoidPointerType() const { - if (const auto *PT = getAs()) + if (const auto *PT = getAsCanonical()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { - if (const auto *RT = getAs()) + if (const auto *RT = getAsCanonical()) return RT->getOriginalDecl()->isUnion(); return false; } bool Type::isComplexType() const { - if (const auto *CT = dyn_cast(CanonicalType)) + if (const auto *CT = getAsCanonical()) return CT->getElementType()->isFloatingType(); return false; } @@ -739,7 +733,7 @@ bool Type::isComplexIntegerType() const { } bool Type::isScopedEnumeralType() const { - if (const auto *ET = getAs()) + if (const auto *ET = getAsCanonical()) return ET->getOriginalDecl()->isScoped(); return false; } @@ -1914,41 +1908,13 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { QualType PointeeType; - if (const auto *PT = getAs()) + if (const auto *PT = getAsCanonical()) PointeeType = PT->getPointeeType(); - else if (const auto *RT = getAs()) + else if (const auto *RT = getAsCanonical()) PointeeType = RT->getPointeeType(); else return nullptr; - - if (const auto *RT = PointeeType->getAs()) - return dyn_cast( - RT->getOriginalDecl()->getDefinitionOrSelf()); - - return nullptr; -} - -CXXRecordDecl *Type::getAsCXXRecordDecl() const { - const auto *TT = dyn_cast(CanonicalType); - if (!isa_and_present(TT)) - return nullptr; - auto *TD = TT->getOriginalDecl(); - if (!isa(TT) && !isa(TD)) - return nullptr; - return cast(TD)->getDefinitionOrSelf(); -} - -RecordDecl *Type::getAsRecordDecl() const { - const auto *TT = dyn_cast(CanonicalType); - if (!isa_and_present(TT)) - return nullptr; - return cast(TT->getOriginalDecl())->getDefinitionOrSelf(); -} - -TagDecl *Type::getAsTagDecl() const { - if (const auto *TT = dyn_cast(CanonicalType)) - return TT->getOriginalDecl()->getDefinitionOrSelf(); - return nullptr; + return PointeeType->getAsCXXRecordDecl(); } const TemplateSpecializationType * @@ -2246,10 +2212,9 @@ bool Type::isSignedIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isSignedInteger(); - if (const EnumType *ET = dyn_cast(CanonicalType)) { + if (const auto *ED = getAsEnumDecl()) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); if (!ED->isComplete() || ED->isScoped()) return false; return ED->getIntegerType()->isSignedIntegerType(); @@ -2267,8 +2232,7 @@ bool Type::isSignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isSignedInteger(); - if (const auto *ET = dyn_cast(CanonicalType)) { - const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *ED = getAsEnumDecl()) { if (!ED->isComplete()) return false; return ED->getIntegerType()->isSignedIntegerType(); @@ -2296,10 +2260,9 @@ bool Type::isUnsignedIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isUnsignedInteger(); - if (const auto *ET = dyn_cast(CanonicalType)) { + if (const auto *ED = getAsEnumDecl()) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); if (!ED->isComplete() || ED->isScoped()) return false; return ED->getIntegerType()->isUnsignedIntegerType(); @@ -2317,8 +2280,7 @@ bool Type::isUnsignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isUnsignedInteger(); - if (const auto *ET = dyn_cast(CanonicalType)) { - const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *ED = getAsEnumDecl()) { if (!ED->isComplete()) return false; return ED->getIntegerType()->isUnsignedIntegerType(); @@ -2398,10 +2360,8 @@ bool Type::isArithmeticType() const { bool Type::hasBooleanRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isBooleanType(); - if (const auto *ET = dyn_cast(CanonicalType)) { - const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *ED = getAsEnumDecl()) return ED->isComplete() && ED->getIntegerType()->isBooleanType(); - } if (const auto *IT = dyn_cast(CanonicalType)) return IT->getNumBits() == 1; return isBooleanType(); @@ -2432,10 +2392,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { } else if (isa(T)) { return STK_MemberPointer; } else if (isa(T)) { - assert(cast(T) - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isComplete()); + assert(T->getAsEnumDecl()->isComplete()); return STK_Integral; } else if (const auto *CT = dyn_cast(T)) { if (CT->getElementType()->isRealFloatingType()) @@ -2459,8 +2416,8 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { /// includes union types. bool Type::isAggregateType() const { if (const auto *Record = dyn_cast(CanonicalType)) { - if (const auto *ClassDecl = dyn_cast( - Record->getOriginalDecl()->getDefinitionOrSelf())) + if (const auto *ClassDecl = + dyn_cast(Record->getOriginalDecl())) return ClassDecl->isAggregate(); return true; @@ -2494,8 +2451,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const { // be completed. return isVoidType(); case Enum: { - EnumDecl *EnumD = - cast(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf(); + auto *EnumD = castAsEnumDecl(); if (Def) *Def = EnumD; return !EnumD->isComplete(); @@ -2503,17 +2459,13 @@ bool Type::isIncompleteType(NamedDecl **Def) const { case Record: { // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). - RecordDecl *Rec = cast(CanonicalType) - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *Rec = castAsRecordDecl(); if (Def) *Def = Rec; return !Rec->isCompleteDefinition(); } case InjectedClassName: { - CXXRecordDecl *Rec = cast(CanonicalType) - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *Rec = castAsCXXRecordDecl(); if (!Rec->isBeingDefined()) return false; if (Def) @@ -2573,7 +2525,7 @@ bool Type::isAlwaysIncompleteType() const { // Forward declarations of structs, classes, enums, and unions could be later // completed in a compilation unit by providing a type definition. - if (getAsTagDecl()) + if (isa(CanonicalType)) return false; // Other types are incompletable. @@ -2797,7 +2749,7 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { case Type::Record: if (const auto *ClassDecl = dyn_cast( cast(CanonicalType)->getOriginalDecl())) - return ClassDecl->getDefinitionOrSelf()->isPOD(); + return ClassDecl->isPOD(); // C struct/union is POD. return true; @@ -2837,23 +2789,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const { // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; - if (const auto *RT = CanonicalType->getAs()) { - if (const auto *ClassDecl = - dyn_cast(RT->getOriginalDecl())) { - // C++20 [class]p6: - // A trivial class is a class that is trivially copyable, and - // has one or more eligible default constructors such that each is - // trivial. - // FIXME: We should merge this definition of triviality into - // CXXRecordDecl::isTrivial. Currently it computes the wrong thing. - return ClassDecl->hasTrivialDefaultConstructor() && - !ClassDecl->hasNonTrivialDefaultConstructor() && - ClassDecl->isTriviallyCopyable(); - } - return true; + if (const auto *ClassDecl = CanonicalType->getAsCXXRecordDecl()) { + // C++20 [class]p6: + // A trivial class is a class that is trivially copyable, and + // has one or more eligible default constructors such that each is + // trivial. + // FIXME: We should merge this definition of triviality into + // CXXRecordDecl::isTrivial. Currently it computes the wrong thing. + return ClassDecl->hasTrivialDefaultConstructor() && + !ClassDecl->hasNonTrivialDefaultConstructor() && + ClassDecl->isTriviallyCopyable(); } + if (isa(CanonicalType)) + return true; + // No other types can match. return false; } @@ -2897,18 +2848,13 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type, if (CanonicalType->isMFloat8Type()) return true; - if (const auto *RT = CanonicalType->getAs()) { - if (const auto *ClassDecl = - dyn_cast(RT->getOriginalDecl())) { - if (IsCopyConstructible) { + if (const auto *RD = CanonicalType->getAsRecordDecl()) { + if (const auto *ClassDecl = dyn_cast(RD)) { + if (IsCopyConstructible) return ClassDecl->isTriviallyCopyConstructible(); - } else { - return ClassDecl->isTriviallyCopyable(); - } + return ClassDecl->isTriviallyCopyable(); } - return !RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->isNonTrivialToPrimitiveCopy(); + return !RD->isNonTrivialToPrimitiveCopy(); } // No other types can match. return false; @@ -2996,11 +2942,9 @@ bool QualType::isWebAssemblyFuncrefType() const { QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { - if (const auto *RT = - getTypePtr()->getBaseElementTypeUnsafe()->getAs()) - if (RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->isNonTrivialToPrimitiveDefaultInitialize()) + if (const auto *RD = + getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + if (RD->isNonTrivialToPrimitiveDefaultInitialize()) return PDIK_Struct; switch (getQualifiers().getObjCLifetime()) { @@ -3014,11 +2958,9 @@ QualType::isNonTrivialToPrimitiveDefaultInitialize() const { } QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const { - if (const auto *RT = - getTypePtr()->getBaseElementTypeUnsafe()->getAs()) - if (RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->isNonTrivialToPrimitiveCopy()) + if (const auto *RD = + getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + if (RD->isNonTrivialToPrimitiveCopy()) return PCK_Struct; Qualifiers Qs = getQualifiers(); @@ -3075,7 +3017,7 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { if (BaseTy->isReferenceType()) return true; // -- a class type that has all of the following properties: - if (const auto *RT = BaseTy->getAs()) { + if (const auto *RD = BaseTy->getAsRecordDecl()) { // -- a trivial destructor, // -- every constructor call and full-expression in the // brace-or-equal-initializers for non-static data members (if any) @@ -3086,8 +3028,8 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { // -- all non-static data members and base classes of literal types // // We resolve DR1361 by ignoring the second bullet. - if (const auto *ClassDecl = dyn_cast(RT->getOriginalDecl())) - return ClassDecl->getDefinitionOrSelf()->isLiteral(); + if (const auto *ClassDecl = dyn_cast(RD)) + return ClassDecl->isLiteral(); return true; } @@ -3139,10 +3081,10 @@ bool Type::isStandardLayoutType() const { // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; - if (const auto *RT = BaseTy->getAs()) { - if (const auto *ClassDecl = dyn_cast(RT->getOriginalDecl())) - if (!ClassDecl->getDefinitionOrSelf()->isStandardLayout()) - return false; + if (const auto *RD = BaseTy->getAsRecordDecl()) { + if (const auto *ClassDecl = dyn_cast(RD); + ClassDecl && !ClassDecl->isStandardLayout()) + return false; // Default to 'true' for non-C++ class types. // FIXME: This is a bit dubious, but plain C structs should trivially meet @@ -3182,10 +3124,8 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; - if (const auto *RT = BaseTy->getAs()) { - if (const auto *ClassDecl = - dyn_cast(RT->getOriginalDecl())) { - ClassDecl = ClassDecl->getDefinitionOrSelf(); + if (const auto *RD = BaseTy->getAsRecordDecl()) { + if (const auto *ClassDecl = dyn_cast(RD)) { // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] if (!ClassDecl->isTrivial()) @@ -3224,7 +3164,7 @@ bool Type::isNothrowT() const { } bool Type::isAlignValT() const { - if (const auto *ET = getAs()) { + if (const auto *ET = getAsCanonical()) { const auto *ED = ET->getOriginalDecl(); IdentifierInfo *II = ED->getIdentifier(); if (II && II->isStr("align_val_t") && ED->isInStdNamespace()) @@ -3234,7 +3174,7 @@ bool Type::isAlignValT() const { } bool Type::isStdByteType() const { - if (const auto *ET = getAs()) { + if (const auto *ET = getAsCanonical()) { const auto *ED = ET->getOriginalDecl(); IdentifierInfo *II = ED->getIdentifier(); if (II && II->isStr("byte") && ED->isInStdNamespace()) @@ -4405,7 +4345,7 @@ bool RecordType::hasConstFields() const { if (FieldTy.isConstQualified()) return true; FieldTy = FieldTy.getCanonicalType(); - if (const auto *FieldRecTy = FieldTy->getAs()) { + if (const auto *FieldRecTy = FieldTy->getAsCanonical()) { if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } @@ -5409,7 +5349,7 @@ bool Type::isObjCARCBridgableType() const { /// Determine whether the given type T is a "bridgeable" C type. bool Type::isCARCBridgableType() const { - const auto *Pointer = getAs(); + const auto *Pointer = getAsCanonical(); if (!Pointer) return false; @@ -5419,7 +5359,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()) + if (const auto *RT = getAsCanonical()) return RT->getOriginalDecl() ->getMostRecentDecl() ->hasAttr(); @@ -5428,7 +5368,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()) + if (const auto *RT = getAsCanonical()) return RT->getOriginalDecl() ->getMostRecentDecl() ->hasAttr(); @@ -5503,8 +5443,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { return DK_objc_weak_lifetime; } - if (const auto *RT = type->getBaseElementTypeUnsafe()->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl(); + if (const auto *RD = type->getBaseElementTypeUnsafe()->getAsRecordDecl()) { if (const auto *CXXRD = dyn_cast(RD)) { /// Check if this is a C++ object with a non-trivial destructor. if (CXXRD->hasDefinition() && !CXXRD->hasTrivialDestructor()) @@ -5512,7 +5451,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { } else { /// Check if this is a C struct that is non-trivial to destroy or an array /// that contains such a struct. - if (RD->getDefinitionOrSelf()->isNonTrivialToPrimitiveDestroy()) + if (RD->isNonTrivialToPrimitiveDestroy()) return DK_nontrivial_c_struct; } } 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()) { + if (auto *TTPT = Pattern->getAsCanonical()) { if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() && Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) { QualType SubstArg = Ctx.getQualifiedType( diff --git a/clang/lib/AST/VTTBuilder.cpp b/clang/lib/AST/VTTBuilder.cpp index 85101aee97e66..89b58b557ddca 100644 --- a/clang/lib/AST/VTTBuilder.cpp +++ b/clang/lib/AST/VTTBuilder.cpp @@ -63,11 +63,7 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { if (I.isVirtual()) continue; - const auto *BaseDecl = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); @@ -91,10 +87,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, return; for (const auto &I : RD->bases()) { - const auto *BaseDecl = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either @@ -157,10 +150,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { for (const auto &I : RD->bases()) { - const auto *BaseDecl = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); // Check if this is a virtual base. if (I.isVirtual()) { diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 823d7543f085f..3fcd3481c2d6b 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -703,7 +703,8 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) { // definition and see whether the param is mutated inside. if (const auto *RefType = ParmType->getAs()) { if (!RefType->getPointeeType().getQualifiers() && - RefType->getPointeeType()->getAs()) { + isa( + RefType->getPointeeType().getCanonicalType())) { FunctionParmMutationAnalyzer *Analyzer = FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer( *Func, Context, Memorized); diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp index f560dd8ae1dd1..68c27eeb7e8e6 100644 --- a/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -83,13 +83,11 @@ static std::pair classifyCapability(QualType QT) { // We need to look at the declaration of the type of the value to determine // which it is. The type should either be a record or a typedef, or a pointer // or reference thereof. - if (const auto *RT = QT->getAs()) { - if (const auto *RD = RT->getOriginalDecl()) - return classifyCapability(*RD->getDefinitionOrSelf()); - } else if (const auto *TT = QT->getAs()) { - if (const auto *TD = TT->getDecl()) - return classifyCapability(*TD); - } else if (QT->isPointerOrReferenceType()) + if (const auto *RD = QT->getAsRecordDecl()) + return classifyCapability(*RD); + if (const auto *TT = QT->getAs()) + return classifyCapability(*TT->getDecl()); + if (QT->isPointerOrReferenceType()) return classifyCapability(QT->getPointeeType()); return ClassifyCapabilityFallback; diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 8a15e5f96aea2..25859885296fa 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -287,10 +287,7 @@ void CIRGenFunction::emitDelegateCallArg(CallArgList &args, // Deactivate the cleanup for the callee-destructed param that was pushed. assert(!cir::MissingFeatures::thunks()); if (type->isRecordType() && - type->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee() && + type->castAsRecordDecl()->isParamDestroyedInCallee() && param->needsDestruction(getContext())) { cgm.errorNYI(param->getSourceRange(), "emitDelegateCallArg: callee-destructed param"); @@ -690,10 +687,8 @@ void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e, // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee. // However, we still have to push an EH-only cleanup in case we unwind before // we make it to the call. - if (argType->isRecordType() && argType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee()) { + if (argType->isRecordType() && + argType->castAsRecordDecl()->isParamDestroyedInCallee()) { assert(!cir::MissingFeatures::msabi()); cgm.errorNYI(e->getSourceRange(), "emitCallArg: msabi is NYI"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 3e5dc22426d8e..722027aa5631d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -120,9 +120,7 @@ static void emitMemberInitializer(CIRGenFunction &cgf, static bool isInitializerOfDynamicClass(const CXXCtorInitializer *baseInit) { const Type *baseType = baseInit->getBaseClass(); - const auto *baseClassDecl = - cast(baseType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *baseClassDecl = baseType->castAsCXXRecordDecl(); return baseClassDecl->isDynamicClass(); } @@ -161,9 +159,7 @@ void CIRGenFunction::emitBaseInitializer(mlir::Location loc, Address thisPtr = loadCXXThisAddress(); const Type *baseType = baseInit->getBaseClass(); - const auto *baseClassDecl = - cast(baseType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *baseClassDecl = baseType->castAsCXXRecordDecl(); bool isBaseVirtual = baseInit->isBaseVirtual(); @@ -568,9 +564,7 @@ void CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) { void CIRGenFunction::destroyCXXObject(CIRGenFunction &cgf, Address addr, QualType type) { - const RecordType *rtype = type->castAs(); - const CXXRecordDecl *record = - cast(rtype->getOriginalDecl())->getDefinitionOrSelf(); + const auto *record = type->castAsCXXRecordDecl(); const CXXDestructorDecl *dtor = record->getDestructor(); // TODO(cir): Unlike traditional codegen, CIRGen should actually emit trivial // dtors which shall be removed on later CIR passes. However, only remove this diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 2b74b27100402..1afac6dd52c2d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1092,11 +1092,7 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { - const auto *derivedClassTy = - e->getSubExpr()->getType()->castAs(); - auto *derivedClassDecl = - cast(derivedClassTy->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *derivedClassDecl = e->getSubExpr()->getType()->castAsCXXRecordDecl(); LValue lv = emitLValue(e->getSubExpr()); Address thisAddr = lv.getAddress(); @@ -1265,17 +1261,11 @@ static void pushTemporaryCleanup(CIRGenFunction &cgf, case SD_Static: case SD_Thread: { CXXDestructorDecl *referenceTemporaryDtor = nullptr; - if (const clang::RecordType *rt = e->getType() - ->getBaseElementTypeUnsafe() - ->getAs()) { + if (const auto *classDecl = + e->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + classDecl && !classDecl->hasTrivialDestructor()) // Get the destructor for the reference temporary. - if (const auto *classDecl = dyn_cast( - rt->getOriginalDecl()->getDefinitionOrSelf())) { - if (!classDecl->hasTrivialDestructor()) - referenceTemporaryDtor = - classDecl->getDefinitionOrSelf()->getDestructor(); - } - } + referenceTemporaryDtor = classDecl->getDestructor(); if (!referenceTemporaryDtor) return; diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 2a3c98c458256..bab9ac73d7e65 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -409,10 +409,7 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr( // the disadvantage is that the generated code is more difficult for // the optimizer, especially with bitfields. unsigned numInitElements = args.size(); - RecordDecl *record = e->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *record = e->getType()->castAsRecordDecl(); // We'll need to enter cleanup scopes in case any of the element // initializers throws an exception. diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index ced3c2273e865..262d2548d5c39 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -680,9 +680,7 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &d) { // assignments and whatnots). Since this is for globals shouldn't // be a problem for the near future. if (cd->isTrivial() && cd->isDefaultConstructor()) { - const auto *cxxrd = - cast(ty->getAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *cxxrd = ty->castAsCXXRecordDecl(); if (cxxrd->getNumBases() != 0) { // There may not be anything additional to do here, but this will // force us to pause and test this path when it is supported. @@ -949,7 +947,7 @@ mlir::Value CIRGenModule::emitNullConstant(QualType t, mlir::Location loc) { errorNYI("CIRGenModule::emitNullConstant ConstantArrayType"); } - if (t->getAs()) + if (t->isRecordType()) errorNYI("CIRGenModule::emitNullConstant RecordType"); assert(t->isMemberDataPointerType() && diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 706c14ae962a8..deabb94b7d129 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -356,12 +356,8 @@ static bool mayDropFunctionReturn(const ASTContext &astContext, QualType returnType) { // 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 *recordType = - returnType.getCanonicalType()->getAs()) { - if (const auto *classDecl = dyn_cast( - recordType->getOriginalDecl()->getDefinitionOrSelf())) - return classDecl->hasTrivialDestructor(); - } + if (const auto *classDecl = returnType->getAsCXXRecordDecl()) + return classDecl->hasTrivialDestructor(); return returnType.isTriviallyCopyableType(astContext); } @@ -829,14 +825,9 @@ std::string CIRGenFunction::getCounterAggTmpAsString() { void CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty) { // Ignore empty classes in C++. - if (getLangOpts().CPlusPlus) { - if (const RecordType *rt = ty->getAs()) { - if (cast(rt->getOriginalDecl()) - ->getDefinitionOrSelf() - ->isEmpty()) - return; - } - } + if (getLangOpts().CPlusPlus) + if (const auto *rd = ty->getAsCXXRecordDecl(); rd && rd->isEmpty()) + return; // Cast the dest ptr to the appropriate i8 pointer type. if (builder.isInt8Ty(destPtr.getElementType())) { diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 46bca51767c02..870fd973e6e9a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1074,8 +1074,7 @@ static bool isVarDeclStrongDefinition(const ASTContext &astContext, if (astContext.isAlignmentRequired(varType)) return true; - if (const auto *rt = varType->getAs()) { - const RecordDecl *rd = rt->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *rd = varType->getAsRecordDecl()) { for (const FieldDecl *fd : rd->fields()) { if (fd->isBitField()) continue; @@ -2178,10 +2177,7 @@ CharUnits CIRGenModule::computeNonVirtualBaseClassOffset( // Get the layout. const ASTRecordLayout &layout = astContext.getASTRecordLayout(rd); - const auto *baseDecl = - cast( - base->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *baseDecl = base->getType()->castAsCXXRecordDecl(); // Add the offset. offset += layout.getBaseClassOffset(baseDecl); diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp index 4ad15e6922ddd..5e1bc8631cac8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp @@ -506,8 +506,9 @@ class OpenACCClauseCIREmitter final const VarDecl *varRecipe, const VarDecl *temporary, DeclContext *dc, QualType baseType, mlir::Value mainOp) { - mlir::ModuleOp mod = - builder.getBlock()->getParent()->getParentOfType(); + mlir::ModuleOp mod = builder.getBlock() + ->getParent() + ->template getParentOfType(); std::string recipeName = getRecipeName(varRef->getSourceRange(), baseType); diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index aada6094d0fd5..bb24933a22ed7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -185,9 +185,8 @@ isSafeToConvert(QualType qt, CIRGenTypes &cgt, qt = at->getValueType(); // If this is a record, check it. - if (const auto *rt = qt->getAs()) - return isSafeToConvert(rt->getOriginalDecl()->getDefinitionOrSelf(), cgt, - alreadyChecked); + if (const auto *rd = qt->getAsRecordDecl()) + return isSafeToConvert(rd, cgt, alreadyChecked); // If this is an array, check the elements, which are embedded inline. if (const auto *at = cgt.getASTContext().getAsArrayType(qt)) @@ -247,10 +246,7 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) { for (const auto &base : cxxRecordDecl->bases()) { if (base.isVirtual()) continue; - convertRecordDeclType(base.getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf()); + convertRecordDeclType(base.getType()->castAsRecordDecl()); } } @@ -466,8 +462,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } case Type::Enum: { - const EnumDecl *ed = - cast(ty)->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ed = ty->castAsEnumDecl(); if (auto integerType = ed->getIntegerType(); !integerType.isNull()) return convertType(integerType); // Return a placeholder 'i32' type. This can be changed later when the @@ -571,10 +566,8 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) { return true; } - if (const RecordType *rt = t->getAs()) { - const RecordDecl *rd = rt->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *rd = t->getAsRecordDecl()) return isZeroInitializable(rd); - } if (t->getAs()) { cgm.errorNYI(SourceLocation(), "isZeroInitializable for MemberPointerType", diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 7b6259b04122d..62a8c59abe604 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -6,12 +6,10 @@ using namespace clang::CIRGen; bool clang::CIRGen::isEmptyRecordForLayout(const ASTContext &context, QualType t) { - const RecordType *rt = t->getAs(); - if (!rt) + const auto *rd = t->getAsRecordDecl(); + if (!rd) return false; - const RecordDecl *rd = rt->getOriginalDecl()->getDefinitionOrSelf(); - // If this is a C++ record, check the bases first. if (const CXXRecordDecl *cxxrd = dyn_cast(rd)) { if (cxxrd->isDynamicClass()) diff --git a/clang/lib/CodeGen/ABIInfo.cpp b/clang/lib/CodeGen/ABIInfo.cpp index 83cc6377d502c..acd678193b5a8 100644 --- a/clang/lib/CodeGen/ABIInfo.cpp +++ b/clang/lib/CodeGen/ABIInfo.cpp @@ -67,8 +67,7 @@ bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base, if (!isHomogeneousAggregate(AT->getElementType(), Base, Members)) return false; Members *= NElements; - } else if (const RecordType *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + } else if (const auto *RD = Ty->getAsRecordDecl()) { if (RD->hasFlexibleArrayMember()) return false; diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index 79dbe70a0c8eb..13c837a0fb680 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -28,8 +28,8 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { } // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); ASTContext &Context = getContext(); if (const auto *EIT = Ty->getAs()) @@ -52,8 +52,8 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace()); // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); if (const auto *EIT = RetTy->getAs()) if (EIT->getNumBits() > @@ -114,7 +114,7 @@ CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT, } CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) { - const RecordType *RT = T->getAs(); + const RecordType *RT = T->getAsCanonical(); if (!RT) return CGCXXABI::RAA_Default; return getRecordArgABI(RT, CXXABI); @@ -124,13 +124,11 @@ bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info) { QualType Ty = FI.getReturnType(); - if (const auto *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (!isa(RD) && !RD->canPassInRegisters()) { - FI.getReturnInfo() = Info.getNaturalAlignIndirect( - Ty, Info.getDataLayout().getAllocaAddrSpace()); - return true; - } + if (const auto *RD = Ty->getAsRecordDecl(); + RD && !isa(RD) && !RD->canPassInRegisters()) { + FI.getReturnInfo() = Info.getNaturalAlignIndirect( + Ty, Info.getDataLayout().getAllocaAddrSpace()); + return true; } return CXXABI.classifyReturnType(FI); @@ -262,7 +260,7 @@ bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, WasArray = true; } - const RecordType *RT = FT->getAs(); + const RecordType *RT = FT->getAsCanonical(); if (!RT) return false; @@ -285,10 +283,9 @@ bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr) { - const RecordType *RT = T->getAs(); - if (!RT) + const auto *RD = T->getAsRecordDecl(); + if (!RD) return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->hasFlexibleArrayMember()) return false; @@ -316,12 +313,10 @@ bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, } bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { - const RecordType *RT = T->getAs(); - if (!RT) + const auto *RD = T->getAsRecordDecl(); + if (!RD) return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { if (CXXRD->isDynamicClass()) @@ -340,11 +335,10 @@ bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { } const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { - const RecordType *RT = T->getAs(); - if (!RT) + const auto *RD = T->getAsRecordDecl(); + if (!RD) return nullptr; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->hasFlexibleArrayMember()) return nullptr; @@ -460,10 +454,9 @@ bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) { } bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) { - const RecordType *RT = Ty->getAs(); - if (!RT) + const auto *RD = Ty->getAsRecordDecl(); + if (!RD) return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 74d92ef038eb9..597127abc9120 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -420,14 +420,11 @@ static void addBlockLayout(CharUnits align, CharUnits size, /// Determines if the given type is safe for constant capture in C++. static bool isSafeForCXXConstantCapture(QualType type) { - const RecordType *recordType = - type->getBaseElementTypeUnsafe()->getAs(); + const auto *record = type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); // Only records can be unsafe. - if (!recordType) return true; - - const auto *record = - cast(recordType->getOriginalDecl())->getDefinitionOrSelf(); + if (!record) + return true; // Maintain semantics for classes with non-trivial dtors or copy ctors. if (!record->hasTrivialDestructor()) return false; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d9cc37d123fb4..9ef38e0a340c3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -997,9 +997,8 @@ static const FieldDecl *FindFlexibleArrayMemberField(CodeGenFunction &CGF, /*IgnoreTemplateOrMacroSubstitution=*/true)) return FD; - if (auto RT = FD->getType()->getAs()) - if (const FieldDecl *FD = - FindFlexibleArrayMemberField(CGF, Ctx, RT->getAsRecordDecl())) + if (const auto *RD = FD->getType()->getAsRecordDecl()) + if (const FieldDecl *FD = FindFlexibleArrayMemberField(CGF, Ctx, RD)) return FD; } @@ -1025,8 +1024,8 @@ static bool GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, return true; } - if (auto RT = Field->getType()->getAs()) { - if (GetFieldOffset(Ctx, RT->getAsRecordDecl(), FD, Offset)) { + if (const auto *RD = Field->getType()->getAsRecordDecl()) { + if (GetFieldOffset(Ctx, RD, FD, Offset)) { Offset += Layout.getFieldOffset(FieldNo); return true; } diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index c7f4bf8a21354..5090a0559eab2 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -1131,8 +1131,7 @@ void CGNVCUDARuntime::handleVarRegistration(const VarDecl *D, // Builtin surfaces and textures and their template arguments are // also registered with CUDA runtime. const auto *TD = cast( - D->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + D->getType()->castAsCXXRecordDecl()); const TemplateArgumentList &Args = TD->getTemplateArgs(); if (TD->hasAttr()) { assert(Args.size() == 2 && diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index f9aff893eb0f0..59aeff6804b61 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -83,9 +83,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { if (I.isVirtual()) continue; // Skip base classes with trivial destructors. - const auto *Base = cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *Base = I.getType()->castAsCXXRecordDecl(); if (Base->hasTrivialDestructor()) continue; // If we've already found a base class with a non-trivial @@ -281,16 +279,8 @@ static CGCallee BuildAppleKextVirtualCall(CodeGenFunction &CGF, CGCallee CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, NestedNameSpecifier Qual, llvm::Type *Ty) { - assert(Qual.getKind() == NestedNameSpecifier::Kind::Type && - "BuildAppleKextVirtualCall - bad Qual kind"); - - const Type *QTy = Qual.getAsType(); - QualType T = QualType(QTy, 0); - const RecordType *RT = T->getAs(); - assert(RT && "BuildAppleKextVirtualCall - Qual type must be record"); - const auto *RD = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); - + const CXXRecordDecl *RD = Qual.getAsRecordDecl(); + assert(RD && "BuildAppleKextVirtualCall - Qual must be record"); if (const auto *DD = dyn_cast(MD)) return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD); diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index cca675838644e..30e5dc2b6cbd9 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -165,10 +165,7 @@ bool CGCXXABI::mayNeedDestruction(const VarDecl *VD) const { // If the variable has an incomplete class type (or array thereof), it // might need destruction. const Type *T = VD->getType()->getBaseElementTypeUnsafe(); - if (T->getAs() && T->isIncompleteType()) - return true; - - return false; + return T->isRecordType() && T->isIncompleteType(); } bool CGCXXABI::isEmittedWithConstantInitializer( diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 466546b2f1309..ce00e1f6e6b0f 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1005,10 +1005,9 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) { return std::make_unique(AT->getElementType(), AT->getZExtSize()); } - if (const RecordType *RT = Ty->getAs()) { + if (const auto *RD = Ty->getAsRecordDecl()) { SmallVector Bases; SmallVector Fields; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); assert(!RD->hasFlexibleArrayMember() && "Cannot expand structure with flexible array."); if (RD->isUnion()) { @@ -1897,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()) { + ReturnType.getCanonicalType()->getAsCanonical()) { if (const auto *ClassDecl = dyn_cast(RT->getOriginalDecl())) return ClassDecl->hasTrivialDestructor(); } @@ -2874,10 +2873,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, // whose destruction / clean-up is carried out within the callee // (e.g., Obj-C ARC-managed structs, MSVC callee-destroyed objects). if (!ParamType.isDestructedType() || !ParamType->isRecordType() || - ParamType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee()) + ParamType->castAsRecordDecl()->isParamDestroyedInCallee()) Attrs.addAttribute(llvm::Attribute::DeadOnReturn); } } @@ -3890,7 +3886,7 @@ static void setUsedBits(CodeGenModule &CGM, const ConstantArrayType *ATy, // the type `QTy`. static void setUsedBits(CodeGenModule &CGM, QualType QTy, int Offset, SmallVectorImpl &Bits) { - if (const auto *RTy = QTy->getAs()) + if (const auto *RTy = QTy->getAsCanonical()) return setUsedBits(CGM, RTy, Offset, Bits); ASTContext &Context = CGM.getContext(); @@ -3934,7 +3930,7 @@ llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src, const llvm::DataLayout &DataLayout = CGM.getDataLayout(); int Size = DataLayout.getTypeStoreSize(ITy); SmallVector Bits(Size); - setUsedBits(CGM, QTy->castAs(), 0, Bits); + setUsedBits(CGM, QTy->castAsCanonical(), 0, Bits); int CharWidth = CGM.getContext().getCharWidth(); uint64_t Mask = @@ -3951,7 +3947,7 @@ llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src, const llvm::DataLayout &DataLayout = CGM.getDataLayout(); int Size = DataLayout.getTypeStoreSize(ATy); SmallVector Bits(Size); - setUsedBits(CGM, QTy->castAs(), 0, Bits); + setUsedBits(CGM, QTy->castAsCanonical(), 0, Bits); // Clear each element of the LLVM array. int CharWidth = CGM.getContext().getCharWidth(); @@ -4308,10 +4304,7 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, // Deactivate the cleanup for the callee-destructed param that was pushed. if (type->isRecordType() && !CurFuncIsThunk && - type->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee() && + type->castAsRecordDecl()->isParamDestroyedInCallee() && param->needsDestruction(getContext())) { EHScopeStack::stable_iterator cleanup = CalleeDestructedParamCleanups.lookup(cast(param)); @@ -4904,10 +4897,8 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee. // However, we still have to push an EH-only cleanup in case we unwind before // we make it to the call. - if (type->isRecordType() && type->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee()) { + if (type->isRecordType() && + type->castAsRecordDecl()->isParamDestroyedInCallee()) { // If we're using inalloca, use the argument memory. Otherwise, use a // temporary. AggValueSlot Slot = args.isUsingInAlloca() diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index e9a92ae0f01cb..bae55aa1e1928 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -180,11 +180,7 @@ CharUnits CodeGenModule::computeNonVirtualBaseClassOffset( // Get the layout. const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const auto *BaseDecl = - cast( - Base->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *BaseDecl = Base->getType()->castAsCXXRecordDecl(); // Add the offset. Offset += Layout.getBaseClassOffset(BaseDecl); @@ -302,9 +298,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( // *start* with a step down to the correct virtual base subobject, // and hence will not require any further steps. if ((*Start)->isVirtual()) { - VBase = cast( - (*Start)->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + VBase = (*Start)->getType()->castAsCXXRecordDecl(); ++Start; } @@ -559,10 +553,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, Address ThisPtr = CGF.LoadCXXThisAddress(); - const Type *BaseType = BaseInit->getBaseClass(); - const auto *BaseClassDecl = - cast(BaseType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *BaseClassDecl = BaseInit->getBaseClass()->castAsCXXRecordDecl(); bool isBaseVirtual = BaseInit->isBaseVirtual(); @@ -1267,10 +1258,7 @@ namespace { static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) { const Type *BaseType = BaseInit->getBaseClass(); - const auto *BaseClassDecl = - cast(BaseType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - return BaseClassDecl->isDynamicClass(); + return BaseType->castAsCXXRecordDecl()->isDynamicClass(); } /// EmitCtorPrologue - This routine generates necessary code to initialize @@ -1377,10 +1365,7 @@ HasTrivialDestructorBody(ASTContext &Context, if (I.isVirtual()) continue; - const CXXRecordDecl *NonVirtualBase = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *NonVirtualBase = I.getType()->castAsCXXRecordDecl(); if (!HasTrivialDestructorBody(Context, NonVirtualBase, MostDerivedClassDecl)) return false; @@ -1389,10 +1374,7 @@ HasTrivialDestructorBody(ASTContext &Context, if (BaseClassDecl == MostDerivedClassDecl) { // Check virtual bases. for (const auto &I : BaseClassDecl->vbases()) { - const auto *VirtualBase = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *VirtualBase = I.getType()->castAsCXXRecordDecl(); if (!HasTrivialDestructorBody(Context, VirtualBase, MostDerivedClassDecl)) return false; @@ -1408,13 +1390,10 @@ FieldHasTrivialDestructorBody(ASTContext &Context, { QualType FieldBaseElementType = Context.getBaseElementType(Field->getType()); - const RecordType *RT = FieldBaseElementType->getAs(); - if (!RT) + auto *FieldClassDecl = FieldBaseElementType->getAsCXXRecordDecl(); + if (!FieldClassDecl) return true; - auto *FieldClassDecl = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); - // The destructor for an implicit anonymous union member is never invoked. if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion()) return true; @@ -1907,11 +1886,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, // We push them in the forward order so that they'll be popped in // the reverse order. for (const auto &Base : ClassDecl->vbases()) { - auto *BaseClassDecl = - cast( - Base.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *BaseClassDecl = Base.getType()->castAsCXXRecordDecl(); if (BaseClassDecl->hasTrivialDestructor()) { // Under SanitizeMemoryUseAfterDtor, poison the trivial base class // memory. For non-trival base classes the same is done in the class @@ -2130,10 +2105,7 @@ void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF, Address addr, QualType type) { - const RecordType *rtype = type->castAs(); - const auto *record = - cast(rtype->getOriginalDecl())->getDefinitionOrSelf(); - const CXXDestructorDecl *dtor = record->getDestructor(); + const CXXDestructorDecl *dtor = type->castAsCXXRecordDecl()->getDestructor(); assert(!dtor->isTrivial()); CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false, /*Delegating=*/false, addr, type); @@ -2652,10 +2624,7 @@ void CodeGenFunction::getVTablePointers(BaseSubobject Base, // Traverse bases. for (const auto &I : RD->bases()) { - auto *BaseDecl = cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); // Ignore classes without a vtable. if (!BaseDecl->isDynamicClass()) continue; @@ -2850,13 +2819,10 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived, if (!getLangOpts().CPlusPlus) return; - auto *ClassTy = T->getAs(); - if (!ClassTy) + const auto *ClassDecl = T->getAsCXXRecordDecl(); + if (!ClassDecl) return; - const auto *ClassDecl = - cast(ClassTy->getOriginalDecl())->getDefinitionOrSelf(); - if (!ClassDecl->isCompleteDefinition() || !ClassDecl->isDynamicClass()) return; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index c44fea3e6383d..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( - BI.getType()->castAs()->getOriginalDecl()) + BI.getType()->castAsCanonical()->getOriginalDecl()) ->getDefinition(); if (!SeenTypes.insert(Base).second) continue; @@ -5921,8 +5921,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, // variable for each member of the anonymous union so that it's possible // to find the name of any field in the union. if (T->isUnionType() && DeclName.empty()) { - const RecordDecl *RD = - T->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = T->castAsRecordDecl(); assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?"); GVE = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 8a1675848e13c..29193e0c541b9 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1568,10 +1568,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { ReturnValue.getElementType(), ReturnValue.getAlignment()); address = MaybeCastStackAddressSpace(AllocaAddr, Ty.getAddressSpace()); - if (const RecordType *RecordTy = Ty->getAs()) { - const auto *RD = RecordTy->getOriginalDecl()->getDefinitionOrSelf(); - const auto *CXXRD = dyn_cast(RD); - if ((CXXRD && !CXXRD->hasTrivialDestructor()) || + if (const auto *RD = Ty->getAsRecordDecl()) { + if (const auto *CXXRD = dyn_cast(RD); + (CXXRD && !CXXRD->hasTrivialDestructor()) || RD->isNonTrivialToPrimitiveDestroy()) { // Create a flag that is used to indicate when the NRVO was applied // to this variable. Set it to zero to indicate that NRVO was not @@ -2728,10 +2727,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // Don't push a cleanup in a thunk for a method that will also emit a // cleanup. if (Ty->isRecordType() && !CurFuncIsThunk && - Ty->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee()) { + Ty->castAsRecordDecl()->isParamDestroyedInCallee()) { if (QualType::DestructionKind DtorKind = D.needsDestruction(getContext())) { assert((DtorKind == QualType::DK_cxx_destructor || diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 2329fa20a2530..9e1b886263ed0 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -414,14 +414,11 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, case SD_Static: case SD_Thread: { CXXDestructorDecl *ReferenceTemporaryDtor = nullptr; - if (const RecordType *RT = - E->getType()->getBaseElementTypeUnsafe()->getAs()) { + if (const auto *ClassDecl = + E->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + ClassDecl && !ClassDecl->hasTrivialDestructor()) // Get the destructor for the reference temporary. - if (auto *ClassDecl = dyn_cast(RT->getOriginalDecl()); - ClassDecl && !ClassDecl->hasTrivialDestructor()) - ReferenceTemporaryDtor = - ClassDecl->getDefinitionOrSelf()->getDestructor(); - } + ReferenceTemporaryDtor = ClassDecl->getDestructor(); if (!ReferenceTemporaryDtor) return; @@ -1929,11 +1926,9 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue, static bool getRangeForType(CodeGenFunction &CGF, QualType Ty, llvm::APInt &Min, llvm::APInt &End, bool StrictEnums, bool IsBool) { - const EnumType *ET = Ty->getAs(); - const EnumDecl *ED = - ET ? ET->getOriginalDecl()->getDefinitionOrSelf() : nullptr; + const auto *ED = Ty->getAsEnumDecl(); bool IsRegularCPlusPlusEnum = - CGF.getLangOpts().CPlusPlus && StrictEnums && ET && !ED->isFixed(); + CGF.getLangOpts().CPlusPlus && StrictEnums && ED && !ED->isFixed(); if (!IsBool && !IsRegularCPlusPlusEnum) return false; @@ -1980,7 +1975,7 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty, bool IsBool = (Ty->hasBooleanRepresentation() && !Ty->isVectorType()) || NSAPI(CGM.getContext()).isObjCBOOLType(Ty); bool NeedsBoolCheck = HasBoolCheck && IsBool; - bool NeedsEnumCheck = HasEnumCheck && Ty->getAs(); + bool NeedsEnumCheck = HasEnumCheck && Ty->isEnumeralType(); if (!NeedsBoolCheck && !NeedsEnumCheck) return false; @@ -5683,12 +5678,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { - const auto *DerivedClassTy = - E->getSubExpr()->getType()->castAs(); - auto *DerivedClassDecl = - cast(DerivedClassTy->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *DerivedClassDecl = E->getSubExpr()->getType()->castAsCXXRecordDecl(); LValue LV = EmitLValue(E->getSubExpr()); Address This = LV.getAddress(); @@ -5706,11 +5696,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_ToUnion: return EmitAggExprToLValue(E); case CK_BaseToDerived: { - const auto *DerivedClassTy = E->getType()->castAs(); - auto *DerivedClassDecl = - cast(DerivedClassTy->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *DerivedClassDecl = E->getType()->castAsCXXRecordDecl(); LValue LV = EmitLValue(E->getSubExpr()); // Perform the base-to-derived conversion diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 04e125c54b1ca..b8150a24d45fc 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -268,11 +268,11 @@ void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) { /// True if the given aggregate type requires special GC API calls. bool AggExprEmitter::TypeRequiresGCollection(QualType T) { // Only record types have members that might require garbage collection. - const RecordType *RecordTy = T->getAs(); - if (!RecordTy) return false; + const auto *Record = T->getAsRecordDecl(); + if (!Record) + return false; // Don't mess with non-trivial C++ types. - RecordDecl *Record = RecordTy->getOriginalDecl()->getDefinitionOrSelf(); if (isa(Record) && (cast(Record)->hasNonTrivialCopyConstructor() || !cast(Record)->hasTrivialDestructor())) @@ -424,10 +424,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); assert(ArrayType && "std::initializer_list constructed from non-array"); - RecordDecl *Record = E->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *Record = E->getType()->castAsRecordDecl(); RecordDecl::field_iterator Field = Record->field_begin(); assert(Field != Record->field_end() && Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -1809,10 +1806,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // the disadvantage is that the generated code is more difficult for // the optimizer, especially with bitfields. unsigned NumInitElements = InitExprs.size(); - RecordDecl *record = ExprToVisit->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + RecordDecl *record = ExprToVisit->getType()->castAsRecordDecl(); // We'll need to enter cleanup scopes in case any of the element // initializers throws an exception. @@ -2120,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()) { + if (const RecordType *RT = E->getType()->getAsCanonical()) { if (!RT->isUnionType()) { RecordDecl *SD = RT->getOriginalDecl()->getDefinitionOrSelf(); CharUnits NumNonZeroBytes = CharUnits::Zero(); @@ -2173,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()) { + .getBaseElementType(E->getType()) + ->getAsCanonical()) { const CXXRecordDecl *RD = cast(RT->getOriginalDecl()); if (RD->hasUserDeclaredConstructor()) return; @@ -2294,9 +2289,7 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty, Address SrcPtr = Src.getAddress(); if (getLangOpts().CPlusPlus) { - if (const RecordType *RT = Ty->getAs()) { - auto *Record = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); + if (const auto *Record = Ty->getAsCXXRecordDecl()) { assert((Record->hasTrivialCopyConstructor() || Record->hasTrivialCopyAssignment() || Record->hasTrivialMoveConstructor() || @@ -2379,8 +2372,7 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty, // Don't do any of the memmove_collectable tests if GC isn't set. if (CGM.getLangOpts().getGC() == LangOptions::NonGC) { // fall through - } else if (const RecordType *RecordTy = Ty->getAs()) { - RecordDecl *Record = RecordTy->getOriginalDecl()->getDefinitionOrSelf(); + } else if (const auto *Record = Ty->getAsRecordDecl()) { if (Record->hasObjectMember()) { CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); @@ -2388,10 +2380,8 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty, } } else if (Ty->isArrayType()) { QualType BaseType = getContext().getBaseElementType(Ty); - if (const RecordType *RecordTy = BaseType->getAs()) { - if (RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasObjectMember()) { + if (const auto *Record = BaseType->getAsRecordDecl()) { + if (Record->hasObjectMember()) { CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); return; diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 57d7eecc62ee1..1e4c72a210f9a 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -180,8 +180,7 @@ static CXXRecordDecl *getCXXRecord(const Expr *E) { QualType T = E->getType(); if (const PointerType *PTy = T->getAs()) T = PTy->getPointeeType(); - const RecordType *Ty = T->castAs(); - return cast(Ty->getOriginalDecl())->getDefinitionOrSelf(); + return T->castAsCXXRecordDecl(); } // Note: This function also emit constructor calls to support a MSVC @@ -1235,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(Init)) { - if (const RecordType *RType = ILE->getType()->getAs()) { - const RecordDecl *RD = RType->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->isStruct()) { + if (const RecordType *RType = + ILE->getType()->getAsCanonical()) { + if (RType->getOriginalDecl()->isStruct()) { + const RecordDecl *RD = RType->getOriginalDecl()->getDefinitionOrSelf(); unsigned NumElements = 0; if (auto *CXXRD = dyn_cast(RD)) NumElements = CXXRD->getNumBases(); @@ -1687,11 +1687,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { QualType AlignValT = sizeType; if (allocatorType->getNumParams() > IndexOfAlignArg) { AlignValT = allocatorType->getParamType(IndexOfAlignArg); - assert(getContext().hasSameUnqualifiedType(AlignValT->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType(), - sizeType) && + assert(getContext().hasSameUnqualifiedType( + AlignValT->castAsEnumDecl()->getIntegerType(), sizeType) && "wrong type for alignment parameter"); ++ParamsToSkip; } else { @@ -1973,9 +1970,7 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, // Find the destructor for the type, if applicable. If the // destructor is virtual, we'll just emit the vcall and return. const CXXDestructorDecl *Dtor = nullptr; - if (const RecordType *RT = ElementType->getAs()) { - auto *RD = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); + if (const auto *RD = ElementType->getAsCXXRecordDecl()) { if (RD->hasDefinition() && !RD->hasTrivialDestructor()) { Dtor = RD->getDestructor(); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index a96c1518d2a1d..36534025ebd0f 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -714,10 +714,7 @@ static bool EmitDesignatedInitUpdater(ConstantEmitter &Emitter, } bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { - RecordDecl *RD = ILE->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = ILE->getType()->castAsRecordDecl(); const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); unsigned FieldNo = -1; @@ -980,8 +977,7 @@ bool ConstStructBuilder::DoZeroInitPadding(const ASTRecordLayout &Layout, llvm::Constant *ConstStructBuilder::Finalize(QualType Type) { Type = Type.getNonReferenceType(); - RecordDecl *RD = - Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + auto *RD = Type->castAsRecordDecl(); llvm::Type *ValTy = CGM.getTypes().ConvertType(Type); return Builder.build(ValTy, RD->hasFlexibleArrayMember()); } @@ -1004,8 +1000,7 @@ llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter, ConstantAggregateBuilder Const(Emitter.CGM); ConstStructBuilder Builder(Emitter, Const, CharUnits::Zero()); - const RecordDecl *RD = - ValTy->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = ValTy->castAsRecordDecl(); const CXXRecordDecl *CD = dyn_cast(RD); if (!Builder.Build(Val, RD, false, CD, CharUnits::Zero())) return nullptr; @@ -1510,10 +1505,8 @@ class ConstExprEmitter llvm::Type *ValTy = CGM.getTypes().ConvertType(destType); bool HasFlexibleArray = false; - if (const auto *RT = destType->getAs()) - HasFlexibleArray = RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember(); + if (const auto *RD = destType->getAsRecordDecl()) + HasFlexibleArray = RD->hasFlexibleArrayMember(); return Const.build(ValTy, HasFlexibleArray); } @@ -2646,11 +2639,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, continue; } - const CXXRecordDecl *base = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *base = I.getType()->castAsCXXRecordDecl(); // Ignore empty bases. if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) || CGM.getContext() @@ -2688,11 +2677,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, // Fill in the virtual bases, if we're working with the complete object. if (CXXR && asCompleteObject) { for (const auto &I : CXXR->vbases()) { - const auto *base = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *base = I.getType()->castAsCXXRecordDecl(); // Ignore empty bases. if (isEmptyRecordForLayout(CGM.getContext(), I.getType())) continue; @@ -2756,10 +2741,9 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { return llvm::ConstantArray::get(ATy, Array); } - if (const RecordType *RT = T->getAs()) - return ::EmitNullConstant(*this, - RT->getOriginalDecl()->getDefinitionOrSelf(), - /*complete object*/ true); + if (const auto *RD = T->getAsRecordDecl()) + return ::EmitNullConstant(*this, RD, + /*asCompleteObject=*/true); assert(T->isMemberDataPointerType() && "Should only see pointers to data members here!"); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index fcbfa5e31d149..63bc0d82a2b56 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3515,9 +3515,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { case OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); - RecordDecl *RD = CurrentType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = CurrentType->castAsRecordDecl(); const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); // Compute the index of the field in its parent. @@ -3551,15 +3549,13 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { } const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout( - CurrentType->castAs()->getOriginalDecl()); + CurrentType->castAsCanonical()->getOriginalDecl()); // Save the element type. CurrentType = ON.getBase()->getType(); // Compute the offset to the base. - auto *BaseRT = CurrentType->castAs(); - auto *BaseRD = - cast(BaseRT->getOriginalDecl())->getDefinitionOrSelf(); + auto *BaseRD = CurrentType->castAsCXXRecordDecl(); CharUnits OffsetInt = RL.getBaseClassOffset(BaseRD); Offset = llvm::ConstantInt::get(ResultType, OffsetInt.getQuantity()); break; diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index 1b941fff8b644..2d70e4c2e0394 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -39,8 +39,7 @@ template struct StructVisitor { template void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) { - const RecordDecl *RD = - QT->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); // Iterate over the fields of the struct. for (const FieldDecl *FD : RD->fields()) { @@ -674,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()) { + if (Size < CharUnits::fromQuantity(16) || + EltTy->getAsCanonical()) { GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStructOffset, Addrs); return; } diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index b5f17b812222a..b01d5471a9836 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -999,10 +999,8 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM, // Compute whether the ivar has strong members. if (CGM.getLangOpts().getGC()) - if (const RecordType *recordType = ivarType->getAs()) - HasStrong = recordType->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasObjectMember(); + if (const auto *RD = ivarType->getAsRecordDecl()) + HasStrong = RD->hasObjectMember(); // We can never access structs with object members with a native // access, because we need to use write barriers. This is what diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index eb4904050ae0f..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()) { + if (const RecordType *record = type->getAsCanonical()) { visitRecord(record, fieldOffset); continue; } @@ -2409,7 +2409,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, if (FQT->isUnionType()) HasUnion = true; - BuildRCBlockVarRecordLayout(FQT->castAs(), + BuildRCBlockVarRecordLayout(FQT->castAsCanonical(), 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(); + auto *RT = FQT->castAsCanonical(); 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()) { + if (const auto *record = type->getAsCanonical()) { 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()) { + if (const auto *record = T->getAsCanonical()) { BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */); llvm::Constant *Result = getBitmapBlockLayout(true); @@ -3353,9 +3353,8 @@ static bool hasWeakMember(QualType type) { return true; } - if (auto recType = type->getAs()) { - for (auto *field : - recType->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + if (auto *RD = type->getAsRecordDecl()) { + for (auto *field : RD->fields()) { if (hasWeakMember(field->getType())) return true; } @@ -5247,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()) { + if (const auto *recType = fieldType->getAsCanonical()) { size_t oldEnd = IvarsInfo.size(); visitRecord(recType, fieldOffset); diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index cbf99534d2ce6..76e0054f4c9da 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -439,10 +439,8 @@ void CGObjCRuntime::destroyCalleeDestroyedArguments(CodeGenFunction &CGF, CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime); } else { QualType QT = param->getType(); - auto *RT = QT->getAs(); - if (RT && RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->isParamDestroyedInCallee()) { + auto *RD = QT->getAsRecordDecl(); + if (RD && RD->isParamDestroyedInCallee()) { RValue RV = I->getRValue(CGF); QualType::DestructionKind DtorKind = QT.isDestructedType(); switch (DtorKind) { diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index f98339d472fa9..b66608319bb51 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -3006,10 +3006,10 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, CGF.GetAddrOfLocalVar(&TaskTypeArg), KmpTaskTWithPrivatesPtrQTy->castAs()); const auto *KmpTaskTWithPrivatesQTyRD = - cast(KmpTaskTWithPrivatesQTy->getAsTagDecl()); + KmpTaskTWithPrivatesQTy->castAsRecordDecl(); LValue Base = CGF.EmitLValueForField(TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin()); - const auto *KmpTaskTQTyRD = cast(KmpTaskTQTy->getAsTagDecl()); + const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl(); auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId); LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI); llvm::Value *PartidParam = PartIdLVal.getPointer(CGF); @@ -3104,11 +3104,10 @@ static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM, CGF.GetAddrOfLocalVar(&TaskTypeArg), KmpTaskTWithPrivatesPtrQTy->castAs()); const auto *KmpTaskTWithPrivatesQTyRD = - cast(KmpTaskTWithPrivatesQTy->getAsTagDecl()); + KmpTaskTWithPrivatesQTy->castAsRecordDecl(); auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin()); Base = CGF.EmitLValueForField(Base, *FI); - for (const auto *Field : - cast(FI->getType()->getAsTagDecl())->fields()) { + for (const auto *Field : FI->getType()->castAsRecordDecl()->fields()) { if (QualType::DestructionKind DtorKind = Field->getType().isDestructedType()) { LValue FieldLValue = CGF.EmitLValueForField(Base, Field); @@ -3212,7 +3211,7 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, LValue Base = CGF.EmitLoadOfPointerLValue( CGF.GetAddrOfLocalVar(&TaskPrivatesArg), TaskPrivatesArg.getType()->castAs()); - const auto *PrivatesQTyRD = cast(PrivatesQTy->getAsTagDecl()); + const auto *PrivatesQTyRD = PrivatesQTy->castAsRecordDecl(); Counter = 0; for (const FieldDecl *Field : PrivatesQTyRD->fields()) { LValue FieldLVal = CGF.EmitLValueForField(Base, Field); @@ -3259,7 +3258,7 @@ static void emitPrivatesInit(CodeGenFunction &CGF, CGF.ConvertTypeForMem(SharedsTy)), SharedsTy); } - FI = cast(FI->getType()->getAsTagDecl())->field_begin(); + FI = FI->getType()->castAsRecordDecl()->field_begin(); for (const PrivateDataTy &Pair : Privates) { // Do not initialize private locals. if (Pair.second.isLocalPrivate()) { @@ -3655,7 +3654,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, } KmpTaskTQTy = SavedKmpTaskTQTy; } - const auto *KmpTaskTQTyRD = cast(KmpTaskTQTy->getAsTagDecl()); + const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl(); // Build particular struct kmp_task_t for the given task. const RecordDecl *KmpTaskTWithPrivatesQTyRD = createKmpTaskTWithPrivatesRecordDecl(CGM, KmpTaskTQTy, Privates); @@ -3915,10 +3914,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, // Fill the data in the resulting kmp_task_t record. // Copy shareds if there are any. Address KmpTaskSharedsPtr = Address::invalid(); - if (!SharedsTy->getAsStructureType() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->field_empty()) { + if (!SharedsTy->castAsRecordDecl()->field_empty()) { KmpTaskSharedsPtr = Address( CGF.EmitLoadOfScalar( CGF.EmitLValueForField( @@ -3948,11 +3944,8 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, enum { Priority = 0, Destructors = 1 }; // Provide pointer to function with destructors for privates. auto FI = std::next(KmpTaskTQTyRD->field_begin(), Data1); - const RecordDecl *KmpCmplrdataUD = (*FI) - ->getType() - ->getAsUnionType() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + const auto *KmpCmplrdataUD = (*FI)->getType()->castAsRecordDecl(); + assert(KmpCmplrdataUD->isUnion()); if (NeedsCleanup) { llvm::Value *DestructorFn = emitDestructorsFunction( CGM, Loc, KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy, @@ -4032,8 +4025,7 @@ CGOpenMPRuntime::getDepobjElements(CodeGenFunction &CGF, LValue DepobjLVal, ASTContext &C = CGM.getContext(); QualType FlagsTy; getDependTypes(C, KmpDependInfoTy, FlagsTy); - RecordDecl *KmpDependInfoRD = - cast(KmpDependInfoTy->getAsTagDecl()); + auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl(); QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy); LValue Base = CGF.EmitLoadOfPointerLValue( DepobjLVal.getAddress().withElementType( @@ -4061,8 +4053,7 @@ static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy, ASTContext &C = CGM.getContext(); QualType FlagsTy; getDependTypes(C, KmpDependInfoTy, FlagsTy); - RecordDecl *KmpDependInfoRD = - cast(KmpDependInfoTy->getAsTagDecl()); + auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl(); llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy); OMPIteratorGeneratorScope IteratorScope( @@ -4333,8 +4324,7 @@ Address CGOpenMPRuntime::emitDepobjDependClause( unsigned NumDependencies = Dependencies.DepExprs.size(); QualType FlagsTy; getDependTypes(C, KmpDependInfoTy, FlagsTy); - RecordDecl *KmpDependInfoRD = - cast(KmpDependInfoTy->getAsTagDecl()); + auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl(); llvm::Value *Size; // Define type kmp_depend_info[]; @@ -4442,8 +4432,7 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, ASTContext &C = CGM.getContext(); QualType FlagsTy; getDependTypes(C, KmpDependInfoTy, FlagsTy); - RecordDecl *KmpDependInfoRD = - cast(KmpDependInfoTy->getAsTagDecl()); + auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl(); llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy); llvm::Value *NumDeps; LValue Base; @@ -11319,7 +11308,7 @@ void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF, RD->completeDefinition(); KmpDimTy = C.getCanonicalTagType(RD); } else { - RD = cast(KmpDimTy->getAsTagDecl()); + RD = KmpDimTy->castAsRecordDecl(); } llvm::APInt Size(/*numBits=*/32, NumIterations.size()); QualType ArrayTy = C.getConstantArrayType(KmpDimTy, Size, nullptr, diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 652fe672f15e3..23e179881fccb 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2221,14 +2221,9 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, void CodeGenFunction::EmitNullInitialization(Address DestPtr, QualType Ty) { // Ignore empty classes in C++. - if (getLangOpts().CPlusPlus) { - if (const RecordType *RT = Ty->getAs()) { - if (cast(RT->getOriginalDecl()) - ->getDefinitionOrSelf() - ->isEmpty()) - return; - } - } + if (getLangOpts().CPlusPlus) + if (const auto *RD = Ty->getAsCXXRecordDecl(); RD && RD->isEmpty()) + return; if (DestPtr.getElementType() != Int8Ty) DestPtr = DestPtr.withElementType(Int8Ty); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index fc65199a0f154..a562a6a1ea6e1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2979,10 +2979,8 @@ class CodeGenFunction : public CodeGenTypeCache { /// hasVolatileMember - returns true if aggregate type has a volatile /// member. bool hasVolatileMember(QualType T) { - if (const RecordType *RT = T->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = T->getAsRecordDecl()) return RD->hasVolatileMember(); - } return false; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 677d8bc82cb0a..094221fed1aed 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()) + if (const auto *RT = + T->getBaseElementTypeUnsafe()->getAsCanonical()) if (auto *RD = dyn_cast(RT->getOriginalDecl())) { RD = RD->getDefinitionOrSelf(); if (RD->getDestructor() && !RD->getDestructor()->hasAttr()) @@ -6075,8 +6076,7 @@ static bool isVarDeclStrongDefinition(const ASTContext &Context, if (Context.isAlignmentRequired(VarType)) return true; - if (const auto *RT = VarType->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = VarType->getAsRecordDecl()) { for (const FieldDecl *FD : RD->fields()) { if (FD->isBitField()) continue; diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index bd2442f01cc50..f8c7d64cc1aa2 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -142,10 +142,9 @@ static bool TypeHasMayAlias(QualType QTy) { /// Check if the given type is a valid base type to be used in access tags. static bool isValidBaseType(QualType QTy) { - if (const RecordType *TTy = QTy->getAs()) { - const RecordDecl *RD = TTy->getOriginalDecl()->getDefinition(); + if (const auto *RD = QTy->getAsRecordDecl()) { // Incomplete types are not valid base access types. - if (!RD) + if (!RD->isCompleteDefinition()) return false; if (RD->hasFlexibleArrayMember()) return false; @@ -296,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(); + const auto *RT = Ty->getAsCanonical(); if (!RT) return getAnyPtr(PtrDepth); @@ -425,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()) { + if (const auto *TTy = QTy->getAsCanonical()) { if (TTy->isUnionType()) { uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); llvm::MDNode *TBAAType = getChar(); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index f2a0a649a88fd..3ffe999d01178 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -311,12 +311,12 @@ llvm::Type *CodeGenTypes::ConvertFunctionTypeInternal(QualType QFT) { // Force conversion of all the relevant record types, to make sure // we re-convert the FunctionType when appropriate. - if (const RecordType *RT = FT->getReturnType()->getAs()) - ConvertRecordDeclType(RT->getOriginalDecl()->getDefinitionOrSelf()); + if (const auto *RD = FT->getReturnType()->getAsRecordDecl()) + ConvertRecordDeclType(RD); if (const FunctionProtoType *FPT = dyn_cast(FT)) for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++) - if (const RecordType *RT = FPT->getParamType(i)->getAs()) - ConvertRecordDeclType(RT->getOriginalDecl()->getDefinitionOrSelf()); + if (const auto *RD = FPT->getParamType(i)->getAsRecordDecl()) + ConvertRecordDeclType(RD); SkippedLayout = true; @@ -700,8 +700,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { break; case Type::Enum: { - const EnumDecl *ED = - cast(Ty)->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = Ty->castAsEnumDecl(); if (ED->isCompleteDefinition() || ED->isFixed()) return ConvertType(ED->getIntegerType()); // Return a placeholder 'i32' type. This can be changed later when the @@ -814,10 +813,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) { if (const CXXRecordDecl *CRD = dyn_cast(RD)) { for (const auto &I : CRD->bases()) { if (I.isVirtual()) continue; - ConvertRecordDeclType(I.getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf()); + ConvertRecordDeclType(I.getType()->castAsRecordDecl()); } } @@ -875,10 +871,8 @@ bool CodeGenTypes::isZeroInitializable(QualType T) { // Records are non-zero-initializable if they contain any // non-zero-initializable subobjects. - if (const RecordType *RT = T->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = T->getAsRecordDecl()) return isZeroInitializable(RD); - } // We have to ask the ABI about member pointers. if (const MemberPointerType *MPT = T->getAs()) diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp index ac56dda74abb7..a21feaa1120c6 100644 --- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp +++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp @@ -85,24 +85,22 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType( Layout.push_back(0); // iterate over all fields of the record, including fields on base classes - llvm::SmallVector RecordTypes; - RecordTypes.push_back(RT); - while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) { - CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl(); + llvm::SmallVector RecordDecls; + RecordDecls.push_back(RT->castAsCXXRecordDecl()); + while (RecordDecls.back()->getNumBases()) { + CXXRecordDecl *D = RecordDecls.back(); assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance"); - RecordTypes.push_back(D->bases_begin()->getType()->getAs()); + RecordDecls.push_back(D->bases_begin()->getType()->castAsCXXRecordDecl()); } unsigned FieldOffset; llvm::Type *FieldType; - while (!RecordTypes.empty()) { - const RecordType *RT = RecordTypes.back(); - RecordTypes.pop_back(); + while (!RecordDecls.empty()) { + const CXXRecordDecl *RD = RecordDecls.pop_back_val(); - for (const auto *FD : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + for (const auto *FD : RD->fields()) { assert((!PackOffsets || Index < PackOffsets->size()) && "number of elements in layout struct does not match number of " "packoffset annotations"); @@ -148,7 +146,7 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType( // create the layout struct type; anonymous struct have empty name but // non-empty qualified name - const CXXRecordDecl *Decl = RT->getAsCXXRecordDecl(); + const auto *Decl = RT->castAsCXXRecordDecl(); std::string Name = Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString(); llvm::StructType *StructTy = @@ -203,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(createLayoutType(Ty->getAs())); + llvm::Type *NewTy = cast( + createLayoutType(Ty->getAsCanonical())); if (!NewTy) return false; assert(isa(NewTy) && "expected target type"); @@ -222,8 +220,8 @@ bool HLSLBufferLayoutBuilder::layoutField(const FieldDecl *FD, } else if (FieldTy->isStructureOrClassType()) { // Create a layout type for the structure - ElemLayoutTy = - createLayoutType(cast(FieldTy->getAs())); + ElemLayoutTy = createLayoutType( + cast(FieldTy->getAsCanonical())); if (!ElemLayoutTy) return false; assert(isa(ElemLayoutTy) && "expected target type"); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 4ed3775f156c9..885b700ffa193 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1397,9 +1397,7 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, // to pass to the deallocation function. // Grab the vtable pointer as an intptr_t*. - auto *ClassDecl = cast( - ElementType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *ClassDecl = ElementType->castAsCXXRecordDecl(); llvm::Value *VTable = CGF.GetVTablePtr(Ptr, CGF.UnqualPtrTy, ClassDecl); // Track back to entry -2 and pull out the offset there. @@ -1484,21 +1482,18 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { // The address of the destructor. If the exception type has a // trivial destructor (or isn't a record), we just pass null. llvm::Constant *Dtor = nullptr; - if (const RecordType *RecordTy = ThrowType->getAs()) { - CXXRecordDecl *Record = - cast(RecordTy->getOriginalDecl())->getDefinitionOrSelf(); - if (!Record->hasTrivialDestructor()) { - // __cxa_throw is declared to take its destructor as void (*)(void *). We - // must match that if function pointers can be authenticated with a - // discriminator based on their type. - const ASTContext &Ctx = getContext(); - QualType DtorTy = Ctx.getFunctionType(Ctx.VoidTy, {Ctx.VoidPtrTy}, - FunctionProtoType::ExtProtoInfo()); - - CXXDestructorDecl *DtorD = Record->getDestructor(); - Dtor = CGM.getAddrOfCXXStructor(GlobalDecl(DtorD, Dtor_Complete)); - Dtor = CGM.getFunctionPointer(Dtor, DtorTy); - } + if (const auto *Record = ThrowType->getAsCXXRecordDecl(); + Record && !Record->hasTrivialDestructor()) { + // __cxa_throw is declared to take its destructor as void (*)(void *). We + // must match that if function pointers can be authenticated with a + // discriminator based on their type. + const ASTContext &Ctx = getContext(); + QualType DtorTy = Ctx.getFunctionType(Ctx.VoidTy, {Ctx.VoidPtrTy}, + FunctionProtoType::ExtProtoInfo()); + + CXXDestructorDecl *DtorD = Record->getDestructor(); + Dtor = CGM.getAddrOfCXXStructor(GlobalDecl(DtorD, Dtor_Complete)); + Dtor = CGM.getFunctionPointer(Dtor, DtorTy); } if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy); @@ -1612,9 +1607,7 @@ llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy, Address ThisPtr, llvm::Type *StdTypeInfoPtrTy) { - auto *ClassDecl = - cast(SrcRecordTy->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *ClassDecl = SrcRecordTy->castAsCXXRecordDecl(); llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, CGM.GlobalsInt8PtrTy, ClassDecl); @@ -1786,9 +1779,7 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast( llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy) { - auto *ClassDecl = - cast(SrcRecordTy->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *ClassDecl = SrcRecordTy->castAsCXXRecordDecl(); llvm::Value *OffsetToTop; if (CGM.getItaniumVTableContext().isRelativeLayout()) { // Get the vtable pointer. @@ -3872,9 +3863,7 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { return false; // Check that the class is dynamic iff the base is. - auto *BaseDecl = cast( - Base->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *BaseDecl = Base->getType()->castAsCXXRecordDecl(); if (!BaseDecl->isEmpty() && BaseDecl->isDynamicClass() != RD->isDynamicClass()) return false; @@ -4394,10 +4383,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base, unsigned Flags = 0; - auto *BaseDecl = cast( - Base->getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *BaseDecl = Base->getType()->castAsCXXRecordDecl(); if (Base->isVirtual()) { // Mark the virtual base as seen. if (!Bases.VirtualBases.insert(BaseDecl).second) { @@ -4495,11 +4481,7 @@ void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // The __base_type member points to the RTTI for the base type. Fields.push_back(ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(Base.getType())); - auto *BaseDecl = - cast( - Base.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *BaseDecl = Base.getType()->castAsCXXRecordDecl(); int64_t OffsetFlags = 0; // All but the lower 8 bits of __offset_flags are a signed offset. 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()) { + if (auto recType = type->getAsCanonical()) { addTypedData(recType->getOriginalDecl(), begin); // Array types. diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index 289f8a9dcf211..d7deece232a9f 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -374,8 +374,8 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, if (!passAsAggregateType(Ty)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); if (const auto *EIT = Ty->getAs()) if (EIT->getNumBits() > 128) @@ -493,10 +493,9 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, auto ContainsOnlyPointers = [&](const auto &Self, QualType Ty) { if (isEmptyRecord(getContext(), Ty, true)) return false; - const RecordType *RT = Ty->getAs(); - if (!RT) + const auto *RD = Ty->getAsRecordDecl(); + if (!RD) return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) if (!Self(Self, I.getType())) @@ -547,9 +546,8 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, if (!passAsAggregateType(RetTy)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); if (const auto *EIT = RetTy->getAs()) if (EIT->getNumBits() > 128) @@ -738,7 +736,7 @@ bool AArch64ABIInfo::passAsPureScalableType( return true; } - if (const RecordType *RT = Ty->getAs()) { + if (const RecordType *RT = Ty->getAsCanonical()) { // 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/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 41bccbb5721b2..0fcbf7e458a34 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -95,8 +95,7 @@ unsigned AMDGPUABIInfo::numRegsForType(QualType Ty) const { return EltNumRegs * VT->getNumElements(); } - if (const RecordType *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = Ty->getAsRecordDecl()) { assert(!RD->hasFlexibleArrayMember()); for (const FieldDecl *Field : RD->fields()) { @@ -152,11 +151,9 @@ ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const { if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); - if (const RecordType *RT = RetTy->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->hasFlexibleArrayMember()) - return DefaultABIInfo::classifyReturnType(RetTy); - } + if (const auto *RD = RetTy->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) + return DefaultABIInfo::classifyReturnType(RetTy); // Pack aggregates <= 4 bytes into single VGPR or pair. uint64_t Size = getContext().getTypeSize(RetTy); @@ -245,11 +242,9 @@ ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, bool Variadic, if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); - if (const RecordType *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->hasFlexibleArrayMember()) - return DefaultABIInfo::classifyArgumentType(Ty); - } + if (const auto *RD = Ty->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) + return DefaultABIInfo::classifyArgumentType(Ty); // Pack aggregates <= 8 bytes into single VGPR or pair. uint64_t Size = getContext().getTypeSize(Ty); diff --git a/clang/lib/CodeGen/Targets/ARC.cpp b/clang/lib/CodeGen/Targets/ARC.cpp index ace524e1976d9..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(); + const RecordType *RT = Ty->getAsCanonical(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) @@ -105,8 +105,8 @@ ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, } // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index 3739e16788c3e..c84c9f2f643ee 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -382,8 +382,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) { - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) { + Ty = ED->getIntegerType(); } if (const auto *EIT = Ty->getAs()) @@ -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(); + const RecordType *RT = Ty->getAsCanonical(); if (!RT) return false; // Ignore records with flexible arrays. @@ -592,9 +592,8 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic, if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); if (const auto *EIT = RetTy->getAs()) if (EIT->getNumBits() > 64) @@ -718,9 +717,8 @@ bool ARMABIInfo::containsAnyFP16Vectors(QualType Ty) const { if (NElements == 0) return false; return containsAnyFP16Vectors(AT->getElementType()); - } else if (const RecordType *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - + } + if (const auto *RD = Ty->getAsRecordDecl()) { // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) if (llvm::any_of(CXXRD->bases(), [this](const CXXBaseSpecifier &B) { diff --git a/clang/lib/CodeGen/Targets/BPF.cpp b/clang/lib/CodeGen/Targets/BPF.cpp index 87d50e671d251..3a7af346f1132 100644 --- a/clang/lib/CodeGen/Targets/BPF.cpp +++ b/clang/lib/CodeGen/Targets/BPF.cpp @@ -47,8 +47,8 @@ class BPFABIInfo : public DefaultABIInfo { } } - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); ASTContext &Context = getContext(); if (const auto *EIT = Ty->getAs()) @@ -69,9 +69,8 @@ class BPFABIInfo : public DefaultABIInfo { getDataLayout().getAllocaAddrSpace()); // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); ASTContext &Context = getContext(); if (const auto *EIT = RetTy->getAs()) diff --git a/clang/lib/CodeGen/Targets/CSKY.cpp b/clang/lib/CodeGen/Targets/CSKY.cpp index 7e5a16f30727f..b9254208f912a 100644 --- a/clang/lib/CodeGen/Targets/CSKY.cpp +++ b/clang/lib/CodeGen/Targets/CSKY.cpp @@ -91,7 +91,7 @@ ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - if (!Ty->getAsUnionType()) + if (!Ty->isUnionType()) if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); @@ -115,8 +115,8 @@ ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft, if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // All integral types are promoted to XLen width, unless passed on the // stack. 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(), + Packoffsets); if (!BufferLayoutTy) return nullptr; diff --git a/clang/lib/CodeGen/Targets/Hexagon.cpp b/clang/lib/CodeGen/Targets/Hexagon.cpp index 0c423429eda4f..97a9300a1b8cd 100644 --- a/clang/lib/CodeGen/Targets/Hexagon.cpp +++ b/clang/lib/CodeGen/Targets/Hexagon.cpp @@ -97,8 +97,8 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty, unsigned *RegsLeft) const { if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 64) @@ -160,9 +160,8 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); if (Size > 64 && RetTy->isBitIntType()) return getNaturalAlignIndirect( diff --git a/clang/lib/CodeGen/Targets/Lanai.cpp b/clang/lib/CodeGen/Targets/Lanai.cpp index 08cb36034f6fd..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(); + const RecordType *RT = Ty->getAsCanonical(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) { @@ -125,8 +125,8 @@ ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty, } // Treat an enum type as its underlying type. - if (const auto *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); bool InReg = shouldUseInReg(Ty, State); diff --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp index af863e6101e2c..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()) { + if (const auto *RTy = EltTy->getAsCanonical()) { if (ArraySize != 0 && isa(RTy->getOriginalDecl()) && isEmptyRecord(getContext(), EltTy, true, true)) return false; @@ -164,7 +164,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper( return true; } - if (const auto *RTy = Ty->getAs()) { + if (const auto *RTy = Ty->getAsCanonical()) { // 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())) @@ -180,10 +180,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper( // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const CXXBaseSpecifier &B : CXXRD->bases()) { - const auto *BDecl = - cast( - B.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *BDecl = B.getType()->castAsCXXRecordDecl(); if (!detectFARsEligibleStructHelper( B.getType(), CurOff + Layout.getBaseClassOffset(BDecl), Field1Ty, Field1Off, Field2Ty, Field2Off)) @@ -370,8 +367,8 @@ ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // All integral types are promoted to GRLen width. if (Size < GRLen && Ty->isIntegralOrEnumerationType()) diff --git a/clang/lib/CodeGen/Targets/Mips.cpp b/clang/lib/CodeGen/Targets/Mips.cpp index e12a34ce07bbe..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(); + const RecordType *RT = Ty->getAsCanonical(); // Unions/vectors are passed in integer registers. if (!RT || !RT->isStructureOrClassType()) { @@ -241,8 +241,8 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { } // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // Make sure we pass indirectly things that are too large. if (const auto *EIT = Ty->getAs()) @@ -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(); + const RecordType *RT = RetTy->getAsCanonical(); SmallVector RTList; if (RT && RT->isStructureOrClassType()) { @@ -332,8 +332,8 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { } // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); // Make sure we pass indirectly things that are too large. if (const auto *EIT = RetTy->getAs()) diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index e874617796f86..400fa200bf7bc 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -130,10 +130,9 @@ bool NVPTXABIInfo::isUnsupportedType(QualType T) const { return true; if (const auto *AT = T->getAsArrayTypeUnsafe()) return isUnsupportedType(AT->getElementType()); - const auto *RT = T->getAs(); - if (!RT) + const auto *RD = T->getAsRecordDecl(); + if (!RD) return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) @@ -173,8 +172,8 @@ ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getDirect(); // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); @@ -182,8 +181,8 @@ ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // Return aggregates type as indirect by value if (isAggregateTypeForABI(Ty)) { diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index 38e76399299ec..380e8c06c46f0 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -153,8 +153,8 @@ class AIXTargetCodeGenInfo : public TargetCodeGenInfo { // extended to 32/64 bits. bool AIXABIInfo::isPromotableTypeForABI(QualType Ty) const { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (getContext().isPromotableIntegerType(Ty)) @@ -294,10 +294,7 @@ void AIXTargetCodeGenInfo::setTargetAttributes( ASTContext &Context = D->getASTContext(); unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8; const auto *Ty = VarD->getType().getTypePtr(); - const RecordDecl *RDecl = - Ty->isRecordType() - ? Ty->getAs()->getOriginalDecl()->getDefinitionOrSelf() - : nullptr; + const RecordDecl *RDecl = Ty->getAsRecordDecl(); bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage(); auto reportUnsupportedWarning = [&](bool ShouldEmitWarning, StringRef Msg) { @@ -708,8 +705,8 @@ class PPC64TargetCodeGenInfo : public TargetCodeGenInfo { bool PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (isPromotableIntegerTypeForABI(Ty)) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index cbb0255fdb03a..adcf04c38a0f8 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()) { + if (const auto *RTy = EltTy->getAsCanonical()) { if (ArraySize != 0 && isa(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()) { + if (const auto *RTy = Ty->getAsCanonical()) { // 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())) @@ -264,10 +264,7 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const CXXBaseSpecifier &B : CXXRD->bases()) { - const auto *BDecl = - cast( - B.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *BDecl = B.getType()->castAsCXXRecordDecl(); CharUnits BaseOff = Layout.getBaseClassOffset(BDecl); bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff, Field1Ty, Field1Off, Field2Ty, @@ -680,8 +677,8 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // All integral types are promoted to XLen width if (Size < XLen && Ty->isIntegralOrEnumerationType()) { diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index 237aea755fa29..4f0c4d0d906b1 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -118,11 +118,9 @@ ABIArgInfo SPIRVABIInfo::classifyReturnType(QualType RetTy) const { if (!isAggregateTypeForABI(RetTy) || getRecordArgABI(RetTy, getCXXABI())) return DefaultABIInfo::classifyReturnType(RetTy); - if (const RecordType *RT = RetTy->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->hasFlexibleArrayMember()) - return DefaultABIInfo::classifyReturnType(RetTy); - } + if (const auto *RD = RetTy->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) + return DefaultABIInfo::classifyReturnType(RetTy); // TODO: The AMDGPU ABI is non-trivial to represent in SPIR-V; in order to // avoid encoding various architecture specific bits here we return everything @@ -186,11 +184,9 @@ ABIArgInfo SPIRVABIInfo::classifyArgumentType(QualType Ty) const { return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), RAA == CGCXXABI::RAA_DirectInMemory); - if (const RecordType *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (RD->hasFlexibleArrayMember()) - return DefaultABIInfo::classifyArgumentType(Ty); - } + if (const auto *RD = Ty->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) + return DefaultABIInfo::classifyArgumentType(Ty); return ABIArgInfo::getDirect(CGT.ConvertType(Ty), 0u, nullptr, false); } @@ -431,8 +427,7 @@ static llvm::Type *getInlineSpirvType(CodeGenModule &CGM, } case SpirvOperandKind::TypeId: { QualType TypeOperand = Operand.getResultType(); - if (auto *RT = TypeOperand->getAs()) { - auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = TypeOperand->getAsRecordDecl()) { assert(RD->isCompleteDefinition() && "Type completion should have been required in Sema"); @@ -505,7 +500,8 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType( llvm::Type *BufferLayoutTy = HLSLBufferLayoutBuilder(CGM, "spirv.Layout") - .createLayoutType(ContainedTy->getAsStructureType(), Packoffsets); + .createLayoutType(ContainedTy->castAsCanonical(), + 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/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 13a42f66f5843..5f3c15d106eb6 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -237,8 +237,8 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const { /*ByVal=*/false); // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // Integer types smaller than a register are extended. if (Size < 64 && Ty->isIntegerType()) diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp index 38cc4d39126be..9b6b72b1dcc05 100644 --- a/clang/lib/CodeGen/Targets/SystemZ.cpp +++ b/clang/lib/CodeGen/Targets/SystemZ.cpp @@ -145,8 +145,8 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { bool SystemZABIInfo::isPromotableIntegerTypeForABI(QualType Ty) const { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (ABIInfo::isPromotableIntegerTypeForABI(Ty)) @@ -208,10 +208,8 @@ llvm::Type *SystemZABIInfo::getFPArgumentType(QualType Ty, } QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const { - const RecordType *RT = Ty->getAs(); - - if (RT && RT->isStructureOrClassType()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = Ty->getAsRecordDecl(); + if (RD && RD->isStructureOrClass()) { QualType Found; // If this is a C++ record, check the bases first. @@ -452,10 +450,9 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { /*ByVal=*/false); // Handle small structures. - if (const RecordType *RT = Ty->getAs()) { + if (const auto *RD = Ty->getAsRecordDecl()) { // Structures with flexible arrays have variable length, so really // fail the size test above. - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->hasFlexibleArrayMember()) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), /*ByVal=*/false); @@ -525,8 +522,7 @@ bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty, if (Ty->isVectorType() && Ctx.getTypeSize(Ty) / 8 >= 16) return true; - if (const auto *RecordTy = Ty->getAs()) { - const RecordDecl *RD = RecordTy->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = Ty->getAsRecordDecl()) { if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) if (CXXRD->hasDefinition()) for (const auto &I : CXXRD->bases()) diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp b/clang/lib/CodeGen/Targets/WebAssembly.cpp index ac8dcd2a0540a..ebe996a4edd8d 100644 --- a/clang/lib/CodeGen/Targets/WebAssembly.cpp +++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp @@ -115,11 +115,9 @@ ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); // For the experimental multivalue ABI, fully expand all other aggregates if (Kind == WebAssemblyABIKind::ExperimentalMV) { - const RecordType *RT = Ty->getAs(); - assert(RT); + const auto *RD = Ty->castAsRecordDecl(); bool HasBitField = false; - for (auto *Field : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + for (auto *Field : RD->fields()) { if (Field->isBitField()) { HasBitField = true; break; diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 61b833a9c1b43..71db63bb89645 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -352,15 +352,15 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, return shouldReturnTypeInRegister(AT->getElementType(), Context); // Otherwise, it must be a record type. - const RecordType *RT = Ty->getAs(); - if (!RT) return false; + const auto *RD = Ty->getAsRecordDecl(); + if (!RD) + return false; // FIXME: Traverse bases here too. // Structure types are passed in register if all fields would be // passed in a register. - for (const auto *FD : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + for (const auto *FD : RD->fields()) { // Empty fields are ignored. if (isEmptyField(Context, FD, true)) continue; @@ -427,11 +427,10 @@ static bool addBaseAndFieldSizes(ASTContext &Context, const CXXRecordDecl *RD, /// optimizations. bool X86_32ABIInfo::canExpandIndirectArgument(QualType Ty) const { // We can only expand structure types. - const RecordType *RT = Ty->getAs(); - if (!RT) + const RecordDecl *RD = Ty->getAsRecordDecl(); + if (!RD) return false; uint64_t Size = 0; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (const auto *CXXRD = dyn_cast(RD)) { if (!IsWin32StructABI) { // On non-Windows, we have to conservatively match our old bitcode @@ -508,13 +507,10 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, } if (isAggregateTypeForABI(RetTy)) { - if (const RecordType *RT = RetTy->getAs()) { + if (const auto *RD = RetTy->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) // Structures with flexible arrays are always indirect. - if (RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) - return getIndirectReturnResult(RetTy, State); - } + return getIndirectReturnResult(RetTy, State); // If specified, structs and unions are always indirect. if (!IsRetSmallStructInRegABI && !RetTy->isAnyComplexType()) @@ -556,8 +552,8 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, } // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); if (const auto *EIT = RetTy->getAs()) if (EIT->getNumBits() > 64) @@ -756,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(); + const RecordType *RT = Ty->getAsCanonical(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) { @@ -885,9 +881,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State, return ABIArgInfo::getDirect(); } - - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); bool InReg = shouldPrimitiveUseInReg(Ty, State); @@ -1850,10 +1845,9 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, return; } - if (const EnumType *ET = Ty->getAs()) { + if (const auto *ED = Ty->getAsEnumDecl()) { // Classify the underlying integer type. - classify(ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(), - OffsetBase, Lo, Hi, isNamedArg); + classify(ED->getIntegerType(), OffsetBase, Lo, Hi, isNamedArg); return; } @@ -2045,7 +2039,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, return; } - if (const RecordType *RT = Ty->getAs()) { + if (const RecordType *RT = Ty->getAsCanonical()) { uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger @@ -2075,11 +2069,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); - const auto *Base = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *Base = I.getType()->castAsCXXRecordDecl(); // Classify this field. // // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a @@ -2191,8 +2181,8 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const { // place naturally. if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); if (Ty->isBitIntType()) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); @@ -2233,8 +2223,8 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, if (!isAggregateTypeForABI(Ty) && !IsIllegalVectorType(Ty) && !Ty->isBitIntType()) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); @@ -2354,8 +2344,7 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, return true; } - if (const RecordType *RT = Ty->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = Ty->getAsRecordDecl()) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // If this is a C++ record, check the bases first. @@ -2363,10 +2352,7 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); - const auto *Base = - cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *Base = I.getType()->castAsCXXRecordDecl(); // If the base is after the span we care about, ignore it. unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base)); @@ -2646,9 +2632,8 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy) const { // so that the parameter gets the right LLVM IR attributes. if (Hi == NoClass && isa(ResType)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = RetTy->getAsEnumDecl()) + RetTy = ED->getIntegerType(); if (RetTy->isIntegralOrEnumerationType() && isPromotableIntegerTypeForABI(RetTy)) @@ -2797,8 +2782,8 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, // so that the parameter gets the right LLVM IR attributes. if (Hi == NoClass && isa(ResType)) { // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); if (Ty->isIntegralOrEnumerationType() && isPromotableIntegerTypeForABI(Ty)) @@ -3324,14 +3309,14 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs, if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); - if (const EnumType *EnumTy = Ty->getAs()) - 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(); + const RecordType *RT = Ty->getAsCanonical(); 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()) return appendPointerType(Enc, PT, CGM, TSC); - if (const EnumType *ET = QT->getAs()) + if (const EnumType *ET = QT->getAsCanonical()) 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()) return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); if (const FunctionType *FT = QT->getAs()) diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index 627a1d6fb3dd5..40f8348241ecc 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1011,7 +1011,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, if ((MK == NSAPI::NSNumberWithInteger || MK == NSAPI::NSNumberWithUnsignedInteger) && !isTruncated) { - if (OrigTy->getAs() || isEnumConstant(OrigArg)) + if (OrigTy->isEnumeralType() || isEnumConstant(OrigArg)) break; if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() && OrigTySize >= Ctx.getTypeSize(Ctx.IntTy)) diff --git a/clang/lib/Frontend/LayoutOverrideSource.cpp b/clang/lib/Frontend/LayoutOverrideSource.cpp index a1866ec09c9d3..0a60e00e5cb12 100644 --- a/clang/lib/Frontend/LayoutOverrideSource.cpp +++ b/clang/lib/Frontend/LayoutOverrideSource.cpp @@ -8,6 +8,7 @@ #include "clang/Frontend/LayoutOverrideSource.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "llvm/Support/raw_ostream.h" #include diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 2b55820b38804..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() && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->castAs()->getOriginalDecl(); + RecordDecl *RD = IvarT->castAsCanonical()->getOriginalDecl(); RD = RD->getDefinition(); if (RD && !RD->getDeclName().getAsIdentifierInfo()) { // decltype(((Foo_IMPL*)0)->bar) * @@ -3638,8 +3638,7 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, return RewriteObjCFieldDeclType(ElemTy, Result); } else if (Type->isRecordType()) { - RecordDecl *RD = - Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + auto *RD = Type->castAsRecordDecl(); if (RD->isCompleteDefinition()) { if (RD->isStruct()) Result += "\n\tstruct "; @@ -3660,28 +3659,26 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, Result += "\t} "; return true; } - } - else if (Type->isEnumeralType()) { - EnumDecl *ED = - Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - if (ED->isCompleteDefinition()) { - Result += "\n\tenum "; - Result += ED->getName(); - if (GlobalDefinedTags.count(ED)) { - // Enum is globall defined, use it. - Result += " "; - return true; - } - - Result += " {\n"; - for (const auto *EC : ED->enumerators()) { - Result += "\t"; Result += EC->getName(); Result += " = "; - Result += toString(EC->getInitVal(), 10); - Result += ",\n"; - } - Result += "\t} "; + } else if (auto *ED = Type->getAsEnumDecl(); + ED && ED->isCompleteDefinition()) { + Result += "\n\tenum "; + Result += ED->getName(); + if (GlobalDefinedTags.count(ED)) { + // Enum is globall defined, use it. + Result += " "; return true; } + + Result += " {\n"; + for (const auto *EC : ED->enumerators()) { + Result += "\t"; + Result += EC->getName(); + Result += " = "; + Result += toString(EC->getInitVal(), 10); + Result += ",\n"; + } + Result += "\t} "; + return true; } Result += "\t"; @@ -3733,15 +3730,7 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec auto *IDecl = dyn_cast(fieldDecl->getDeclContext()); - TagDecl *TD = nullptr; - if (Type->isRecordType()) { - TD = Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - } - else if (Type->isEnumeralType()) { - TD = Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - } - - if (TD) { + if (auto *TD = Type->getAsTagDecl()) { if (GlobalDefinedTags.count(TD)) return; @@ -5723,10 +5712,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { } } } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = VD->getType()->castAsRecordDecl(); if (RD->isCompleteDefinition()) RewriteRecordBody(RD); } @@ -7467,7 +7453,8 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { IvarT = GetGroupRecordTypeForObjCIvarBitfield(D); if (!IvarT->getAs() && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->castAs()->getOriginalDecl(); + RecordDecl *RD = + IvarT->castAsCanonical()->getOriginalDecl(); RD = RD->getDefinition(); if (RD && !RD->getDeclName().getAsIdentifierInfo()) { // decltype(((Foo_IMPL*)0)->bar) * diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index 0242fc1f6e827..b9c025de87739 100644 --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -4835,10 +4835,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { } } } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = VD->getType()->castAsRecordDecl(); if (RD->isCompleteDefinition()) RewriteRecordBody(RD); } diff --git a/clang/lib/Index/IndexTypeSourceInfo.cpp b/clang/lib/Index/IndexTypeSourceInfo.cpp index 9a699c3c896de..74c6c116b274e 100644 --- a/clang/lib/Index/IndexTypeSourceInfo.cpp +++ b/clang/lib/Index/IndexTypeSourceInfo.cpp @@ -61,7 +61,7 @@ class TypeIndexer : public RecursiveASTVisitor { SourceLocation Loc = TL.getNameLoc(); TypedefNameDecl *ND = TL.getDecl(); if (ND->isTransparentTag()) { - TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl(); + auto *Underlying = ND->getUnderlyingType()->castAsTagDecl(); return IndexCtx.handleReference(Underlying, Loc, Parent, ParentDC, SymbolRoleSet(), Relations); } 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()) { + if (const TemplateTypeParmType *TTP = + T->getAsCanonical()) { Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); return; } diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp index 4f5f43e1b3ade..fbbed6c095c5b 100644 --- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp +++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp @@ -101,15 +101,11 @@ static std::string EnumToString(const Value &V) { llvm::raw_string_ostream SS(Str); ASTContext &Ctx = const_cast(V.getASTContext()); - QualType DesugaredTy = V.getType().getDesugaredType(Ctx); - const EnumType *EnumTy = DesugaredTy.getNonReferenceType()->getAs(); - assert(EnumTy && "Fail to cast to enum type"); - - EnumDecl *ED = EnumTy->getOriginalDecl()->getDefinitionOrSelf(); uint64_t Data = V.convertTo(); bool IsFirst = true; - llvm::APSInt AP = Ctx.MakeIntValue(Data, DesugaredTy); + llvm::APSInt AP = Ctx.MakeIntValue(Data, V.getType()); + auto *ED = V.getType()->castAsEnumDecl(); for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) { if (I->getInitVal() == AP) { if (!IsFirst) @@ -665,8 +661,8 @@ __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, if (VRef.getKind() == Value::K_PtrOrObj) { VRef.setPtr(va_arg(args, void *)); } else { - if (const auto *ET = QT->getAs()) - QT = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = QT->getAsEnumDecl()) + QT = ED->getIntegerType(); switch (QT->castAs()->getKind()) { default: llvm_unreachable("unknown type kind!"); diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp index 84ba508e9cbc8..d4c9d51ffcb61 100644 --- a/clang/lib/Interpreter/Value.cpp +++ b/clang/lib/Interpreter/Value.cpp @@ -101,8 +101,8 @@ static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) { if (Ctx.hasSameType(QT, Ctx.VoidTy)) return Value::K_Void; - if (const auto *ET = QT->getAs()) - QT = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = QT->getAsEnumDecl()) + QT = ED->getIntegerType(); const auto *BT = QT->getAs(); if (!BT || BT->isNullPtrType()) @@ -147,15 +147,12 @@ Value::Value(const Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) { } while (ArrTy); ElementsSize = static_cast(ArrSize.getZExtValue()); } - if (const auto *RT = DtorTy->getAs()) { - if (CXXRecordDecl *CXXRD = - llvm::dyn_cast(RT->getOriginalDecl())) { - if (llvm::Expected Addr = - Interp.CompileDtorCall(CXXRD->getDefinitionOrSelf())) - DtorF = reinterpret_cast(Addr->getValue()); - else - llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs()); - } + if (auto *CXXRD = DtorTy->getAsCXXRecordDecl()) { + if (llvm::Expected Addr = + Interp.CompileDtorCall(CXXRD)) + DtorF = reinterpret_cast(Addr->getValue()); + else + llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs()); } size_t AllocSize = diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b870c5af1e588..39fa25f66f3b7 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1882,23 +1882,21 @@ class DeferredDiagnosticsEmitter // Visit the dtors of all members for (const FieldDecl *FD : RD->fields()) { QualType FT = FD->getType(); - if (const auto *RT = FT->getAs()) - if (const auto *ClassDecl = - dyn_cast(RT->getOriginalDecl())) - if (const auto *Def = ClassDecl->getDefinition()) - if (CXXDestructorDecl *MemberDtor = Def->getDestructor()) - asImpl().visitUsedDecl(MemberDtor->getLocation(), MemberDtor); + if (const auto *ClassDecl = FT->getAsCXXRecordDecl(); + ClassDecl && + (ClassDecl->isBeingDefined() || ClassDecl->isCompleteDefinition())) + if (CXXDestructorDecl *MemberDtor = ClassDecl->getDestructor()) + asImpl().visitUsedDecl(MemberDtor->getLocation(), MemberDtor); } // Also visit base class dtors for (const auto &Base : RD->bases()) { QualType BaseType = Base.getType(); - if (const auto *RT = BaseType->getAs()) - if (const auto *BaseDecl = - dyn_cast(RT->getOriginalDecl())) - if (const auto *Def = BaseDecl->getDefinition()) - if (CXXDestructorDecl *BaseDtor = Def->getDestructor()) - asImpl().visitUsedDecl(BaseDtor->getLocation(), BaseDtor); + if (const auto *BaseDecl = BaseType->getAsCXXRecordDecl(); + BaseDecl && + (BaseDecl->isBeingDefined() || BaseDecl->isCompleteDefinition())) + if (CXXDestructorDecl *BaseDtor = BaseDecl->getDestructor()) + asImpl().visitUsedDecl(BaseDtor->getLocation(), BaseDtor); } } @@ -1909,12 +1907,11 @@ class DeferredDiagnosticsEmitter if (VD->isThisDeclarationADefinition() && VD->needsDestruction(S.Context)) { QualType VT = VD->getType(); - if (const auto *RT = VT->getAs()) - if (const auto *ClassDecl = - dyn_cast(RT->getOriginalDecl())) - if (const auto *Def = ClassDecl->getDefinition()) - if (CXXDestructorDecl *Dtor = Def->getDestructor()) - asImpl().visitUsedDecl(Dtor->getLocation(), Dtor); + if (const auto *ClassDecl = VT->getAsCXXRecordDecl(); + ClassDecl && (ClassDecl->isBeingDefined() || + ClassDecl->isCompleteDefinition())) + if (CXXDestructorDecl *Dtor = ClassDecl->getDestructor()) + asImpl().visitUsedDecl(Dtor->getLocation(), Dtor); } Inherited::VisitDeclStmt(DS); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index ba560d3c52340..17415b4185eff 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -439,10 +439,8 @@ static AccessResult MatchesFriend(Sema &S, static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, CanQualType Friend) { - if (const RecordType *RT = Friend->getAs()) - return MatchesFriend( - S, EC, - cast(RT->getOriginalDecl())->getDefinitionOrSelf()); + if (const auto *RD = Friend->getAsCXXRecordDecl()) + return MatchesFriend(S, EC, RD); // TODO: we can do better than this if (Friend->isDependentType()) @@ -1786,10 +1784,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, if (!getLangOpts().AccessControl || Found.getAccess() == AS_public) return AR_accessible; - const RecordType *RT = ObjectExpr->getType()->castAs(); - CXXRecordDecl *NamingClass = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); - + auto *NamingClass = ObjectExpr->getType()->castAsCXXRecordDecl(); AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, ObjectExpr->getType()); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range; diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp index 6428435ed9d2a..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()) { + if (const auto *RT = ArgType->getAsCanonical()) if (!RT->getOriginalDecl()->getDeclName().isEmpty()) return true; - } else if (const auto *ET = Ty->getAs()) { - if (!ET->getOriginalDecl()->getDeclName().isEmpty()) - return true; - } return false; } @@ -99,13 +94,12 @@ static bool isValidPreserveEnumValueArg(Expr *Arg) { return false; // The type must be EnumType. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - const auto *ET = Ty->getAs(); - if (!ET) + const auto *ED = ArgType->getAsEnumDecl(); + if (!ED) return false; // The enum value must be supported. - return llvm::is_contained(ET->getOriginalDecl()->enumerators(), Enumerator); + return llvm::is_contained(ED->enumerators(), Enumerator); } bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index fbf64d3d57050..2e3cbb336a0c8 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -421,13 +421,10 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, } for (const auto *B : Bases) { - const RecordType *BaseType = B->getType()->getAs(); - if (!BaseType) { + auto *BaseClassDecl = B->getType()->getAsCXXRecordDecl(); + if (!BaseClassDecl) continue; - } - CXXRecordDecl *BaseClassDecl = - cast(BaseType->getOriginalDecl())->getDefinitionOrSelf(); Sema::SpecialMemberOverloadResult SMOR = SemaRef.LookupSpecialMember(BaseClassDecl, CSM, /* ConstArg */ ConstRHS, @@ -466,15 +463,11 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, continue; } - const RecordType *FieldType = - getASTContext().getBaseElementType(F->getType())->getAs(); - if (!FieldType) { + auto *FieldRecDecl = + getASTContext().getBaseElementType(F->getType())->getAsCXXRecordDecl(); + if (!FieldRecDecl) continue; - } - CXXRecordDecl *FieldRecDecl = - cast(FieldType->getOriginalDecl()) - ->getDefinitionOrSelf(); Sema::SpecialMemberOverloadResult SMOR = SemaRef.LookupSpecialMember(FieldRecDecl, CSM, /* ConstArg */ ConstRHS && !F->isMutable(), diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 45de8ff3ba264..ef14dde5203a6 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -133,11 +133,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, return const_cast( NNS.getAsNamespaceAndPrefix().Namespace->getNamespace()); - case NestedNameSpecifier::Kind::Type: { - auto *TD = NNS.getAsType()->getAsTagDecl(); - assert(TD && "Non-tag type in nested-name-specifier"); - return TD; - } + case NestedNameSpecifier::Kind::Type: + return NNS.getAsType()->castAsTagDecl(); case NestedNameSpecifier::Kind::Global: return Context.getTranslationUnitDecl(); diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index da43848a1a7d0..8ee3e0c7105b9 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -595,13 +595,11 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, DifferentPtrness--; } if (!DifferentPtrness) { - auto RecFrom = From->getAs(); - auto RecTo = To->getAs(); - if (RecFrom && RecTo) { - auto DeclFrom = RecFrom->getAsCXXRecordDecl(); + if (auto *DeclFrom = From->getAsCXXRecordDecl(), + *DeclTo = To->getAsCXXRecordDecl(); + DeclFrom && DeclTo) { if (!DeclFrom->isCompleteDefinition()) S.Diag(DeclFrom->getLocation(), diag::note_type_incomplete) << DeclFrom; - auto DeclTo = RecTo->getAsCXXRecordDecl(); if (!DeclTo->isCompleteDefinition()) S.Diag(DeclTo->getLocation(), diag::note_type_incomplete) << DeclTo; } @@ -865,7 +863,7 @@ void CastOperation::CheckDynamicCast() { return; } - const RecordType *DestRecord = DestPointee->getAs(); + const auto *DestRecord = DestPointee->getAsCanonical(); if (DestPointee->isVoidType()) { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { @@ -912,7 +910,7 @@ void CastOperation::CheckDynamicCast() { SrcPointee = SrcType; } - const RecordType *SrcRecord = SrcPointee->getAs(); + const auto *SrcRecord = SrcPointee->getAsCanonical(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, diag::err_bad_cast_incomplete, @@ -1454,7 +1452,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly // converted to an integral type. [...] A value of a scoped enumeration type // can also be explicitly converted to a floating-point type [...]. - if (const EnumType *Enum = SrcType->getAs()) { + if (const EnumType *Enum = dyn_cast(SrcType)) { if (Enum->getOriginalDecl()->isScoped()) { if (DestType->isBooleanType()) { Kind = CK_IntegralToBoolean; @@ -1486,8 +1484,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, if (SrcType->isIntegralOrEnumerationType()) { // [expr.static.cast]p10 If the enumeration type has a fixed underlying // type, the value is first converted to that type by integral conversion - const EnumType *Enum = DestType->castAs(); - const EnumDecl *ED = Enum->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = DestType->castAsEnumDecl(); Kind = ED->isFixed() && ED->getIntegerType()->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast; @@ -1581,11 +1578,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // See if it looks like the user is trying to convert between // related record types, and select a better diagnostic if so. - if (auto SrcPointer = SrcType->getAs()) - if (auto DestPointer = DestType->getAs()) - if (SrcPointer->getPointeeType()->getAs() && - DestPointer->getPointeeType()->getAs()) - msg = diag::err_bad_cxx_cast_unrelated_class; + if (const auto *SrcPointer = SrcType->getAs()) + if (const auto *DestPointer = DestType->getAs()) + if (SrcPointer->getPointeeType()->isRecordType() && + DestPointer->getPointeeType()->isRecordType()) + msg = diag::err_bad_cxx_cast_unrelated_class; if (SrcType->isMatrixType() && DestType->isMatrixType()) { if (Self.CheckMatrixCast(OpRange, DestType, SrcType, Kind)) { @@ -3097,7 +3094,8 @@ void CastOperation::CheckCStyleCast() { if (!DestType->isScalarType() && !DestType->isVectorType() && !DestType->isMatrixType()) { - if (const RecordType *DestRecordTy = DestType->getAs()) { + if (const RecordType *DestRecordTy = + DestType->getAsCanonical()) { 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 6e777fb9aec8e..7c557f775d567 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5278,13 +5278,10 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { // extra checking to see what their promotable type actually is. if (!Context.isPromotableIntegerType(Type)) return false; - if (!Type->isEnumeralType()) + const auto *ED = Type->getAsEnumDecl(); + if (!ED) return true; - const EnumDecl *ED = Type->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); - return !(ED && - Context.typesAreCompatible(ED->getPromotionType(), Type)); + return !Context.typesAreCompatible(ED->getPromotionType(), Type); }()) { unsigned Reason = 0; if (Type->isReferenceType()) Reason = 1; @@ -7891,16 +7888,10 @@ bool DecomposePrintfHandler::HandlePrintfSpecifier( template static llvm::SmallPtrSet CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { - const RecordType *RT = Ty->getAs(); + auto *RD = Ty->getAsCXXRecordDecl(); llvm::SmallPtrSet Results; - if (!RT) - return Results; - CXXRecordDecl *RD = dyn_cast(RT->getOriginalDecl()); - if (!RD) - return Results; - RD = RD->getDefinition(); - if (!RD) + if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition())) return Results; LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(), @@ -8438,10 +8429,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, bool IsEnum = false; bool IsScopedEnum = false; QualType IntendedTy = ExprTy; - if (auto EnumTy = ExprTy->getAs()) { - IntendedTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); - if (EnumTy->isUnscopedEnumerationType()) { + if (const auto *ED = ExprTy->getAsEnumDecl()) { + IntendedTy = ED->getIntegerType(); + if (!ED->isScoped()) { ExprTy = IntendedTy; // This controls whether we're talking about the underlying type or not, // which we only want to do when it's an unscoped enum. @@ -9741,10 +9731,7 @@ struct SearchNonTrivialToInitializeField S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); } void visitStruct(QualType FT, SourceLocation SL) { - for (const FieldDecl *FD : FT->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->fields()) + for (const FieldDecl *FD : FT->castAsRecordDecl()->fields()) visit(FD->getType(), FD->getLocation()); } void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK, @@ -9789,10 +9776,7 @@ struct SearchNonTrivialToCopyField S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); } void visitStruct(QualType FT, SourceLocation SL) { - for (const FieldDecl *FD : FT->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->fields()) + for (const FieldDecl *FD : FT->castAsRecordDecl()->fields()) visit(FD->getType(), FD->getLocation()); } void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT, @@ -10063,17 +10047,16 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, PDiag(diag::warn_arc_object_memaccess) << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); - else if (const auto *RT = PointeeTy->getAs()) { + else if (const auto *RD = PointeeTy->getAsRecordDecl()) { // FIXME: Do not consider incomplete types even though they may be // completed later. GCC does not diagnose such code, but we may want to // consider diagnosing it in the future, perhaps under a different, but // related, diagnostic group. bool NonTriviallyCopyableCXXRecord = - getLangOpts().CPlusPlus && !RT->isIncompleteType() && - !RT->desugar().isTriviallyCopyableType(Context); + getLangOpts().CPlusPlus && RD->isCompleteDefinition() && + !PointeeTy.isTriviallyCopyableType(Context); - const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && RD->isNonTrivialToPrimitiveDefaultInitialize()) { DiagRuntimeBehavior(Dest->getExprLoc(), Dest, @@ -10593,20 +10576,15 @@ struct IntRange { if (!C.getLangOpts().CPlusPlus) { // For enum types in C code, use the underlying datatype. - if (const auto *ET = dyn_cast(T)) - T = ET->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType() - .getDesugaredType(C) - .getTypePtr(); - } else if (const auto *ET = dyn_cast(T)) { + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType().getDesugaredType(C).getTypePtr(); + } else if (auto *Enum = T->getAsEnumDecl()) { // For enum types in C++, use the known bit width of the enumerators. - EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf(); // In C++11, enums can have a fixed underlying type. Use this type to // compute the range. if (Enum->isFixed()) { return IntRange(C.getIntWidth(QualType(T, 0)), - !ET->isSignedIntegerOrEnumerationType()); + !Enum->getIntegerType()->isSignedIntegerType()); } unsigned NumPositive = Enum->getNumPositiveBits(); @@ -10642,10 +10620,8 @@ struct IntRange { T = CT->getElementType().getTypePtr(); if (const AtomicType *AT = dyn_cast(T)) T = AT->getValueType().getTypePtr(); - if (const EnumType *ET = dyn_cast(T)) - T = C.getCanonicalType( - ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType()) - .getTypePtr(); + if (const auto *ED = T->getAsEnumDecl()) + T = C.getCanonicalType(ED->getIntegerType()).getTypePtr(); if (const auto *EIT = dyn_cast(T)) return IntRange(EIT->getNumBits(), EIT->isUnsigned()); @@ -11616,10 +11592,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, if (BitfieldType->isBooleanType()) return false; - if (BitfieldType->isEnumeralType()) { - EnumDecl *BitfieldEnumDecl = BitfieldType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) { // If the underlying enum type was not explicitly specified as an unsigned // type and the enum contain only positive values, MSVC++ will cause an // inconsistency by storing this as a signed type. @@ -11648,15 +11621,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, // The RHS is not constant. If the RHS has an enum type, make sure the // bitfield is wide enough to hold all the values of the enum without // truncation. - const auto *EnumTy = OriginalInit->getType()->getAs(); + const auto *ED = OriginalInit->getType()->getAsEnumDecl(); const PreferredTypeAttr *PTAttr = nullptr; - if (!EnumTy) { + if (!ED) { PTAttr = Bitfield->getAttr(); if (PTAttr) - EnumTy = PTAttr->getType()->getAs(); + ED = PTAttr->getType()->getAsEnumDecl(); } - if (EnumTy) { - EnumDecl *ED = EnumTy->getOriginalDecl()->getDefinitionOrSelf(); + if (ED) { bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType(); // Enum types are implicitly signed on Windows, so check if there are any @@ -12720,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()) - if (const EnumType *TargetEnum = Target->getAs()) + if (const EnumType *SourceEnum = Source->getAsCanonical()) + if (const EnumType *TargetEnum = Target->getAsCanonical()) if (SourceEnum->getOriginalDecl()->hasNameForLinkage() && TargetEnum->getOriginalDecl()->hasNameForLinkage() && SourceEnum != TargetEnum) { @@ -15361,17 +15333,13 @@ static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) { if (TC1 != TC2) return false; - if (TC1 == Type::Enum) { - return isLayoutCompatible( - C, cast(T1)->getOriginalDecl()->getDefinitionOrSelf(), - cast(T2)->getOriginalDecl()->getDefinitionOrSelf()); - } else if (TC1 == Type::Record) { + if (TC1 == Type::Enum) + return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl()); + if (TC1 == Type::Record) { if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType()) return false; - return isLayoutCompatible( - C, cast(T1)->getOriginalDecl()->getDefinitionOrSelf(), - cast(T2)->getOriginalDecl()->getDefinitionOrSelf()); + return isLayoutCompatible(C, T1->getAsRecordDecl(), T2->getAsRecordDecl()); } return false; @@ -15728,9 +15696,7 @@ void Sema::RefersToMemberWithReducedAlignment( return; if (ME->isArrow()) BaseType = BaseType->getPointeeType(); - RecordDecl *RD = BaseType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = BaseType->castAsRecordDecl(); if (RD->isInvalidDecl()) return; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index c6adead5a65f5..03bf4b3690b13 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5113,10 +5113,7 @@ void SemaCodeCompletion::CodeCompleteExpression( PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() || Data.PreferredType->isMemberPointerType() || Data.PreferredType->isBlockPointerType(); - if (Data.PreferredType->isEnumeralType()) { - EnumDecl *Enum = Data.PreferredType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + if (auto *Enum = Data.PreferredType->getAsEnumDecl()) { // FIXME: collect covered enumerators in cases like: // if (x == my_enum::one) { ... } else if (x == ^) {} AddEnumerators(Results, getASTContext(), Enum, SemaRef.CurContext, @@ -6240,18 +6237,14 @@ void SemaCodeCompletion::CodeCompleteCase(Scope *S) { if (!Switch->getCond()) return; QualType type = Switch->getCond()->IgnoreImplicit()->getType(); - if (!type->isEnumeralType()) { + EnumDecl *Enum = type->getAsEnumDecl(); + if (!Enum) { CodeCompleteExpressionData Data(type); Data.IntegralConstantExpression = true; CodeCompleteExpression(S, Data); return; } - // Code-complete the cases of a switch statement over an enumeration type - // by providing the list of - EnumDecl *Enum = - type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion // token, in case we are code-completing in the middle of the switch and not diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 160d7353cacd9..a825fdc1748c6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5291,14 +5291,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // UNION_TYPE; <- where UNION_TYPE is a typedef union. if ((Tag && Tag->getDeclName()) || DS.getTypeSpecType() == DeclSpec::TST_typename) { - RecordDecl *Record = nullptr; - if (Tag) - Record = dyn_cast(Tag); - else if (const RecordType *RT = - DS.getRepAsType().get()->getAsStructureType()) - Record = RT->getOriginalDecl()->getDefinitionOrSelf(); - else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType()) - Record = UT->getOriginalDecl()->getDefinitionOrSelf(); + RecordDecl *Record = dyn_cast_or_null(Tag); + if (!Record) + Record = DS.getRepAsType().get()->getAsRecordDecl(); if (Record && getLangOpts().MicrosoftExt) { Diag(DS.getBeginLoc(), diag::ext_ms_anonymous_record) @@ -9816,8 +9811,7 @@ static void checkIsValidOpenCLKernelParameter( // At this point we already handled everything except of a RecordType. assert(PT->isRecordType() && "Unexpected type."); - const RecordDecl *PD = - PT->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *PD = PT->castAsRecordDecl(); VisitStack.push_back(PD); assert(VisitStack.back() && "First decl null?"); @@ -9845,9 +9839,7 @@ static void checkIsValidOpenCLKernelParameter( "Unexpected type."); const Type *FieldRecTy = FieldTy->getPointeeOrArrayElementType(); - RD = FieldRecTy->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + RD = FieldRecTy->castAsRecordDecl(); } else { RD = cast(Next); } @@ -13375,8 +13367,7 @@ struct DiagNonTrivalCUnionDefaultInitializeVisitor } void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = - QT->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); if (RD->isUnion()) { if (OrigLoc.isValid()) { bool IsUnion = false; @@ -13442,8 +13433,7 @@ struct DiagNonTrivalCUnionDestructedTypeVisitor } void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = - QT->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); if (RD->isUnion()) { if (OrigLoc.isValid()) { bool IsUnion = false; @@ -13508,8 +13498,7 @@ struct DiagNonTrivalCUnionCopyVisitor } void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = - QT->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); if (RD->isUnion()) { if (OrigLoc.isValid()) { bool IsUnion = false; @@ -14480,11 +14469,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // version of one of these types, or an array of one of the preceding // types and is declared without an initializer. if (getLangOpts().CPlusPlus && Var->hasLocalStorage()) { - if (const RecordType *Record - = Context.getBaseElementType(Type)->getAs()) { - CXXRecordDecl *CXXRecord = - cast(Record->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (const auto *CXXRecord = + Context.getBaseElementType(Type)->getAsCXXRecordDecl()) { // Mark the function (if we're in one) for further checking even if the // looser rules of C++11 do not require such checks, so that we can // diagnose incompatibilities with C++98. @@ -14947,8 +14933,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Require the destructor. if (!type->isDependentType()) - if (const RecordType *recordType = baseType->getAs()) - FinalizeVarWithDestructor(var, recordType); + if (auto *RD = baseType->getAsCXXRecordDecl()) + FinalizeVarWithDestructor(var, RD); // If this variable must be emitted, add it as an initializer for the current // module. @@ -19119,17 +19105,16 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (!InvalidDecl && getLangOpts().CPlusPlus) { if (Record->isUnion()) { - if (const RecordType *RT = EltTy->getAs()) { - CXXRecordDecl *RDecl = cast(RT->getOriginalDecl()); - if (RDecl->getDefinition()) { - // C++ [class.union]p1: An object of a class with a non-trivial - // constructor, a non-trivial copy constructor, a non-trivial - // destructor, or a non-trivial copy assignment operator - // cannot be a member of a union, nor can an array of such - // objects. - if (CheckNontrivialField(NewFD)) - NewFD->setInvalidDecl(); - } + if (const auto *RD = EltTy->getAsCXXRecordDecl(); + RD && (RD->isBeingDefined() || RD->isCompleteDefinition())) { + + // C++ [class.union]p1: An object of a class with a non-trivial + // constructor, a non-trivial copy constructor, a non-trivial + // destructor, or a non-trivial copy assignment operator + // cannot be a member of a union, nor can an array of such + // objects. + if (CheckNontrivialField(NewFD)) + NewFD->setInvalidDecl(); } // C++ [class.union]p1: If a union contains a member of reference type, @@ -19185,55 +19170,51 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { return false; QualType EltTy = Context.getBaseElementType(FD->getType()); - if (const RecordType *RT = EltTy->getAs()) { - CXXRecordDecl *RDecl = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); - if (RDecl->getDefinition()) { - // We check for copy constructors before constructors - // because otherwise we'll never get complaints about - // copy constructors. - - CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid; - // We're required to check for any non-trivial constructors. Since the - // implicit default constructor is suppressed if there are any - // user-declared constructors, we just need to check that there is a - // trivial default constructor and a trivial copy constructor. (We don't - // worry about move constructors here, since this is a C++98 check.) - if (RDecl->hasNonTrivialCopyConstructor()) - member = CXXSpecialMemberKind::CopyConstructor; - else if (!RDecl->hasTrivialDefaultConstructor()) - member = CXXSpecialMemberKind::DefaultConstructor; - else if (RDecl->hasNonTrivialCopyAssignment()) - member = CXXSpecialMemberKind::CopyAssignment; - else if (RDecl->hasNonTrivialDestructor()) - member = CXXSpecialMemberKind::Destructor; - - if (member != CXXSpecialMemberKind::Invalid) { - if (!getLangOpts().CPlusPlus11 && - getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) { - // Objective-C++ ARC: it is an error to have a non-trivial field of - // a union. However, system headers in Objective-C programs - // occasionally have Objective-C lifetime objects within unions, - // and rather than cause the program to fail, we make those - // members unavailable. - SourceLocation Loc = FD->getLocation(); - if (getSourceManager().isInSystemHeader(Loc)) { - if (!FD->hasAttr()) - FD->addAttr(UnavailableAttr::CreateImplicit(Context, "", - UnavailableAttr::IR_ARCFieldWithOwnership, Loc)); - return false; - } + if (const auto *RDecl = EltTy->getAsCXXRecordDecl(); + RDecl && (RDecl->isBeingDefined() || RDecl->isCompleteDefinition())) { + // We check for copy constructors before constructors + // because otherwise we'll never get complaints about + // copy constructors. + + CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid; + // We're required to check for any non-trivial constructors. Since the + // implicit default constructor is suppressed if there are any + // user-declared constructors, we just need to check that there is a + // trivial default constructor and a trivial copy constructor. (We don't + // worry about move constructors here, since this is a C++98 check.) + if (RDecl->hasNonTrivialCopyConstructor()) + member = CXXSpecialMemberKind::CopyConstructor; + else if (!RDecl->hasTrivialDefaultConstructor()) + member = CXXSpecialMemberKind::DefaultConstructor; + else if (RDecl->hasNonTrivialCopyAssignment()) + member = CXXSpecialMemberKind::CopyAssignment; + else if (RDecl->hasNonTrivialDestructor()) + member = CXXSpecialMemberKind::Destructor; + + if (member != CXXSpecialMemberKind::Invalid) { + if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount && + RDecl->hasObjectMember()) { + // Objective-C++ ARC: it is an error to have a non-trivial field of + // a union. However, system headers in Objective-C programs + // occasionally have Objective-C lifetime objects within unions, + // and rather than cause the program to fail, we make those + // members unavailable. + SourceLocation Loc = FD->getLocation(); + if (getSourceManager().isInSystemHeader(Loc)) { + if (!FD->hasAttr()) + FD->addAttr(UnavailableAttr::CreateImplicit( + Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, Loc)); + return false; } - - Diag( - FD->getLocation(), - getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member - : diag::err_illegal_union_or_anon_struct_member) - << FD->getParent()->isUnion() << FD->getDeclName() << member; - DiagnoseNontrivial(RDecl, member); - return !getLangOpts().CPlusPlus11; } + + Diag(FD->getLocation(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member + : diag::err_illegal_union_or_anon_struct_member) + << FD->getParent()->isUnion() << FD->getDeclName() << member; + DiagnoseNontrivial(RDecl, member); + return !getLangOpts().CPlusPlus11; } } @@ -19509,11 +19490,9 @@ bool Sema::EntirelyFunctionPointers(const RecordDecl *Record) { return PointeeType.getDesugaredType(Context)->isFunctionType(); } // If a member is a struct entirely of function pointers, that counts too. - if (const RecordType *RT = FieldType->getAs()) { - const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (Record->isStruct() && EntirelyFunctionPointers(Record)) - return true; - } + if (const auto *Record = FieldType->getAsRecordDecl(); + Record && Record->isStruct() && EntirelyFunctionPointers(Record)) + return true; return false; }; @@ -19667,10 +19646,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (const RecordType *FDTTy = FDTy->getAs()) { - if (Record && FDTTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { + } else if (const auto *RD = FDTy->getAsRecordDecl()) { + if (Record && RD->hasFlexibleArrayMember()) { // A type which contains a flexible array member is considered to be a // flexible array member. Record->setHasFlexibleArrayMember(true); @@ -19696,7 +19673,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // Ivars can not have abstract class types FD->setInvalidDecl(); } - const RecordDecl *RD = FDTTy->getOriginalDecl()->getDefinitionOrSelf(); if (Record && RD->hasObjectMember()) Record->setHasObjectMember(true); if (Record && RD->hasVolatileMember()) @@ -19730,10 +19706,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasObjectMember(true); else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); - if (BaseType->isRecordType() && BaseType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasObjectMember()) + if (const auto *RD = BaseType->getAsRecordDecl(); + RD && RD->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || BaseType.isObjCGCStrong()) @@ -19765,10 +19739,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasNonTrivialToPrimitiveDestructCUnion(true); } - if (const auto *RT = FT->getAs()) { - if (RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->getArgPassingRestrictions() == + if (const auto *RD = FT->getAsRecordDecl()) { + if (RD->getArgPassingRestrictions() == RecordArgPassingKind::CanNeverPassInRegs) Record->setArgPassingRestrictions( RecordArgPassingKind::CanNeverPassInRegs); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3685bcefbf764..3ded60cd8b073 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -169,7 +169,7 @@ static bool isIntOrBool(Expr *Exp) { // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. -static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { +static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordDecl *Record) { auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record, OverloadedOperatorKind Op) { DeclContextLookupResult Result = @@ -177,7 +177,6 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { return !Result.empty(); }; - const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf(); bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star); bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow); if (foundStarOperator && foundArrowOperator) @@ -212,14 +211,14 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, if (QT->isAnyPointerType()) return true; - if (const auto *RT = QT->getAs()) { + if (const auto *RD = QT->getAsRecordDecl()) { // If it's an incomplete type, it could be a smart pointer; skip it. // (We don't want to force template instantiation if we can avoid it, // since that would alter the order in which templates are instantiated.) - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; - if (threadSafetyCheckIsSmartPointer(S, RT)) + if (threadSafetyCheckIsSmartPointer(S, RD)) return true; } @@ -229,13 +228,13 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, /// Checks that the passed in QualType either is of RecordType or points /// to RecordType. Returns the relevant RecordType, null if it does not exit. -static const RecordType *getRecordType(QualType QT) { - if (const auto *RT = QT->getAs()) - return RT; +static const RecordDecl *getRecordDecl(QualType QT) { + if (const auto *RD = QT->getAsRecordDecl()) + return RD; - // Now check if we point to record type. - if (const auto *PT = QT->getAs()) - return PT->getPointeeType()->getAs(); + // Now check if we point to a record. + if (const auto *PT = QT->getAsCanonical()) + return PT->getPointeeType()->getAsRecordDecl(); return nullptr; } @@ -257,36 +256,34 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) { } static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { - const RecordType *RT = getRecordType(Ty); + const auto *RD = getRecordDecl(Ty); - if (!RT) + if (!RD) return false; // Don't check for the capability if the class hasn't been defined yet. - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; // Allow smart pointers to be used as capability objects. // FIXME -- Check the type that the smart pointer points to. - if (threadSafetyCheckIsSmartPointer(S, RT)) + if (threadSafetyCheckIsSmartPointer(S, RD)) return true; - return checkRecordDeclForAttr( - RT->getOriginalDecl()->getDefinitionOrSelf()); + return checkRecordDeclForAttr(RD); } static bool checkRecordTypeForScopedCapability(Sema &S, QualType Ty) { - const RecordType *RT = getRecordType(Ty); + const auto *RD = getRecordDecl(Ty); - if (!RT) + if (!RD) return false; // Don't check for the capability if the class hasn't been defined yet. - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; - return checkRecordDeclForAttr( - RT->getOriginalDecl()->getDefinitionOrSelf()); + return checkRecordDeclForAttr(RD); } static bool checkTypedefTypeForCapability(QualType Ty) { @@ -401,10 +398,10 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, ArgTy = DRE->getDecl()->getType(); // First see if we can just cast to record type, or pointer to record type. - const RecordType *RT = getRecordType(ArgTy); + const auto *RD = getRecordDecl(ArgTy); // Now check if we index into a record type function param. - if(!RT && ParamIdxOk) { + if (!RD && ParamIdxOk) { const auto *FD = dyn_cast(D); const auto *IL = dyn_cast(ArgExp); if(FD && IL) { @@ -3639,7 +3636,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType T = cast(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); - if (!T->getAs()) { + if (!T->isRecordType()) { S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); AL.setInvalid(); return; @@ -4163,10 +4160,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RecordDecl *RD = nullptr; const auto *TD = dyn_cast(D); if (TD && TD->getUnderlyingType()->isUnionType()) - RD = TD->getUnderlyingType() - ->getAsUnionType() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + RD = TD->getUnderlyingType()->getAsRecordDecl(); else RD = dyn_cast(D); @@ -4739,14 +4733,14 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, // GCC allows 'mode' attribute on enumeration types (even incomplete), except // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. - if ((isa(D) || OldElemTy->getAs()) && + if ((isa(D) || OldElemTy->isEnumeralType()) && VectorSize.getBoolValue()) { Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange(); return; } bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() && !OldElemTy->isBitIntType()) || - OldElemTy->getAs(); + OldElemTy->isEnumeralType(); if (!OldElemTy->getAs() && !OldElemTy->isComplexType() && !IntegralOrAnyEnumType) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index bb57968830a65..4b0dead182543 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2187,10 +2187,7 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef, return false; } } else if (Field->isAnonymousStructOrUnion()) { - const RecordDecl *RD = Field->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + const auto *RD = Field->getType()->castAsRecordDecl(); for (auto *I : RD->fields()) // If an anonymous union contains an anonymous struct of which any member // is initialized, all members must be initialized. @@ -2925,9 +2922,7 @@ NoteIndirectBases(ASTContext &Context, IndirectBaseSet &Set, { // Even though the incoming type is a base, it might not be // a class -- it could be a template parm, for instance. - if (auto Rec = Type->getAs()) { - auto Decl = Rec->getAsCXXRecordDecl(); - + if (const auto *Decl = Type->getAsCXXRecordDecl()) { // Iterate over its bases. for (const auto &BaseSpec : Decl->bases()) { QualType Base = Context.getCanonicalType(BaseSpec.getType()) @@ -2986,9 +2981,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, if (Bases.size() > 1) NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType); - if (const RecordType *Record = NewBaseType->getAs()) { - const CXXRecordDecl *RD = cast(Record->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (const auto *RD = NewBaseType->getAsCXXRecordDecl()) { if (Class->isInterface() && (!RD->isInterfaceLike() || KnownBase->getAccessSpecifier() != AS_public)) { @@ -5479,7 +5472,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, CXXCtorInitializer *Member = Initializers[i]; if (Member->isBaseInitializer()) - Info.AllBaseFields[Member->getBaseClass()->getAs()] = Member; + Info.AllBaseFields[Member->getBaseClass()->getAsCanonical()] = + Member; else { Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member; @@ -5507,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())) { + if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup( + VBase.getType()->getAsCanonical())) { // [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 @@ -5546,8 +5540,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, if (Base.isVirtual()) continue; - if (CXXCtorInitializer *Value - = Info.AllBaseFields.lookup(Base.getType()->getAs())) { + if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup( + Base.getType()->getAsCanonical())) { Info.AllToInit.push_back(Value); } else if (!AnyErrors) { CXXCtorInitializer *CXXBaseInit; @@ -5635,7 +5629,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, } static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl &IdealInits) { - if (const RecordType *RT = Field->getType()->getAs()) { + if (const RecordType *RT = Field->getType()->getAsCanonical()) { const RecordDecl *RD = RT->getOriginalDecl(); if (RD->isAnonymousStructOrUnion()) { for (auto *Field : RD->getDefinitionOrSelf()->fields()) @@ -7611,12 +7605,9 @@ static bool defaultedSpecialMemberIsConstexpr( // class is a constexpr function, and if (!S.getLangOpts().CPlusPlus23) { for (const auto &B : ClassDecl->bases()) { - const RecordType *BaseType = B.getType()->getAs(); - if (!BaseType) + auto *BaseClassDecl = B.getType()->getAsCXXRecordDecl(); + if (!BaseClassDecl) continue; - CXXRecordDecl *BaseClassDecl = - cast(BaseType->getOriginalDecl()) - ->getDefinitionOrSelf(); if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg, InheritedCtor, Inherited)) return false; @@ -7638,7 +7629,7 @@ static bool defaultedSpecialMemberIsConstexpr( F->hasInClassInitializer()) continue; QualType BaseType = S.Context.getBaseElementType(F->getType()); - if (const RecordType *RecordTy = BaseType->getAs()) { + if (const RecordType *RecordTy = BaseType->getAsCanonical()) { CXXRecordDecl *FieldRecDecl = cast(RecordTy->getOriginalDecl()) ->getDefinitionOrSelf(); @@ -10478,11 +10469,7 @@ struct FindHiddenVirtualMethod { /// method overloads virtual methods in a base class without overriding any, /// to be used with CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - RecordDecl *BaseRecord = Specifier->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); - + auto *BaseRecord = Specifier->getType()->castAsRecordDecl(); DeclarationName Name = Method->getDeclName(); assert(Name.getNameKind() == DeclarationName::Identifier); @@ -10637,7 +10624,8 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { return; } - if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs()) + if (const auto *RT = + FT->getBaseElementTypeUnsafe()->getAsCanonical()) if (!RT->isDependentType() && !cast(RT->getOriginalDecl()->getDefinitionOrSelf()) ->canPassInRegisters()) { @@ -12658,15 +12646,12 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, return nullptr; } - auto *Enum = dyn_cast_if_present(EnumTy->getAsTagDecl()); + auto *Enum = EnumTy->getAsEnumDecl(); if (!Enum) { Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy; return nullptr; } - if (auto *Def = Enum->getDefinition()) - Enum = Def; - if (TSI == nullptr) TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc); @@ -13937,12 +13922,10 @@ struct SpecialMemberExceptionSpecInfo } bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) { - auto *RT = Base->getType()->getAs(); - if (!RT) + auto *BaseClass = Base->getType()->getAsCXXRecordDecl(); + if (!BaseClass) return false; - auto *BaseClass = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass); if (auto *BaseCtor = SMOR.getMethod()) { visitSubobjectCall(Base, BaseCtor); @@ -13966,11 +13949,9 @@ bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) { E = S.BuildCXXDefaultInitExpr(Loc, FD).get(); if (E) ExceptSpec.CalledExpr(E); - } else if (auto *RT = S.Context.getBaseElementType(FD->getType()) - ->getAs()) { - visitClassSubobject( - cast(RT->getOriginalDecl())->getDefinitionOrSelf(), FD, - FD->getType().getCVRQualifiers()); + } else if (auto *RD = S.Context.getBaseElementType(FD->getType()) + ->getAsCXXRecordDecl()) { + visitClassSubobject(RD, FD, FD->getType().getCVRQualifiers()); } return false; } @@ -14785,11 +14766,9 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()), VK_PRValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); - const Type *E = T->getBaseElementTypeUnsafe(); - bool NeedsCollectableMemCpy = E->isRecordType() && E->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasObjectMember(); + bool NeedsCollectableMemCpy = false; + if (auto *RD = T->getBaseElementTypeUnsafe()->getAsRecordDecl()) + NeedsCollectableMemCpy = RD->hasObjectMember(); // Create a reference to the __builtin_objc_memmove_collectable function StringRef MemCpyName = NeedsCollectableMemCpy ? @@ -14865,10 +14844,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, // the class is used (as if by explicit qualification; that is, // ignoring any possible virtual overriding functions in more derived // classes); - if (const RecordType *RecordTy = T->getAs()) { - CXXRecordDecl *ClassDecl = - cast(RecordTy->getOriginalDecl())->getDefinitionOrSelf(); - + if (auto *ClassDecl = T->getAsCXXRecordDecl()) { // Look for operator=. DeclarationName Name = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); @@ -15340,7 +15316,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); - if (!BaseType->getAs() && BaseType.isConstQualified()) { + if (!BaseType->isRecordType() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getCanonicalTagType(ClassDecl) << 1 << Field->getDeclName(); @@ -15729,7 +15705,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); - if (!BaseType->getAs() && BaseType.isConstQualified()) { + if (!BaseType->isRecordType() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getCanonicalTagType(ClassDecl) << 1 << Field->getDeclName(); @@ -16322,15 +16298,14 @@ ExprResult Sema::BuildCXXConstructExpr( Constructor); } -void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { +void Sema::FinalizeVarWithDestructor(VarDecl *VD, CXXRecordDecl *ClassDecl) { if (VD->isInvalidDecl()) return; // If initializing the variable failed, don't also diagnose problems with // the destructor, they're likely related. if (VD->getInit() && VD->getInit()->containsErrors()) return; - CXXRecordDecl *ClassDecl = - cast(Record->getOriginalDecl())->getDefinitionOrSelf(); + ClassDecl = ClassDecl->getDefinitionOrSelf(); if (ClassDecl->isInvalidDecl()) return; if (ClassDecl->hasIrrelevantDestructor()) return; if (ClassDecl->isDependentContext()) return; @@ -16988,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(); - if (TArgs && TArgs->getDepth() == PmType->getDepth() && + if (const auto *TArgs = + PmArgs->getType()->getAsCanonical(); + TArgs && TArgs->getDepth() == PmType->getDepth() && TArgs->getIndex() == PmType->getIndex()) { if (!SemaRef.inTemplateInstantiation()) SemaRef.Diag(TpDecl->getLocation(), @@ -17337,7 +17312,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, Invalid = true; if (!Invalid && !ExDeclType->isDependentType()) { - if (const RecordType *recordType = ExDeclType->getAs()) { + if (auto *ClassDecl = ExDeclType->getAsCXXRecordDecl()) { // Insulate this from anything else we might currently be parsing. EnterExpressionEvaluationContext scope( *this, ExpressionEvaluationContext::PotentiallyEvaluated); @@ -17374,7 +17349,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, } // And make sure it's destructable. - FinalizeVarWithDestructor(ExDecl, recordType); + FinalizeVarWithDestructor(ExDecl, ClassDecl); } } } @@ -18813,8 +18788,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, // that of B::f, the class type in the return type of D::f shall be // complete at the point of declaration of D::f or shall be the class // type D. - if (const RecordType *RT = NewClassTy->getAs()) { - if (!RT->getOriginalDecl()->isEntityBeingDefined() && + if (const auto *RD = NewClassTy->getAsCXXRecordDecl()) { + if (!RD->isBeingDefined() && RequireCompleteType(New->getLocation(), NewClassTy, diag::err_covariant_return_incomplete, New->getDeclName())) @@ -19169,9 +19144,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, return; for (const auto &I : RD->bases()) { - const auto *Base = cast( - I.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *Base = I.getType()->castAsCXXRecordDecl(); if (Base->getNumVBases() == 0) continue; MarkVirtualMembersReferenced(Loc, Base); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 88ed83eca243e..98eb5afb7c992 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3848,10 +3848,8 @@ SemaObjC::ObjCContainerKind SemaObjC::getObjCContainerKind() const { static bool IsVariableSizedType(QualType T) { if (T->isIncompleteArrayType()) return true; - const auto *RecordTy = T->getAs(); - return (RecordTy && RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()); + const auto *RD = T->getAsRecordDecl(); + return RD && RD->hasFlexibleArrayMember(); } static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { @@ -3896,15 +3894,11 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { << ivar->getDeclName() << IvarTy << TagTypeKind::Class; // Use "class" for Obj-C. IsInvalidIvar = true; - } else if (const RecordType *RecordTy = IvarTy->getAs()) { - if (RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { - S.Diag(ivar->getLocation(), - diag::err_objc_variable_sized_type_not_at_end) - << ivar->getDeclName() << IvarTy; - IsInvalidIvar = true; - } + } else if (const auto *RD = IvarTy->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) { + S.Diag(ivar->getLocation(), diag::err_objc_variable_sized_type_not_at_end) + << ivar->getDeclName() << IvarTy; + IsInvalidIvar = true; } if (IsInvalidIvar) { S.Diag(ivar->getNextIvar()->getLocation(), @@ -5541,11 +5535,8 @@ void SemaObjC::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { AllToInit.push_back(Member); // Be sure that the destructor is accessible and is marked as referenced. - if (const RecordType *RecordTy = - Context.getBaseElementType(Field->getType()) - ->getAs()) { - CXXRecordDecl *RD = cast(RecordTy->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (auto *RD = Context.getBaseElementType(Field->getType()) + ->getAsCXXRecordDecl()) { if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(RD)) { SemaRef.MarkFunctionReferenced(Field->getLocation(), Destructor); SemaRef.CheckDestructorAccess( diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 94413b5b92d22..552c92996dc2e 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -163,9 +163,8 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { DiagID = diag::ext_incomplete_in_exception_spec; ReturnValueOnError = false; } - if (!(PointeeT->isRecordType() && PointeeT->castAs() - ->getOriginalDecl() - ->isEntityBeingDefined()) && + if (auto *RD = PointeeT->getAsRecordDecl(); + !(RD && RD->isBeingDefined()) && RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) return ReturnValueOnError; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 911c80adfd539..b26fa29257696 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1528,8 +1528,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()->getOriginalDecl()->hasNameForLinkage() || - !R->castAs()->getOriginalDecl()->hasNameForLinkage()) { + else if (!L->castAsCanonical() + ->getOriginalDecl() + ->hasNameForLinkage() || + !R->castAsCanonical() + ->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 different warning group. @@ -8605,16 +8609,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // If both operands are the same structure or union type, the result is that // type. - if (const RecordType *LHSRT = LHSTy->getAs()) { // C99 6.5.15p3 - if (const RecordType *RHSRT = RHSTy->getAs()) - if (declaresSameEntity(LHSRT->getOriginalDecl(), - RHSRT->getOriginalDecl())) - // "If both the operands have structure or union type, the result has - // that type." This implies that CV qualifiers are dropped. - return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), - RHSTy.getUnqualifiedType()); - // FIXME: Type of conditional expression must be complete in C mode. - } + // FIXME: Type of conditional expression must be complete in C mode. + if (LHSTy->isRecordType() && + Context.hasSameUnqualifiedType(LHSTy, RHSTy)) // C99 6.5.15p3 + return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), + RHSTy.getUnqualifiedType()); // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). @@ -11406,7 +11405,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, } static bool isScopedEnumerationType(QualType T) { - if (const EnumType *ET = T->getAs()) + if (const EnumType *ET = T->getAsCanonical()) return ET->getOriginalDecl()->isScoped(); return false; } @@ -12296,10 +12295,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, S.InvalidOperands(Loc, LHS, RHS); return QualType(); } - QualType IntType = LHSStrippedType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType(); + QualType IntType = LHSStrippedType->castAsEnumDecl()->getIntegerType(); assert(IntType->isArithmeticType()); // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we @@ -13722,7 +13718,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()) { + if (const auto *FieldRecTy = FieldTy->getAsCanonical()) { if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } @@ -13738,7 +13734,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(); + const auto *RTy = Ty->getAsCanonical(); bool DiagEmitted = false; if (const MemberExpr *ME = dyn_cast(E)) @@ -16156,11 +16152,10 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, return ExprError(); // Look for the designated field. - const RecordType *RC = CurrentType->getAs(); - if (!RC) + auto *RD = CurrentType->getAsRecordDecl(); + if (!RD) return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) << CurrentType); - RecordDecl *RD = RC->getOriginalDecl()->getDefinitionOrSelf(); // C++ [lib.support.types]p5: // The macro offsetof accepts a restricted set of type arguments in this @@ -16557,8 +16552,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, auto *Var = cast(Cap.getVariable()); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { - if (const RecordType *Record = - Cap.getCaptureType()->getAs()) { + if (auto *Record = Cap.getCaptureType()->getAsCXXRecordDecl()) { // The capture logic needs the destructor, so make sure we mark it. // Usually this is unnecessary because most local variables have // their destructors marked at declaration time, but parameters are @@ -16786,9 +16780,8 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // va_arg. Instead, get the underlying type of the enumeration and pass // that. QualType UnderlyingType = TInfo->getType(); - if (const auto *ET = UnderlyingType->getAs()) - UnderlyingType = - ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = UnderlyingType->getAsEnumDecl()) + UnderlyingType = ED->getIntegerType(); if (Context.typesAreCompatible(PromoteType, UnderlyingType, /*CompareUnqualified*/ true)) PromoteType = QualType(); @@ -18785,19 +18778,16 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, } // Prohibit structs with flexible array members too. // We cannot capture what is in the tail end of the struct. - if (const RecordType *VTTy = Var->getType()->getAs()) { - if (VTTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { - if (Diagnose) { - if (IsBlock) - S.Diag(Loc, diag::err_ref_flexarray_type); - else - S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var; - S.Diag(Var->getLocation(), diag::note_previous_decl) << Var; - } - return false; + if (const auto *VTD = Var->getType()->getAsRecordDecl(); + VTD && VTD->hasFlexibleArrayMember()) { + if (Diagnose) { + if (IsBlock) + S.Diag(Loc, diag::err_ref_flexarray_type); + else + S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var; + S.Diag(Var->getLocation(), diag::note_previous_decl) << Var; } + return false; } const bool HasBlocksAttr = Var->hasAttr(); // Lambdas and captured statements are not allowed to capture __block @@ -19877,7 +19867,7 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { // C++2a [basic.def.odr]p4: // [...] an expression of non-volatile-qualified non-class type to which // the lvalue-to-rvalue conversion is applied [...] - if (E->getType().isVolatileQualified() || E->getType()->getAs()) + if (E->getType().isVolatileQualified() || E->getType()->isRecordType()) return E; ExprResult Result = diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 2a82842095446..5a9279d928465 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -543,7 +543,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, QualType T = Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(), Quals); - if (T->getAs() && + if (T->isRecordType() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); @@ -570,9 +570,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, } QualType T = E->getType(); - if (const RecordType *RecordT = T->getAs()) { - CXXRecordDecl *RecordD = cast(RecordT->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (auto *RecordD = T->getAsCXXRecordDecl()) { // C++ [expr.typeid]p3: // [...] If the type of the expression is a class type, the class // shall be completely-defined. @@ -1975,8 +1973,8 @@ static UsualDeallocFnInfo resolveDeallocationOverload( static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, TypeAwareAllocationMode PassType, QualType allocType) { - const RecordType *record = - allocType->getBaseElementTypeUnsafe()->getAs(); + const auto *record = + allocType->getBaseElementTypeUnsafe()->getAsCanonical(); if (!record) return false; // Try to find an operator delete[] in class scope. @@ -2297,8 +2295,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, ConvertedSize = PerformImplicitConversion( *ArraySize, Context.getSizeType(), AssignmentAction::Converting); - if (!ConvertedSize.isInvalid() && - (*ArraySize)->getType()->getAs()) + if (!ConvertedSize.isInvalid() && (*ArraySize)->getType()->isRecordType()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) << (*ArraySize)->getType() << 0 << "'size_t'"; @@ -3055,9 +3052,7 @@ bool Sema::FindAllocationFunctions( LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && DeleteScope != AllocationFunctionScope::Global) { - auto *RD = cast( - AllocElemType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *RD = AllocElemType->castAsCXXRecordDecl(); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) @@ -4070,9 +4065,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, ? diag::err_delete_incomplete : diag::warn_delete_incomplete, Ex.get())) { - if (const RecordType *RT = PointeeElem->getAs()) - PointeeRD = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); + PointeeRD = PointeeElem->getAsCXXRecordDecl(); } } @@ -4840,10 +4833,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (FromType->isVectorType() || ToType->isVectorType()) StepTy = adjustVectorType(Context, FromType, ToType, &ElTy); if (ElTy->isBooleanType()) { - assert(FromType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isFixed() && + assert(FromType->castAsEnumDecl()->isFixed() && SCS.Second == ICK_Integral_Promotion && "only enums with fixed underlying type can promote to bool"); From = ImpCastExprToType(From, StepTy, CK_IntegralToBoolean, VK_PRValue, @@ -5529,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(); - const RecordType *TRec = TTy->getAs(); + const RecordType *FRec = FTy->getAsCanonical(); + const RecordType *TRec = TTy->getAsCanonical(); bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(QuestionLoc, FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || @@ -7528,12 +7518,10 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { } // GCC seems to also exclude expressions of incomplete enum type. - if (const EnumType *T = E->getType()->getAs()) { - if (!T->getOriginalDecl()->getDefinitionOrSelf()->isComplete()) { - // FIXME: stupid workaround for a codegen bug! - E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); - return E; - } + if (const auto *ED = E->getType()->getAsEnumDecl(); ED && !ED->isComplete()) { + // FIXME: stupid workaround for a codegen bug! + E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); + return E; } ExprResult Res = DefaultFunctionArrayLvalueConversion(E); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 03b5c79cf70e3..331f6e585555b 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -638,8 +638,7 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { // Look for the appropriate method within NSNumber. BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType); BoxedType = NSNumberPointer; - } else if (const EnumType *ET = ValueType->getAs()) { - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + } else if (const auto *ED = ValueType->getAsEnumDecl()) { if (!ED->isComplete()) { Diag(Loc, diag::err_objc_incomplete_boxed_expression_type) << ValueType << ValueExpr->getSourceRange(); @@ -3846,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()) { + if (const RecordType *RT = QT->getAsCanonical()) { for (auto *Redecl : RT->getOriginalDecl()->getMostRecentDecl()->redecls()) { if (auto *attr = Redecl->getAttr()) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f87715950c74c..8fff463e5aa67 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -236,9 +236,8 @@ static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context, static unsigned calculateLegacyCbufferSize(const ASTContext &Context, QualType T) { constexpr unsigned CBufferAlign = 16; - if (const RecordType *RT = T->getAs()) { + if (const auto *RD = T->getAsRecordDecl()) { unsigned Size = 0; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); for (const FieldDecl *Field : RD->fields()) { QualType Ty = Field->getType(); unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty); @@ -364,8 +363,8 @@ static bool isInvalidConstantBufferLeafElementType(const Type *Ty) { Ty = Ty->getUnqualifiedDesugaredType(); if (Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray()) return true; - if (Ty->isRecordType()) - return Ty->getAsCXXRecordDecl()->isEmpty(); + if (const auto *RD = Ty->getAsCXXRecordDecl()) + return RD->isEmpty(); if (Ty->isConstantArrayType() && isZeroSizedArray(cast(Ty))) return true; @@ -387,14 +386,14 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) { QualType Ty = Field->getType(); if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr())) return true; - if (Ty->isRecordType() && - requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl())) + if (const auto *RD = Ty->getAsCXXRecordDecl(); + RD && requiresImplicitBufferLayoutStructure(RD)) return true; } // check bases for (const CXXBaseSpecifier &Base : RD->bases()) if (requiresImplicitBufferLayoutStructure( - Base.getType()->getAsCXXRecordDecl())) + Base.getType()->castAsCXXRecordDecl())) return true; return false; } @@ -459,8 +458,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty, if (isInvalidConstantBufferLeafElementType(Ty)) return nullptr; - if (Ty->isRecordType()) { - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (auto *RD = Ty->getAsCXXRecordDecl()) { if (requiresImplicitBufferLayoutStructure(RD)) { RD = createHostLayoutStruct(S, RD); if (!RD) @@ -511,7 +509,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, assert(NumBases == 1 && "HLSL supports only one base type"); (void)NumBases; CXXBaseSpecifier Base = *StructDecl->bases_begin(); - CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); + CXXRecordDecl *BaseDecl = Base.getType()->castAsCXXRecordDecl(); if (requiresImplicitBufferLayoutStructure(BaseDecl)) { BaseDecl = createHostLayoutStruct(S, BaseDecl); if (BaseDecl) { @@ -3194,10 +3192,7 @@ static void BuildFlattenedTypeList(QualType BaseTy, List.insert(List.end(), VT->getNumElements(), VT->getElementType()); continue; } - if (const auto *RT = dyn_cast(T)) { - const CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); - assert(RD && "HLSL record types should all be CXXRecordDecls!"); - + if (const auto *RD = T->getAsCXXRecordDecl()) { if (RD->isStandardLayout()) RD = RD->getStandardLayoutBaseWithFields(); @@ -3967,19 +3962,19 @@ class InitListTransformer { return true; } - if (auto *RTy = Ty->getAs()) { - llvm::SmallVector RecordTypes; - RecordTypes.push_back(RTy); - while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) { - CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl(); + if (auto *RD = Ty->getAsCXXRecordDecl()) { + llvm::SmallVector RecordDecls; + RecordDecls.push_back(RD); + while (RecordDecls.back()->getNumBases()) { + CXXRecordDecl *D = RecordDecls.back(); assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance"); - RecordTypes.push_back(D->bases_begin()->getType()->getAs()); + RecordDecls.push_back( + D->bases_begin()->getType()->castAsCXXRecordDecl()); } - while (!RecordTypes.empty()) { - const RecordType *RT = RecordTypes.pop_back_val(); - for (auto *FD : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + while (!RecordDecls.empty()) { + CXXRecordDecl *RD = RecordDecls.pop_back_val(); + for (auto *FD : RD->fields()) { DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess()); DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc()); ExprResult Res = S.BuildFieldReferenceExpr( @@ -4016,21 +4011,20 @@ class InitListTransformer { for (uint64_t I = 0; I < Size; ++I) Inits.push_back(generateInitListsImpl(ElTy)); } - if (auto *RTy = Ty->getAs()) { - llvm::SmallVector RecordTypes; - RecordTypes.push_back(RTy); - while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) { - CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl(); + if (auto *RD = Ty->getAsCXXRecordDecl()) { + llvm::SmallVector RecordDecls; + RecordDecls.push_back(RD); + while (RecordDecls.back()->getNumBases()) { + CXXRecordDecl *D = RecordDecls.back(); assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance"); - RecordTypes.push_back(D->bases_begin()->getType()->getAs()); + RecordDecls.push_back( + D->bases_begin()->getType()->castAsCXXRecordDecl()); } - while (!RecordTypes.empty()) { - const RecordType *RT = RecordTypes.pop_back_val(); - for (auto *FD : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + while (!RecordDecls.empty()) { + CXXRecordDecl *RD = RecordDecls.pop_back_val(); + for (auto *FD : RD->fields()) Inits.push_back(generateInitListsImpl(FD->getType())); - } } } auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 60f9d449fc037..91590da35c1eb 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()) + if (const RecordType *RType = ILE->getType()->getAsCanonical()) if (!RType->getOriginalDecl()->isUnion()) assert((Init < NumInits || VerifyOnly) && "This ILE should have been expanded"); @@ -921,8 +921,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (ILE->isTransparent()) return; - if (const RecordType *RType = ILE->getType()->getAs()) { - const RecordDecl *RDecl = RType->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RDecl = ILE->getType()->getAsRecordDecl()) { if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) { FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, RequiresSecondPass, FillWithNoInit); @@ -1126,8 +1125,7 @@ int InitListChecker::numArrayElements(QualType DeclType) { } int InitListChecker::numStructUnionElements(QualType DeclType) { - RecordDecl *structDecl = - DeclType->castAs()->getOriginalDecl()->getDefinitionOrSelf(); + auto *structDecl = DeclType->castAsRecordDecl(); int InitializableMembers = 0; if (auto *CXXRD = dyn_cast(structDecl)) InitializableMembers += CXXRD->getNumBases(); @@ -1156,22 +1154,14 @@ static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) { // Allows elide brace initialization for aggregates with empty base. if (Entity.getKind() == InitializedEntity::EK_Base) { - auto *ParentRD = Entity.getParent() - ->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *ParentRD = Entity.getParent()->getType()->castAsRecordDecl(); CXXRecordDecl *CXXRD = cast(ParentRD); return CXXRD->getNumBases() == 1 && CXXRD->field_empty(); } // Allow brace elision if the only subobject is a field. if (Entity.getKind() == InitializedEntity::EK_Member) { - auto *ParentRD = Entity.getParent() - ->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *ParentRD = Entity.getParent()->getType()->castAsRecordDecl(); if (CXXRecordDecl *CXXRD = dyn_cast(ParentRD)) { if (CXXRD->getNumBases()) { return false; @@ -2348,7 +2338,9 @@ void InitListChecker::CheckStructUnionTypes( Field != FieldEnd; ++Field) { if (Field->hasInClassInitializer() || (Field->isAnonymousStructOrUnion() && - Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) { + Field->getType() + ->castAsCXXRecordDecl() + ->hasInClassInitializer())) { StructuredList->setInitializedFieldInUnion(*Field); // FIXME: Actually build a CXXDefaultInitExpr? return; @@ -4535,11 +4527,7 @@ static void TryConstructorInitialization(Sema &S, } } - const RecordType *DestRecordType = DestType->getAs(); - assert(DestRecordType && "Constructor initialization requires record type"); - auto *DestRecordDecl = cast(DestRecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *DestRecordDecl = DestType->castAsCXXRecordDecl(); // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -5026,7 +5014,7 @@ static void TryListInitialization(Sema &S, // class type with a default constructor, the object is // value-initialized. if (InitList->getNumInits() == 0) { - CXXRecordDecl *RD = DestType->getAsCXXRecordDecl(); + CXXRecordDecl *RD = DestType->castAsCXXRecordDecl(); if (S.LookupDefaultConstructor(RD)) { TryValueInitialization(S, Entity, Kind, Sequence, InitList); return; @@ -5057,10 +5045,9 @@ static void TryListInitialization(Sema &S, // is direct-list-initialization, the object is initialized with the // value T(v); if a narrowing conversion is required to convert v to // the underlying type of T, the program is ill-formed. - auto *ET = DestType->getAs(); if (S.getLangOpts().CPlusPlus17 && - Kind.getKind() == InitializationKind::IK_DirectList && ET && - ET->getOriginalDecl()->getDefinitionOrSelf()->isFixed() && + Kind.getKind() == InitializationKind::IK_DirectList && + DestType->isEnumeralType() && DestType->castAsEnumDecl()->isFixed() && !S.Context.hasSameUnqualifiedType(E->getType(), DestType) && (E->getType()->isIntegralOrUnscopedEnumerationType() || E->getType()->isFloatingType())) { @@ -5165,14 +5152,10 @@ static OverloadingResult TryRefInitWithConversionFunction( bool AllowExplicitCtors = false; bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding(); - const RecordType *T1RecordType = nullptr; - if (AllowRValues && (T1RecordType = T1->getAs()) && - S.isCompleteType(Kind.getLocation(), T1)) { + auto *T1RecordDecl = AllowRValues ? T1->getAsCXXRecordDecl() : nullptr; + if (T1RecordDecl && S.isCompleteType(Kind.getLocation(), T1)) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. - auto *T1RecordDecl = cast(T1RecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - for (NamedDecl *D : S.LookupConstructors(T1RecordDecl)) { auto Info = getConstructorInfo(D); if (!Info.Constructor) @@ -5194,18 +5177,13 @@ static OverloadingResult TryRefInitWithConversionFunction( } } } - if (T1RecordType && - T1RecordType->getOriginalDecl()->getDefinitionOrSelf()->isInvalidDecl()) + if (T1RecordDecl && T1RecordDecl->isInvalidDecl()) return OR_No_Viable_Function; - const RecordType *T2RecordType = nullptr; - if ((T2RecordType = T2->getAs()) && - S.isCompleteType(Kind.getLocation(), T2)) { + const CXXRecordDecl *T2RecordDecl = T2->getAsCXXRecordDecl(); + if (T2RecordDecl && S.isCompleteType(Kind.getLocation(), T2)) { // The type we're converting from is a class type, enumerate its conversion // functions. - auto *T2RecordDecl = cast(T2RecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { NamedDecl *D = *I; @@ -5240,8 +5218,7 @@ static OverloadingResult TryRefInitWithConversionFunction( } } } - if (T2RecordType && - T2RecordType->getOriginalDecl()->getDefinitionOrSelf()->isInvalidDecl()) + if (T2RecordDecl && T2RecordDecl->isInvalidDecl()) return OR_No_Viable_Function; SourceLocation DeclLoc = Initializer->getBeginLoc(); @@ -5718,64 +5695,60 @@ static void TryValueInitialization(Sema &S, // -- if T is an array type, then each element is value-initialized; T = S.Context.getBaseElementType(T); - if (const RecordType *RT = T->getAs()) { - if (CXXRecordDecl *ClassDecl = - dyn_cast(RT->getOriginalDecl())) { - ClassDecl = ClassDecl->getDefinitionOrSelf(); - bool NeedZeroInitialization = true; - // C++98: - // -- if T is a class type (clause 9) with a user-declared constructor - // (12.1), then the default constructor for T is called (and the - // initialization is ill-formed if T has no accessible default - // constructor); - // C++11: - // -- if T is a class type (clause 9) with either no default constructor - // (12.1 [class.ctor]) or a default constructor that is user-provided - // or deleted, then the object is default-initialized; - // - // Note that the C++11 rule is the same as the C++98 rule if there are no - // defaulted or deleted constructors, so we just use it unconditionally. - CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); - if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) - NeedZeroInitialization = false; - - // -- if T is a (possibly cv-qualified) non-union class type without a - // user-provided or deleted default constructor, then the object is - // zero-initialized and, if T has a non-trivial default constructor, - // default-initialized; - // The 'non-union' here was removed by DR1502. The 'non-trivial default - // constructor' part was removed by DR1507. - if (NeedZeroInitialization) - Sequence.AddZeroInitializationStep(Entity.getType()); - - // C++03: - // -- if T is a non-union class type without a user-declared constructor, - // then every non-static data member and base class component of T is - // value-initialized; - // [...] A program that calls for [...] value-initialization of an - // entity of reference type is ill-formed. - // - // C++11 doesn't need this handling, because value-initialization does not - // occur recursively there, and the implicit default constructor is - // defined as deleted in the problematic cases. - if (!S.getLangOpts().CPlusPlus11 && - ClassDecl->hasUninitializedReferenceMember()) { - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference); - return; - } - - // If this is list-value-initialization, pass the empty init list on when - // building the constructor call. This affects the semantics of a few - // things (such as whether an explicit default constructor can be called). - Expr *InitListAsExpr = InitList; - MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); - bool InitListSyntax = InitList; + if (auto *ClassDecl = T->getAsCXXRecordDecl()) { + bool NeedZeroInitialization = true; + // C++98: + // -- if T is a class type (clause 9) with a user-declared constructor + // (12.1), then the default constructor for T is called (and the + // initialization is ill-formed if T has no accessible default + // constructor); + // C++11: + // -- if T is a class type (clause 9) with either no default constructor + // (12.1 [class.ctor]) or a default constructor that is user-provided + // or deleted, then the object is default-initialized; + // + // Note that the C++11 rule is the same as the C++98 rule if there are no + // defaulted or deleted constructors, so we just use it unconditionally. + CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); + if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) + NeedZeroInitialization = false; + + // -- if T is a (possibly cv-qualified) non-union class type without a + // user-provided or deleted default constructor, then the object is + // zero-initialized and, if T has a non-trivial default constructor, + // default-initialized; + // The 'non-union' here was removed by DR1502. The 'non-trivial default + // constructor' part was removed by DR1507. + if (NeedZeroInitialization) + Sequence.AddZeroInitializationStep(Entity.getType()); - // FIXME: Instead of creating a CXXConstructExpr of array type here, - // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr. - return TryConstructorInitialization( - S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax); + // C++03: + // -- if T is a non-union class type without a user-declared constructor, + // then every non-static data member and base class component of T is + // value-initialized; + // [...] A program that calls for [...] value-initialization of an + // entity of reference type is ill-formed. + // + // C++11 doesn't need this handling, because value-initialization does not + // occur recursively there, and the implicit default constructor is + // defined as deleted in the problematic cases. + if (!S.getLangOpts().CPlusPlus11 && + ClassDecl->hasUninitializedReferenceMember()) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference); + return; } + + // If this is list-value-initialization, pass the empty init list on when + // building the constructor call. This affects the semantics of a few + // things (such as whether an explicit default constructor can be called). + Expr *InitListAsExpr = InitList; + MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); + bool InitListSyntax = InitList; + + // FIXME: Instead of creating a CXXConstructExpr of array type here, + // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr. + return TryConstructorInitialization( + S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax); } Sequence.AddZeroInitializationStep(Entity.getType()); @@ -5917,10 +5890,8 @@ static void TryOrBuildParenListInitialization( AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength), /*SizeExpr=*/nullptr, ArraySizeModifier::Normal, 0); } - } else if (auto *RT = Entity.getType()->getAs()) { - bool IsUnion = RT->isUnionType(); - const auto *RD = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); + } else if (auto *RD = Entity.getType()->getAsCXXRecordDecl()) { + bool IsUnion = RD->isUnion(); if (RD->isInvalidDecl()) { // Exit early to avoid confusion when processing members. // We do the same for braced list initialization in @@ -6106,15 +6077,12 @@ static void TryUserDefinedConversion(Sema &S, // explicit conversion operators. bool AllowExplicit = Kind.AllowExplicit(); - if (const RecordType *DestRecordType = DestType->getAs()) { + if (DestType->isRecordType()) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. - auto *DestRecordDecl = - cast(DestRecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - // Try to complete the type we're converting to. if (S.isCompleteType(Kind.getLocation(), DestType)) { + auto *DestRecordDecl = DestType->castAsCXXRecordDecl(); for (NamedDecl *D : S.LookupConstructors(DestRecordDecl)) { auto Info = getConstructorInfo(D); if (!Info.Constructor) @@ -6140,17 +6108,14 @@ static void TryUserDefinedConversion(Sema &S, SourceLocation DeclLoc = Initializer->getBeginLoc(); - if (const RecordType *SourceRecordType = SourceType->getAs()) { + if (SourceType->isRecordType()) { // The type we're converting from is a class type, enumerate its conversion // functions. // We can only enumerate the conversion functions for a complete type; if // the type isn't complete, simply skip this step. if (S.isCompleteType(DeclLoc, SourceType)) { - auto *SourceRecordDecl = - cast(SourceRecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *SourceRecordDecl = SourceType->castAsCXXRecordDecl(); const auto &Conversions = SourceRecordDecl->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { @@ -6237,7 +6202,7 @@ static void TryUserDefinedConversion(Sema &S, Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType, HadMultipleCandidates); - if (ConvType->getAs()) { + if (ConvType->isRecordType()) { // The call is used to direct-initialize [...] the object that is the // destination of the copy-initialization. // @@ -7180,10 +7145,7 @@ static ExprResult CopyObject(Sema &S, return CurInit; // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); - CXXRecordDecl *Class = nullptr; - if (const RecordType *Record = T->getAs()) - Class = - cast(Record->getOriginalDecl())->getDefinitionOrSelf(); + auto *Class = T->getAsCXXRecordDecl(); if (!Class) return CurInit; @@ -7328,7 +7290,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, Expr *CurInitExpr) { assert(S.getLangOpts().CPlusPlus11); - const RecordType *Record = CurInitExpr->getType()->getAs(); + auto *Record = CurInitExpr->getType()->getAsCXXRecordDecl(); if (!Record) return; @@ -7338,8 +7300,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, // Find constructors which would have been considered. OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); - DeclContext::lookup_result Ctors = S.LookupConstructors( - cast(Record->getOriginalDecl())->getDefinitionOrSelf()); + DeclContext::lookup_result Ctors = S.LookupConstructors(Record); // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -7803,7 +7764,7 @@ ExprResult InitializationSequence::Perform(Sema &S, DiagID = diag::ext_default_init_const; S.Diag(Kind.getLocation(), DiagID) - << DestType << (bool)DestType->getAs() + << DestType << DestType->isRecordType() << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, ZeroInitializationFixit); } @@ -8169,10 +8130,8 @@ ExprResult InitializationSequence::Perform(Sema &S, // FIXME: It makes no sense to do this here. This should happen // regardless of how we initialized the entity. QualType T = CurInit.get()->getType(); - if (const RecordType *Record = T->getAs()) { - CXXDestructorDecl *Destructor = - S.LookupDestructor(cast(Record->getOriginalDecl()) - ->getDefinitionOrSelf()); + if (auto *Record = T->castAsCXXRecordDecl()) { + CXXDestructorDecl *Destructor = S.LookupDestructor(Record); S.CheckDestructorAccess(CurInit.get()->getBeginLoc(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkFunctionReferenced(CurInit.get()->getBeginLoc(), Destructor); @@ -8560,9 +8519,8 @@ ExprResult InitializationSequence::Perform(Sema &S, S.isStdInitializerList(Step->Type, &ElementType); assert(IsStdInitializerList && "StdInitializerList step to non-std::initializer_list"); - const CXXRecordDecl *Record = - Step->Type->getAsCXXRecordDecl()->getDefinition(); - assert(Record && Record->isCompleteDefinition() && + const auto *Record = Step->Type->castAsCXXRecordDecl(); + assert(Record->isCompleteDefinition() && "std::initializer_list should have already be " "complete/instantiated by this point"); @@ -9225,11 +9183,8 @@ bool InitializationSequence::Diagnose(Sema &S, << S.Context.getCanonicalTagType(Constructor->getParent()) << /*base=*/0 << Entity.getType() << InheritedFrom; - RecordDecl *BaseDecl = Entity.getBaseSpecifier() - ->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *BaseDecl = + Entity.getBaseSpecifier()->getType()->castAsRecordDecl(); S.Diag(BaseDecl->getLocation(), diag::note_previous_decl) << S.Context.getCanonicalTagType(BaseDecl); } else { @@ -9242,8 +9197,7 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Entity.getDecl()->getLocation(), diag::note_member_declared_at); - if (const RecordType *Record - = Entity.getType()->getAs()) + if (const auto *Record = Entity.getType()->getAs()) S.Diag(Record->getOriginalDecl()->getLocation(), diag::note_previous_decl) << S.Context.getCanonicalTagType(Record->getOriginalDecl()); @@ -9326,7 +9280,7 @@ bool InitializationSequence::Diagnose(Sema &S, << VD; } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) - << DestType << (bool)DestType->getAs(); + << DestType << DestType->isRecordType(); } break; @@ -10021,7 +9975,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // dependent. e.g. // using AliasFoo = Foo; if (const auto *CTSD = llvm::dyn_cast( - RT->getAsCXXRecordDecl())) + RT->getOriginalDecl())) Template = CTSD->getSpecializedTemplate(); } } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 8a81cbe2623d8..fbc2e7eb30676 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -641,9 +641,8 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) { } // - it is an expression of that formal enum type. - if (const EnumType *ET = E->getType()->getAs()) { - return ET->getOriginalDecl()->getDefinitionOrSelf(); - } + if (auto *ED = E->getType()->getAsEnumDecl()) + return ED; // Otherwise, nope. return nullptr; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e28492b579564..5ae82eaa50684 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2770,10 +2770,7 @@ bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { // members of Class itself. That is, the naming class is Class, and the // access includes the access of the base. for (const auto &BaseSpec : Class->bases()) { - CXXRecordDecl *RD = - cast( - BaseSpec.getType()->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *RD = BaseSpec.getType()->castAsCXXRecordDecl(); LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); Result.setBaseObjectType(Context.getCanonicalTagType(Class)); LookupQualifiedName(Result, RD); @@ -3114,17 +3111,15 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // Visit the base classes. for (const auto &Base : Class->bases()) { - const RecordType *BaseType = Base.getType()->getAs(); + CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); // In dependent contexts, we do ADL twice, and the first time around, // the base type might be a dependent TemplateSpecializationType, or a // TemplateTypeParmType. If that happens, simply ignore it. // FIXME: If we want to support export, we probably need to add the // namespace of the template in a TemplateSpecializationType, or even // the classes and namespaces of known non-dependent arguments. - if (!BaseType) + if (!BaseDecl) continue; - CXXRecordDecl *BaseDecl = cast(BaseType->getOriginalDecl()) - ->getDefinitionOrSelf(); if (Result.addClassTransitive(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); @@ -3209,8 +3204,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // member’s class; else it has no associated class. case Type::Enum: { // FIXME: This should use the original decl. - EnumDecl *Enum = - cast(T)->getOriginalDecl()->getDefinitionOrSelf(); + auto *Enum = T->castAsEnumDecl(); DeclContext *Ctx = Enum->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) @@ -4262,10 +4256,9 @@ class LookupVisibleHelper { continue; RD = TD->getTemplatedDecl(); } else { - const auto *Record = BaseType->getAs(); - if (!Record) + RD = BaseType->getAsCXXRecordDecl(); + if (!RD) continue; - RD = Record->getOriginalDecl()->getDefinitionOrSelf(); } // FIXME: It would be nice to be able to determine whether referencing 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(); + const RecordType *RecordTy = T->getAsCanonical(); 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(); + const auto *RT = PT->getPointeeType()->getAsCanonical(); if (!RT) return false; diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index bf6c364e40cc4..1880cec6ec8e5 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1320,10 +1320,8 @@ Decl *SemaObjC::ActOnPropertyImplDecl( CompleteTypeErr = true; } if (!CompleteTypeErr) { - const RecordType *RecordTy = PropertyIvarType->getAs(); - if (RecordTy && RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { + if (const auto *RD = PropertyIvarType->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) { Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar) << PropertyIvarType; CompleteTypeErr = true; // suppress later diagnostics about the ivar diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 7d800c446b595..8f666cee72937 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -18628,12 +18628,12 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, // the set of member candidates is empty. LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); Lookup.suppressDiagnostics(); - if (const auto *TyRec = Ty->getAs()) { + if (Ty->isRecordType()) { // Complete the type if it can be completed. // If the type is neither complete nor being defined, bail out now. bool IsComplete = SemaRef.isCompleteType(Loc, Ty); - RecordDecl *RD = TyRec->getOriginalDecl()->getDefinition(); - if (IsComplete || RD) { + auto *RD = Ty->castAsRecordDecl(); + if (IsComplete || RD->isBeingDefined()) { Lookup.clear(); SemaRef.LookupQualifiedName(Lookup, RD); if (Lookup.empty()) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7c4405b414c47..14fa8478fe317 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -369,8 +369,8 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( // A conversion to an enumeration type is narrowing if the conversion to // the underlying type is narrowing. This only arises for expressions of // the form 'Enum{init}'. - if (auto *ET = ToType->getAs()) - ToType = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = ToType->getAsEnumDecl()) + ToType = ED->getIntegerType(); switch (Second) { // 'bool' is an integral type; dispatch to the right place to handle it. @@ -1058,13 +1058,12 @@ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc, if (isa(EqFD)) { // If F is a class member, search scope is class type of first operand. QualType RHS = FirstOperand->getType(); - auto *RHSRec = RHS->getAs(); + auto *RHSRec = RHS->getAsCXXRecordDecl(); if (!RHSRec) return true; LookupResult Members(S, NotEqOp, OpLoc, Sema::LookupNameKind::LookupMemberName); - S.LookupQualifiedName(Members, - RHSRec->getOriginalDecl()->getDefinitionOrSelf()); + S.LookupQualifiedName(Members, RHSRec); Members.suppressAccessDiagnostics(); for (NamedDecl *Op : Members) if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction())) @@ -1802,7 +1801,7 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, // constructor (i.e., a user-defined conversion function) is // called for those cases. QualType FromType = From->getType(); - if (ToType->getAs() && FromType->getAs() && + if (ToType->isRecordType() && (S.Context.hasSameUnqualifiedType(FromType, ToType) || S.IsDerivedFrom(From->getBeginLoc(), FromType, ToType))) { ICS.setStandard(); @@ -2662,11 +2661,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // integral promotion can be applied to its underlying type, a prvalue of an // unscoped enumeration type whose underlying type is fixed can also be // converted to a prvalue of the promoted underlying type. - if (const EnumType *FromEnumType = FromType->getAs()) { + if (const auto *FromED = FromType->getAsEnumDecl()) { // C++0x 7.2p9: Note that this implicit enum to int conversion is not // provided for a scoped enumeration. - const EnumDecl *FromED = - FromEnumType->getOriginalDecl()->getDefinitionOrSelf(); if (FromED->isScoped()) return false; @@ -3969,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()) { + if (const RecordType *ToRecordType = ToType->getAsCanonical()) { // 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 @@ -3979,7 +3976,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // that class. The argument list is the expression-list within // the parentheses of the initializer. if (S.Context.hasSameUnqualifiedType(ToType, From->getType()) || - (From->getType()->getAs() && + (From->getType()->isRecordType() && S.IsDerivedFrom(From->getBeginLoc(), From->getType(), ToType))) ConstructorsOnly = true; @@ -4059,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()) { + From->getType()->getAsCanonical()) { if (auto *FromRecordDecl = dyn_cast(FromRecordType->getOriginalDecl())) { FromRecordDecl = FromRecordDecl->getDefinitionOrSelf(); @@ -4509,12 +4506,10 @@ getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) { if (SCS.Second != ICK_Integral_Promotion) return FixedEnumPromotion::None; - QualType FromType = SCS.getFromType(); - if (!FromType->isEnumeralType()) + const auto *Enum = SCS.getFromType()->getAsEnumDecl(); + if (!Enum) return FixedEnumPromotion::None; - EnumDecl *Enum = - FromType->castAs()->getOriginalDecl()->getDefinitionOrSelf(); if (!Enum->isFixed()) return FixedEnumPromotion::None; @@ -5150,10 +5145,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, Expr *Init, QualType T2, bool AllowRvalues, bool AllowExplicit) { assert(T2->isRecordType() && "Can only find conversions of record types."); - auto *T2RecordDecl = - cast(T2->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *T2RecordDecl = T2->castAsCXXRecordDecl(); OverloadCandidateSet CandidateSet( DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion); const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions(); @@ -6821,7 +6813,7 @@ ExprResult Sema::PerformContextualImplicitConversion( // We can only perform contextual implicit conversions on objects of class // type. - const RecordType *RecordTy = T->getAs(); + const RecordType *RecordTy = T->getAsCanonical(); if (!RecordTy || !getLangOpts().CPlusPlus) { if (!Converter.Suppress) Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange(); @@ -8341,10 +8333,7 @@ void Sema::AddConversionCandidate( QualType ObjectType = From->getType(); if (const auto *FromPtrType = ObjectType->getAs()) ObjectType = FromPtrType->getPointeeType(); - const auto *ConversionContext = - cast(ObjectType->castAs()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *ConversionContext = ObjectType->castAsCXXRecordDecl(); // C++23 [over.best.ics.general] // However, if the target is [...] // - the object parameter of a user-defined conversion function @@ -8742,10 +8731,9 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // defined, the set of member candidates is the result of the // qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, // the set of member candidates is empty. - if (const RecordType *T1Rec = T1->getAs()) { + if (T1->isRecordType()) { bool IsComplete = isCompleteType(OpLoc, T1); - CXXRecordDecl *T1RD = - cast(T1Rec->getOriginalDecl())->getDefinition(); + auto *T1RD = T1->getAsCXXRecordDecl(); // Complete the type if it can be completed. // If the type is neither complete nor being defined, bail out now. if (!T1RD || (!IsComplete && !T1RD->isBeingDefined())) @@ -9054,8 +9042,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, Ty = Ty.getLocalUnqualifiedType(); // Flag if we ever add a non-record type. - const RecordType *TyRec = Ty->getAs(); - HasNonRecordTypes = HasNonRecordTypes || !TyRec; + bool TyIsRec = Ty->isRecordType(); + HasNonRecordTypes = HasNonRecordTypes || !TyIsRec; // Flag if we encounter an arithmetic type. HasArithmeticOrEnumeralTypes = @@ -9090,13 +9078,12 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, MatrixTypes.insert(Ty); } else if (Ty->isNullPtrType()) { HasNullPtrType = true; - } else if (AllowUserConversions && TyRec) { + } else if (AllowUserConversions && TyIsRec) { // No conversion functions in incomplete types. if (!SemaRef.isCompleteType(Loc, Ty)) return; - auto *ClassDecl = - cast(TyRec->getOriginalDecl())->getDefinitionOrSelf(); + auto *ClassDecl = Ty->castAsCXXRecordDecl(); for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { if (isa(D)) D = cast(D)->getTargetDecl(); @@ -10155,7 +10142,7 @@ class BuiltinOperatorOverloadBuilder { continue; for (QualType MemPtrTy : CandidateTypes[1].member_pointer_types()) { const MemberPointerType *mptr = cast(MemPtrTy); - CXXRecordDecl *D1 = C1->getAsCXXRecordDecl(), + CXXRecordDecl *D1 = C1->castAsCXXRecordDecl(), *D2 = mptr->getMostRecentCXXRecordDecl(); if (!declaresSameEntity(D1, D2) && !S.IsDerivedFrom(CandidateSet.getLocation(), D1, D2)) @@ -10208,7 +10195,9 @@ class BuiltinOperatorOverloadBuilder { if (S.getLangOpts().CPlusPlus11) { for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) { - if (!EnumTy->castAs()->getOriginalDecl()->isScoped()) + if (!EnumTy->castAsCanonical() + ->getOriginalDecl() + ->isScoped()) continue; if (!AddedTypes.insert(S.Context.getCanonicalType(EnumTy)).second) @@ -16353,9 +16342,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, diag::err_incomplete_object_call, Object.get())) return true; - const auto *Record = Object.get()->getType()->castAs(); + auto *Record = Object.get()->getType()->castAsCXXRecordDecl(); LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); - LookupQualifiedName(R, Record->getOriginalDecl()->getDefinitionOrSelf()); + LookupQualifiedName(R, Record); R.suppressAccessDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); @@ -16374,8 +16363,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // we filter them out to produce better error diagnostics, ie to avoid // showing 2 failed overloads instead of one. bool IgnoreSurrogateFunctions = false; - if (CandidateSet.nonDeferredCandidatesCount() == 1 && - Record->getAsCXXRecordDecl()->isLambda()) { + if (CandidateSet.nonDeferredCandidatesCount() == 1 && Record->isLambda()) { const OverloadCandidate &Candidate = *CandidateSet.begin(); if (!Candidate.Viable && Candidate.FailureKind == ovl_fail_constraints_not_satisfied) @@ -16399,9 +16387,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - const auto &Conversions = cast(Record->getOriginalDecl()) - ->getDefinitionOrSelf() - ->getVisibleConversionFunctions(); + const auto &Conversions = Record->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); !IgnoreSurrogateFunctions && I != E; ++I) { NamedDecl *D = *I; @@ -16622,10 +16608,7 @@ ExprResult Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, return ExprError(); LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName); - LookupQualifiedName(R, Base->getType() - ->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf()); + LookupQualifiedName(R, Base->getType()->castAsRecordDecl()); R.suppressAccessDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 46d7372dd056b..bfa458d207b46 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -41,10 +41,7 @@ void SemaPPC::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { return; QualType ArgType = Arg->getType(); - for (const FieldDecl *FD : ArgType->castAs() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->fields()) { + for (const FieldDecl *FD : ArgType->castAsRecordDecl()->fields()) { if (const auto *AA = FD->getAttr()) { CharUnits Alignment = getASTContext().toCharUnitsFromBits( AA->getAlignment(getASTContext())); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index bc1ddb80961a2..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(); - const EnumType *CaseEnumType = CaseType->getAs(); + const EnumType *CondEnumType = CondType->getAsCanonical(); + const EnumType *CaseEnumType = CaseType->getAsCanonical(); if (!CondEnumType || !CaseEnumType) return; @@ -1590,12 +1590,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // we still do the analysis to preserve this information in the AST // (which can be used by flow-based analyes). // - const EnumType *ET = CondTypeBeforePromotion->getAs(); - // If switch has default case, then ignore it. if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond && - ET) { - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + CondTypeBeforePromotion->isEnumeralType()) { + const auto *ED = CondTypeBeforePromotion->castAsEnumDecl(); if (!ED->isCompleteDefinition() || ED->enumerators().empty()) goto enum_out; @@ -1730,8 +1728,7 @@ void Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr) { - const auto *ET = DstType->getAs(); - if (!ET) + if (!DstType->isEnumeralType()) return; if (!SrcType->isIntegerType() || @@ -1741,7 +1738,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, if (SrcExpr->isTypeDependent() || SrcExpr->isValueDependent()) return; - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = DstType->castAsEnumDecl(); if (!ED->isClosed()) return; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index cd8b98c7444eb..13211007f358d 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(FoundDecl)) - RT = VD->getType()->getAs(); + RT = VD->getType()->getAsCanonical(); else if (TypedefNameDecl *TD = dyn_cast(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()) QT = PT->getPointeeType(); - RT = QT->getAs(); + RT = QT->getAsCanonical(); } else if (TypeDecl *TD = dyn_cast(FoundDecl)) - RT = Context.getTypeDeclType(TD)->getAs(); + RT = QualType(Context.getCanonicalTypeDeclType(TD)) + ->getAsCanonical(); else if (FieldDecl *TD = dyn_cast(FoundDecl)) - RT = TD->getType()->getAs(); + RT = TD->getType()->getAsCanonical(); if (!RT) return true; @@ -944,16 +945,15 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr); } - const RecordType *RT = T->getAs(); + const auto *RD = T->getAsRecordDecl(); // FIXME: Diagnose this as field access into a scalar type. - if (!RT) + if (!RD) return ExprResult(); LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc, LookupMemberName); - if (!LookupQualifiedName(FieldResult, - RT->getOriginalDecl()->getDefinitionOrSelf())) + if (!LookupQualifiedName(FieldResult, RD->getDefinitionOrSelf())) return ExprResult(); // Only normal and indirect field results will work. diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp index a99222c5ed55f..d21d79344d5c7 100644 --- a/clang/lib/Sema/SemaSwift.cpp +++ b/clang/lib/Sema/SemaSwift.cpp @@ -129,9 +129,9 @@ static bool isErrorParameter(Sema &S, QualType QT) { // Check for CFError**. if (const auto *PT = Pointee->getAs()) - if (const auto *RT = PT->getPointeeType()->getAs()) - if (S.ObjC().isCFError(RT->getOriginalDecl()->getDefinitionOrSelf())) - return true; + if (auto *RD = PT->getPointeeType()->getAsRecordDecl(); + RD && S.ObjC().isCFError(RD)) + return true; return false; } @@ -271,12 +271,10 @@ static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D, } // Check for CFError *. if (const auto *PtrTy = Param->getAs()) { - if (const auto *RT = PtrTy->getPointeeType()->getAs()) { - if (S.ObjC().isCFError( - RT->getOriginalDecl()->getDefinitionOrSelf())) { - AnyErrorParams = true; - break; - } + if (auto *RD = PtrTy->getPointeeType()->getAsRecordDecl(); + RD && S.ObjC().isCFError(RD)) { + AnyErrorParams = true; + break; } } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 36bffc5e5e3c9..3dc77fa8ddea1 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()) { + if (const EnumType *EnumT = T->getAsCanonical()) { // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization // check here. EnumDecl *Enum = EnumT->getOriginalDecl(); // Get to the parent type. if (TypeDecl *Parent = dyn_cast(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()) { + if (auto *RT = OperandArg->getAsCanonical()) { 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(); + RT = ConstantType->getAsCanonical(); Literal = true; LiteralLoc = SpecDecl->getSourceRange().getBegin(); } @@ -4086,7 +4086,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, return TypeResult(true); // Check the tag kind - if (const RecordType *RT = Result->getAs()) { + // FIXME: This looks like it doesn't need canonical type and definition. + if (const RecordType *RT = Result->getAsCanonical()) { RecordDecl *D = RT->getOriginalDecl()->getDefinitionOrSelf(); IdentifierInfo *Id = D->getIdentifier(); @@ -4132,7 +4133,7 @@ static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg, case TemplateArgument::Type: { QualType Type = Arg.getAsType(); const TemplateTypeParmType *TPT = - Arg.getAsType()->getAs(); + Arg.getAsType()->getAsCanonical(); return TPT && !Type.hasQualifiers() && TPT->getDepth() == Depth && TPT->getIndex() == Index; } @@ -7411,9 +7412,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, // always a no-op, except when the parameter type is bool. In // that case, this may extend the argument from 1 bit to 8 bits. QualType IntegerType = ParamType; - if (const EnumType *Enum = IntegerType->getAs()) - IntegerType = - Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = IntegerType->getAsEnumDecl()) + IntegerType = ED->getIntegerType(); Value = Value.extOrTrunc(IntegerType->isBitIntType() ? Context.getIntWidth(IntegerType) : Context.getTypeSize(IntegerType)); @@ -7510,9 +7510,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, } QualType IntegerType = ParamType; - if (const EnumType *Enum = IntegerType->getAs()) { - IntegerType = - Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = IntegerType->getAsEnumDecl()) { + IntegerType = ED->getIntegerType(); } if (ParamType->isBooleanType()) { @@ -8028,8 +8027,8 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue( // any integral type with C++11 enum classes, make sure we create the right // type of literal for it. QualType T = OrigT; - if (const EnumType *ET = OrigT->getAs()) - T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = OrigT->getAsEnumDecl()) + T = ED->getIntegerType(); Expr *E; if (T->isAnyCharacterType()) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 93983bf6d1607..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() - ->template_arguments(); + PResolved = + TP->castAsCanonical()->template_arguments(); } else { const auto *TT = P->castAs(); TNP = TT->getTemplateName(S.Context); @@ -1437,7 +1436,8 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { if (auto *ParamRef = Param->getAs()) { if (ParamRef->getPointeeType().getQualifiers()) return false; - auto *TypeParm = ParamRef->getPointeeType()->getAs(); + auto *TypeParm = + ParamRef->getPointeeType()->getAsCanonical(); return TypeParm && TypeParm->getIndex() >= FirstInnerIndex; } return false; @@ -1702,7 +1702,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // // T // cv-list T - if (const auto *TTP = P->getAs()) { + if (const auto *TTP = P->getAsCanonical()) { // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth()) @@ -3559,7 +3559,7 @@ static bool isSimpleTemplateIdType(QualType T) { // // This only arises during class template argument deduction for a copy // deduction candidate, where it permits slicing. - if (T->getAs()) + if (isa(T.getCanonicalType())) return true; return false; @@ -5596,7 +5596,7 @@ static TemplateDeductionResult CheckDeductionConsistency( // so let it transform their specializations instead. bool IsDeductionGuide = isa(FTD->getTemplatedDecl()); if (IsDeductionGuide) { - if (auto *Injected = P->getAs()) + if (auto *Injected = P->getAsCanonical()) 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()) + if (auto *Injected = T1->getAsCanonical()) T1 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType( S.Context); - if (auto *Injected = T2->getAs()) + if (auto *Injected = T2->getAsCanonical()) T2 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType( S.Context); } diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 604591408728c..3d54d1eb4373a 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -995,8 +995,8 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { // Cases where template arguments in the RHS of the alias are not // dependent. e.g. // using AliasFoo = Foo; - if (const auto *CTSD = llvm::dyn_cast( - RT->getAsCXXRecordDecl())) { + if (const auto *CTSD = + dyn_cast(RT->getOriginalDecl())) { Template = CTSD->getSpecializedTemplate(); AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray(); } @@ -1056,7 +1056,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, // The (trailing) return type of the deduction guide. const TemplateSpecializationType *FReturnType = RType->getAs(); - if (const auto *ICNT = RType->getAs()) + if (const auto *ICNT = RType->getAsCanonical()) // implicitly-generated deduction guide. FReturnType = cast( ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType( diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 681ee796440f3..ee1b520fa46e9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6973,19 +6973,15 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // If our context used to be dependent, we may need to instantiate // it before performing lookup into that context. bool IsBeingInstantiated = false; - if (CXXRecordDecl *Spec = dyn_cast(ParentDC)) { + if (auto *Spec = dyn_cast(ParentDC)) { if (!Spec->isDependentContext()) { - CanQualType T = Context.getCanonicalTagType(Spec); - const RecordType *Tag = T->getAs(); - assert(Tag && "type of non-dependent record is not a RecordType"); - auto *TagDecl = - cast(Tag->getOriginalDecl())->getDefinitionOrSelf(); - if (TagDecl->isBeingDefined()) + if (Spec->isEntityBeingDefined()) IsBeingInstantiated = true; - else if (RequireCompleteType(Loc, T, diag::err_incomplete_type)) + else if (RequireCompleteType(Loc, Context.getCanonicalTagType(Spec), + diag::err_incomplete_type)) return nullptr; - ParentDC = TagDecl; + ParentDC = Spec->getDefinitionOrSelf(); } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d745cdbf0526f..3f31a05d382a6 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2115,12 +2115,10 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM, return QualType(); } - if (const RecordType *EltTy = T->getAs()) { + if (const auto *RD = T->getAsRecordDecl()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. - if (EltTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) + if (RD->hasFlexibleArrayMember()) Diag(Loc, diag::ext_flexible_array_in_array) << T; } else if (T->isObjCObjectType()) { Diag(Loc, diag::err_objc_array_of_interfaces) << T; @@ -3975,10 +3973,7 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator, if (numNormalPointers == 0) return PointerDeclaratorKind::NonPointer; - if (auto recordType = type->getAs()) { - RecordDecl *recordDecl = - recordType->getOriginalDecl()->getDefinitionOrSelf(); - + if (auto *recordDecl = type->getAsRecordDecl()) { // If this is CFErrorRef*, report it as such. if (numNormalPointers == 2 && numTypeSpecifierPointers < 2 && S.ObjC().isCFError(recordDecl)) { @@ -9622,19 +9617,16 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, if (T->isVariableArrayType()) return true; - const RecordType *RT = ElemType->getAs(); - if (!RT) + if (!ElemType->isRecordType()) return true; - const CXXRecordDecl *RD = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); - // A partially-defined class type can't be a literal type, because a literal // class type must have a trivial destructor (which can't be checked until // the class definition is complete). if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T)) return true; + const auto *RD = ElemType->castAsCXXRecordDecl(); // [expr.prim.lambda]p3: // This class type is [not] a literal type. if (RD->isLambda() && !getLangOpts().CPlusPlus17) { diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 0b4d5916f8dc3..8686bd94f1a2d 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -556,13 +556,11 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, } } -static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, +static bool HasNoThrowOperator(CXXRecordDecl *RD, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, bool (CXXRecordDecl::*HasTrivial)() const, bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { - CXXRecordDecl *RD = - cast(RT->getOriginalDecl())->getDefinitionOrSelf(); if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) return true; @@ -1007,8 +1005,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (T.isPODType(C) || T->isObjCLifetimeType()) return true; - if (const RecordType *RT = T->getAs()) - return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, + if (auto *RD = T->getAsCXXRecordDecl()) + return HasNoThrowOperator(RD, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialCopyAssignment, &CXXRecordDecl::hasNonTrivialCopyAssignment, &CXXMethodDecl::isCopyAssignmentOperator); @@ -1020,8 +1018,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (T.isPODType(C)) return true; - if (const RecordType *RT = C.getBaseElementType(T)->getAs()) - return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, + if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) + return HasNoThrowOperator(RD, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialMoveAssignment, &CXXRecordDecl::hasNonTrivialMoveAssignment, &CXXMethodDecl::isMoveAssignmentOperator); @@ -1585,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(); - const RecordType *rhsRecord = RhsT->getAs(); + const RecordType *lhsRecord = LhsT->getAsCanonical(); + const RecordType *rhsRecord = RhsT->getAsCanonical(); if (!rhsRecord || !lhsRecord) { const ObjCObjectType *LHSObjTy = LhsT->getAs(); const ObjCObjectType *RHSObjTy = RhsT->getAs(); @@ -1645,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(); - const RecordType *DerivedRecord = RhsT->getAs(); + const RecordType *BaseRecord = LhsT->getAsCanonical(); + const RecordType *DerivedRecord = RhsT->getAsCanonical(); if (!BaseRecord || !DerivedRecord) { DiagnoseVLAInCXXTypeTrait(Self, Lhs, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 1d14ead778446..885b2aa2c8f94 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14380,9 +14380,9 @@ TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E) { Expr *Op = E->getExprOperand(); auto EvalCtx = Sema::ExpressionEvaluationContext::Unevaluated; if (E->isGLValue()) - if (auto *RecordT = Op->getType()->getAs()) - if (cast(RecordT->getOriginalDecl())->isPolymorphic()) - EvalCtx = SemaRef.ExprEvalContexts.back().Context; + if (auto *RD = Op->getType()->getAsCXXRecordDecl(); + RD && RD->isPolymorphic()) + EvalCtx = SemaRef.ExprEvalContexts.back().Context; EnterExpressionEvaluationContext Unevaluated(SemaRef, EvalCtx, Sema::ReuseLambdaContextDecl); @@ -14623,12 +14623,9 @@ TreeTransform::TransformCXXNewExpr(CXXNewExpr *E) { if (E->isArray() && !E->getAllocatedType()->isDependentType()) { QualType ElementType = SemaRef.Context.getBaseElementType(E->getAllocatedType()); - if (const RecordType *RecordT = ElementType->getAs()) { - CXXRecordDecl *Record = cast(RecordT->getOriginalDecl()) - ->getDefinitionOrSelf(); - if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) { + if (CXXRecordDecl *Record = ElementType->getAsCXXRecordDecl()) { + if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Destructor); - } } } @@ -14694,13 +14691,9 @@ TreeTransform::TransformCXXDeleteExpr(CXXDeleteExpr *E) { if (!E->getArgument()->isTypeDependent()) { QualType Destroyed = SemaRef.Context.getBaseElementType( E->getDestroyedType()); - if (const RecordType *DestroyedRec = Destroyed->getAs()) { - CXXRecordDecl *Record = - cast(DestroyedRec->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (auto *Record = Destroyed->getAsCXXRecordDecl()) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), SemaRef.LookupDestructor(Record)); - } } return E; @@ -17650,12 +17643,13 @@ TreeTransform::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()) || - (isArrow && BaseType->getAs() && - !BaseType->castAs()->getPointeeType() - ->template getAs())){ + (!isArrow && !isa(CanonicalBaseType)) || + (isArrow && isa(CanonicalBaseType) && + !cast(CanonicalBaseType) + ->getPointeeType() + ->getAsCanonical())) { // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr( Base, OperatorLoc, isArrow ? tok::arrow : tok::period, SS, ScopeType, @@ -17682,13 +17676,11 @@ TreeTransform::RebuildCXXPseudoDestructorExpr(Expr *Base, } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. - return getSema().BuildMemberReferenceExpr(Base, BaseType, - OperatorLoc, isArrow, - SS, TemplateKWLoc, - /*FIXME: FirstQualifier*/ nullptr, - NameInfo, - /*TemplateArgs*/ nullptr, - /*S*/nullptr); + return getSema().BuildMemberReferenceExpr( + Base, Base->getType(), OperatorLoc, isArrow, SS, TemplateKWLoc, + /*FIXME: FirstQualifier*/ nullptr, NameInfo, + /*TemplateArgs*/ nullptr, + /*S*/ nullptr); } template diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h index ad475ab0f42ae..546b3a9e66e21 100644 --- a/clang/lib/Sema/UsedDeclVisitor.h +++ b/clang/lib/Sema/UsedDeclVisitor.h @@ -70,12 +70,10 @@ class UsedDeclVisitor : public EvaluatedExprVisitor { QualType DestroyedOrNull = E->getDestroyedType(); if (!DestroyedOrNull.isNull()) { QualType Destroyed = S.Context.getBaseElementType(DestroyedOrNull); - if (const RecordType *DestroyedRec = Destroyed->getAs()) { - CXXRecordDecl *Record = - cast(DestroyedRec->getOriginalDecl()); - if (auto *Def = Record->getDefinition()) - asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Def)); - } + if (auto *Record = Destroyed->getAsCXXRecordDecl(); + Record && + (Record->isBeingDefined() || Record->isCompleteDefinition())) + asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record)); } Inherited::VisitCXXDeleteExpr(E); diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 731e506a5d259..e98710aadacf2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -258,7 +258,7 @@ class FindUninitializedField { const FieldRegion *FR = MrMgr.getFieldRegion(I, R); FieldChain.push_back(I); T = I->getType(); - if (T->getAsStructureType()) { + if (T->isStructureType()) { if (Find(FR)) return true; } else { diff --git a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 90c6537d71d9d..781216da77f73 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -49,11 +49,10 @@ class CastSizeChecker : public Checker< check::PreStmt > { /// of struct bar. static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize, CharUnits TypeSize, QualType ToPointeeTy) { - const RecordType *RT = ToPointeeTy->getAs(); - if (!RT) + const auto *RD = ToPointeeTy->getAsRecordDecl(); + if (!RD) return false; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); RecordDecl::field_iterator Iter(RD->field_begin()); RecordDecl::field_iterator End(RD->field_end()); const FieldDecl *Last = nullptr; diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp index 054b2e96bd13b..76a1470aaac44 100644 --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -139,18 +139,11 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE, if (!ValueToCast) return; - const QualType T = CE->getType(); // Check whether the cast type is an enum. - if (!T->isEnumeralType()) + const auto *ED = CE->getType()->getAsEnumDecl(); + if (!ED) return; - // If the cast is an enum, get its declaration. - // If the isEnumeralType() returned true, then the declaration must exist - // even if it is a stub declaration. It is up to the getDeclValuesForEnum() - // function to handle this. - const EnumDecl *ED = - T->castAs()->getOriginalDecl()->getDefinitionOrSelf(); - // [[clang::flag_enum]] annotated enums are by definition should be ignored. if (ED->hasAttr()) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 828b6f91d81c2..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(); + const RecordType *RT = T->getAsCanonical(); if (!RT) return false; @@ -195,14 +195,10 @@ static bool IsPartOfAST(const CXXRecordDecl *R) { if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R)) return true; - for (const auto &BS : R->bases()) { - QualType T = BS.getType(); - if (const RecordType *baseT = T->getAs()) { - CXXRecordDecl *baseD = cast(baseT->getOriginalDecl()); - if (IsPartOfAST(baseD)) - return true; - } - } + for (const auto &BS : R->bases()) + if (const auto *baseD = BS.getType()->getAsCXXRecordDecl(); + baseD && IsPartOfAST(baseD)) + return true; return false; } @@ -243,11 +239,9 @@ void ASTFieldVisitor::Visit(FieldDecl *D) { if (AllocatesMemory(T)) ReportError(T); - if (const RecordType *RT = T->getAs()) { - const RecordDecl *RD = RT->getOriginalDecl()->getDefinition(); + if (const auto *RD = T->getAsRecordDecl()) for (auto *I : RD->fields()) Visit(I); - } FieldChain.pop_back(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp index 7ef659518ab1b..1554604b374ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp @@ -118,12 +118,12 @@ class PaddingChecker : public Checker> { Elts = CArrTy->getZExtSize(); if (Elts == 0) return; - const RecordType *RT = ArrTy->getElementType()->getAs(); - if (RT == nullptr) + const auto *RD = ArrTy->getElementType()->getAsRecordDecl(); + if (!RD) return; // TODO: Recurse into the fields to see if they have excess padding. - visitRecord(RT->getOriginalDecl()->getDefinitionOrSelf(), Elts); + visitRecord(RD, Elts); } bool shouldSkipDecl(const RecordDecl *RD) const { 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(); + const RecordType *RT = PointeeQT->getAsCanonical(); if (!RT) { if (TD->hasAttr() || TD->hasAttr()) { RecordlessTypes.insert(TD->getASTContext() diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index c853c00019c10..785cdfa15bf04 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3165,7 +3165,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { // feasible then it shouldn't be considered for making 'default:' reachable. const SwitchStmt *SS = builder.getSwitch(); const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts(); - if (CondExpr->getType()->getAs()) { + if (CondExpr->getType()->isEnumeralType()) { if (SS->isAllEnumCasesCovered()) return; } diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 02375b0c3469a..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()->getOriginalDecl(); + R->getValueType()->castAsCanonical()->getOriginalDecl(); if (!RD->getDefinition()) return UnknownVal(); @@ -2844,9 +2844,7 @@ RegionStoreManager::bindStruct(LimitedRegionBindingsConstRef B, QualType T = R->getValueType(); assert(T->isStructureOrClassType()); - const RecordType* RT = T->castAs(); - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); - + const auto *RD = T->castAsRecordDecl(); if (!RD->isCompleteDefinition()) return B; 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@-1 {{ambiguous conversion from derived class 'E' to base class 'cwg381::B': + /* expected-error@-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 class Foo : public T {}; { "kind": "inheritsFrom", "source": "c:@ST>1#T@Foo", - "target": "", + "target": "c:input.h@9", "targetFallback": "T" } ], diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index e1aa9bb0721f8..858423a06576a 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1728,7 +1728,7 @@ bool CursorVisitor::VisitUsingTypeLoc(UsingTypeLoc TL) { if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) return true; - auto *underlyingDecl = TL.getTypePtr()->desugar()->getAsTagDecl(); + auto *underlyingDecl = TL.getTypePtr()->getAsTagDecl(); if (underlyingDecl) { return Visit(MakeCursorTypeRef(underlyingDecl, TL.getNameLoc(), TU)); } diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 15df9af889386..5badbd7d65e48 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -9189,7 +9189,7 @@ struct ImportInjectedClassNameType : public ASTImporterOptionSpecificTestBase { .getTypePtr(); ASSERT_TRUE(Ty); EXPECT_FALSE(Ty->isCanonicalUnqualified()); - const auto *InjTy = Ty->castAs(); + const auto *InjTy = dyn_cast(Ty); EXPECT_TRUE(InjTy); for (const Decl *ReD : D->redecls()) { if (ReD == D) @@ -9204,8 +9204,6 @@ struct ImportInjectedClassNameType : public ASTImporterOptionSpecificTestBase { EXPECT_FALSE(ReTy->isCanonicalUnqualified()); EXPECT_NE(ReTy, Ty); EXPECT_TRUE(Ctx.hasSameType(ReTy, Ty)); - const auto *ReInjTy = Ty->castAs(); - EXPECT_TRUE(ReInjTy); } } diff --git a/clang/unittests/AST/RandstructTest.cpp b/clang/unittests/AST/RandstructTest.cpp index cba446fc529e1..a90665b2c0631 100644 --- a/clang/unittests/AST/RandstructTest.cpp +++ b/clang/unittests/AST/RandstructTest.cpp @@ -531,8 +531,7 @@ TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsRetainFieldOrder) { for (const Decl *D : RD->decls()) if (const FieldDecl *FD = dyn_cast(D)) { - if (const auto *Record = FD->getType()->getAs()) { - RD = Record->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RD = FD->getType()->getAsRecordDecl()) { if (RD->isAnonymousStructOrUnion()) { // These field orders shouldn't change. if (RD->isUnion()) { 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"; }