diff options
Diffstat (limited to 'clang/include')
142 files changed, 14466 insertions, 12325 deletions
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index 0f2e496..7162571 100644 --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -141,6 +141,9 @@ class CommonTypeInfo : public CommonEntityInfo { /// The NS error domain for this type. std::optional<std::string> NSErrorDomain; + /// The Swift protocol that this type should be automatically conformed to. + std::optional<std::string> SwiftConformance; + public: CommonTypeInfo() {} @@ -165,6 +168,14 @@ public: : std::nullopt; } + std::optional<std::string> getSwiftConformance() const { + return SwiftConformance; + } + + void setSwiftConformance(std::optional<std::string> conformance) { + SwiftConformance = conformance; + } + friend bool operator==(const CommonTypeInfo &, const CommonTypeInfo &); CommonTypeInfo &operator|=(const CommonTypeInfo &RHS) { @@ -175,6 +186,8 @@ public: setSwiftBridge(RHS.getSwiftBridge()); if (!NSErrorDomain) setNSErrorDomain(RHS.getNSErrorDomain()); + if (SwiftConformance) + setSwiftConformance(RHS.getSwiftConformance()); return *this; } @@ -185,7 +198,8 @@ public: inline bool operator==(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) { return static_cast<const CommonEntityInfo &>(LHS) == RHS && LHS.SwiftBridge == RHS.SwiftBridge && - LHS.NSErrorDomain == RHS.NSErrorDomain; + LHS.NSErrorDomain == RHS.NSErrorDomain && + LHS.SwiftConformance == RHS.SwiftConformance; } inline bool operator!=(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) { @@ -737,11 +751,9 @@ public: std::optional<std::string> SwiftImportAs; std::optional<std::string> SwiftRetainOp; std::optional<std::string> SwiftReleaseOp; + std::optional<std::string> SwiftDestroyOp; std::optional<std::string> SwiftDefaultOwnership; - /// The Swift protocol that this type should be automatically conformed to. - std::optional<std::string> SwiftConformance; - std::optional<EnumExtensibilityKind> EnumExtensibility; TagInfo() @@ -787,12 +799,11 @@ public: SwiftRetainOp = RHS.SwiftRetainOp; if (!SwiftReleaseOp) SwiftReleaseOp = RHS.SwiftReleaseOp; + if (!SwiftDestroyOp) + SwiftDestroyOp = RHS.SwiftDestroyOp; if (!SwiftDefaultOwnership) SwiftDefaultOwnership = RHS.SwiftDefaultOwnership; - if (!SwiftConformance) - SwiftConformance = RHS.SwiftConformance; - if (!HasFlagEnum) setFlagEnum(RHS.isFlagEnum()); @@ -818,8 +829,8 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) { LHS.SwiftImportAs == RHS.SwiftImportAs && LHS.SwiftRetainOp == RHS.SwiftRetainOp && LHS.SwiftReleaseOp == RHS.SwiftReleaseOp && + LHS.SwiftDestroyOp == RHS.SwiftDestroyOp && LHS.SwiftDefaultOwnership == RHS.SwiftDefaultOwnership && - LHS.SwiftConformance == RHS.SwiftConformance && LHS.isFlagEnum() == RHS.isFlagEnum() && LHS.isSwiftCopyable() == RHS.isSwiftCopyable() && LHS.isSwiftEscapable() == RHS.isSwiftEscapable() && diff --git a/clang/include/clang/AST/APNumericStorage.h b/clang/include/clang/AST/APNumericStorage.h index 95eddbc..e1948a5 100644 --- a/clang/include/clang/AST/APNumericStorage.h +++ b/clang/include/clang/AST/APNumericStorage.h @@ -28,7 +28,6 @@ class APNumericStorage { uint64_t VAL; ///< Used to store the <= 64 bits integer value. uint64_t *pVal; ///< Used to store the >64 bits integer value. }; - unsigned BitWidth; bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; } @@ -36,6 +35,7 @@ class APNumericStorage { void operator=(const APNumericStorage &) = delete; protected: + unsigned BitWidth; APNumericStorage() : VAL(0), BitWidth(0) {} llvm::APInt getIntValue() const { @@ -51,6 +51,7 @@ protected: class APIntStorage : private APNumericStorage { public: llvm::APInt getValue() const { return getIntValue(); } + unsigned getBitWidth() const { return BitWidth; } void setValue(const ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); } diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 9999a30..cb942ea 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -143,7 +143,7 @@ public: AddrLabelDiff }; - class LValueBase { + class alignas(uint64_t) LValueBase { typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue, DynamicAllocLValue> PtrTy; diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index 7ccac44..72da005 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_AST_ASTCONCEPT_H #include "clang/AST/DeclarationName.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/UnsignedOrNone.h" @@ -177,12 +177,7 @@ public: SourceLocation getLocation() const { return getConceptNameLoc(); } - SourceLocation getBeginLoc() const LLVM_READONLY { - // Note that if the qualifier is null the template KW must also be null. - if (auto QualifierLoc = getNestedNameSpecifierLoc()) - return QualifierLoc.getBeginLoc(); - return getConceptNameInfo().getBeginLoc(); - } + SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY { return getTemplateArgsAsWritten() && diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 2b7ba41..1c17333 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -230,13 +230,16 @@ class ASTContext : public RefCountedBase<ASTContext> { SubstTemplateTypeParmTypes; mutable llvm::FoldingSet<SubstTemplateTypeParmPackType> SubstTemplateTypeParmPackTypes; + mutable llvm::FoldingSet<SubstBuiltinTemplatePackType> + SubstBuiltinTemplatePackTypes; mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> TemplateSpecializationTypes; mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize}; + mutable llvm::FoldingSet<TagTypeFoldingSetPlaceholder> TagTypes; + mutable llvm::FoldingSet<FoldingSetPlaceholder<UnresolvedUsingType>> + UnresolvedUsingTypes; mutable llvm::FoldingSet<UsingType> UsingTypes; - mutable llvm::FoldingSet<TypedefType> TypedefTypes; - mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes{ - GeneralTypesLog2InitSize}; + mutable llvm::FoldingSet<FoldingSetPlaceholder<TypedefType>> TypedefTypes; mutable llvm::FoldingSet<DependentNameType> DependentNameTypes; mutable llvm::DenseMap<llvm::FoldingSetNodeID, DependentTemplateSpecializationType *> @@ -282,11 +285,11 @@ class ASTContext : public RefCountedBase<ASTContext> { llvm::to_underlying(PredefinedSugarType::Kind::Last) + 1> PredefinedSugarTypes{}; - /// The set of nested name specifiers. + /// Internal storage for NestedNameSpecifiers. /// /// This set is managed by the NestedNameSpecifier class. - mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; - mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr; + mutable llvm::FoldingSet<NamespaceAndPrefixStorage> + NamespaceAndPrefixStorages; /// A cache mapping from RecordDecls to ASTRecordLayouts. /// @@ -639,7 +642,7 @@ public: /// contain data that is address discriminated. This includes /// implicitly authenticated values like vtable pointers, as well as /// explicitly qualified fields. - bool containsAddressDiscriminatedPointerAuth(QualType T) { + bool containsAddressDiscriminatedPointerAuth(QualType T) const { if (!isPointerAuthenticationAvailable()) return false; return findPointerAuthContent(T) != PointerAuthContent::None; @@ -653,8 +656,7 @@ public: bool containsNonRelocatablePointerAuth(QualType T) { if (!isPointerAuthenticationAvailable()) return false; - return findPointerAuthContent(T) == - PointerAuthContent::AddressDiscriminatedData; + return findPointerAuthContent(T) != PointerAuthContent::None; } private: @@ -672,8 +674,8 @@ private: bool isPointerAuthenticationAvailable() const { return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; } - PointerAuthContent findPointerAuthContent(QualType T); - llvm::DenseMap<const RecordDecl *, PointerAuthContent> + PointerAuthContent findPointerAuthContent(QualType T) const; + mutable llvm::DenseMap<const RecordDecl *, PointerAuthContent> RecordContainsAddressDiscriminatedPointerAuth; ImportDecl *FirstLocalImport = nullptr; @@ -1386,8 +1388,6 @@ private: /// Return a type with extended qualifiers. QualType getExtQualType(const Type *Base, Qualifiers Quals) const; - QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; - QualType getPipeType(QualType T, bool ReadOnly) const; public: @@ -1630,7 +1630,7 @@ public: /// Return the uniqued reference to the type for a member pointer to /// the specified type in the specified nested name. - QualType getMemberPointerType(QualType T, NestedNameSpecifier *Qualifier, + QualType getMemberPointerType(QualType T, NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) const; /// Return a non-unique reference to the type for a variable array of @@ -1767,34 +1767,53 @@ private: bool IsCanon = false) const; public: + QualType getTypeDeclType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypeDecl *Decl) const; + /// Return the unique reference to the type for the specified type /// declaration. - QualType getTypeDeclType(const TypeDecl *Decl, - const TypeDecl *PrevDecl = nullptr) const { - assert(Decl && "Passed null for Decl param"); - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - if (PrevDecl) { - assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl"); - Decl->TypeForDecl = PrevDecl->TypeForDecl; - return QualType(PrevDecl->TypeForDecl, 0); - } + QualType getTypeDeclType(const TypeDecl *Decl) const; - return getTypeDeclTypeSlow(Decl); - } + /// Use the normal 'getFooBarType' constructors to obtain these types. + QualType getTypeDeclType(const TagDecl *) const = delete; + QualType getTypeDeclType(const TypedefDecl *) const = delete; + QualType getTypeDeclType(const TypeAliasDecl *) const = delete; + QualType getTypeDeclType(const UnresolvedUsingTypenameDecl *) const = delete; + + CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) const; - QualType getUsingType(const UsingShadowDecl *Found, - QualType Underlying) const; + QualType getUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const UsingShadowDecl *D, + QualType UnderlyingType = QualType()) const; /// Return the unique reference to the type for the specified /// typedef-name decl. - QualType getTypedefType(const TypedefNameDecl *Decl, - QualType Underlying = QualType()) const; + /// FIXME: TypeMatchesDeclOrNone is a workaround for a serialization issue: + /// The decl underlying type might still not be available. + QualType getTypedefType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const TypedefNameDecl *Decl, QualType UnderlyingType = QualType(), + std::optional<bool> TypeMatchesDeclOrNone = std::nullopt) const; + + CanQualType getCanonicalTagType(const TagDecl *TD) const; + QualType getTagType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *TD, + bool OwnsTag) const; - QualType getRecordType(const RecordDecl *Decl) const; +private: + UnresolvedUsingType *getUnresolvedUsingTypeInternal( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, void *InsertPos, + const Type *CanonicalType) const; - QualType getEnumType(const EnumDecl *Decl) const; + TagType *getTagTypeInternal(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *Tag, + bool OwnsTag, bool IsInjected, + const Type *CanonicalType, + bool WithFoldingSetNode) const; +public: /// Compute BestType and BestPromotionType for an enum based on the highest /// number of negative and positive bits of its elements. /// Returns true if enum width is too large. @@ -1843,10 +1862,11 @@ public: return MembersRepresentableByInt; } - QualType - getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const; - - QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; + CanQualType + getCanonicalUnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) const; + QualType getUnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D) const; QualType getAttributedType(attr::Kind attrKind, QualType modifiedType, QualType equivalentType, @@ -1876,6 +1896,7 @@ public: QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, unsigned Index, bool Final, const TemplateArgument &ArgPack); + QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack); QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, @@ -1886,18 +1907,20 @@ public: TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const; QualType - getTemplateSpecializationType(TemplateName T, + getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, ArrayRef<TemplateArgument> SpecifiedArgs, ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying = QualType()) const; QualType - getTemplateSpecializationType(TemplateName T, + getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, ArrayRef<TemplateArgumentLoc> SpecifiedArgs, ArrayRef<TemplateArgument> CanonicalArgs, QualType Canon = QualType()) const; TypeSourceInfo *getTemplateSpecializationTypeInfo( + ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc, TemplateName T, SourceLocation TLoc, const TemplateArgumentListInfo &SpecifiedArgs, ArrayRef<TemplateArgument> CanonicalArgs, @@ -1908,11 +1931,8 @@ public: QualType getMacroQualifiedType(QualType UnderlyingTy, const IdentifierInfo *MacroII) const; - QualType getElaboratedType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, QualType NamedType, - TagDecl *OwnedTagDecl = nullptr) const; QualType getDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier NNS, const IdentifierInfo *Name) const; QualType getDependentTemplateSpecializationType( @@ -1999,21 +2019,17 @@ public: QualType getUnconstrainedType(QualType T) const; /// C++17 deduced class template specialization type. - QualType getDeducedTemplateSpecializationType(TemplateName Template, + QualType getDeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + TemplateName Template, QualType DeducedType, bool IsDependent) const; private: - QualType getDeducedTemplateSpecializationTypeInternal(TemplateName Template, - QualType DeducedType, - bool IsDependent, - QualType Canon) const; + QualType getDeducedTemplateSpecializationTypeInternal( + ElaboratedTypeKeyword Keyword, TemplateName Template, + QualType DeducedType, bool IsDependent, QualType Canon) const; public: - /// Return the unique reference to the type for the specified TagDecl - /// (struct/union/class/enum) decl. - QualType getTagDeclType(const TagDecl *Decl) const; - /// Return the unique type for "size_t" (C99 7.17), defined in /// <stddef.h>. /// @@ -2089,7 +2105,9 @@ public: /// if it hasn't yet been built. QualType getRawCFConstantStringType() const { if (CFConstantStringTypeDecl) - return getTypedefType(CFConstantStringTypeDecl); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, + CFConstantStringTypeDecl); return QualType(); } void setCFConstantStringType(QualType T); @@ -2186,10 +2204,11 @@ public: } #include "clang/Basic/BuiltinTemplates.inc" - /// Retrieve the Objective-C "instancetype" type, if already known; - /// otherwise, returns a NULL type; + /// Retrieve the Objective-C "instancetype" type. QualType getObjCInstanceType() { - return getTypeDeclType(getObjCInstanceTypeDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, + getObjCInstanceTypeDecl()); } /// Retrieve the typedef declaration corresponding to the Objective-C @@ -2202,7 +2221,8 @@ public: /// Retrieve the C FILE type. QualType getFILEType() const { if (FILEDecl) - return getTypeDeclType(FILEDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, FILEDecl); return QualType(); } @@ -2214,7 +2234,8 @@ public: /// Retrieve the C jmp_buf type. QualType getjmp_bufType() const { if (jmp_bufDecl) - return getTypeDeclType(jmp_bufDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, jmp_bufDecl); return QualType(); } @@ -2226,7 +2247,8 @@ public: /// Retrieve the C sigjmp_buf type. QualType getsigjmp_bufType() const { if (sigjmp_bufDecl) - return getTypeDeclType(sigjmp_bufDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, sigjmp_bufDecl); return QualType(); } @@ -2238,12 +2260,13 @@ public: /// Retrieve the C ucontext_t type. QualType getucontext_tType() const { if (ucontext_tDecl) - return getTypeDeclType(ucontext_tDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, ucontext_tDecl); return QualType(); } /// The result type of logical operations, '<', '>', '!=', etc. - QualType getLogicalOperationType() const { + CanQualType getLogicalOperationType() const { return getLangOpts().CPlusPlus ? BoolTy : IntTy; } @@ -2308,7 +2331,8 @@ public: /// This is set up lazily, by Sema. \c id is always a (typedef for a) /// pointer type, a pointer to a struct. QualType getObjCIdType() const { - return getTypeDeclType(getObjCIdDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getObjCIdDecl()); } /// Retrieve the typedef corresponding to the predefined 'SEL' type @@ -2318,7 +2342,8 @@ public: /// Retrieve the type that corresponds to the predefined Objective-C /// 'SEL' type. QualType getObjCSelType() const { - return getTypeDeclType(getObjCSelDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getObjCSelDecl()); } PointerAuthQualifier getObjCMemberSelTypePtrAuth(); @@ -2332,7 +2357,8 @@ public: /// This is set up lazily, by Sema. \c Class is always a (typedef for a) /// pointer type, a pointer to a struct. QualType getObjCClassType() const { - return getTypeDeclType(getObjCClassDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getObjCClassDecl()); } /// Retrieve the Objective-C class declaration corresponding to @@ -2351,7 +2377,8 @@ public: /// type of 'BOOL' type. QualType getBOOLType() const { - return getTypeDeclType(getBOOLDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getBOOLDecl()); } /// Retrieve the type of the Objective-C \c Protocol class. @@ -2365,7 +2392,8 @@ public: /// Retrieve the type of the \c __builtin_va_list type. QualType getBuiltinVaListType() const { - return getTypeDeclType(getBuiltinVaListDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getBuiltinVaListDecl()); } /// Retrieve the C type declaration corresponding to the predefined @@ -2379,16 +2407,17 @@ public: /// Retrieve the type of the \c __builtin_ms_va_list type. QualType getBuiltinMSVaListType() const { - return getTypeDeclType(getBuiltinMSVaListDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getBuiltinMSVaListDecl()); } /// Retrieve the implicitly-predeclared 'struct _GUID' declaration. TagDecl *getMSGuidTagDecl() const { return MSGuidTagDecl; } /// Retrieve the implicitly-predeclared 'struct _GUID' type. - QualType getMSGuidType() const { + CanQualType getMSGuidType() const { assert(MSGuidTagDecl && "asked for GUID type but MS extensions disabled"); - return getTagDeclType(MSGuidTagDecl); + return getCanonicalTagType(MSGuidTagDecl); } /// Retrieve the implicitly-predeclared 'struct type_info' declaration. @@ -2477,7 +2506,7 @@ public: UnresolvedSetIterator End) const; TemplateName getAssumedTemplateName(DeclarationName Name) const; - TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + TemplateName getQualifiedTemplateName(NestedNameSpecifier Qualifier, bool TemplateKeyword, TemplateName Template) const; TemplateName @@ -2919,32 +2948,6 @@ public: /// Determine if two types are similar, ignoring only CVR qualifiers. bool hasCvrSimilarType(QualType T1, QualType T2); - /// Retrieves the "canonical" nested name specifier for a - /// given nested name specifier. - /// - /// The canonical nested name specifier is a nested name specifier - /// that uniquely identifies a type or namespace within the type - /// system. For example, given: - /// - /// \code - /// namespace N { - /// struct S { - /// template<typename T> struct X { typename T* type; }; - /// }; - /// } - /// - /// template<typename T> struct Y { - /// typename N::S::X<T>::type member; - /// }; - /// \endcode - /// - /// Here, the nested-name-specifier for N::S::X<T>:: will be - /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined - /// by declarations in the type system and the canonical type for - /// the template type parameter 'T' is template-param-0-0. - NestedNameSpecifier * - getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; - /// Retrieves the default calling convention for the current context. /// /// The context's default calling convention may differ from the current @@ -3158,7 +3161,7 @@ public: mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, FunctionProtoType::ExceptionSpecInfo ESI2, SmallVectorImpl<QualType> &ExceptionTypeStorage, - bool AcceptDependent); + bool AcceptDependent) const; // For two "same" types, return a type which has // the common sugar between them. If Unqualified is true, @@ -3166,7 +3169,7 @@ public: // The result will drop the qualifiers which do not occur // in both types. QualType getCommonSugaredType(QualType X, QualType Y, - bool Unqualified = false); + bool Unqualified = false) const; private: // Helper for integer ordering @@ -3184,23 +3187,11 @@ public: bool propertyTypesAreCompatible(QualType, QualType); bool typesAreBlockPointerCompatible(QualType, QualType); - bool isObjCIdType(QualType T) const { - if (const auto *ET = dyn_cast<ElaboratedType>(T)) - T = ET->getNamedType(); - return T == getObjCIdType(); - } + bool isObjCIdType(QualType T) const { return T == getObjCIdType(); } - bool isObjCClassType(QualType T) const { - if (const auto *ET = dyn_cast<ElaboratedType>(T)) - T = ET->getNamedType(); - return T == getObjCClassType(); - } + bool isObjCClassType(QualType T) const { return T == getObjCClassType(); } - bool isObjCSelType(QualType T) const { - if (const auto *ET = dyn_cast<ElaboratedType>(T)) - T = ET->getNamedType(); - return T == getObjCSelType(); - } + bool isObjCSelType(QualType T) const { return T == getObjCSelType(); } bool ObjCQualifiedIdTypesAreCompatible(const ObjCObjectPointerType *LHS, const ObjCObjectPointerType *RHS, @@ -3731,7 +3722,7 @@ public: /// Resolve the root record to be used to derive the vtable pointer /// authentication policy for the specified record. const CXXRecordDecl * - baseForVTableAuthentication(const CXXRecordDecl *ThisClass); + baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const; bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl, StringRef MangledName); diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index c40b926..4a0ca45 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -404,7 +404,7 @@ class TypeSourceInfo; /// /// \returns The equivalent nested-name-specifier in the "to" /// context, or the import error. - llvm::Expected<NestedNameSpecifier *> Import(NestedNameSpecifier *FromNNS); + llvm::Expected<NestedNameSpecifier> Import(NestedNameSpecifier FromNNS); /// Import the given nested-name-specifier-loc from the "from" /// context into the "to" context. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 8ebabb2..fe08d637 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -394,12 +394,14 @@ public: } void VisitMemberPointerType(const MemberPointerType *T) { // FIXME: Provide a NestedNameSpecifier visitor. - NestedNameSpecifier *Qualifier = T->getQualifier(); - if (NestedNameSpecifier::SpecifierKind K = Qualifier->getKind(); - K == NestedNameSpecifier::TypeSpec) - Visit(Qualifier->getAsType()); + NestedNameSpecifier Qualifier = T->getQualifier(); + if (NestedNameSpecifier::Kind K = Qualifier.getKind(); + K == NestedNameSpecifier::Kind::Type) + Visit(Qualifier.getAsType()); if (T->isSugared()) - Visit(T->getMostRecentCXXRecordDecl()->getTypeForDecl()); + Visit(cast<MemberPointerType>(T->getCanonicalTypeUnqualified()) + ->getQualifier() + .getAsType()); Visit(T->getPointeeType()); } void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); } @@ -510,7 +512,7 @@ public: } void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { // FIXME: Provide NestedNamespecifierLoc visitor. - Visit(TL.getQualifierLoc().getTypeLoc()); + Visit(TL.getQualifierLoc().castAsTypeLoc()); } void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { Visit(TL.getSizeExpr()); @@ -647,21 +649,8 @@ public: template <typename SpecializationDecl> void dumpTemplateDeclSpecialization(const SpecializationDecl *D) { - for (const auto *RedeclWithBadType : D->redecls()) { - // FIXME: The redecls() range sometimes has elements of a less-specific - // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives - // us TagDecls, and should give CXXRecordDecls). - auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); - if (!Redecl) { - // Found the injected-class-name for a class template. This will be - // dumped as part of its surrounding class so we don't need to dump it - // here. - assert(isa<CXXRecordDecl>(RedeclWithBadType) && - "expected an injected-class-name"); - continue; - } - Visit(Redecl); - } + for (const auto *Redecl : D->redecls()) + Visit(cast<SpecializationDecl>(Redecl)); } template <typename TemplateDecl> @@ -772,17 +761,16 @@ public: } void VisitUsingShadowDecl(const UsingShadowDecl *D) { - if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) - Visit(TD->getTypeForDecl()); + Visit(D->getTargetDecl()); } void VisitFriendDecl(const FriendDecl *D) { if (D->getFriendType()) { // Traverse any CXXRecordDecl owned by this type, since // it will not be in the parent context: - if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>()) - if (auto *TD = ET->getOwnedTagDecl()) - Visit(TD); + if (auto *TT = D->getFriendType()->getType()->getAs<TagType>()) + if (TT->isTagOwned()) + Visit(TT->getOriginalDecl()); } else { Visit(D->getFriendDecl()); } diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h index 3988a15..6f40705 100644 --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -307,7 +307,7 @@ public: /// For nodes which represent textual entities in the source code, /// return their SourceRange. For all other nodes, return SourceRange(). - SourceRange getSourceRange() const; + SourceRange getSourceRange(bool IncludeQualifier = false) const; /// @{ /// Imposes an order on \c DynTypedNode. @@ -336,9 +336,9 @@ public: NodeKind)) { auto NNSLA = getUnchecked<NestedNameSpecifierLoc>(); auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>(); - return std::make_pair(NNSLA.getNestedNameSpecifier(), + return std::make_pair(NNSLA.getNestedNameSpecifier().getAsVoidPointer(), NNSLA.getOpaqueData()) < - std::make_pair(NNSLB.getNestedNameSpecifier(), + std::make_pair(NNSLB.getNestedNameSpecifier().getAsVoidPointer(), NNSLB.getOpaqueData()); } @@ -393,8 +393,9 @@ public: if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame( Val.NodeKind)) { auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>(); - return llvm::hash_combine(NNSL.getNestedNameSpecifier(), - NNSL.getOpaqueData()); + return llvm::hash_combine( + NNSL.getNestedNameSpecifier().getAsVoidPointer(), + NNSL.getOpaqueData()); } assert(Val.getMemoizationData()); @@ -539,8 +540,8 @@ struct DynTypedNode::BaseConverter< : public DynCastPtrConverter<T, Attr> {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {}; +struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> + : public ValueConverter<NestedNameSpecifier> {}; template <> struct DynTypedNode::BaseConverter< diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index 0a2db9e..0d187eb4 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -193,11 +193,11 @@ public: auto elemTy = origTy; unsigned pathLength = asImpl().readUInt32(); for (unsigned i = 0; i < pathLength; ++i) { - if (elemTy->template getAs<RecordType>()) { + if (elemTy->isRecordType()) { unsigned int_ = asImpl().readUInt32(); Decl *decl = asImpl().template readDeclAs<Decl>(); if (auto *recordDecl = dyn_cast<CXXRecordDecl>(decl)) - elemTy = getASTContext().getRecordType(recordDecl); + elemTy = getASTContext().getCanonicalTagType(recordDecl); else elemTy = cast<ValueDecl>(decl)->getType(); path.push_back( @@ -252,39 +252,34 @@ public: return EffectConditionExpr{asImpl().readExprRef()}; } - NestedNameSpecifier *readNestedNameSpecifier() { + NestedNameSpecifier readNestedNameSpecifier() { auto &ctx = getASTContext(); // We build this up iteratively. - NestedNameSpecifier *cur = nullptr; + NestedNameSpecifier cur = std::nullopt; uint32_t depth = asImpl().readUInt32(); for (uint32_t i = 0; i != depth; ++i) { auto kind = asImpl().readNestedNameSpecifierKind(); switch (kind) { - case NestedNameSpecifier::Identifier: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readIdentifier()); + case NestedNameSpecifier::Kind::Namespace: + cur = + NestedNameSpecifier(ctx, asImpl().readNamespaceBaseDeclRef(), cur); continue; - - case NestedNameSpecifier::Namespace: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readNamespaceBaseDeclRef()); + case NestedNameSpecifier::Kind::Type: + assert(!cur); + cur = NestedNameSpecifier(asImpl().readQualType().getTypePtr()); continue; - - case NestedNameSpecifier::TypeSpec: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readQualType().getTypePtr()); + case NestedNameSpecifier::Kind::Global: + assert(!cur); + cur = NestedNameSpecifier::getGlobal(); continue; - - case NestedNameSpecifier::Global: - cur = NestedNameSpecifier::GlobalSpecifier(ctx); - continue; - - case NestedNameSpecifier::Super: - cur = NestedNameSpecifier::SuperSpecifier(ctx, - asImpl().readCXXRecordDeclRef()); + case NestedNameSpecifier::Kind::MicrosoftSuper: + assert(!cur); + cur = NestedNameSpecifier(asImpl().readCXXRecordDeclRef()); continue; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("bad nested name specifier kind"); } diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index c105bbb..8ea0c29 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -176,12 +176,12 @@ public: asImpl().writeUInt32(path.size()); auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext(); for (auto elem : path) { - if (elemTy->getAs<RecordType>()) { + if (elemTy->isRecordType()) { asImpl().writeUInt32(elem.getAsBaseOrMember().getInt()); const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer(); if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) { asImpl().writeDeclRef(recordDecl); - elemTy = ctx.getRecordType(recordDecl); + elemTy = ctx.getCanonicalTagType(recordDecl); } else { const auto *valueDecl = cast<ValueDecl>(baseOrMember); asImpl().writeDeclRef(valueDecl); @@ -229,42 +229,43 @@ public: asImpl().writeExprRef(CE.getCondition()); } - void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { + void writeNestedNameSpecifier(NestedNameSpecifier NNS) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. - SmallVector<NestedNameSpecifier *, 8> nestedNames; + SmallVector<NestedNameSpecifier, 8> nestedNames; // Push each of the NNS's onto a stack for serialization in reverse order. while (NNS) { nestedNames.push_back(NNS); - NNS = NNS->getPrefix(); + NNS = NNS.getKind() == NestedNameSpecifier::Kind::Namespace + ? NNS.getAsNamespaceAndPrefix().Prefix + : std::nullopt; } asImpl().writeUInt32(nestedNames.size()); while (!nestedNames.empty()) { NNS = nestedNames.pop_back_val(); - NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); + NestedNameSpecifier::Kind kind = NNS.getKind(); asImpl().writeNestedNameSpecifierKind(kind); switch (kind) { - case NestedNameSpecifier::Identifier: - asImpl().writeIdentifier(NNS->getAsIdentifier()); + case NestedNameSpecifier::Kind::Namespace: + asImpl().writeNamespaceBaseDeclRef( + NNS.getAsNamespaceAndPrefix().Namespace); continue; - - case NestedNameSpecifier::Namespace: - asImpl().writeNamespaceBaseDeclRef(NNS->getAsNamespace()); - continue; - - case NestedNameSpecifier::TypeSpec: - asImpl().writeQualType(QualType(NNS->getAsType(), 0)); + case NestedNameSpecifier::Kind::Type: + asImpl().writeQualType(QualType(NNS.getAsType(), 0)); continue; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // Don't need to write an associated value. continue; - case NestedNameSpecifier::Super: - asImpl().writeDeclRef(NNS->getAsRecordDecl()); + case NestedNameSpecifier::Kind::MicrosoftSuper: + asImpl().writeDeclRef(NNS.getAsMicrosoftSuper()); continue; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("bad nested name specifier kind"); } diff --git a/clang/include/clang/AST/CXXInheritance.h b/clang/include/clang/AST/CXXInheritance.h index bbef018..e893260 100644 --- a/clang/include/clang/AST/CXXInheritance.h +++ b/clang/include/clang/AST/CXXInheritance.h @@ -359,7 +359,7 @@ class CXXFinalOverriderMap /// A set of all the primary bases for a class. class CXXIndirectPrimaryBaseSet - : public llvm::SmallSet<const CXXRecordDecl*, 32> {}; + : public llvm::SmallPtrSet<const CXXRecordDecl *, 32> {}; inline bool inheritanceModelHasVBPtrOffsetField(MSInheritanceModel Inheritance) { diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 35db689..b5a4e94e13 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -453,7 +453,7 @@ template<> struct CanProxyAdaptor<MemberPointerType> : public CanProxyBase<MemberPointerType> { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier *, getQualifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier, getQualifier) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const CXXRecordDecl *, getMostRecentCXXRecordDecl) }; @@ -551,21 +551,18 @@ struct CanProxyAdaptor<UnaryTransformType> template<> struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getOriginalDecl) }; template<> struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getOriginalDecl) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields) }; template<> struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getOriginalDecl) }; template<> diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h index dd99067..5ba95c8 100644 --- a/clang/include/clang/AST/Comment.h +++ b/clang/include/clang/AST/Comment.h @@ -19,6 +19,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" namespace clang { class Decl; @@ -119,6 +120,11 @@ protected: LLVM_PREFERRED_TYPE(CommandTraits::KnownCommandIDs) unsigned CommandID : CommandInfo::NumCommandIDBits; + + /// Describes the syntax that was used in a documentation command. + /// Contains values from CommandMarkerKind enum. + LLVM_PREFERRED_TYPE(CommandMarkerKind) + unsigned CommandMarker : 1; }; enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 3 + CommandInfo::NumCommandIDBits }; @@ -347,6 +353,16 @@ public: InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK); InlineCommandCommentBits.CommandID = CommandID; } + InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd, + unsigned CommandID, InlineCommandRenderKind RK, + CommandMarkerKind CommandMarker, ArrayRef<Argument> Args) + : InlineContentComment(CommentKind::InlineCommandComment, LocBegin, + LocEnd), + Args(Args) { + InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK); + InlineCommandCommentBits.CommandID = CommandID; + InlineCommandCommentBits.CommandMarker = llvm::to_underlying(CommandMarker); + } static bool classof(const Comment *C) { return C->getCommentKind() == CommentKind::InlineCommandComment; @@ -384,6 +400,11 @@ public: SourceRange getArgRange(unsigned Idx) const { return Args[Idx].Range; } + + CommandMarkerKind getCommandMarker() const { + return static_cast<CommandMarkerKind>( + InlineCommandCommentBits.CommandMarker); + } }; /// Abstract class for opening and closing HTML tags. HTML tags are always diff --git a/clang/include/clang/AST/CommentHTMLTags.td b/clang/include/clang/AST/CommentHTMLTags.td index a1ce8c6..9b89bc0 100644 --- a/clang/include/clang/AST/CommentHTMLTags.td +++ b/clang/include/clang/AST/CommentHTMLTags.td @@ -51,6 +51,11 @@ def Col : Tag<"col"> { let EndTagForbidden = 1; } def Tr : Tag<"tr"> { let EndTagOptional = 1; } def Th : Tag<"th"> { let EndTagOptional = 1; } def Td : Tag<"td"> { let EndTagOptional = 1; } +def Summary : Tag<"summary">; +def Details : Tag<"details">; +def Mark : Tag<"mark">; +def Figure : Tag<"figure">; +def FigCaption : Tag<"figcaption">; // Define a list of attributes that are not safe to pass through to HTML // output if the input is untrusted. diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h index 916d794..3169e2b 100644 --- a/clang/include/clang/AST/CommentSema.h +++ b/clang/include/clang/AST/CommentSema.h @@ -131,6 +131,7 @@ public: InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, unsigned CommandID, + CommandMarkerKind CommandMarker, ArrayRef<Comment::Argument> Args); InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 08fe1f8..7c9245d 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -20,9 +20,9 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" -#include "clang/AST/NestedNameSpecifier.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" @@ -833,9 +833,9 @@ public: /// Retrieve the nested-name-specifier that qualifies the name of this /// declaration, if it was present in the source. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() - : nullptr; + : std::nullopt; } /// Retrieve the nested-name-specifier (with source-location @@ -3526,10 +3526,16 @@ protected: public: // Low-level accessor. If you just want the type defined by this node, // check out ASTContext::getTypeDeclType or one of - // ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you + // ASTContext::getTypedefType, ASTContext::getTagType, etc. if you // already know the specific kind of node this is. - const Type *getTypeForDecl() const { return TypeForDecl; } - void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } + const Type *getTypeForDecl() const { + assert(!isa<TagDecl>(this)); + return TypeForDecl; + } + void setTypeForDecl(const Type *TD) { + assert(!isa<TagDecl>(this)); + TypeForDecl = TD; + } SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; } void setLocStart(SourceLocation L) { LocStart = L; } @@ -3635,6 +3641,10 @@ public: return isTransparentTagSlow(); } + // These types are created lazily, use the ASTContext methods to obtain them. + const Type *getTypeForDecl() const = delete; + void setTypeForDecl(const Type *TD) = delete; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { @@ -3754,14 +3764,6 @@ protected: /// True if this decl is currently being defined. void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; } - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - void setMayHaveOutOfDateDef(bool V = true) { - TagDeclBits.MayHaveOutOfDateDef = V; - } - public: friend class ASTDeclReader; friend class ASTDeclWriter; @@ -3842,12 +3844,6 @@ public: TagDeclBits.IsFreeStanding = isFreeStanding; } - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - bool mayHaveOutOfDateDef() const { return TagDeclBits.MayHaveOutOfDateDef; } - /// Whether this declaration declares a type that is /// dependent, i.e., a type that somehow depends on template /// parameters. @@ -3888,6 +3884,19 @@ public: /// the struct/union/class/enum. TagDecl *getDefinition() const; + TagDecl *getDefinitionOrSelf() const { + if (TagDecl *Def = getDefinition()) + return Def; + return const_cast<TagDecl *>(this); + } + + /// Determines whether this entity is in the process of being defined. + bool isEntityBeingDefined() const { + if (const TagDecl *Def = getDefinition()) + return Def->isBeingDefined(); + return false; + } + StringRef getKindName() const { return TypeWithKeyword::getTagTypeKindName(getTagKind()); } @@ -3906,6 +3915,10 @@ public: 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? /// @@ -3934,9 +3947,9 @@ public: /// Retrieve the nested-name-specifier that qualifies the name of this /// declaration, if it was present in the source. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() - : nullptr; + : std::nullopt; } /// Retrieve the nested-name-specifier (with source-location @@ -3958,6 +3971,10 @@ public: return getExtInfo()->TemplParamLists[i]; } + // These types are created lazily, use the ASTContext methods to obtain them. + const Type *getTypeForDecl() const = delete; + void setTypeForDecl(const Type *TD) = delete; + using TypeDecl::printName; void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override; @@ -4087,6 +4104,10 @@ public: return cast_or_null<EnumDecl>(TagDecl::getDefinition()); } + EnumDecl *getDefinitionOrSelf() const { + return cast_or_null<EnumDecl>(TagDecl::getDefinitionOrSelf()); + } + static EnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, @@ -4469,6 +4490,10 @@ public: return cast_or_null<RecordDecl>(TagDecl::getDefinition()); } + RecordDecl *getDefinitionOrSelf() const { + return cast_or_null<RecordDecl>(TagDecl::getDefinitionOrSelf()); + } + /// Returns whether this record is a union, or contains (at any nesting level) /// a union member. This is used by CMSE to warn about possible information /// leaks. @@ -5299,6 +5324,8 @@ void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) { /// We use this function to break a cycle between the inline definitions in /// Type.h and Decl.h. inline bool IsEnumDeclComplete(EnumDecl *ED) { + if (const auto *Def = ED->getDefinition()) + return Def->isComplete(); return ED->isComplete(); } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index dd67ebc..c6326a8 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -410,9 +410,6 @@ protected: virtual ~Decl(); - /// Update a potentially out-of-date declaration. - void updateOutOfDate(IdentifierInfo &II) const; - Linkage getCachedLinkage() const { return static_cast<Linkage>(CacheValidAndLinkage); } @@ -625,6 +622,12 @@ public: void setReferenced(bool R = true) { Referenced = R; } + /// When doing manipulations which might change the computed linkage, + /// such as changing the DeclContext after the declaration has already been + /// used, invalidating the cache will make sure its linkage will be + /// recomputed. + void invalidateCachedLinkage() { setCachedLinkage(Linkage::Invalid); } + /// Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. @@ -1564,13 +1567,6 @@ protected: LLVM_PREFERRED_TYPE(bool) uint64_t IsFreeStanding : 1; - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - LLVM_PREFERRED_TYPE(bool) - uint64_t MayHaveOutOfDateDef : 1; - /// Has the full definition of this type been required by a use somewhere in /// the TU. LLVM_PREFERRED_TYPE(bool) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 33ae3d6..8802664 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" @@ -545,20 +545,6 @@ public: return const_cast<CXXRecordDecl*>(this)->getMostRecentDecl(); } - CXXRecordDecl *getMostRecentNonInjectedDecl() { - CXXRecordDecl *Recent = getMostRecentDecl(); - while (Recent->isInjectedClassName()) { - // FIXME: Does injected class name need to be in the redeclarations chain? - assert(Recent->getPreviousDecl()); - Recent = Recent->getPreviousDecl(); - } - return Recent; - } - - const CXXRecordDecl *getMostRecentNonInjectedDecl() const { - return const_cast<CXXRecordDecl*>(this)->getMostRecentNonInjectedDecl(); - } - CXXRecordDecl *getDefinition() const { // We only need an update if we don't already know which // declaration is the definition. @@ -566,13 +552,18 @@ public: return DD ? DD->Definition : nullptr; } + CXXRecordDecl *getDefinitionOrSelf() const { + if (auto *Def = getDefinition()) + return Def; + return const_cast<CXXRecordDecl *>(this); + } + bool hasDefinition() const { return DefinitionData || dataPtr(); } static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl = nullptr, - bool DelayTypeCreation = false); + CXXRecordDecl *PrevDecl = nullptr); static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC, TypeSourceInfo *Info, SourceLocation Loc, unsigned DependencyKind, bool IsGeneric, @@ -1903,6 +1894,20 @@ public: /// \endcode bool isInjectedClassName() const; + /// Determines whether this declaration has is canonically of an injected + /// class type. These are non-instantiated class template patterns, which can + /// be used from within the class template itself. For example: + /// + /// \code + /// template<class T> struct C { + /// C *t; // Here `C *` is a pointer to an injected class type. + /// }; + /// \endcode + bool hasInjectedClassType() const; + + CanQualType + getCanonicalTemplateSpecializationType(const ASTContext &Ctx) const; + // Determine whether this type is an Interface Like type for // __interface inheritance purposes. bool isInterfaceLike() const; @@ -3131,7 +3136,7 @@ public: /// Retrieve the nested-name-specifier that qualifies the /// name of the namespace. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3252,7 +3257,7 @@ public: /// Retrieve the nested-name-specifier that qualifies the /// name of the namespace. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3614,7 +3619,7 @@ public: NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3804,13 +3809,11 @@ public: /// The source location of the 'enum' keyword. SourceLocation getEnumLoc() const { return EnumLocation; } void setEnumLoc(SourceLocation L) { EnumLocation = L; } - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } NestedNameSpecifierLoc getQualifierLoc() const { - if (auto ETL = EnumType->getTypeLoc().getAs<ElaboratedTypeLoc>()) - return ETL.getQualifierLoc(); - return NestedNameSpecifierLoc(); + return getEnumTypeLoc().getPrefix(); } // Returns the "qualifier::Name" part as a TypeLoc. TypeLoc getEnumTypeLoc() const { @@ -3822,7 +3825,9 @@ public: void setEnumType(TypeSourceInfo *TSI) { EnumType = TSI; } public: - EnumDecl *getEnumDecl() const { return cast<EnumDecl>(EnumType->getType()->getAsTagDecl()); } + EnumDecl *getEnumDecl() const { + return EnumType->getType()->castAs<clang::EnumType>()->getOriginalDecl(); + } static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation UsingL, SourceLocation EnumL, @@ -3970,7 +3975,7 @@ public: NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -4060,7 +4065,7 @@ public: NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 9014d76..2541edb 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -643,6 +643,9 @@ public: /// from the explicitly-specified bound. SourceLocation getColonLoc() const { return ColonLoc; } + using TypeDecl::getTypeForDecl; + using TypeDecl::setTypeForDecl; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCTypeParam; } diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 32de203..bba7236 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1796,7 +1796,10 @@ public: } BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; } + + bool isPackProducingBuiltinTemplate() const; }; +bool isPackProducingBuiltinTemplateName(TemplateName N); /// Provides information about an explicit instantiation of a variable or class /// template. @@ -1898,14 +1901,14 @@ public: void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const override; - // FIXME: This is broken. CXXRecordDecl::getMostRecentDecl() returns a - // different "most recent" declaration from this function for the same - // declaration, because we don't override getMostRecentDeclImpl(). But - // it's not clear that we should override that, because the most recent - // declaration as a CXXRecordDecl sometimes is the injected-class-name. ClassTemplateSpecializationDecl *getMostRecentDecl() { return cast<ClassTemplateSpecializationDecl>( - getMostRecentNonInjectedDecl()); + CXXRecordDecl::getMostRecentDecl()); + } + + ClassTemplateSpecializationDecl *getDefinitionOrSelf() const { + return cast<ClassTemplateSpecializationDecl>( + CXXRecordDecl::getDefinitionOrSelf()); } /// Retrieve the template that this specialization specializes. @@ -2123,10 +2126,13 @@ class ClassTemplatePartialSpecializationDecl llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool> InstantiatedFromMember; + mutable CanQualType CanonInjectedTST; + ClassTemplatePartialSpecializationDecl( ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args, + CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl); ClassTemplatePartialSpecializationDecl(ASTContext &C) @@ -2143,7 +2149,7 @@ public: Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - ArrayRef<TemplateArgument> Args, QualType CanonInjectedType, + ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl); static ClassTemplatePartialSpecializationDecl * @@ -2160,12 +2166,6 @@ public: return TemplateParams; } - /// Get the template argument list of the template parameter list. - ArrayRef<TemplateArgument> - getInjectedTemplateArgs(const ASTContext &Context) const { - return getTemplateParameters()->getInjectedTemplateArgs(Context); - } - /// \brief All associated constraints of this partial specialization, /// including the requires clause and any constraints derived from /// constrained-parameters. @@ -2247,14 +2247,10 @@ public: return First->InstantiatedFromMember.setInt(true); } - /// Retrieves the injected specialization type for this partial - /// specialization. This is not the same as the type-decl-type for - /// this partial specialization, which is an InjectedClassNameType. - QualType getInjectedSpecializationType() const { - assert(getTypeForDecl() && "partial specialization has no type set!"); - return cast<InjectedClassNameType>(getTypeForDecl()) - ->getInjectedSpecializationType(); - } + /// Retrieves the canonical injected specialization type for this partial + /// specialization. + CanQualType + getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const; SourceRange getSourceRange() const override LLVM_READONLY; @@ -2289,8 +2285,8 @@ protected: llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> PartialSpecializations; - /// The injected-class-name type for this class template. - QualType InjectedClassNameType; + /// The Injected Template Specialization Type for this declaration. + CanQualType CanonInjectedTST; Common() = default; }; @@ -2427,7 +2423,7 @@ public: findPartialSpecInstantiatedFromMember( ClassTemplatePartialSpecializationDecl *D); - /// Retrieve the template specialization type of the + /// Retrieve the canonical template specialization type of the /// injected-class-name for this class template. /// /// The injected-class-name for a class template \c X is \c @@ -2441,7 +2437,8 @@ public: /// typedef array this_type; // "array" is equivalent to "array<T, N>" /// }; /// \endcode - QualType getInjectedClassNameSpecialization(); + CanQualType + getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const; using spec_iterator = SpecIterator<ClassTemplateSpecializationDecl>; using spec_range = llvm::iterator_range<spec_iterator>; diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 284228d..a7185f5 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/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index bdcaabc..c439525 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -293,7 +293,7 @@ inline TypeDependence toSemanticDependence(TypeDependence D) { } inline NestedNameSpecifierDependence -toNestedNameSpecifierDependendence(TypeDependence D) { +toNestedNameSpecifierDependence(TypeDependence D) { return Dependence(D).nestedNameSpecifier(); } diff --git a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h index 703cca2..7b5bdca 100644 --- a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h @@ -134,8 +134,7 @@ public: /// Recursively visit a C++ nested-name-specifier. /// /// \returns false if the visitation was terminated early, true otherwise. - virtual bool - TraverseNestedNameSpecifier(MaybeConst<NestedNameSpecifier> *NNS); + virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); /// Recursively visit a C++ nested-name-specifier with location /// information. @@ -181,14 +180,14 @@ public: /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type). - virtual bool TraverseType(QualType T); + virtual bool TraverseType(QualType T, bool TraverseQualifier = true); /// Recursively visit a type with location, by dispatching to /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type location). - virtual bool TraverseTypeLoc(TypeLoc TL); + virtual bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true); /// Recursively visit an Objective-C protocol reference with location /// information. @@ -273,7 +272,8 @@ public: #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ bool WalkUpFrom##CLASS##Type(MaybeConst<CLASS##Type> *T); \ - virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T); + virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T, \ + bool TraverseQualifier = true); #include "clang/AST/TypeNodes.inc" #define TYPE(CLASS, BASE) \ @@ -283,7 +283,8 @@ public: // TypeLocs. #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ - virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); + virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, \ + bool TraverseQualifier); #include "clang/AST/TypeLocNodes.def" #define TYPELOC(CLASS, BASE) \ diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 237b3b2..23a0996 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" @@ -40,6 +40,7 @@ #include <optional> namespace clang { + class AllocSizeAttr; class APValue; class ASTContext; class BlockDecl; @@ -1369,7 +1370,7 @@ public: /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name. Otherwise, returns NULL. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } @@ -3261,6 +3262,15 @@ public: setDependence(getDependence() | ExprDependence::TypeValueInstantiation); } + /// Try to get the alloc_size attribute of the callee. May return null. + const AllocSizeAttr *getCalleeAllocSizeAttr() const; + + /// Evaluates the total size in bytes allocated by calling a function + /// decorated with alloc_size. Returns std::nullopt if the the result cannot + /// be evaluated. + std::optional<llvm::APInt> + evaluateBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const; + bool isCallToStdMove() const; static bool classof(const Stmt *T) { @@ -3398,7 +3408,7 @@ public: /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// NULL. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } @@ -3548,6 +3558,7 @@ public: QualType T, ExprValueKind VK, Expr *init, bool fileScope) : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary), LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) { + assert(Init && "Init is a nullptr"); setDependence(computeDependence(this)); } @@ -3577,19 +3588,11 @@ public: APValue &getStaticValue() const; SourceLocation getBeginLoc() const LLVM_READONLY { - // FIXME: Init should never be null. - if (!Init) - return SourceLocation(); if (LParenLoc.isInvalid()) return Init->getBeginLoc(); return LParenLoc; } - SourceLocation getEndLoc() const LLVM_READONLY { - // FIXME: Init should never be null. - if (!Init) - return SourceLocation(); - return Init->getEndLoc(); - } + SourceLocation getEndLoc() const LLVM_READONLY { return Init->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CompoundLiteralExprClass; @@ -5110,9 +5113,9 @@ public: "trying to dereference an invalid iterator"); IntegerLiteral *N = EExpr->FakeChildNode; N->setValue(*EExpr->Ctx, - llvm::APInt(N->getValue().getBitWidth(), + llvm::APInt(N->getBitWidth(), EExpr->Data->BinaryData->getCodeUnit(CurOffset), - N->getType()->isSignedIntegerType())); + /*Signed=*/true)); // We want to return a reference to the fake child node in the // EmbedExpr, not the local variable N. return const_cast<typename BaseTy::reference>(EExpr->FakeChildNode); diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 7a26934..9fedb23 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1712,6 +1712,19 @@ public: CXXConstructExprBits.IsImmediateEscalating = Set; } + /// Returns the WarnUnusedResultAttr that is declared on the callee + /// or its return type declaration, together with a NamedDecl that + /// refers to the declaration the attribute is attached to. + std::pair<const NamedDecl *, const WarnUnusedResultAttr *> + getUnusedResultAttr(const ASTContext &Ctx) const { + return getUnusedResultAttrImpl(getConstructor(), getType()); + } + + /// Returns true if this call expression should warn on unused results. + bool hasUnusedResultAttr(const ASTContext &Ctx) const { + return getUnusedResultAttr(Ctx).second != nullptr; + } + SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; SourceRange getParenOrBraceRange() const { return ParenOrBraceRange; } @@ -2781,7 +2794,7 @@ public: /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// null. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3222,7 +3235,7 @@ public: SourceLocation getNameLoc() const { return NameInfo.getLoc(); } /// Fetches the nested-name qualifier, if one was given. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3540,7 +3553,7 @@ public: /// Retrieve the nested-name-specifier that qualifies this /// declaration. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3955,7 +3968,7 @@ public: } /// Retrieve the nested-name-specifier that qualifies the member name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index 570662b..8640780 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -240,7 +240,6 @@ public: void VisitInjectedClassNameType(const InjectedClassNameType *ICNT); void VisitObjCInterfaceType(const ObjCInterfaceType *OIT); void VisitPackExpansionType(const PackExpansionType *PET); - void VisitElaboratedType(const ElaboratedType *ET); void VisitMacroQualifiedType(const MacroQualifiedType *MQT); void VisitMemberPointerType(const MemberPointerType *MPT); diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 1614f9d..f198a8b 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -6,507 +6,266 @@ // //===----------------------------------------------------------------------===// // -// This file defines the NestedNameSpecifier class, which represents -// a C++ nested-name-specifier. +// This file completes the definition of the NestedNameSpecifier class. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H -#include "clang/AST/DependenceFlags.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceLocation.h" +#include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifierBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/Support/Compiler.h" -#include <cstdint> -#include <cstdlib> -#include <utility> namespace clang { -class ASTContext; -class CXXRecordDecl; -class IdentifierInfo; -class LangOptions; -class NamespaceBaseDecl; -struct PrintingPolicy; -class Type; -class TypeLoc; - -/// Represents a C++ nested name specifier, such as -/// "\::std::vector<int>::". -/// -/// C++ nested name specifiers are the prefixes to qualified -/// names. For example, "foo::" in "foo::x" is a nested name -/// specifier. Nested name specifiers are made up of a sequence of -/// specifiers, each of which can be a namespace, type, identifier -/// (for dependent names), decltype specifier, or the global specifier ('::'). -/// The last two specifiers can only appear at the start of a -/// nested-namespace-specifier. -class NestedNameSpecifier : public llvm::FoldingSetNode { - /// Enumeration describing - enum StoredSpecifierKind { - StoredIdentifier = 0, - StoredDecl = 1, - StoredTypeSpec = 2 - }; - - /// The nested name specifier that precedes this nested name - /// specifier. - /// - /// The pointer is the nested-name-specifier that precedes this - /// one. The integer stores one of the first four values of type - /// SpecifierKind. - llvm::PointerIntPair<NestedNameSpecifier *, 2, StoredSpecifierKind> Prefix; - - /// The last component in the nested name specifier, which - /// can be an identifier, a declaration, or a type. - /// - /// When the pointer is NULL, this specifier represents the global - /// specifier '::'. Otherwise, the pointer is one of - /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of - /// specifier as encoded within the prefix. - void* Specifier = nullptr; - -public: - /// The kind of specifier that completes this nested name - /// specifier. - enum SpecifierKind { - /// An identifier, stored as an IdentifierInfo*. - Identifier, - - /// A namespace-like entity, stored as a NamespaceBaseDecl*. - Namespace, - - /// A type, stored as a Type*. - TypeSpec, - - /// The global specifier '::'. There is no stored value. - Global, - - /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of - /// the class it appeared in. - Super - }; - -private: - /// Builds the global specifier. - NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {} - - /// Copy constructor used internally to clone nested name - /// specifiers. - NestedNameSpecifier(const NestedNameSpecifier &Other) = default; - - /// Either find or insert the given nested name specifier - /// mockup in the given context. - static NestedNameSpecifier *FindOrInsert(const ASTContext &Context, - const NestedNameSpecifier &Mockup); - -public: - NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete; - - /// Builds a specifier combining a prefix and an identifier. - /// - /// The prefix must be dependent, since nested name specifiers - /// referencing an identifier are only permitted when the identifier - /// cannot be resolved. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const IdentifierInfo *II); - - /// Builds a nested name specifier that names a namespace or namespace alias. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceBaseDecl *NS); - - /// Builds a nested name specifier that names a type. - static NestedNameSpecifier * - Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const Type *T); - - /// Builds a specifier that consists of just an identifier. - /// - /// The nested-name-specifier is assumed to be dependent, but has no - /// prefix because the prefix is implied by something outside of the - /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent - /// type. - static NestedNameSpecifier *Create(const ASTContext &Context, - const IdentifierInfo *II); - - /// Returns the nested name specifier representing the global - /// scope. - static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); - - /// Returns the nested name specifier representing the __super scope - /// for the given CXXRecordDecl. - static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, - CXXRecordDecl *RD); - - /// Return the prefix of this nested name specifier. - /// - /// The prefix contains all of the parts of the nested name - /// specifier that precede this current specifier. For example, for a - /// nested name specifier that represents "foo::bar::", the current - /// specifier will contain "bar::" and the prefix will contain - /// "foo::". - NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } - - /// Determine what kind of nested name specifier is stored. - SpecifierKind getKind() const; - - /// Retrieve the identifier stored in this nested name - /// specifier. - IdentifierInfo *getAsIdentifier() const { - if (Prefix.getInt() == StoredIdentifier) - return (IdentifierInfo *)Specifier; - - return nullptr; +auto NestedNameSpecifier::getKind() const -> Kind { + if (!isStoredKind()) { + switch (getFlagKind()) { + case FlagKind::Null: + return Kind::Null; + case FlagKind::Global: + return Kind::Global; + case FlagKind::Invalid: + llvm_unreachable("use of invalid NestedNameSpecifier"); + } + llvm_unreachable("unhandled FlagKind"); } + switch (auto [K, Ptr] = getStored(); K) { + case StoredKind::Type: + return Kind::Type; + case StoredKind::NamespaceWithGlobal: + case StoredKind::NamespaceWithNamespace: + return Kind::Namespace; + case StoredKind::NamespaceOrSuper: + switch (static_cast<const Decl *>(Ptr)->getKind()) { + case Decl::Namespace: + case Decl::NamespaceAlias: + return Kind::Namespace; + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + return Kind::MicrosoftSuper; + default: + llvm_unreachable("unexpected decl kind"); + } + } + llvm_unreachable("unknown StoredKind"); +} - /// Retrieve the namespace or namespace alias stored in this nested name - /// specifier. - NamespaceBaseDecl *getAsNamespace() const; - - /// Retrieve the record declaration stored in this nested name - /// specifier. - CXXRecordDecl *getAsRecordDecl() const; - - /// Retrieve the type stored in this nested name specifier. - const Type *getAsType() const { - if (Prefix.getInt() == StoredTypeSpec) - return (const Type *)Specifier; +NestedNameSpecifier::NestedNameSpecifier(const Type *T) + : NestedNameSpecifier({StoredKind::Type, T}) { + assert(getKind() == Kind::Type); +} - return nullptr; +auto NestedNameSpecifier::MakeNamespacePtrKind( + const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) -> PtrKind { + switch (Prefix.getKind()) { + case Kind::Null: + return {StoredKind::NamespaceOrSuper, Namespace}; + case Kind::Global: + return {StoredKind::NamespaceWithGlobal, Namespace}; + case Kind::Namespace: + return {StoredKind::NamespaceWithNamespace, + MakeNamespaceAndPrefixStorage(Ctx, Namespace, Prefix)}; + case Kind::MicrosoftSuper: + case Kind::Type: + llvm_unreachable("invalid prefix for namespace"); } + llvm_unreachable("unhandled kind"); +} - /// Fully translate this nested name specifier to a type. - /// Unlike getAsType, this will convert this entire nested - /// name specifier chain into its equivalent type. - const Type *translateToType(const ASTContext &Context) const; +/// Builds a nested name specifier that names a namespace. +NestedNameSpecifier::NestedNameSpecifier(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) + : NestedNameSpecifier(MakeNamespacePtrKind(Ctx, Namespace, Prefix)) { + assert(getKind() == Kind::Namespace); +} - NestedNameSpecifierDependence getDependence() const; +/// Builds a nested name specifier that names a class through microsoft's +/// __super specifier. +NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD) + : NestedNameSpecifier({StoredKind::NamespaceOrSuper, RD}) { + assert(getKind() == Kind::MicrosoftSuper); +} - /// Whether this nested name specifier refers to a dependent - /// type or not. - bool isDependent() const; +CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { + switch (getKind()) { + case Kind::MicrosoftSuper: + return getAsMicrosoftSuper(); + case Kind::Type: + return getAsType()->getAsCXXRecordDecl(); + case Kind::Global: + case Kind::Namespace: + case Kind::Null: + return nullptr; + } + llvm_unreachable("Invalid NNS Kind!"); +} - /// Whether this nested name specifier involves a template - /// parameter. - bool isInstantiationDependent() const; +NestedNameSpecifier NestedNameSpecifier::getCanonical() const { + switch (getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + // These are canonical and unique. + return *this; + case NestedNameSpecifier::Kind::Namespace: { + // A namespace is canonical; build a nested-name-specifier with + // this namespace and no prefix. + const NamespaceBaseDecl *ND = getAsNamespaceAndPrefix().Namespace; + return NestedNameSpecifier( + {StoredKind::NamespaceOrSuper, ND->getNamespace()->getCanonicalDecl()}); + } + case NestedNameSpecifier::Kind::Type: + return NestedNameSpecifier( + getAsType()->getCanonicalTypeInternal().getTypePtr()); + } + llvm_unreachable("unhandled kind"); +} - /// Whether this nested-name-specifier contains an unexpanded - /// parameter pack (for C++11 variadic templates). - bool containsUnexpandedParameterPack() const; +bool NestedNameSpecifier::isCanonical() const { + return *this == getCanonical(); +} - /// Whether this nested name specifier contains an error. - bool containsErrors() const; +TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const { + return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/0)); +} - /// Print this nested name specifier to the given output stream. If - /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. - /// `ns::SomeTemplate<int, MyClass>` instead of - /// `ns::SomeTemplate<Container::value_type, T>`. - void print(raw_ostream &OS, const PrintingPolicy &Policy, - bool ResolveTemplateArguments = false, - bool PrintFinalScopeResOp = true) const; +TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const { + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type) + return TypeLoc(); + return castAsTypeLoc(); +} - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Prefix.getOpaqueValue()); - ID.AddPointer(Specifier); +unsigned +NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier Qualifier) { + // Location of the trailing '::'. + unsigned Length = sizeof(SourceLocation::UIntTy); + + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Global: + // Nothing more to add. + break; + + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::MicrosoftSuper: + // The location of the identifier or namespace name. + Length += sizeof(SourceLocation::UIntTy); + break; + + case NestedNameSpecifier::Kind::Type: + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + Length += sizeof(void *); + break; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("Expected a non-NULL qualifier"); } - /// Dump the nested name specifier to standard output to aid - /// in debugging. - void dump(const LangOptions &LO) const; - void dump() const; - void dump(llvm::raw_ostream &OS) const; - void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; -}; + return Length; +} -/// A C++ nested-name-specifier augmented with source location -/// information. -class NestedNameSpecifierLoc { - NestedNameSpecifier *Qualifier = nullptr; - void *Data = nullptr; - - /// Determines the data length for the last component in the - /// given nested-name-specifier. - static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); - - /// Determines the data length for the entire - /// nested-name-specifier. - static unsigned getDataLength(NestedNameSpecifier *Qualifier); - -public: - /// Construct an empty nested-name-specifier. - NestedNameSpecifierLoc() = default; - - /// Construct a nested-name-specifier with source location information - /// from - NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) - : Qualifier(Qualifier), Data(Data) {} - - /// Evaluates true when this nested-name-specifier location is - /// non-empty. - explicit operator bool() const { return Qualifier; } - - /// Evaluates true when this nested-name-specifier location is - /// non-empty. - bool hasQualifier() const { return Qualifier; } - - /// Retrieve the nested-name-specifier to which this instance - /// refers. - NestedNameSpecifier *getNestedNameSpecifier() const { - return Qualifier; - } +NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const { + auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + return {Namespace, NestedNameSpecifierLoc(Prefix, Data)}; +} - /// Retrieve the opaque pointer that refers to source-location data. - void *getOpaqueData() const { return Data; } - - /// Retrieve the source range covering the entirety of this - /// nested-name-specifier. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector<int>::, the returned source range would cover - /// from the initial '::' to the last '::'. - SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(getBeginLoc(), getEndLoc()); - } +NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const { + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) + return {}; + return castAsNamespaceAndPrefix(); +} - /// Retrieve the source range covering just the last part of - /// this nested-name-specifier, not including the prefix. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector<int>::, the returned source range would cover - /// from "vector" to the last '::'. - SourceRange getLocalSourceRange() const; - - /// Retrieve the location of the beginning of this - /// nested-name-specifier. - SourceLocation getBeginLoc() const { - if (!Qualifier) - return SourceLocation(); - - NestedNameSpecifierLoc First = *this; - while (NestedNameSpecifierLoc Prefix = First.getPrefix()) - First = Prefix; - return First.getLocalSourceRange().getBegin(); +unsigned NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier Qualifier) { + unsigned Length = 0; + for (; Qualifier; Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) { + Length += getLocalDataLength(Qualifier); + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) + break; } + return Length; +} - /// Retrieve the location of the end of this - /// nested-name-specifier. - SourceLocation getEndLoc() const { return getLocalSourceRange().getEnd(); } +unsigned NestedNameSpecifierLoc::getDataLength() const { + return getDataLength(Qualifier); +} - /// Retrieve the location of the beginning of this - /// component of the nested-name-specifier. - SourceLocation getLocalBeginLoc() const { - return getLocalSourceRange().getBegin(); +SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { + switch (auto Kind = Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + return SourceRange(); + case NestedNameSpecifier::Kind::Global: + return LoadSourceLocation(/*Offset=*/0); + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::MicrosoftSuper: { + unsigned Offset = + Kind == NestedNameSpecifier::Kind::Namespace + ? getDataLength(Qualifier.getAsNamespaceAndPrefix().Prefix) + : 0; + return SourceRange( + LoadSourceLocation(Offset), + LoadSourceLocation(Offset + sizeof(SourceLocation::UIntTy))); } - - /// Retrieve the location of the end of this component of the - /// nested-name-specifier. - SourceLocation getLocalEndLoc() const { - return getLocalSourceRange().getEnd(); + case NestedNameSpecifier::Kind::Type: { + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + void *TypeData = LoadPointer(/*Offset=*/0); + TypeLoc TL(Qualifier.getAsType(), TypeData); + return SourceRange(TL.getBeginLoc(), LoadSourceLocation(sizeof(void *))); } - - /// Return the prefix of this nested-name-specifier. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector<int>::, the prefix is \c \::std::. Note that the - /// returned prefix may be empty, if this is the first component of - /// the nested-name-specifier. - NestedNameSpecifierLoc getPrefix() const { - if (!Qualifier) - return *this; - - return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data); } - /// For a nested-name-specifier that refers to a type, - /// retrieve the type with source-location information. - TypeLoc getTypeLoc() const; + llvm_unreachable("Invalid NNS Kind!"); +} - /// Determines the data length for the entire - /// nested-name-specifier. - unsigned getDataLength() const { return getDataLength(Qualifier); } +SourceRange NestedNameSpecifierLoc::getSourceRange() const { + return SourceRange(getBeginLoc(), getEndLoc()); +} - friend bool operator==(NestedNameSpecifierLoc X, - NestedNameSpecifierLoc Y) { - return X.Qualifier == Y.Qualifier && X.Data == Y.Data; - } +SourceLocation NestedNameSpecifierLoc::getEndLoc() const { + return getLocalSourceRange().getEnd(); +} - friend bool operator!=(NestedNameSpecifierLoc X, - NestedNameSpecifierLoc Y) { - return !(X == Y); - } -}; +/// Retrieve the location of the beginning of this +/// component of the nested-name-specifier. +SourceLocation NestedNameSpecifierLoc::getLocalBeginLoc() const { + return getLocalSourceRange().getBegin(); +} -/// Class that aids in the construction of nested-name-specifiers along -/// with source-location information for all of the components of the +/// Retrieve the location of the end of this component of the /// nested-name-specifier. -class NestedNameSpecifierLocBuilder { - /// The current representation of the nested-name-specifier we're - /// building. - NestedNameSpecifier *Representation = nullptr; - - /// Buffer used to store source-location information for the - /// nested-name-specifier. - /// - /// Note that we explicitly manage the buffer (rather than using a - /// SmallVector) because \c Declarator expects it to be possible to memcpy() - /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. - char *Buffer = nullptr; - - /// The size of the buffer used to store source-location information - /// for the nested-name-specifier. - unsigned BufferSize = 0; - - /// The capacity of the buffer used to store source-location - /// information for the nested-name-specifier. - unsigned BufferCapacity = 0; - -public: - NestedNameSpecifierLocBuilder() = default; - NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); - - NestedNameSpecifierLocBuilder & - operator=(const NestedNameSpecifierLocBuilder &Other); - - ~NestedNameSpecifierLocBuilder() { - if (BufferCapacity) - free(Buffer); - } +SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const { + return getLocalSourceRange().getEnd(); +} - /// Retrieve the representation of the nested-name-specifier. - NestedNameSpecifier *getRepresentation() const { return Representation; } - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'type::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param TL The TypeLoc that describes the type preceding the '::'. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'identifier::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Identifier The identifier. - /// - /// \param IdentifierLoc The location of the identifier. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'namespace::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Namespace The namespace or namespace alias. - /// - /// \param NamespaceLoc The location of the namespace name or the namespace - // alias. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, NamespaceBaseDecl *Namespace, - SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); - - /// Turn this (empty) nested-name-specifier into the global - /// nested-name-specifier '::'. - void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); - - /// Turns this (empty) nested-name-specifier into '__super' - /// nested-name-specifier. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param RD The declaration of the class in which nested-name-specifier - /// appeared. - /// - /// \param SuperLoc The location of the '__super' keyword. - /// name. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, - SourceLocation SuperLoc, SourceLocation ColonColonLoc); - - /// Make a new nested-name-specifier from incomplete source-location - /// information. - /// - /// This routine should be used very, very rarely, in cases where we - /// need to synthesize a nested-name-specifier. Most code should instead use - /// \c Adopt() with a proper \c NestedNameSpecifierLoc. - void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, - SourceRange R); - - /// Adopt an existing nested-name-specifier (with source-range - /// information). - void Adopt(NestedNameSpecifierLoc Other); - - /// Retrieve the source range covered by this nested-name-specifier. - SourceRange getSourceRange() const LLVM_READONLY { - return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); - } +SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const { + return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); +} - /// Retrieve a nested-name-specifier with location information, - /// copied into the given AST context. - /// - /// \param Context The context into which this nested-name-specifier will be - /// copied. - NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; - - /// Retrieve a nested-name-specifier with location - /// information based on the information in this builder. - /// - /// This loc will contain references to the builder's internal data and may - /// be invalidated by any change to the builder. - NestedNameSpecifierLoc getTemporary() const { - return NestedNameSpecifierLoc(Representation, Buffer); - } +} // namespace clang + +namespace llvm { + +template <> struct DenseMapInfo<clang::NestedNameSpecifier> { + static clang::NestedNameSpecifier getEmptyKey() { return std::nullopt; } - /// Clear out this builder, and prepare it to build another - /// nested-name-specifier with source-location information. - void Clear() { - Representation = nullptr; - BufferSize = 0; + static clang::NestedNameSpecifier getTombstoneKey() { + return clang::NestedNameSpecifier::getInvalid(); } - /// Retrieve the underlying buffer. - /// - /// \returns A pair containing a pointer to the buffer of source-location - /// data and the size of the source-location data that resides in that - /// buffer. - std::pair<char *, unsigned> getBuffer() const { - return std::make_pair(Buffer, BufferSize); + static unsigned getHashValue(const clang::NestedNameSpecifier &V) { + return hash_combine(V.getAsVoidPointer()); } }; -/// Insertion operator for diagnostics. This allows sending -/// NestedNameSpecifiers into a diagnostic with <<. -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, - NestedNameSpecifier *NNS) { - DB.AddTaggedVal(reinterpret_cast<uint64_t>(NNS), - DiagnosticsEngine::ak_nestednamespec); - return DB; -} - -} // namespace clang - -namespace llvm { - template <> struct DenseMapInfo<clang::NestedNameSpecifierLoc> { - using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier *>; + using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier>; using SecondInfo = DenseMapInfo<void *>; static clang::NestedNameSpecifierLoc getEmptyKey() { diff --git a/clang/include/clang/AST/NestedNameSpecifierBase.h b/clang/include/clang/AST/NestedNameSpecifierBase.h new file mode 100644 index 0000000..73c60ba --- /dev/null +++ b/clang/include/clang/AST/NestedNameSpecifierBase.h @@ -0,0 +1,586 @@ +//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H + +#include "clang/AST/DependenceFlags.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cstdint> +#include <cstdlib> +#include <utility> + +namespace clang { + +class ASTContext; +class CXXRecordDecl; +class NamedDecl; +class IdentifierInfo; +class LangOptions; +class NamespaceBaseDecl; +struct PrintingPolicy; +class Type; +class TypeLoc; + +struct NamespaceAndPrefix; +struct alignas(8) NamespaceAndPrefixStorage; + +/// Represents a C++ nested name specifier, such as +/// "\::std::vector<int>::". +/// +/// C++ nested name specifiers are the prefixes to qualified +/// names. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, decltype specifier, or +/// the global specifier ('::'). The last two specifiers can only appear at the +/// start of a nested-namespace-specifier. +class NestedNameSpecifier { + enum class FlagKind { Null, Global, Invalid }; + enum class StoredKind { + Type, + NamespaceOrSuper, + NamespaceWithGlobal, + NamespaceWithNamespace + }; + static constexpr uintptr_t FlagBits = 2, FlagMask = (1u << FlagBits) - 1u, + FlagOffset = 1, PtrOffset = FlagBits + FlagOffset, + PtrMask = (1u << PtrOffset) - 1u; + + uintptr_t StoredOrFlag; + + explicit NestedNameSpecifier(uintptr_t StoredOrFlag) + : StoredOrFlag(StoredOrFlag) {} + struct PtrKind { + StoredKind SK; + const void *Ptr; + }; + explicit NestedNameSpecifier(PtrKind PK) + : StoredOrFlag(uintptr_t(PK.Ptr) | (uintptr_t(PK.SK) << FlagOffset)) { + assert(PK.Ptr != nullptr); + assert((uintptr_t(PK.Ptr) & ((1u << PtrOffset) - 1u)) == 0); + assert((uintptr_t(PK.Ptr) >> PtrOffset) != 0); + } + + explicit constexpr NestedNameSpecifier(FlagKind K) + : StoredOrFlag(uintptr_t(K) << FlagOffset) {} + + bool isStoredKind() const { return (StoredOrFlag >> PtrOffset) != 0; } + + std::pair<StoredKind, const void *> getStored() const { + assert(isStoredKind()); + return {StoredKind(StoredOrFlag >> FlagOffset & FlagMask), + reinterpret_cast<const void *>(StoredOrFlag & ~PtrMask)}; + } + + FlagKind getFlagKind() const { + assert(!isStoredKind()); + return FlagKind(StoredOrFlag >> FlagOffset); + } + + static const NamespaceAndPrefixStorage * + MakeNamespaceAndPrefixStorage(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + static inline PtrKind MakeNamespacePtrKind(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + +public: + static constexpr NestedNameSpecifier getInvalid() { + return NestedNameSpecifier(FlagKind::Invalid); + } + + static constexpr NestedNameSpecifier getGlobal() { + return NestedNameSpecifier(FlagKind::Global); + } + + NestedNameSpecifier() : NestedNameSpecifier(FlagKind::Invalid) {} + + /// The kind of specifier that completes this nested name + /// specifier. + enum class Kind { + /// Empty. + Null, + + /// The global specifier '::'. There is no stored value. + Global, + + /// A type, stored as a Type*. + Type, + + /// A namespace-like entity, stored as a NamespaceBaseDecl*. + Namespace, + + /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of + /// the class it appeared in. + MicrosoftSuper, + }; + + inline Kind getKind() const; + + NestedNameSpecifier(std::nullopt_t) : StoredOrFlag(0) {} + + explicit inline NestedNameSpecifier(const Type *T); + + /// Builds a nested name specifier that names a namespace. + inline NestedNameSpecifier(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + + /// Builds a nested name specifier that names a class through microsoft's + /// __super specifier. + explicit inline NestedNameSpecifier(CXXRecordDecl *RD); + + explicit operator bool() const { return StoredOrFlag != 0; } + + void *getAsVoidPointer() const { + return reinterpret_cast<void *>(StoredOrFlag); + } + static NestedNameSpecifier getFromVoidPointer(const void *Ptr) { + return NestedNameSpecifier(reinterpret_cast<uintptr_t>(Ptr)); + } + + const Type *getAsType() const { + auto [Kind, Ptr] = getStored(); + assert(Kind == StoredKind::Type); + assert(Ptr != nullptr); + return static_cast<const Type *>(Ptr); + } + + inline NamespaceAndPrefix getAsNamespaceAndPrefix() const; + + CXXRecordDecl *getAsMicrosoftSuper() const { + auto [Kind, Ptr] = getStored(); + assert(Kind == StoredKind::NamespaceOrSuper); + assert(Ptr != nullptr); + return static_cast<CXXRecordDecl *>(const_cast<void *>(Ptr)); + } + + /// Retrieve the record declaration stored in this nested name + /// specifier, or null. + inline CXXRecordDecl *getAsRecordDecl() const; + + friend bool operator==(NestedNameSpecifier LHS, NestedNameSpecifier RHS) { + return LHS.StoredOrFlag == RHS.StoredOrFlag; + } + friend bool operator!=(NestedNameSpecifier LHS, NestedNameSpecifier RHS) { + return LHS.StoredOrFlag != RHS.StoredOrFlag; + } + + /// Retrieves the "canonical" nested name specifier for a + /// given nested name specifier. + /// + /// The canonical nested name specifier is a nested name specifier + /// that uniquely identifies a type or namespace within the type + /// system. For example, given: + /// + /// \code + /// namespace N { + /// struct S { + /// template<typename T> struct X { typename T* type; }; + /// }; + /// } + /// + /// template<typename T> struct Y { + /// typename N::S::X<T>::type member; + /// }; + /// \endcode + /// + /// Here, the nested-name-specifier for N::S::X<T>:: will be + /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined + /// by declarations in the type system and the canonical type for + /// the template type parameter 'T' is template-param-0-0. + inline NestedNameSpecifier getCanonical() const; + + /// Whether this nested name specifier is canonical. + inline bool isCanonical() const; + + /// Whether this nested name specifier starts with a '::'. + bool isFullyQualified() const; + + NestedNameSpecifierDependence getDependence() const; + + /// Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const { + return getDependence() & NestedNameSpecifierDependence::Dependent; + } + + /// Whether this nested name specifier involves a template + /// parameter. + bool isInstantiationDependent() const { + return getDependence() & NestedNameSpecifierDependence::Instantiation; + } + + /// Whether this nested-name-specifier contains an unexpanded + /// parameter pack (for C++11 variadic templates). + bool containsUnexpandedParameterPack() const { + return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; + } + + /// Whether this nested name specifier contains an error. + bool containsErrors() const { + return getDependence() & NestedNameSpecifierDependence::Error; + } + + /// Print this nested name specifier to the given output stream. If + /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. + /// `ns::SomeTemplate<int, MyClass>` instead of + /// `ns::SomeTemplate<Container::value_type, T>`. + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool ResolveTemplateArguments = false, + bool PrintFinalScopeResOp = true) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(StoredOrFlag); + } + + /// Dump the nested name specifier to aid in debugging. + void dump(llvm::raw_ostream *OS = nullptr, + const LangOptions *LO = nullptr) const; + void dump(const LangOptions &LO) const; + void dump(llvm::raw_ostream &OS) const; + void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; + + static constexpr auto NumLowBitsAvailable = FlagOffset; +}; + +struct NamespaceAndPrefix { + const NamespaceBaseDecl *Namespace; + NestedNameSpecifier Prefix; +}; + +struct alignas(8) NamespaceAndPrefixStorage : NamespaceAndPrefix, + llvm::FoldingSetNode { + NamespaceAndPrefixStorage(const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) + : NamespaceAndPrefix{Namespace, Prefix} {} + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Namespace, Prefix); } + static void Profile(llvm::FoldingSetNodeID &ID, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) { + ID.AddPointer(Namespace); + Prefix.Profile(ID); + } +}; + +NamespaceAndPrefix NestedNameSpecifier::getAsNamespaceAndPrefix() const { + auto [Kind, Ptr] = getStored(); + switch (Kind) { + case StoredKind::NamespaceOrSuper: + case StoredKind::NamespaceWithGlobal: + return {static_cast<const NamespaceBaseDecl *>(Ptr), + Kind == StoredKind::NamespaceWithGlobal + ? NestedNameSpecifier::getGlobal() + : std::nullopt}; + case StoredKind::NamespaceWithNamespace: + return *static_cast<const NamespaceAndPrefixStorage *>(Ptr); + case StoredKind::Type:; + } + llvm_unreachable("unexpected stored kind"); +} + +struct NamespaceAndPrefixLoc; + +/// A C++ nested-name-specifier augmented with source location +/// information. +class NestedNameSpecifierLoc { + NestedNameSpecifier Qualifier = std::nullopt; + void *Data = nullptr; + + /// Load a (possibly unaligned) source location from a given address + /// and offset. + SourceLocation LoadSourceLocation(unsigned Offset) const { + SourceLocation::UIntTy Raw; + memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(Raw)); + return SourceLocation::getFromRawEncoding(Raw); + } + + /// Load a (possibly unaligned) pointer from a given address and + /// offset. + void *LoadPointer(unsigned Offset) const { + void *Result; + memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void *)); + return Result; + } + + /// Determines the data length for the last component in the + /// given nested-name-specifier. + static inline unsigned getLocalDataLength(NestedNameSpecifier Qualifier); + + /// Determines the data length for the entire + /// nested-name-specifier. + static inline unsigned getDataLength(NestedNameSpecifier Qualifier); + +public: + /// Construct an empty nested-name-specifier. + NestedNameSpecifierLoc() = default; + + /// Construct a nested-name-specifier with source location information + /// from + NestedNameSpecifierLoc(NestedNameSpecifier Qualifier, void *Data) + : Qualifier(Qualifier), Data(Data) {} + + /// Evaluates true when this nested-name-specifier location is + /// non-empty. + explicit operator bool() const { return bool(Qualifier); } + + /// Evaluates true when this nested-name-specifier location is + /// non-empty. + bool hasQualifier() const { return bool(Qualifier); } + + /// Retrieve the nested-name-specifier to which this instance + /// refers. + NestedNameSpecifier getNestedNameSpecifier() const { return Qualifier; } + + /// Retrieve the opaque pointer that refers to source-location data. + void *getOpaqueData() const { return Data; } + + /// Retrieve the source range covering the entirety of this + /// nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector<int>::, the returned source range would cover + /// from the initial '::' to the last '::'. + inline SourceRange getSourceRange() const LLVM_READONLY; + + /// Retrieve the source range covering just the last part of + /// this nested-name-specifier, not including the prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector<int>::, the returned source range would cover + /// from "vector" to the last '::'. + inline SourceRange getLocalSourceRange() const; + + /// Retrieve the location of the beginning of this + /// nested-name-specifier. + SourceLocation getBeginLoc() const; + + /// Retrieve the location of the end of this + /// nested-name-specifier. + inline SourceLocation getEndLoc() const; + + /// Retrieve the location of the beginning of this + /// component of the nested-name-specifier. + inline SourceLocation getLocalBeginLoc() const; + + /// Retrieve the location of the end of this component of the + /// nested-name-specifier. + inline SourceLocation getLocalEndLoc() const; + + /// For a nested-name-specifier that refers to a namespace, + /// retrieve the namespace and its prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::chrono::, the prefix is \c \::std::. Note that the + /// returned prefix may be empty, if this is the first component of + /// the nested-name-specifier. + inline NamespaceAndPrefixLoc castAsNamespaceAndPrefix() const; + inline NamespaceAndPrefixLoc getAsNamespaceAndPrefix() const; + + /// For a nested-name-specifier that refers to a type, + /// retrieve the type with source-location information. + inline TypeLoc castAsTypeLoc() const; + inline TypeLoc getAsTypeLoc() const; + + /// Determines the data length for the entire + /// nested-name-specifier. + inline unsigned getDataLength() const; + + friend bool operator==(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { + return X.Qualifier == Y.Qualifier && X.Data == Y.Data; + } + + friend bool operator!=(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { + return !(X == Y); + } +}; + +struct NamespaceAndPrefixLoc { + const NamespaceBaseDecl *Namespace = nullptr; + NestedNameSpecifierLoc Prefix; + + explicit operator bool() const { return Namespace != nullptr; } +}; + +/// Class that aids in the construction of nested-name-specifiers along +/// with source-location information for all of the components of the +/// nested-name-specifier. +class NestedNameSpecifierLocBuilder { + /// The current representation of the nested-name-specifier we're + /// building. + NestedNameSpecifier Representation = std::nullopt; + + /// Buffer used to store source-location information for the + /// nested-name-specifier. + /// + /// Note that we explicitly manage the buffer (rather than using a + /// SmallVector) because \c Declarator expects it to be possible to memcpy() + /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. + char *Buffer = nullptr; + + /// The size of the buffer used to store source-location information + /// for the nested-name-specifier. + unsigned BufferSize = 0; + + /// The capacity of the buffer used to store source-location + /// information for the nested-name-specifier. + unsigned BufferCapacity = 0; + + void PushTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, + SourceRange R); + +public: + NestedNameSpecifierLocBuilder() = default; + NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); + + NestedNameSpecifierLocBuilder & + operator=(const NestedNameSpecifierLocBuilder &Other); + + ~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); + } + + /// Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier getRepresentation() const { return Representation; } + + /// Make a nested-name-specifier of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, const NamespaceBaseDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc); + + /// Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, + SourceRange R) { + Representation = Qualifier; + BufferSize = 0; + PushTrivial(Context, Qualifier, R); + } + + /// Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// Retrieve the source range covered by this nested-name-specifier. + inline SourceRange getSourceRange() const LLVM_READONLY; + + /// Retrieve a nested-name-specifier with location information, + /// copied into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// Retrieve a nested-name-specifier with location + /// information based on the information in this builder. + /// + /// This loc will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + + /// Clear out this builder, and prepare it to build another + /// nested-name-specifier with source-location information. + void Clear() { + Representation = std::nullopt; + BufferSize = 0; + } + + /// Retrieve the underlying buffer. + /// + /// \returns A pair containing a pointer to the buffer of source-location + /// data and the size of the source-location data that resides in that + /// buffer. + std::pair<char *, unsigned> getBuffer() const { + return std::make_pair(Buffer, BufferSize); + } +}; + +/// Insertion operator for diagnostics. This allows sending +/// NestedNameSpecifiers into a diagnostic with <<. +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + NestedNameSpecifier NNS) { + DB.AddTaggedVal(reinterpret_cast<uintptr_t>(NNS.getAsVoidPointer()), + DiagnosticsEngine::ak_nestednamespec); + return DB; +} + +} // namespace clang + +namespace llvm { + +template <> struct PointerLikeTypeTraits<clang::NestedNameSpecifier> { + static void *getAsVoidPointer(clang::NestedNameSpecifier P) { + return P.getAsVoidPointer(); + } + static clang::NestedNameSpecifier getFromVoidPointer(const void *P) { + return clang::NestedNameSpecifier::getFromVoidPointer(P); + } + static constexpr int NumLowBitsAvailable = + clang::NestedNameSpecifier::NumLowBitsAvailable; +}; + +} // namespace llvm + +#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H diff --git a/clang/include/clang/AST/ODRHash.h b/clang/include/clang/AST/ODRHash.h index 11f917a..ae3fab6 100644 --- a/clang/include/clang/AST/ODRHash.h +++ b/clang/include/clang/AST/ODRHash.h @@ -93,7 +93,7 @@ public: void AddQualType(QualType T); void AddStmt(const Stmt *S); void AddIdentifierInfo(const IdentifierInfo *II); - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS); + void AddNestedNameSpecifier(NestedNameSpecifier NNS); void AddDependentTemplateName(const DependentTemplateStorage &Name); void AddTemplateName(TemplateName Name); void AddDeclarationNameInfo(DeclarationNameInfo NameInfo, diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 8c848a1..2f4aba1 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -876,21 +876,32 @@ public: } }; +// A 'pair' to stand in for the recipe. RecipeDecl is the main declaration, and +// InitFromTemporary is the 'temp' declaration we put in to be 'copied from'. +struct OpenACCFirstPrivateRecipe { + VarDecl *RecipeDecl, *InitFromTemporary; + OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T) + : RecipeDecl(R), InitFromTemporary(T) {} + OpenACCFirstPrivateRecipe(std::pair<VarDecl *, VarDecl *> p) + : RecipeDecl(p.first), InitFromTemporary(p.second) {} +}; + class OpenACCFirstPrivateClause final : public OpenACCClauseWithVarList, private llvm::TrailingObjects<OpenACCFirstPrivateClause, Expr *, - VarDecl *> { + OpenACCFirstPrivateRecipe> { friend TrailingObjects; OpenACCFirstPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef<Expr *> VarList, - ArrayRef<VarDecl *> InitRecipes, + ArrayRef<OpenACCFirstPrivateRecipe> InitRecipes, SourceLocation EndLoc) : OpenACCClauseWithVarList(OpenACCClauseKind::FirstPrivate, BeginLoc, LParenLoc, EndLoc) { assert(VarList.size() == InitRecipes.size()); setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList); - llvm::uninitialized_copy(InitRecipes, getTrailingObjects<VarDecl *>()); + llvm::uninitialized_copy(InitRecipes, + getTrailingObjects<OpenACCFirstPrivateRecipe>()); } public: @@ -900,19 +911,20 @@ public: // Gets a list of 'made up' `VarDecl` objects that can be used by codegen to // ensure that we properly initialize each of these variables. - ArrayRef<VarDecl *> getInitRecipes() { - return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(), - getExprs().size()}; + ArrayRef<OpenACCFirstPrivateRecipe> getInitRecipes() { + return ArrayRef<OpenACCFirstPrivateRecipe>{ + getTrailingObjects<OpenACCFirstPrivateRecipe>(), getExprs().size()}; } - ArrayRef<VarDecl *> getInitRecipes() const { - return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(), - getExprs().size()}; + ArrayRef<OpenACCFirstPrivateRecipe> getInitRecipes() const { + return ArrayRef<OpenACCFirstPrivateRecipe>{ + getTrailingObjects<OpenACCFirstPrivateRecipe>(), getExprs().size()}; } static OpenACCFirstPrivateClause * Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, - ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes, + ArrayRef<Expr *> VarList, + ArrayRef<OpenACCFirstPrivateRecipe> InitRecipes, SourceLocation EndLoc); size_t numTrailingObjects(OverloadToken<Expr *>) const { @@ -1238,19 +1250,32 @@ public: SourceLocation EndLoc); }; +// A structure to stand in for the recipe on a reduction. RecipeDecl is the +// 'main' declaration used for initializaiton, which is fixed. +struct OpenACCReductionRecipe { + VarDecl *RecipeDecl; + // TODO: OpenACC: this should eventually have the operations here too. +}; + class OpenACCReductionClause final : public OpenACCClauseWithVarList, - private llvm::TrailingObjects<OpenACCReductionClause, Expr *> { + private llvm::TrailingObjects<OpenACCReductionClause, Expr *, + OpenACCReductionRecipe> { friend TrailingObjects; OpenACCReductionOperator Op; OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc, OpenACCReductionOperator Operator, - ArrayRef<Expr *> VarList, SourceLocation EndLoc) + ArrayRef<Expr *> VarList, + ArrayRef<OpenACCReductionRecipe> Recipes, + SourceLocation EndLoc) : OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc, LParenLoc, EndLoc), Op(Operator) { - setExprs(getTrailingObjects(VarList.size()), VarList); + assert(VarList.size() == Recipes.size()); + setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList); + llvm::uninitialized_copy(Recipes, getTrailingObjects< + OpenACCReductionRecipe > ()); } public: @@ -1258,12 +1283,26 @@ public: return C->getClauseKind() == OpenACCClauseKind::Reduction; } + ArrayRef<OpenACCReductionRecipe> getRecipes() { + return ArrayRef<OpenACCReductionRecipe>{ + getTrailingObjects<OpenACCReductionRecipe>(), getExprs().size()}; + } + + ArrayRef<OpenACCReductionRecipe> getRecipes() const { + return ArrayRef<OpenACCReductionRecipe>{ + getTrailingObjects<OpenACCReductionRecipe>(), getExprs().size()}; + } + static OpenACCReductionClause * Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList, - SourceLocation EndLoc); + ArrayRef<OpenACCReductionRecipe> Recipes, SourceLocation EndLoc); OpenACCReductionOperator getReductionOp() const { return Op; } + + size_t numTrailingObjects(OverloadToken<Expr *>) const { + return getExprs().size(); + } }; class OpenACCLinkClause final diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 1118d3e..72effbc 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -1865,62 +1865,43 @@ public: /// \endcode /// In this example directive '#pragma omp error' has simple /// 'message' clause with user error message of "GNU compiler required.". -class OMPMessageClause final : public OMPClause { +class OMPMessageClause final + : public OMPOneStmtClause<llvm::omp::OMPC_message, OMPClause>, + public OMPClauseWithPreInit { friend class OMPClauseReader; - /// Location of '(' - SourceLocation LParenLoc; - - // Expression of the 'message' clause. - Stmt *MessageString = nullptr; - /// Set message string of the clause. - void setMessageString(Expr *MS) { MessageString = MS; } - - /// Sets the location of '('. - void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + void setMessageString(Expr *MS) { setStmt(MS); } public: /// Build 'message' clause with message string argument /// /// \param MS Argument of the clause (message string). + /// \param HelperMS Helper statement for the construct. + /// \param CaptureRegion Innermost OpenMP region where expressions in this + /// clause must be captured. /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - OMPMessageClause(Expr *MS, SourceLocation StartLoc, SourceLocation LParenLoc, + OMPMessageClause(Expr *MS, Stmt *HelperMS, OpenMPDirectiveKind CaptureRegion, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) - : OMPClause(llvm::omp::OMPC_message, StartLoc, EndLoc), - LParenLoc(LParenLoc), MessageString(MS) {} - - /// Build an empty clause. - OMPMessageClause() - : OMPClause(llvm::omp::OMPC_message, SourceLocation(), SourceLocation()) { + : OMPOneStmtClause(MS, StartLoc, LParenLoc, EndLoc), + OMPClauseWithPreInit(this) { + setPreInitStmt(HelperMS, CaptureRegion); } - /// Returns the locaiton of '('. - SourceLocation getLParenLoc() const { return LParenLoc; } + /// Build an empty clause. + OMPMessageClause() : OMPOneStmtClause(), OMPClauseWithPreInit(this) {} /// Returns message string of the clause. - Expr *getMessageString() const { return cast_or_null<Expr>(MessageString); } - - child_range children() { - return child_range(&MessageString, &MessageString + 1); - } - - const_child_range children() const { - return const_child_range(&MessageString, &MessageString + 1); - } - - child_range used_children() { - return child_range(child_iterator(), child_iterator()); - } - - const_child_range used_children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); - } + Expr *getMessageString() const { return getStmtAs<Expr>(); } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == llvm::omp::OMPC_message; + /// Try to evaluate the message string at compile time. + std::optional<std::string> tryEvaluateString(ASTContext &Ctx) const { + if (Expr *MessageExpr = getMessageString()) + return MessageExpr->tryEvaluateString(Ctx); + return std::nullopt; } }; diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 875769c..fd995a6 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -63,9 +63,9 @@ struct PrintingPolicy { SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant), - SuppressElaboration(false), SuppressInitializers(false), - ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), - SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), + SuppressInitializers(false), ConstantArraySizeAsWritten(false), + AnonymousTagLocations(true), SuppressStrongLifetime(false), + SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), SuppressDefaultTemplateArgs(true), Bool(LO.Bool), Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus), @@ -150,11 +150,6 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode) unsigned SuppressInlineNamespace : 2; - /// Ignore qualifiers and tag keywords as specified by elaborated type sugar, - /// instead letting the underlying type print as normal. - LLVM_PREFERRED_TYPE(bool) - unsigned SuppressElaboration : 1; - /// Suppress printing of variable initializers. /// /// This flag is used when printing the loop variable in a for-range diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 0438e4d..5b10127 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -127,9 +127,8 @@ def LValuePathSerializationHelper : PropertyType<"APValue::LValuePathSerializationHelper"> { let BufferElementTypes = [ LValuePathEntry ]; } -def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">; -def NestedNameSpecifierKind : - EnumPropertyType<"NestedNameSpecifier::SpecifierKind">; +def NestedNameSpecifier : PropertyType<"NestedNameSpecifier">; +def NestedNameSpecifierKind : EnumPropertyType<"NestedNameSpecifier::Kind">; def OverloadedOperatorKind : EnumPropertyType; def Qualifiers : PropertyType; def QualType : DefaultValuePropertyType; diff --git a/clang/include/clang/AST/QualTypeNames.h b/clang/include/clang/AST/QualTypeNames.h index daa86cd..9f5cf04 100644 --- a/clang/include/clang/AST/QualTypeNames.h +++ b/clang/include/clang/AST/QualTypeNames.h @@ -87,6 +87,16 @@ std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx, /// specifier "::" should be prepended or not. QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, bool WithGlobalNsPrefix = false); + +/// Get the fully qualified name for the declared context of a declaration. +/// +/// \param[in] Ctx - the ASTContext to be used. +/// \param[in] Decl - the declaration for which to get the fully qualified name. +/// \param[in] WithGlobalNsPrefix - If true, then the global namespace +/// specifier "::" will be prepended to the fully qualified name. +NestedNameSpecifier +getFullyQualifiedDeclaredContext(const ASTContext &Ctx, const Decl *Decl, + bool WithGlobalNsPrefix = false); } // end namespace TypeName } // end namespace clang #endif // LLVM_CLANG_AST_QUALTYPENAMES_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 62991d9..02581c8 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -216,14 +216,14 @@ public: /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type). - bool TraverseType(QualType T); + bool TraverseType(QualType T, bool TraverseQualifier = true); /// Recursively visit a type with location, by dispatching to /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type location). - bool TraverseTypeLoc(TypeLoc TL); + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true); /// Recursively visit an attribute, by dispatching to /// Traverse*Attr() based on the argument's dynamic type. @@ -242,7 +242,7 @@ public: /// Recursively visit a C++ nested-name-specifier. /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); /// Recursively visit a C++ nested-name-specifier with location /// information. @@ -389,7 +389,8 @@ public: // Declare Traverse*() for all concrete Type classes. #define ABSTRACT_TYPE(CLASS, BASE) -#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T); +#define TYPE(CLASS, BASE) \ + bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier); #include "clang/AST/TypeNodes.inc" // The above header #undefs ABSTRACT_TYPE and TYPE upon exit. @@ -410,7 +411,8 @@ public: // Declare Traverse*() for all concrete TypeLoc classes. #define ABSTRACT_TYPELOC(CLASS, BASE) -#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); +#define TYPELOC(CLASS, BASE) \ + bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier); #include "clang/AST/TypeLocNodes.def" // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit. @@ -490,6 +492,8 @@ private: bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, unsigned Count); bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); + bool TraverseSubstPackTypeHelper(SubstPackType *T); + bool TraverseSubstPackTypeLocHelper(SubstPackTypeLoc TL); bool TraverseRecordHelper(RecordDecl *D); bool TraverseCXXRecordHelper(CXXRecordDecl *D); bool TraverseDeclaratorHelper(DeclaratorDecl *D); @@ -499,6 +503,8 @@ private: bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); bool TraverseOMPLoopDirective(OMPLoopDirective *S); bool TraverseOMPClause(OMPClause *C); + bool TraverseTagType(TagType *T, bool TraverseQualifier); + bool TraverseTagTypeLoc(TagTypeLoc TL, bool TraverseQualifier); #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) bool Visit##Class(Class *C); #include "llvm/Frontend/OpenMP/OMP.inc" @@ -698,7 +704,8 @@ RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S, DataRecursionQueue *Queue) { } template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { +bool RecursiveASTVisitor<Derived>::TraverseType(QualType T, + bool TraverseQualifier) { if (T.isNull()) return true; @@ -707,7 +714,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { #define TYPE(CLASS, BASE) \ case Type::CLASS: \ return getDerived().Traverse##CLASS##Type( \ - static_cast<CLASS##Type *>(const_cast<Type *>(T.getTypePtr()))); + static_cast<CLASS##Type *>(const_cast<Type *>(T.getTypePtr())), \ + TraverseQualifier); #include "clang/AST/TypeNodes.inc" } @@ -715,7 +723,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { } template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) { +bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL, + bool TraverseQualifier) { if (TL.isNull()) return true; @@ -723,7 +732,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) { #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ case TypeLoc::CLASS: \ - return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>()); + return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>(), \ + TraverseQualifier); #include "clang/AST/TypeLocNodes.def" } @@ -779,46 +789,43 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) { template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier( - NestedNameSpecifier *NNS) { - if (!NNS) + NestedNameSpecifier NNS) { + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return true; - - if (NNS->getPrefix()) - TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix())); - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Namespace: + TRY_TO(TraverseNestedNameSpecifier(NNS.getAsNamespaceAndPrefix().Prefix)); + return true; + case NestedNameSpecifier::Kind::Type: { + auto *T = const_cast<Type *>(NNS.getAsType()); + TRY_TO(TraverseNestedNameSpecifier(T->getPrefix())); + TRY_TO(TraverseType(QualType(T, 0), /*TraverseQualifier=*/false)); return true; - - case NestedNameSpecifier::TypeSpec: - TRY_TO(TraverseType(QualType(NNS->getAsType(), 0))); } - - return true; + } + llvm_unreachable("unhandled kind"); } template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS) { - if (!NNS) + switch (NNS.getNestedNameSpecifier().getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return true; - - if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) - TRY_TO(TraverseNestedNameSpecifierLoc(Prefix)); - - switch (NNS.getNestedNameSpecifier()->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Namespace: + TRY_TO( + TraverseNestedNameSpecifierLoc(NNS.castAsNamespaceAndPrefix().Prefix)); return true; - - case NestedNameSpecifier::TypeSpec: - TRY_TO(TraverseTypeLoc(NNS.getTypeLoc())); - break; + case NestedNameSpecifier::Kind::Type: { + TypeLoc TL = NNS.castAsTypeLoc(); + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getPrefix())); + TRY_TO(TraverseTypeLoc(TL, /*TraverseQualifier=*/false)); + return true; + } } return true; @@ -975,10 +982,13 @@ RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE, // This macro makes available a variable T, the passed-in type. #define DEF_TRAVERSE_TYPE(TYPE, CODE) \ template <typename Derived> \ - bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T) { \ + bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T, \ + bool TraverseQualifier) { \ if (!getDerived().shouldTraversePostOrder()) \ TRY_TO(WalkUpFrom##TYPE(T)); \ - { CODE; } \ + { \ + CODE; \ + } \ if (getDerived().shouldTraversePostOrder()) \ TRY_TO(WalkUpFrom##TYPE(T)); \ return true; \ @@ -1000,10 +1010,11 @@ DEF_TRAVERSE_TYPE(RValueReferenceType, { TRY_TO(TraverseType(T->getPointeeType())); }) DEF_TRAVERSE_TYPE(MemberPointerType, { - TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - if (T->isSugared()) - TRY_TO(TraverseType( - QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0))); + NestedNameSpecifier Qualifier = + T->isSugared() ? cast<MemberPointerType>(T->getCanonicalTypeUnqualified()) + ->getQualifier() + : T->getQualifier(); + TRY_TO(TraverseNestedNameSpecifier(Qualifier)); TRY_TO(TraverseType(T->getPointeeType())); }) @@ -1087,9 +1098,18 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { TRY_TO(TraverseStmt(NE)); }) -DEF_TRAVERSE_TYPE(UsingType, {}) -DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) -DEF_TRAVERSE_TYPE(TypedefType, {}) +DEF_TRAVERSE_TYPE(UsingType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) +DEF_TRAVERSE_TYPE(UnresolvedUsingType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) +DEF_TRAVERSE_TYPE(TypedefType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) DEF_TRAVERSE_TYPE(TypeOfExprType, { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) @@ -1115,27 +1135,15 @@ DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments())); } }) -DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { - TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseType(T->getDeducedType())); -}) -DEF_TRAVERSE_TYPE(RecordType, {}) -DEF_TRAVERSE_TYPE(EnumType, {}) DEF_TRAVERSE_TYPE(TemplateTypeParmType, {}) DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { TRY_TO(TraverseType(T->getReplacementType())); }) -DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { - TRY_TO(TraverseTemplateArgument(T->getArgumentPack())); -}) - -DEF_TRAVERSE_TYPE(TemplateSpecializationType, { - TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseTemplateArguments(T->template_arguments())); -}) - -DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, + { TRY_TO(TraverseSubstPackTypeHelper(T)); }) +DEF_TRAVERSE_TYPE(SubstBuiltinTemplatePackType, + { TRY_TO(TraverseSubstPackTypeHelper(T)); }) DEF_TRAVERSE_TYPE(AttributedType, { TRY_TO(TraverseType(T->getModifiedType())); }) @@ -1165,22 +1173,54 @@ DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); }) DEF_TRAVERSE_TYPE(MacroQualifiedType, { TRY_TO(TraverseType(T->getUnderlyingType())); }) -DEF_TRAVERSE_TYPE(ElaboratedType, { - if (T->getQualifier()) { +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTagType(TagType *T, + bool TraverseQualifier) { + if (TraverseQualifier) TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - } - TRY_TO(TraverseType(T->getNamedType())); -}) + return true; +} -DEF_TRAVERSE_TYPE(DependentNameType, - { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); }) +DEF_TRAVERSE_TYPE(EnumType, { TRY_TO(TraverseTagType(T, TraverseQualifier)); }) +DEF_TRAVERSE_TYPE(RecordType, + { TRY_TO(TraverseTagType(T, TraverseQualifier)); }) +DEF_TRAVERSE_TYPE(InjectedClassNameType, + { TRY_TO(TraverseTagType(T, TraverseQualifier)); }) + +DEF_TRAVERSE_TYPE(DependentNameType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { const DependentTemplateStorage &S = T->getDependentTemplateName(); - TRY_TO(TraverseNestedNameSpecifier(S.getQualifier())); + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(S.getQualifier())); + TRY_TO(TraverseTemplateArguments(T->template_arguments())); +}) + +DEF_TRAVERSE_TYPE(TemplateSpecializationType, { + if (TraverseQualifier) { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + } else { + // FIXME: Try to preserve the rest of the template name. + TRY_TO(TraverseTemplateName(TemplateName( + T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true)))); + } TRY_TO(TraverseTemplateArguments(T->template_arguments())); }) +DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { + if (TraverseQualifier) { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + } else { + // FIXME: Try to preserve the rest of the template name. + TRY_TO(TraverseTemplateName(TemplateName( + T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true)))); + } + TRY_TO(TraverseType(T->getDeducedType())); +}) + DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); }) DEF_TRAVERSE_TYPE(ObjCTypeParamType, {}) @@ -1221,13 +1261,16 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {}) // continue to work. #define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \ template <typename Derived> \ - bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \ + bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc( \ + TYPE##Loc TL, bool TraverseQualifier) { \ if (!getDerived().shouldTraversePostOrder()) { \ TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ if (getDerived().shouldWalkTypesOfTypeLocs()) \ TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE *>(TL.getTypePtr()))); \ } \ - { CODE; } \ + { \ + CODE; \ + } \ if (getDerived().shouldTraversePostOrder()) { \ TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ if (getDerived().shouldWalkTypesOfTypeLocs()) \ @@ -1237,8 +1280,10 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {}) } template <typename Derived> -bool -RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { +bool RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc( + QualifiedTypeLoc TL, bool TraverseQualifier) { + assert(TraverseQualifier && + "Qualifiers should never occur within NestedNameSpecifiers"); // Move this over to the 'main' typeloc tree. Note that this is a // move -- we pretend that we were really looking at the unqualified // typeloc all along -- rather than a recursion, so we don't follow @@ -1391,9 +1436,21 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { TRY_TO(TraverseStmt(NE)); }) -DEF_TRAVERSE_TYPELOC(UsingType, {}) -DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) -DEF_TRAVERSE_TYPELOC(TypedefType, {}) +DEF_TRAVERSE_TYPELOC(UsingType, { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); +}) +DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); +}) +DEF_TRAVERSE_TYPELOC(TypedefType, { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); +}) DEF_TRAVERSE_TYPELOC(TypeOfExprType, { TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); }) @@ -1423,30 +1480,30 @@ DEF_TRAVERSE_TYPELOC(AutoType, { } }) -DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { - TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); - TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); -}) - -DEF_TRAVERSE_TYPELOC(RecordType, {}) -DEF_TRAVERSE_TYPELOC(EnumType, {}) DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {}) DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType())); }) -DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeLocHelper( + SubstPackTypeLoc TL) { TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack())); -}) + return true; +} -// FIXME: use the loc for the template name? -DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { - TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { - TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); - } -}) +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeHelper( + SubstPackType *T) { + TRY_TO(TraverseTemplateArgument(T->getArgumentPack())); + return true; +} + +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, + { TRY_TO(TraverseSubstPackTypeLocHelper(TL)); }) -DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {}) +DEF_TRAVERSE_TYPELOC(SubstBuiltinTemplatePackType, + { TRY_TO(TraverseSubstPackTypeLocHelper(TL)); }) DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); }) @@ -1468,27 +1525,63 @@ DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType, DEF_TRAVERSE_TYPELOC(HLSLInlineSpirvType, { TRY_TO(TraverseType(TL.getType())); }) -DEF_TRAVERSE_TYPELOC(ElaboratedType, { - if (TL.getQualifierLoc()) { - TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); - } - TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc())); -}) +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTagTypeLoc(TagTypeLoc TL, + bool TraverseQualifier) { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); + return true; +} + +DEF_TRAVERSE_TYPELOC(EnumType, + { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); }) +DEF_TRAVERSE_TYPELOC(RecordType, + { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); }) +DEF_TRAVERSE_TYPELOC(InjectedClassNameType, + { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); }) DEF_TRAVERSE_TYPELOC(DependentNameType, { - TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); }) DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { - if (TL.getQualifierLoc()) { + if (TraverseQualifier) TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); } +}) + +DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + + // FIXME: Try to preserve the rest of the template name. + TRY_TO(TraverseTemplateName( + TemplateName(TL.getTypePtr()->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true)))); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); } }) +DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + + const auto *T = TL.getTypePtr(); + // FIXME: Try to preserve the rest of the template name. + TRY_TO( + TraverseTemplateName(TemplateName(T->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true)))); + + TRY_TO(TraverseType(T->getDeducedType())); +}) + DEF_TRAVERSE_TYPELOC(PackExpansionType, { TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); }) @@ -1631,8 +1724,9 @@ DEF_TRAVERSE_DECL(FriendDecl, { TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); // Traverse any CXXRecordDecl owned by this type, since // it will not be in the parent context: - if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>()) - TRY_TO(TraverseDecl(ET->getOwnedTagDecl())); + if (auto *TT = D->getFriendType()->getType()->getAs<TagType>(); + TT && TT->isTagOwned()) + TRY_TO(TraverseDecl(TT->getOriginalDecl())); } else { TRY_TO(TraverseDecl(D->getFriendDecl())); } diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index eb384ea..de248ac 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -15,9 +15,9 @@ #define LLVM_CLANG_AST_TEMPLATEBASE_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.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" @@ -478,31 +478,25 @@ public: /// Location information for a TemplateArgument. struct TemplateArgumentLocInfo { -private: struct TemplateTemplateArgLocInfo { - // FIXME: We'd like to just use the qualifier in the TemplateName, - // but template arguments get canonicalized too quickly. - NestedNameSpecifier *Qualifier; void *QualifierLocData; + SourceLocation TemplateKwLoc; SourceLocation TemplateNameLoc; SourceLocation EllipsisLoc; }; - llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *> - Pointer; - TemplateTemplateArgLocInfo *getTemplate() const { return cast<TemplateTemplateArgLocInfo *>(Pointer); } -public: TemplateArgumentLocInfo() {} TemplateArgumentLocInfo(TypeSourceInfo *Declarator) { Pointer = Declarator; } TemplateArgumentLocInfo(Expr *E) { Pointer = E; } // Ctx is used for allocation -- this case is unusually large and also rare, // so we store the payload out-of-line. - TemplateArgumentLocInfo(ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, + TemplateArgumentLocInfo(ASTContext &Ctx, SourceLocation TemplateKwLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc); @@ -512,10 +506,8 @@ public: Expr *getAsExpr() const { return cast<Expr *>(Pointer); } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { - const auto *Template = getTemplate(); - return NestedNameSpecifierLoc(Template->Qualifier, - Template->QualifierLocData); + SourceLocation getTemplateKwLoc() const { + return getTemplate()->TemplateKwLoc; } SourceLocation getTemplateNameLoc() const { @@ -525,6 +517,10 @@ public: SourceLocation getTemplateEllipsisLoc() const { return getTemplate()->EllipsisLoc; } + +private: + llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *> + Pointer; }; /// Location wrapper for a TemplateArgument. TemplateArgument is to @@ -558,14 +554,10 @@ public: } TemplateArgumentLoc(ASTContext &Ctx, const TemplateArgument &Argument, + SourceLocation TemplateKWLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, - SourceLocation EllipsisLoc = SourceLocation()) - : Argument(Argument), - LocInfo(Ctx, QualifierLoc, TemplateNameLoc, EllipsisLoc) { - assert(Argument.getKind() == TemplateArgument::Template || - Argument.getKind() == TemplateArgument::TemplateExpansion); - } + SourceLocation EllipsisLoc = SourceLocation()); /// - Fetches the primary location of the argument. SourceLocation getLocation() const { @@ -614,13 +606,15 @@ public: return LocInfo.getAsExpr(); } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { + SourceLocation getTemplateKWLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) - return NestedNameSpecifierLoc(); - return LocInfo.getTemplateQualifierLoc(); + return SourceLocation(); + return LocInfo.getTemplateKwLoc(); } + NestedNameSpecifierLoc getTemplateQualifierLoc() const; + SourceLocation getTemplateNameLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 63949f8..abb0669 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -14,7 +14,7 @@ #define LLVM_CLANG_AST_TEMPLATENAME_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/UnsignedOrNone.h" @@ -339,6 +339,14 @@ public: /// structure, if any. DependentTemplateName *getAsDependentTemplateName() const; + // Retrieve the qualifier and template keyword stored in either a underlying + // DependentTemplateName or QualifiedTemplateName. + std::tuple<NestedNameSpecifier, bool> getQualifierAndTemplateKeyword() const; + + NestedNameSpecifier getQualifier() const { + return std::get<0>(getQualifierAndTemplateKeyword()); + } + /// Retrieve the using shadow declaration through which the underlying /// template declaration is introduced, if any. UsingShadowDecl *getAsUsingShadowDecl() const; @@ -503,7 +511,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// "template" keyword is always redundant in this case (otherwise, /// the template name would be a dependent name and we would express /// this name with DependentTemplateName). - llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; + llvm::PointerIntPair<NestedNameSpecifier, 1, bool> Qualifier; /// The underlying template name, it is either /// 1) a Template -- a template declaration that this qualified name refers @@ -512,7 +520,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// using-shadow declaration. TemplateName UnderlyingTemplate; - QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + QualifiedTemplateName(NestedNameSpecifier NNS, bool TemplateKeyword, TemplateName Template) : Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) { assert(UnderlyingTemplate.getKind() == TemplateName::Template || @@ -521,7 +529,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { public: /// Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); } /// Whether the template name was prefixed by the "template" /// keyword. @@ -534,9 +542,9 @@ public: Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS, bool TemplateKeyword, TemplateName TN) { - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddBoolean(TemplateKeyword); ID.AddPointer(TN.getAsVoidPointer()); } @@ -585,18 +593,18 @@ class DependentTemplateStorage { /// /// The bit stored in this qualifier describes whether the \c Name field /// was preceeded by a template keyword. - llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier; + llvm::PointerIntPair<NestedNameSpecifier, 1, bool> Qualifier; /// The dependent template name. IdentifierOrOverloadedOperator Name; public: - DependentTemplateStorage(NestedNameSpecifier *Qualifier, + DependentTemplateStorage(NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword); /// Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); } IdentifierOrOverloadedOperator getName() const { return Name; } @@ -609,10 +617,10 @@ public: Profile(ID, getQualifier(), getName(), hasTemplateKeyword()); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword) { - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddBoolean(HasTemplateKeyword); Name.Profile(ID); } diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1917a8a..6d279511 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -211,7 +211,7 @@ public: void dumpAccessSpecifier(AccessSpecifier AS); void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C); void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK); - void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS); + void dumpNestedNameSpecifier(NestedNameSpecifier NNS); void dumpConceptReference(const ConceptReference *R); void dumpTemplateArgument(const TemplateArgument &TA); void dumpBareTemplateName(TemplateName TN); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 12dce30..48575c1 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -9,8284 +9,67 @@ /// \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/NestedNameSpecifier.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 <bitset> -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <cstring> -#include <optional> -#include <string> -#include <type_traits> -#include <utility> +#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 T> class AbstractTypeReader; - template <class T> class AbstractTypeWriter; -} - -} // namespace clang - -namespace llvm { - - template <typename T> - 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 <typename> 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 TemplateArgument; -class TemplateArgumentListInfo; -class TemplateArgumentLoc; -class TemplateTypeParmDecl; -class TypedefNameDecl; -class UnresolvedUsingTypenameDecl; -class UsingShadowDecl; - -using CanQualType = CanQual<Type>; - -// 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<uint64_t>(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<LangAS>((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<uint64_t>(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<const Type *,Qualifiers> asPair() const { - return std::pair<const Type *, Qualifiers>(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<llvm::PointerUnion<const Type *, const ExtQuals *>, - Qualifiers::FastWidth> Value; - - const ExtQuals *getExtQualsUnsafe() const { - return cast<const ExtQuals *>(Value.getPointer()); - } - - const Type *getTypePtrUnsafe() const { - return cast<const Type *>(Value.getPointer()); - } - - const ExtQualsTypeCommonBase *getCommonPtr() const { - assert(!isNull() && "Cannot retrieve a NULL type pointer"); - auto CommonPtrVal = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); - CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); - return reinterpret_cast<ExtQualsTypeCommonBase*>(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<void*>(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<NonConstantStorageReason> - 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<const ExtQuals *>(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<ParenType>(*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<QualType> 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<clang::QualType> { - 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 <class T> 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<TypeDependence>; - - /// 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<Linkage>(CachedLinkage); - } - - bool hasLocalOrUnnamedType() const { - assert(isCacheValid() && "getting linkage from invalid cache"); - return CachedLocalOrUnnamed; - } - }; - enum { NumTypeBits = 8 + llvm::BitWidth<TypeDependence> + 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 TypeWithKeywordBitfields { - friend class TypeWithKeyword; - - 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 ElaboratedTypeBitfields { - friend class ElaboratedType; - - LLVM_PREFERRED_TYPE(TypeWithKeywordBitfields) - unsigned : NumTypeWithKeywordBits; - - /// Whether the ElaboratedType has a trailing OwnedTagDecl. - LLVM_PREFERRED_TYPE(bool) - unsigned HasOwnedTagDecl : 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 UsingBitfields { - friend class UsingType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// True if the underlying type is different from the declared one. - LLVM_PREFERRED_TYPE(bool) - unsigned hasTypeDifferentFromDecl : 1; - }; - - class TypedefBitfields { - friend class TypedefType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// 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 SubstTemplateTypeParmPackTypeBitfields { - friend class SubstTemplateTypeParmPackType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - // The index of the template parameter this substitution represents. - unsigned Index : 16; - - /// 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; - }; - - class TemplateSpecializationTypeBitfields { - friend class TemplateSpecializationType; - - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; - - /// 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(TypeWithKeywordBitfields) - 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; - UsingBitfields UsingBits; - BuiltinTypeBitfields BuiltinTypeBits; - FunctionTypeBitfields FunctionTypeBits; - ObjCObjectTypeBitfields ObjCObjectTypeBits; - ReferenceTypeBitfields ReferenceTypeBits; - TypeWithKeywordBitfields TypeWithKeywordBits; - ElaboratedTypeBitfields ElaboratedTypeBits; - VectorTypeBitfields VectorTypeBits; - TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits; - SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits; - SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits; - TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; - DependentTemplateSpecializationTypeBitfields - DependentTemplateSpecializationTypeBits; - PackExpansionTypeBitfields PackExpansionTypeBits; - CountAttributedTypeBitfields CountAttributedTypeBits; - PresefinedSugarTypeBitfields PredefinedSugarTypeBits; - }; - -private: - template <class T> 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<unsigned>(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<unsigned>(D); - } - - void addDependence(TypeDependence D) { setDependence(getDependence() | D); } - -public: - friend class ASTReader; - friend class ASTWriter; - template <class T> friend class serialization::AbstractTypeReader; - template <class T> 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<TypeClass>(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<typename ...T> - /// 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<FunctionNoProtoType>(); } - bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } - 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<foo> - bool isObjCQualifiedIdType() const; // id<foo> - bool isObjCQualifiedClassType() const; // Class<foo> - 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 - /// <NSCopying>. - /// - /// \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 <NSCopying>. - /// - /// 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 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<TypeDependence>(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<AutoType>(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<specific type>'. Look through sugar for - /// an instance of \<specific type>. This scheme will eventually - /// replace the specific getAsXXXX methods above. - /// - /// There are some specializations of this member template listed - /// immediately following this class. - template <typename T> 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<specific type>. Look through specific kinds - /// of sugar (parens, attributes, etc) for an instance of \<specific type>. - /// 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 \<specific type> - /// to another type that is still canonically a \<specific type>. - template <typename T> 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<specific type>. Look through sugar for - /// the underlying instance of \<specific type>. - /// - /// This method has the same relationship to getAs<T> as cast<T> has - /// to dyn_cast<T>; which is to say, the underlying type *must* - /// have the intended type, and this method will never return null. - template <typename T> const T *castAs() const; - - /// A variant of castAs<> for array type which silently discards - /// qualifiers from the outermost type. - const ArrayType *castAsArrayTypeUnsafe() 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<NullabilityKind> 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<ArrayRef<QualType>> - 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<Class##Type>(CanonicalType); \ -} \ -template <> inline const Class##Type *Type::castAs() const { \ - return cast<Class##Type>(CanonicalType); \ +inline CXXRecordDecl *Type::getAsCXXRecordDecl() const { + const auto *TT = dyn_cast<TagType>(CanonicalType); + if (!isa_and_present<RecordType, InjectedClassNameType>(TT)) + return nullptr; + auto *TD = TT->getOriginalDecl(); + if (isa<RecordType>(TT) && !isa<CXXRecordDecl>(TD)) + return nullptr; + return cast<CXXRecordDecl>(TD)->getDefinitionOrSelf(); } -#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<Kind>(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<ValueDecl *, 1, unsigned>; - -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<TypeCoupledDeclRefInfo> 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>; - - 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<TypeCoupledDeclRefInfo> 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<CountAttributedType, - TypeCoupledDeclRefInfo> { - 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<TypeCoupledDeclRefInfo> CoupledDecls); - - unsigned numTrailingObjects(OverloadToken<TypeCoupledDeclRefInfo>) 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<ReferenceType>(); - 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<unsigned>(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<int64_t>(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<typename T, int Size> -/// 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<typename T, int AddrSpace> -/// 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<typename T, int Size> -/// 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<typename T, int Size> -/// 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<uint16_t>(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 HasArmTypeAttributes : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned EffectsHaveConditions : 1; - unsigned NumFunctionEffects : 4; - - FunctionTypeExtraBitfields() - : NumExceptionType(0), HasArmTypeAttributes(false), - EffectsHaveConditions(false), NumFunctionEffects(0) {} - }; - - /// 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 : unsigned { - 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 (ArmStateValue)((AttrBits & SME_ZAMask) >> SME_ZAShift); - } - - static ArmStateValue getArmZT0State(unsigned AttrBits) { - return (ArmStateValue)((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. - 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<size_t>(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<FunctionEffect> - 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 <typename Container> 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<FunctionEffect> Effects; - ArrayRef<EffectConditionExpr> 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<FunctionEffect> FX, - ArrayRef<EffectConditionExpr> 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<FunctionEffect> FX, - ArrayRef<EffectConditionExpr> Conds); - - FunctionEffectsRef() = default; - - bool empty() const { return Effects.empty(); } - size_t size() const { return Effects.size(); } - - ArrayRef<FunctionEffect> effects() const { return Effects; } - ArrayRef<EffectConditionExpr> conditions() const { return Conditions; } - - using iterator = FunctionEffectIterator<FunctionEffectsRef>; - 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<EndBitPos>; - - 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<size_t>(K); - } - - constexpr static FunctionEffect::Kind posToKind(size_t Pos) { - return static_cast<FunctionEffect::Kind>(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<FunctionEffect> Effects; - SmallVector<EffectConditionExpr> 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<FunctionEffectSet>; - 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<Conflict>; - - // 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::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<QualType> 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; - LLVM_PREFERRED_TYPE(bool) - unsigned Variadic : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned HasTrailingReturn : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned CFIUncheckedCallee : 1; - unsigned AArch64SMEAttributes : 9; - Qualifiers TypeQuals; - RefQualifierKind RefQualifier = RQ_None; - ExceptionSpecInfo ExceptionSpec; - const ExtParameterInfo *ExtParameterInfos = nullptr; - SourceLocation EllipsisLoc; - FunctionEffectsRef FunctionEffects; - - 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() || - !FunctionEffects.empty(); - } - - bool requiresFunctionProtoTypeArmAttributes() const { - return AArch64SMEAttributes != SME_NormalFunction; - } - - void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) { - if (Enable) - AArch64SMEAttributes |= Kind; - else - AArch64SMEAttributes &= ~Kind; - } - }; - -private: - unsigned numTrailingObjects(OverloadToken<QualType>) const { - return getNumParams(); - } - - unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { - return isVariadic(); - } - - unsigned numTrailingObjects(OverloadToken<FunctionTypeArmAttributes>) const { - return hasArmTypeAttributes(); - } - - unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const { - return hasExtraBitfields(); - } - - unsigned numTrailingObjects(OverloadToken<ExceptionType>) const { - return getExceptionSpecSize().NumExceptionType; - } - - unsigned numTrailingObjects(OverloadToken<Expr *>) const { - return getExceptionSpecSize().NumExprPtr; - } - - unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const { - return getExceptionSpecSize().NumFunctionDeclPtr; - } - - unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) const { - return hasExtParameterInfos() ? getNumParams() : 0; - } - - unsigned numTrailingObjects(OverloadToken<Qualifiers>) const { - return hasExtQualifiers() ? 1 : 0; - } - - unsigned numTrailingObjects(OverloadToken<FunctionEffect>) 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<QualType> 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 hasArmTypeAttributes() const { - return FunctionTypeBits.HasExtraBitfields && - getTrailingObjects<FunctionTypeExtraBitfields>() - ->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<QualType> 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.AArch64SMEAttributes = getAArch64SMEAttributes(); - EPI.FunctionEffects = getFunctionEffects(); - return EPI; - } - - /// Get the kind of exception specification on this function. - ExceptionSpecificationType getExceptionSpecType() const { - return static_cast<ExceptionSpecificationType>( - 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<FunctionTypeExtraBitfields>() - ->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<Expr *>(); - } - - /// 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<FunctionDecl *>()[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<FunctionDecl *>()[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>() - : 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<Qualifiers>(); - else - return getFastTypeQuals(); - } - - /// Retrieve the ref-qualifier associated with this function type. - RefQualifierKind getRefQualifier() const { - return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); - } - - using param_type_iterator = const QualType *; - - ArrayRef<QualType> param_types() const { - return {param_type_begin(), param_type_end()}; - } - - param_type_iterator param_type_begin() const { - return getTrailingObjects<QualType>(); - } - - param_type_iterator param_type_end() const { - return param_type_begin() + getNumParams(); - } - - using exception_iterator = const QualType *; - - ArrayRef<QualType> exceptions() const { - return {exception_begin(), exception_end()}; - } - - exception_iterator exception_begin() const { - return reinterpret_cast<exception_iterator>( - getTrailingObjects<ExceptionType>()); - } - - 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<ExtParameterInfo> getExtParameterInfos() const { - assert(hasExtParameterInfos()); - return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(), - 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<ExtParameterInfo>(); - } - - /// 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<FunctionTypeArmAttributes>() - ->AArch64SMEAttributes; - } - - ExtParameterInfo getExtParameterInfo(unsigned I) const { - assert(I < getNumParams() && "parameter index out of range"); - if (hasExtParameterInfos()) - return getTrailingObjects<ExtParameterInfo>()[I]; - return ExtParameterInfo(); - } - - ParameterABI getParameterABI(unsigned I) const { - assert(I < getNumParams() && "parameter index out of range"); - if (hasExtParameterInfos()) - return getTrailingObjects<ExtParameterInfo>()[I].getABI(); - return ParameterABI::Ordinary; - } - - bool isParamConsumed(unsigned I) const { - assert(I < getNumParams() && "parameter index out of range"); - if (hasExtParameterInfos()) - return getTrailingObjects<ExtParameterInfo>()[I].isConsumed(); - return false; - } - - unsigned getNumFunctionEffects() const { - return hasExtraBitfields() - ? getTrailingObjects<FunctionTypeExtraBitfields>() - ->NumFunctionEffects - : 0; - } - - // For serialization. - ArrayRef<FunctionEffect> getFunctionEffectsWithoutConditions() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); - if (Bitfields->NumFunctionEffects > 0) - return getTrailingObjects<FunctionEffect>( - Bitfields->NumFunctionEffects); - } - return {}; - } - - unsigned getNumFunctionEffectConditions() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); - if (Bitfields->EffectsHaveConditions) - return Bitfields->NumFunctionEffects; - } - return 0; - } - - // For serialization. - ArrayRef<EffectConditionExpr> getFunctionEffectConditions() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); - if (Bitfields->EffectsHaveConditions) - return getTrailingObjects<EffectConditionExpr>( - Bitfields->NumFunctionEffects); - } - return {}; - } - - // Combines effects with their conditions. - FunctionEffectsRef getFunctionEffects() const { - if (hasExtraBitfields()) { - const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); - if (Bitfields->NumFunctionEffects > 0) { - const size_t NumConds = Bitfields->EffectsHaveConditions - ? Bitfields->NumFunctionEffects - : 0; - return FunctionEffectsRef( - getTrailingObjects<FunctionEffect>(Bitfields->NumFunctionEffects), - {NumConds ? getTrailingObjects<EffectConditionExpr>() : 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); -}; - -/// Represents the dependent type named by a dependently-scoped -/// typename using declaration, e.g. -/// using typename Base<T>::foo; -/// -/// Template instantiation turns these into the underlying type. -class UnresolvedUsingType : public Type { - friend class ASTContext; // ASTContext creates these. - - UnresolvedUsingTypenameDecl *Decl; - - UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), - TypeDependence::DependentInstantiation), - Decl(const_cast<UnresolvedUsingTypenameDecl *>(D)) {} - -public: - UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == UnresolvedUsing; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - return Profile(ID, Decl); - } - - static void Profile(llvm::FoldingSetNodeID &ID, - UnresolvedUsingTypenameDecl *D) { - ID.AddPointer(D); - } -}; - -class UsingType final : public Type, - public llvm::FoldingSetNode, - private llvm::TrailingObjects<UsingType, QualType> { - UsingShadowDecl *Found; - friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - - UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon); - -public: - UsingShadowDecl *getFoundDecl() const { return Found; } - QualType getUnderlyingType() const; - - bool isSugared() const { return true; } - - // This always has the 'same' type as declared, but not necessarily identical. - QualType desugar() const { return getUnderlyingType(); } - - // Internal helper, for debugging purposes. - bool typeMatchesDecl() const { return !UsingBits.hasTypeDifferentFromDecl; } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Found, getUnderlyingType()); - } - static void Profile(llvm::FoldingSetNodeID &ID, const UsingShadowDecl *Found, - QualType Underlying) { - ID.AddPointer(Found); - Underlying.Profile(ID); - } - static bool classof(const Type *T) { return T->getTypeClass() == Using; } -}; - -class TypedefType final : public Type, - public llvm::FoldingSetNode, - private llvm::TrailingObjects<TypedefType, QualType> { - TypedefNameDecl *Decl; - friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - - TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType UnderlyingType, - bool HasTypeDifferentFromDecl); - -public: - 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; } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Decl, typeMatchesDecl() ? QualType() : desugar()); - } - static void Profile(llvm::FoldingSetNodeID &ID, const TypedefNameDecl *Decl, - QualType Underlying) { - ID.AddPointer(Decl); - if (!Underlying.isNull()) - Underlying.Profile(ID); - } - - 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<AttributedType>(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<TypeOfKind>(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<TypeOfKind>(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<PackIndexingType, QualType> { - 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<QualType> 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<QualType> 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<QualType> Expansions); - -private: - const QualType *getExpansionsPtr() const { return getTrailingObjects(); } - - static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr, - ArrayRef<QualType> 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 Type { - friend class ASTReader; - template <class T> friend class serialization::AbstractTypeReader; - - /// Stores the TagDecl associated with this type. The decl may point to any - /// TagDecl that declares the entity. - TagDecl *decl; - -protected: - TagType(TypeClass TC, const TagDecl *D, QualType can); - -public: - TagDecl *getDecl() const; - - /// Determines whether this type is in the process of being defined. - bool isBeingDefined() const; - - static bool classof(const Type *T) { - return T->getTypeClass() == Enum || T->getTypeClass() == Record; - } -}; - -/// A helper class that allows the use of isa/cast/dyncast -/// to detect TagType objects of structs/unions/classes. -class RecordType : public TagType { -protected: - friend class ASTContext; // ASTContext creates these. - - explicit RecordType(const RecordDecl *D) - : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) {} - explicit RecordType(TypeClass TC, RecordDecl *D) - : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) {} - -public: - RecordDecl *getDecl() const { - return reinterpret_cast<RecordDecl*>(TagType::getDecl()); - } - - /// Recursively check all fields in the record for const-ness. If any field - /// is declared const, return true. Otherwise, return false. - bool hasConstFields() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - 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 : public TagType { - friend class ASTContext; // ASTContext creates these. - - explicit EnumType(const EnumDecl *D) - : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) {} - -public: - EnumDecl *getDecl() const { - return reinterpret_cast<EnumDecl*>(TagType::getDecl()); - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { return T->getTypeClass() == Enum; } -}; - -/// 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<Kind>(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<NullabilityKind> 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<NullabilityKind> 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<uint32_t>(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<HLSLInlineSpirvType, SpirvOperand> { - 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<SpirvOperand> 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<SpirvOperand> 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<SpirvOperand> 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<SubstTemplateTypeParmType, QualType> { - friend class ASTContext; - friend class llvm::TrailingObjects<SubstTemplateTypeParmType, QualType>; - - 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 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 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; - - llvm::PointerIntPair<Decl *, 1, bool> 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 SubstTemplateTypeParmPackTypeBits.Index; } - - // This substitution will be Final, which means the substitution will be fully - // sugared: it doesn't need to be resugared later. - bool getFinal() const; - - unsigned getNumArgs() const { - return SubstTemplateTypeParmPackTypeBits.NumArgs; - } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - TemplateArgument getArgumentPack() const; - - 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<TemplateArgument> TypeConstraintArgs); - -public: - ArrayRef<TemplateArgument> getTypeConstraintArguments() const { - return {reinterpret_cast<const TemplateArgument *>(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<TemplateArgument> Arguments); - - static bool classof(const Type *T) { - return T->getTypeClass() == Auto; - } -}; - -/// Represents a C++17 deduced template specialization type. -class DeducedTemplateSpecializationType : public DeducedType, - public llvm::FoldingSetNode { - friend class ASTContext; // ASTContext creates these - - /// The name of the template whose arguments will be deduced. - TemplateName Template; - - DeducedTemplateSpecializationType(TemplateName Template, - QualType DeducedAsType, - bool IsDeducedAsDependent, QualType Canon) - : DeducedType(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, getTemplateName(), getDeducedType(), isDependentType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template, - QualType Deduced, bool IsDependent) { - 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<int> will refer to a tag type for -/// the instantiation \c std::vector<int, std::allocator<int>> -/// -/// 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 Type, 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(TemplateName T, bool IsAlias, - ArrayRef<TemplateArgument> 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<TemplateArgumentLoc> Args, - ArrayRef<TemplateArgument> Converted); - static bool - anyDependentTemplateArguments(const TemplateArgumentListInfo &, - ArrayRef<TemplateArgument> Converted); - static bool anyInstantiationDependentTemplateArguments( - ArrayRef<TemplateArgumentLoc> Args); - - /// True if this template specialization type matches a current - /// instantiation in the context in which it is found. - bool isCurrentInstantiation() const { - return isa<InjectedClassNameType>(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<typename T, typename U, typename V> struct S; - /// template<typename T, typename U> using A = S<T, int, U>; - /// template<typename... Ts> struct X { - /// typedef A<Ts...> 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<TemplateArgument> template_arguments() const { - return {reinterpret_cast<const TemplateArgument *>(this + 1), - TemplateSpecializationTypeBits.NumArgs}; - } - - bool isSugared() const { - return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); - } - - QualType desugar() const { - return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); - } - - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); - static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - ArrayRef<TemplateArgument> 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<TemplateArgument> Args, - const PrintingPolicy &Policy, - const TemplateParameterList *TPL = nullptr); - -void printTemplateArgumentList(raw_ostream &OS, - ArrayRef<TemplateArgumentLoc> 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<TemplateArgument> Args, - unsigned Depth); - -/// 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 : public Type { - friend class ASTContext; // ASTContext creates these. - friend class ASTNodeImporter; - friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not - // currently suitable for AST reading, too much - // interdependencies. - template <class T> friend class serialization::AbstractTypeReader; - - CXXRecordDecl *Decl; - - /// The template specialization which this type represents. - /// For example, in - /// template <class T> class A { ... }; - /// this is A<T>, whereas in - /// template <class X, class Y> class A<B<X,Y> > { ... }; - /// this is A<B<X,Y> >. - /// - /// It is always unqualified, always a template specialization type, - /// and always dependent. - QualType InjectedType; - - InjectedClassNameType(CXXRecordDecl *D, QualType TST) - : Type(InjectedClassName, QualType(), - TypeDependence::DependentInstantiation), - Decl(D), InjectedType(TST) { - assert(isa<TemplateSpecializationType>(TST)); - assert(!TST.hasQualifiers()); - assert(TST->isDependentType()); - } - -public: - QualType getInjectedSpecializationType() const { return InjectedType; } - - const TemplateSpecializationType *getInjectedTST() const { - return cast<TemplateSpecializationType>(InjectedType.getTypePtr()); - } - - TemplateName getTemplateName() const { - return getInjectedTST()->getTemplateName(); - } - - CXXRecordDecl *getDecl() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == InjectedClassName; - } -}; - -/// 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 -}; - -/// A helper class for Type nodes having an ElaboratedTypeKeyword. -/// The keyword in stored in the free bits of the base class. -/// Also provides a few static helpers for converting and printing -/// elaborated type keyword and tag type kind enumerations. -class TypeWithKeyword : public Type { -protected: - TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, - QualType Canonical, TypeDependence Dependence) - : Type(tc, Canonical, Dependence) { - TypeWithKeywordBits.Keyword = llvm::to_underlying(Keyword); - } - -public: - ElaboratedTypeKeyword getKeyword() const { - return static_cast<ElaboratedTypeKeyword>(TypeWithKeywordBits.Keyword); - } - - /// 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)); - } - - class CannotCastToThisType {}; - static CannotCastToThisType classof(const Type *); -}; - -/// Represents a type that was referred to using an elaborated type -/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, -/// or both. -/// -/// This type is used to keep track of a type name as written in the -/// source code, including tag keywords and any nested-name-specifiers. -/// The type itself is always "sugar", used to express what was written -/// in the source code but containing no additional semantic information. -class ElaboratedType final - : public TypeWithKeyword, - public llvm::FoldingSetNode, - private llvm::TrailingObjects<ElaboratedType, TagDecl *> { - friend class ASTContext; // ASTContext creates these - friend TrailingObjects; - - /// The nested name specifier containing the qualifier. - NestedNameSpecifier *NNS; - - /// The type that this qualified name refers to. - QualType NamedType; - - /// The (re)declaration of this tag type owned by this occurrence is stored - /// as a trailing object if there is one. Use getOwnedTagDecl to obtain - /// it, or obtain a null pointer if there is none. - - ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, - QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) - : TypeWithKeyword(Keyword, Elaborated, CanonType, - // Any semantic dependence on the qualifier will have - // been incorporated into NamedType. We still need to - // track syntactic (instantiation / error / pack) - // dependence on the qualifier. - NamedType->getDependence() | - (NNS ? toSyntacticDependence( - toTypeDependence(NNS->getDependence())) - : TypeDependence::None)), - NNS(NNS), NamedType(NamedType) { - ElaboratedTypeBits.HasOwnedTagDecl = false; - if (OwnedTagDecl) { - ElaboratedTypeBits.HasOwnedTagDecl = true; - *getTrailingObjects() = OwnedTagDecl; - } - } - -public: - /// Retrieve the qualification on this type. - NestedNameSpecifier *getQualifier() const { return NNS; } - - /// Retrieve the type named by the qualified-id. - QualType getNamedType() const { return NamedType; } - - /// Remove a single level of sugar. - QualType desugar() const { return getNamedType(); } - - /// Returns whether this type directly provides sugar. - bool isSugared() const { return true; } - - /// Return the (re)declaration of this type owned by this occurrence of this - /// type, or nullptr if there is none. - TagDecl *getOwnedTagDecl() const { - return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects() : nullptr; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, QualType NamedType, - TagDecl *OwnedTagDecl) { - ID.AddInteger(llvm::to_underlying(Keyword)); - ID.AddPointer(NNS); - NamedType.Profile(ID); - ID.AddPointer(OwnedTagDecl); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } -}; - -/// 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 | - toTypeDependence(NNS->getDependence())), - NNS(NNS), Name(Name) { - assert(NNS); - 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)); - ID.AddPointer(NNS); - 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<T>::template B<T> -class DependentTemplateSpecializationType : public TypeWithKeyword { - friend class ASTContext; // ASTContext creates these - - DependentTemplateStorage Name; - - DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, - const DependentTemplateStorage &Name, - ArrayRef<TemplateArgument> Args, - QualType Canon); - -public: - const DependentTemplateStorage &getDependentTemplateName() const { - return Name; - } - - ArrayRef<TemplateArgument> template_arguments() const { - return {reinterpret_cast<const TemplateArgument *>(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<TemplateArgument> 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<typename ...Types> struct tuple; -/// -/// template<typename ...Types> -/// struct tuple_of_references { -/// typedef tuple<Types&...> 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 T> -class ObjCProtocolQualifiers { -protected: - ObjCProtocolQualifiers() = default; - - ObjCProtocolDecl * const *getProtocolStorage() const { - return const_cast<ObjCProtocolQualifiers*>(this)->getProtocolStorage(); - } - - ObjCProtocolDecl **getProtocolStorage() { - return static_cast<T*>(this)->getProtocolStorageImpl(); - } - - void setNumProtocols(unsigned N) { - static_cast<T*>(this)->setNumProtocolsImpl(N); - } - - void initialize(ArrayRef<ObjCProtocolDecl *> 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_iterator>; - - 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<const T*>(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<ObjCProtocolDecl *> getProtocols() const { - return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols()); - } -}; - -/// Represents a type parameter type in Objective C. It can take -/// a list of protocols. -class ObjCTypeParamType : public Type, - public ObjCProtocolQualifiers<ObjCTypeParamType>, - public llvm::FoldingSetNode { - friend class ASTContext; - friend class ObjCProtocolQualifiers<ObjCTypeParamType>; - - /// 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<ObjCProtocolDecl *> 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<ObjCProtocolDecl *> 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<T>; -/// \@protocol P; -/// \endcode -/// -/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType -/// with base C and no protocols. -/// -/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P]. -/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no -/// protocol list. -/// 'C<C*><P>' 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<P>' 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<ObjCObjectType> { - friend class ObjCProtocolQualifiers<ObjCObjectType>; - - // 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<const ObjCObjectType *, 1, bool> - CachedSuperClassType; - - QualType *getTypeArgStorage(); - const QualType *getTypeArgStorage() const { - return const_cast<ObjCObjectType *>(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<QualType> typeArgs, - ArrayRef<ObjCProtocolDecl *> 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<BuiltinType>()) - 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<QualType> getTypeArgs() const; - - /// Retrieve the type arguments of this object type as they were - /// written. - ArrayRef<QualType> 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<QualType> typeArgs, - ArrayRef<ObjCProtocolDecl *> protocols, - bool isKindOf) - : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} - -public: - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - QualType Base, - ArrayRef<QualType> typeArgs, - ArrayRef<ObjCProtocolDecl *> protocols, - bool isKindOf); -}; - -inline QualType *ObjCObjectType::getTypeArgStorage() { - return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1); +inline CXXRecordDecl *Type::castAsCXXRecordDecl() const { + const auto *TT = cast<TagType>(CanonicalType); + return cast<CXXRecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf(); } -inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { - return reinterpret_cast<ObjCProtocolDecl**>( - getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); +inline RecordDecl *Type::getAsRecordDecl() const { + const auto *TT = dyn_cast<TagType>(CanonicalType); + if (!isa_and_present<RecordType, InjectedClassNameType>(TT)) + return nullptr; + return cast<RecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf(); } -inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { - return reinterpret_cast<ObjCProtocolDecl**>( - static_cast<ObjCTypeParamType*>(this)+1); +inline RecordDecl *Type::castAsRecordDecl() const { + const auto *TT = cast<TagType>(CanonicalType); + return cast<RecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf(); } -/// 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<NSCopyable, NSAmazing>`. -/// -/// 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 <class T> friend class serialization::AbstractTypeReader; - - ObjCInterfaceDecl *Decl; - - ObjCInterfaceType(const ObjCInterfaceDecl *D) - : ObjCObjectType(Nonce_ObjCInterface), - Decl(const_cast<ObjCInterfaceDecl*>(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<ObjCObjectType>()) { - if (const auto *T = dyn_cast<ObjCInterfaceType>(ObjT)) - return T->getDecl(); - - baseType = ObjT->getBaseType(); - } - +inline EnumDecl *Type::getAsEnumDecl() const { + if (const auto *TT = dyn_cast<EnumType>(CanonicalType)) + return TT->getOriginalDecl()->getDefinitionOrSelf(); 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<P>' -/// and 'Class<P>' 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<P> AP; - /// typedef A A1; - /// typedef A1<P> A1P; - /// typedef A1P<Q> A1PQ; - /// \endcode - /// For 'A*', getObjectType() will return 'A'. - /// For 'A<P>*', getObjectType() will return 'A<P>'. - /// For 'AP*', getObjectType() will return 'A<P>'. - /// For 'A1*', getObjectType() will return 'A'. - /// For 'A1<P>*', getObjectType() will return 'A1<P>'. - /// For 'A1P*', getObjectType() will return 'A1<P>'. - /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because - /// adding protocols to a protocol-qualified base discards the - /// old qualifiers (for now). But if it didn't, getObjectType() - /// would return 'A1P<Q>' (and we'd have to make iterating over - /// qualifiers more complicated). - const ObjCObjectType *getObjectType() const { - return PointeeType->castAs<ObjCObjectType>(); - } - - /// 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<P>' for some non-empty set of - /// protocols. - bool isObjCQualifiedIdType() const { - return getObjectType()->isObjCQualifiedId(); - } - - /// True if this is equivalent to 'Class<P>' 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<QualType> getTypeArgs() const { - return getObjectType()->getTypeArgs(); - } - - /// Retrieve the type arguments for this type. - ArrayRef<QualType> 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_iterator>; - - 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<Expr*, 1, bool> 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<FunctionProtoType>()) - 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<FunctionType>(T) && - (!isa<ArrayType>(T) || isa<ArrayParameterType>(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(); +inline EnumDecl *Type::castAsEnumDecl() const { + return cast<EnumType>(CanonicalType) + ->getOriginalDecl() + ->getDefinitionOrSelf(); } -/// Return the address space of this type. -inline LangAS QualType::getAddressSpace() const { - return getQualifiers().getAddressSpace(); +inline TagDecl *Type::getAsTagDecl() const { + if (const auto *TT = dyn_cast<TagType>(CanonicalType)) + return TT->getOriginalDecl()->getDefinitionOrSelf(); + return nullptr; } -/// Return the gc attribute of this type. -inline Qualifiers::GC QualType::getObjCGCAttr() const { - return getQualifiers().getObjCGCAttr(); +inline TagDecl *Type::castAsTagDecl() const { + return cast<TagType>(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf(); } inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const { @@ -8307,809 +90,6 @@ inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const { return false; } -inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { - if (const auto *PT = t.getAs<PointerType>()) { - if (const auto *FT = PT->getPointeeType()->getAs<FunctionType>()) - return FT->getExtInfo(); - } else if (const auto *FT = t.getAs<FunctionType>()) - 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<ReferenceType>()) - 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<FunctionType>(CanonicalType); -} - -inline bool Type::isPointerType() const { - return isa<PointerType>(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<BlockPointerType>(CanonicalType); -} - -inline bool Type::isReferenceType() const { - return isa<ReferenceType>(CanonicalType); -} - -inline bool Type::isLValueReferenceType() const { - return isa<LValueReferenceType>(CanonicalType); -} - -inline bool Type::isRValueReferenceType() const { - return isa<RValueReferenceType>(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<PointerType>()) - return !T->getPointeeType()->isFunctionType(); - else - return false; -} - -inline bool Type::isCFIUncheckedCalleeFunctionType() const { - if (const auto *Fn = getAs<FunctionProtoType>()) - return Fn->hasCFIUncheckedCallee(); - return false; -} - -inline bool Type::hasPointeeToToCFIUncheckedCalleeFunctionType() const { - QualType Pointee; - if (const auto *PT = getAs<PointerType>()) - Pointee = PT->getPointeeType(); - else if (const auto *RT = getAs<ReferenceType>()) - Pointee = RT->getPointeeType(); - else if (const auto *MPT = getAs<MemberPointerType>()) - Pointee = MPT->getPointeeType(); - else if (const auto *DT = getAs<DecayedType>()) - Pointee = DT->getPointeeType(); - else - return false; - return Pointee->isCFIUncheckedCalleeFunctionType(); -} - -inline bool Type::isFunctionPointerType() const { - if (const auto *T = getAs<PointerType>()) - return T->getPointeeType()->isFunctionType(); - else - return false; -} - -inline bool Type::isFunctionReferenceType() const { - if (const auto *T = getAs<ReferenceType>()) - return T->getPointeeType()->isFunctionType(); - else - return false; -} - -inline bool Type::isMemberPointerType() const { - return isa<MemberPointerType>(CanonicalType); -} - -inline bool Type::isMemberFunctionPointerType() const { - if (const auto *T = getAs<MemberPointerType>()) - return T->isMemberFunctionPointer(); - else - return false; -} - -inline bool Type::isMemberDataPointerType() const { - if (const auto *T = getAs<MemberPointerType>()) - return T->isMemberDataPointer(); - else - return false; -} - -inline bool Type::isArrayType() const { - return isa<ArrayType>(CanonicalType); -} - -inline bool Type::isConstantArrayType() const { - return isa<ConstantArrayType>(CanonicalType); -} - -inline bool Type::isIncompleteArrayType() const { - return isa<IncompleteArrayType>(CanonicalType); -} - -inline bool Type::isVariableArrayType() const { - return isa<VariableArrayType>(CanonicalType); -} - -inline bool Type::isArrayParameterType() const { - return isa<ArrayParameterType>(CanonicalType); -} - -inline bool Type::isDependentSizedArrayType() const { - return isa<DependentSizedArrayType>(CanonicalType); -} - -inline bool Type::isBuiltinType() const { - return isa<BuiltinType>(CanonicalType); -} - -inline bool Type::isRecordType() const { - return isa<RecordType>(CanonicalType); -} - -inline bool Type::isEnumeralType() const { - return isa<EnumType>(CanonicalType); -} - -inline bool Type::isAnyComplexType() const { - return isa<ComplexType>(CanonicalType); -} - -inline bool Type::isVectorType() const { - return isa<VectorType>(CanonicalType); -} - -inline bool Type::isExtVectorType() const { - return isa<ExtVectorType>(CanonicalType); -} - -inline bool Type::isExtVectorBoolType() const { - if (!isExtVectorType()) - return false; - return cast<ExtVectorType>(CanonicalType)->getElementType()->isBooleanType(); -} - -inline bool Type::isSubscriptableVectorType() const { - return isVectorType() || isSveVLSBuiltinType(); -} - -inline bool Type::isMatrixType() const { - return isa<MatrixType>(CanonicalType); -} - -inline bool Type::isConstantMatrixType() const { - return isa<ConstantMatrixType>(CanonicalType); -} - -inline bool Type::isDependentAddressSpaceType() const { - return isa<DependentAddressSpaceType>(CanonicalType); -} - -inline bool Type::isObjCObjectPointerType() const { - return isa<ObjCObjectPointerType>(CanonicalType); -} - -inline bool Type::isObjCObjectType() const { - return isa<ObjCObjectType>(CanonicalType); -} - -inline bool Type::isObjCObjectOrInterfaceType() const { - return isa<ObjCInterfaceType>(CanonicalType) || - isa<ObjCObjectType>(CanonicalType); -} - -inline bool Type::isAtomicType() const { - return isa<AtomicType>(CanonicalType); -} - -inline bool Type::isUndeducedAutoType() const { - return isa<AutoType>(CanonicalType); -} - -inline bool Type::isObjCQualifiedIdType() const { - if (const auto *OPT = getAs<ObjCObjectPointerType>()) - return OPT->isObjCQualifiedIdType(); - return false; -} - -inline bool Type::isObjCQualifiedClassType() const { - if (const auto *OPT = getAs<ObjCObjectPointerType>()) - return OPT->isObjCQualifiedClassType(); - return false; -} - -inline bool Type::isObjCIdType() const { - if (const auto *OPT = getAs<ObjCObjectPointerType>()) - return OPT->isObjCIdType(); - return false; -} - -inline bool Type::isObjCClassType() const { - if (const auto *OPT = getAs<ObjCObjectPointerType>()) - return OPT->isObjCClassType(); - return false; -} - -inline bool Type::isObjCSelType() const { - if (const auto *OPT = getAs<PointerType>()) - return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); - return false; -} - -inline bool Type::isObjCBuiltinType() const { - return isObjCIdType() || isObjCClassType() || isObjCSelType(); -} - -inline bool Type::isDecltypeType() const { - return isa<DecltypeType>(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<PipeType>(CanonicalType); -} - -inline bool Type::isBitIntType() const { - return isa<BitIntType>(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<HLSLAttributedResourceType>(this); -} - -inline bool Type::isHLSLInlineSpirvType() const { - return isa<HLSLInlineSpirvType>(this); -} - -inline bool Type::isTemplateTypeParmType() const { - return isa<TemplateTypeParmType>(CanonicalType); -} - -inline bool Type::isSpecificBuiltinType(unsigned K) const { - if (const BuiltinType *BT = getAs<BuiltinType>()) { - return BT->getKind() == static_cast<BuiltinType::Kind>(K); - } - return false; -} - -inline bool Type::isPlaceholderType() const { - if (const auto *BT = dyn_cast<BuiltinType>(this)) - return BT->isPlaceholderType(); - return false; -} - -inline const BuiltinType *Type::getAsPlaceholderType() const { - if (const auto *BT = dyn_cast<BuiltinType>(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<BuiltinType>(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<BuiltinType>(CanonicalType)) - return BT->isInteger(); - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { - // Incomplete enum types are not treated as integer types. - // FIXME: In C++, enum types are never integer types. - return IsEnumDeclComplete(ET->getDecl()) && - !IsEnumDeclScoped(ET->getDecl()); - } - return isBitIntType(); -} - -inline bool Type::isFixedPointType() const { - if (const auto *BT = dyn_cast<BuiltinType>(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<BuiltinType>(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<BuiltinType>(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<BuiltinType>(CanonicalType)) - return BT->getKind() > BuiltinType::Void && - BT->getKind() <= BuiltinType::NullPtr; - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) - // Enums are scalar types, but only if they are defined. Incomplete enums - // are not treated as scalar types. - return IsEnumDeclComplete(ET->getDecl()); - return isa<PointerType>(CanonicalType) || - isa<BlockPointerType>(CanonicalType) || - isa<MemberPointerType>(CanonicalType) || - isa<ComplexType>(CanonicalType) || - isa<ObjCObjectPointerType>(CanonicalType) || - isBitIntType(); -} - -inline bool Type::isIntegralOrEnumerationType() const { - if (const auto *BT = dyn_cast<BuiltinType>(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<EnumType>(CanonicalType)) - return IsEnumDeclComplete(ET->getDecl()); - - return isBitIntType(); -} - -inline bool Type::isBooleanType() const { - if (const auto *BT = dyn_cast<BuiltinType>(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<TypedefType>()) - return true; - if (auto *TST = getAs<TemplateSpecializationType>()) - 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<uint64_t>(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 <typename T> -using TypeIsArrayType = - std::integral_constant<bool, std::is_same<T, ArrayType>::value || - std::is_base_of<ArrayType, T>::value>; - -// Member-template getAs<specific type>'. -template <typename T> const T *Type::getAs() const { - static_assert(!TypeIsArrayType<T>::value, - "ArrayType cannot be used with getAs!"); - - // If this is directly a T type, return it. - if (const auto *Ty = dyn_cast<T>(this)) - return Ty; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<T>(CanonicalType)) - return nullptr; - - // If this is a typedef for the type, strip the typedef off without - // losing all typedef information. - return cast<T>(getUnqualifiedDesugaredType()); -} - -template <typename T> const T *Type::getAsAdjusted() const { - static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!"); - - // If this is directly a T type, return it. - if (const auto *Ty = dyn_cast<T>(this)) - return Ty; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<T>(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<AttributedType>(Ty)) - Ty = A->getModifiedType().getTypePtr(); - else if (const auto *A = dyn_cast<BTFTagAttributedType>(Ty)) - Ty = A->getWrappedType().getTypePtr(); - else if (const auto *A = dyn_cast<HLSLAttributedResourceType>(Ty)) - Ty = A->getWrappedType().getTypePtr(); - else if (const auto *E = dyn_cast<ElaboratedType>(Ty)) - Ty = E->desugar().getTypePtr(); - else if (const auto *P = dyn_cast<ParenType>(Ty)) - Ty = P->desugar().getTypePtr(); - else if (const auto *A = dyn_cast<AdjustedType>(Ty)) - Ty = A->desugar().getTypePtr(); - else if (const auto *M = dyn_cast<MacroQualifiedType>(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<T>(Ty); -} - -inline const ArrayType *Type::getAsArrayTypeUnsafe() const { - // If this is directly an array type, return it. - if (const auto *arr = dyn_cast<ArrayType>(this)) - return arr; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<ArrayType>(CanonicalType)) - return nullptr; - - // If this is a typedef for the type, strip the typedef off without - // losing all typedef information. - return cast<ArrayType>(getUnqualifiedDesugaredType()); -} - -template <typename T> const T *Type::castAs() const { - static_assert(!TypeIsArrayType<T>::value, - "ArrayType cannot be used with castAs!"); - - if (const auto *ty = dyn_cast<T>(this)) return ty; - assert(isa<T>(CanonicalType)); - return cast<T>(getUnqualifiedDesugaredType()); -} - -inline const ArrayType *Type::castAsArrayTypeUnsafe() const { - assert(isa<ArrayType>(CanonicalType)); - if (const auto *arr = dyn_cast<ArrayType>(this)) return arr; - return cast<ArrayType>(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<PointerType>(Adjusted)); -#endif -} - -QualType DecayedType::getPointeeType() const { - QualType Decayed = getDecayedType(); - (void)AttributedType::stripOuterNullability(Decayed); - return cast<PointerType>(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<char> &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<FunctionProtoType>()) - 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 0000000..db2ab04 --- /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 <bitset> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <optional> +#include <string> +#include <type_traits> +#include <utility> + +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 T> class AbstractTypeReader; + template <class T> class AbstractTypeWriter; +} + +} // namespace clang + +namespace llvm { + + template <typename T> + 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 <typename> 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<Type>; + +// 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<uint64_t>(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<LangAS>((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<uint64_t>(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<const Type *,Qualifiers> asPair() const { + return std::pair<const Type *, Qualifiers>(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<llvm::PointerUnion<const Type *, const ExtQuals *>, + Qualifiers::FastWidth> Value; + + const ExtQuals *getExtQualsUnsafe() const { + return cast<const ExtQuals *>(Value.getPointer()); + } + + const Type *getTypePtrUnsafe() const { + return cast<const Type *>(Value.getPointer()); + } + + const ExtQualsTypeCommonBase *getCommonPtr() const { + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + auto CommonPtrVal = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + return reinterpret_cast<ExtQualsTypeCommonBase*>(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<void*>(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<NonConstantStorageReason> + 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<const ExtQuals *>(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<ParenType>(*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<QualType> 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<clang::QualType> { + 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 <class T> 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<TypeDependence>; + + /// 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<Linkage>(CachedLinkage); + } + + bool hasLocalOrUnnamedType() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return CachedLocalOrUnnamed; + } + }; + enum { NumTypeBits = 8 + llvm::BitWidth<TypeDependence> + 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 <class> 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 <class T> 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<unsigned>(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<unsigned>(D); + } + + void addDependence(TypeDependence D) { setDependence(getDependence() | D); } + +public: + friend class ASTReader; + friend class ASTWriter; + template <class T> friend class serialization::AbstractTypeReader; + template <class T> 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<TypeClass>(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<typename ...T> + /// 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<FunctionNoProtoType>(); } + bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } + 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<foo> + bool isObjCQualifiedIdType() const; // id<foo> + bool isObjCQualifiedClassType() const; // Class<foo> + 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 + /// <NSCopying>. + /// + /// \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 <NSCopying>. + /// + /// 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<TypeDependence>(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<AutoType>(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<specific type>'. Look through sugar for + /// an instance of \<specific type>. 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 <typename T> const T *getAs() const; + + /// If this type is canonically the specified type, return its canonical type + /// cast to that specified type, otherwise returns null. + template <typename T> const T *getAsCanonical() const { + return dyn_cast<T>(CanonicalType); + } + + /// Return this type's canonical type cast to the specified type. + /// If the type is not canonically that specified type, the behaviour is + /// undefined. + template <typename T> const T *castAsCanonical() const { + return cast<T>(CanonicalType); + } + +// It is not helpful to use these on types which are never canonical +#define TYPE(Class, Base) +#define NEVER_CANONICAL_TYPE(Class) \ + template <> inline const Class##Type *Type::getAsCanonical() const = delete; \ + template <> inline const Class##Type *Type::castAsCanonical() const = delete; +#include "clang/AST/TypeNodes.inc" + + /// Look through sugar for an instance of TemplateSpecializationType which + /// is not a type alias, or null if there is no such type. + /// This is used when you want as-written template arguments or the template + /// 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<specific type>. Look through specific kinds + /// of sugar (parens, attributes, etc) for an instance of \<specific type>. + /// 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 \<specific type> + /// to another type that is still canonically a \<specific type>. + template <typename T> 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<specific type>. Look through sugar for + /// the underlying instance of \<specific type>. + /// + /// This method has the same relationship to getAs<T> as cast<T> has + /// to dyn_cast<T>; which is to say, the underlying type *must* + /// have the intended type, and this method will never return null. + template <typename T> 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<NullabilityKind> 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<ArrayRef<QualType>> + 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<Class##Type>(CanonicalType); \ + } \ + template <> inline const Class##Type *Type::castAs() const { \ + return cast<Class##Type>(CanonicalType); \ + } +#include "clang/AST/TypeNodes.inc" + +/// This class is used for builtin types like 'int'. Builtin +/// 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<Kind>(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<ValueDecl *, 1, unsigned>; + +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<TypeCoupledDeclRefInfo> 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>; + + 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<TypeCoupledDeclRefInfo> 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<CountAttributedType, + TypeCoupledDeclRefInfo> { + 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<TypeCoupledDeclRefInfo> CoupledDecls); + + unsigned numTrailingObjects(OverloadToken<TypeCoupledDeclRefInfo>) 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<ReferenceType>(); + 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<unsigned>(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<int64_t>(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<typename T, int Size> +/// 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<typename T, int AddrSpace> +/// 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<typename T, int Size> +/// 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<typename T, int Size> +/// 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<uint16_t>(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<ArmStateValue>((AttrBits & SME_ZAMask) >> SME_ZAShift); + } + + static ArmStateValue getArmZT0State(unsigned AttrBits) { + return static_cast<ArmStateValue>((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<size_t>(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<FunctionEffect> + 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 <typename Container> 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<FunctionEffect> Effects; + ArrayRef<EffectConditionExpr> 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<FunctionEffect> FX, + ArrayRef<EffectConditionExpr> 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<FunctionEffect> FX, + ArrayRef<EffectConditionExpr> Conds); + + FunctionEffectsRef() = default; + + bool empty() const { return Effects.empty(); } + size_t size() const { return Effects.size(); } + + ArrayRef<FunctionEffect> effects() const { return Effects; } + ArrayRef<EffectConditionExpr> conditions() const { return Conditions; } + + using iterator = FunctionEffectIterator<FunctionEffectsRef>; + 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<EndBitPos>; + + 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<size_t>(K); + } + + constexpr static FunctionEffect::Kind posToKind(size_t Pos) { + return static_cast<FunctionEffect::Kind>(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<FunctionEffect> Effects; + SmallVector<EffectConditionExpr> 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<FunctionEffectSet>; + 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<Conflict>; + + // 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<QualType> 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<bool>(ExtraAttributeInfo); + } + + void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) { + if (Enable) + AArch64SMEAttributes |= Kind; + else + AArch64SMEAttributes &= ~Kind; + } + }; + +private: + unsigned numTrailingObjects(OverloadToken<QualType>) const { + return getNumParams(); + } + + unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { + return isVariadic(); + } + + unsigned numTrailingObjects(OverloadToken<FunctionTypeArmAttributes>) const { + return hasArmTypeAttributes(); + } + + unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const { + return hasExtraBitfields(); + } + + unsigned + numTrailingObjects(OverloadToken<FunctionTypeExtraAttributeInfo>) const { + return hasExtraAttributeInfo(); + } + + unsigned numTrailingObjects(OverloadToken<ExceptionType>) const { + return getExceptionSpecSize().NumExceptionType; + } + + unsigned numTrailingObjects(OverloadToken<Expr *>) const { + return getExceptionSpecSize().NumExprPtr; + } + + unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const { + return getExceptionSpecSize().NumFunctionDeclPtr; + } + + unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) const { + return hasExtParameterInfos() ? getNumParams() : 0; + } + + unsigned numTrailingObjects(OverloadToken<Qualifiers>) const { + return hasExtQualifiers() ? 1 : 0; + } + + unsigned numTrailingObjects(OverloadToken<FunctionEffect>) 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<QualType> 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<FunctionTypeExtraBitfields>() + ->HasExtraAttributeInfo; + } + + bool hasArmTypeAttributes() const { + return FunctionTypeBits.HasExtraBitfields && + getTrailingObjects<FunctionTypeExtraBitfields>() + ->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<QualType> 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<ExceptionSpecificationType>( + 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<FunctionTypeExtraBitfields>() + ->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<Expr *>(); + } + + /// 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<FunctionDecl *>()[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<FunctionDecl *>()[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>() + : 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<Qualifiers>(); + else + return getFastTypeQuals(); + } + + /// Retrieve the ref-qualifier associated with this function type. + RefQualifierKind getRefQualifier() const { + return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); + } + + using param_type_iterator = const QualType *; + + ArrayRef<QualType> param_types() const { + return {param_type_begin(), param_type_end()}; + } + + param_type_iterator param_type_begin() const { + return getTrailingObjects<QualType>(); + } + + param_type_iterator param_type_end() const { + return param_type_begin() + getNumParams(); + } + + using exception_iterator = const QualType *; + + ArrayRef<QualType> exceptions() const { + return {exception_begin(), exception_end()}; + } + + exception_iterator exception_begin() const { + return reinterpret_cast<exception_iterator>( + getTrailingObjects<ExceptionType>()); + } + + 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<ExtParameterInfo> getExtParameterInfos() const { + assert(hasExtParameterInfos()); + return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(), + 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<ExtParameterInfo>(); + } + + /// Return the extra attribute information. + FunctionTypeExtraAttributeInfo getExtraAttributeInfo() const { + if (hasExtraAttributeInfo()) + return *getTrailingObjects<FunctionTypeExtraAttributeInfo>(); + 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<FunctionTypeArmAttributes>() + ->AArch64SMEAttributes; + } + + ExtParameterInfo getExtParameterInfo(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasExtParameterInfos()) + return getTrailingObjects<ExtParameterInfo>()[I]; + return ExtParameterInfo(); + } + + ParameterABI getParameterABI(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasExtParameterInfos()) + return getTrailingObjects<ExtParameterInfo>()[I].getABI(); + return ParameterABI::Ordinary; + } + + bool isParamConsumed(unsigned I) const { + assert(I < getNumParams() && "parameter index out of range"); + if (hasExtParameterInfos()) + return getTrailingObjects<ExtParameterInfo>()[I].isConsumed(); + return false; + } + + unsigned getNumFunctionEffects() const { + return hasExtraBitfields() + ? getTrailingObjects<FunctionTypeExtraBitfields>() + ->NumFunctionEffects + : 0; + } + + // For serialization. + ArrayRef<FunctionEffect> getFunctionEffectsWithoutConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); + if (Bitfields->NumFunctionEffects > 0) + return getTrailingObjects<FunctionEffect>( + Bitfields->NumFunctionEffects); + } + return {}; + } + + unsigned getNumFunctionEffectConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); + if (Bitfields->EffectsHaveConditions) + return Bitfields->NumFunctionEffects; + } + return 0; + } + + // For serialization. + ArrayRef<EffectConditionExpr> getFunctionEffectConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); + if (Bitfields->EffectsHaveConditions) + return getTrailingObjects<EffectConditionExpr>( + Bitfields->NumFunctionEffects); + } + return {}; + } + + // Combines effects with their conditions. + FunctionEffectsRef getFunctionEffects() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>(); + if (Bitfields->NumFunctionEffects > 0) { + const size_t NumConds = Bitfields->EffectsHaveConditions + ? Bitfields->NumFunctionEffects + : 0; + return FunctionEffectsRef( + getTrailingObjects<FunctionEffect>(Bitfields->NumFunctionEffects), + {NumConds ? getTrailingObjects<EffectConditionExpr>() : 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 T> class KeywordWrapper : public T, public KeywordHelpers { +protected: + template <class... As> + KeywordWrapper(ElaboratedTypeKeyword Keyword, As &&...as) + : T(std::forward<As>(as)...) { + this->KeywordWrapperBits.Keyword = llvm::to_underlying(Keyword); + } + +public: + ElaboratedTypeKeyword getKeyword() const { + return static_cast<ElaboratedTypeKeyword>(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<Type> { +protected: + TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, + QualType Canonical, TypeDependence Dependence) + : KeywordWrapper(Keyword, tc, Canonical, Dependence) {} +}; + +template <class T> 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<const T *>( + reinterpret_cast<const char *>(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<T>::foo; +/// +/// Template instantiation turns these into the underlying type. +class UnresolvedUsingType final + : public TypeWithKeyword, + private llvm::TrailingObjects<UnresolvedUsingType, + FoldingSetPlaceholder<UnresolvedUsingType>, + NestedNameSpecifier> { + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; + + UnresolvedUsingTypenameDecl *Decl; + + unsigned numTrailingObjects( + OverloadToken<FoldingSetPlaceholder<UnresolvedUsingType>>) const { + assert(UnresolvedUsingBits.hasQualifier || + getKeyword() != ElaboratedTypeKeyword::None); + return 1; + } + + FoldingSetPlaceholder<UnresolvedUsingType> *getFoldingSetPlaceholder() { + assert(numTrailingObjects( + OverloadToken<FoldingSetPlaceholder<UnresolvedUsingType>>{}) == + 1); + return getTrailingObjects<FoldingSetPlaceholder<UnresolvedUsingType>>(); + } + + UnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, + const Type *CanonicalType); + +public: + NestedNameSpecifier getQualifier() const { + return UnresolvedUsingBits.hasQualifier + ? *getTrailingObjects<NestedNameSpecifier>() + : 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<UsingType, NestedNameSpecifier> { + 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<TypedefType, + FoldingSetPlaceholder<TypedefType>, + NestedNameSpecifier, QualType> { + TypedefNameDecl *Decl; + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; + + unsigned + numTrailingObjects(OverloadToken<FoldingSetPlaceholder<TypedefType>>) const { + assert(TypedefBits.hasQualifier || TypedefBits.hasTypeDifferentFromDecl || + getKeyword() != ElaboratedTypeKeyword::None); + return 1; + } + + unsigned numTrailingObjects(OverloadToken<NestedNameSpecifier>) const { + return TypedefBits.hasQualifier; + } + + TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TypedefNameDecl *D, + QualType UnderlyingType, bool HasTypeDifferentFromDecl); + + FoldingSetPlaceholder<TypedefType> *getFoldingSetPlaceholder() { + assert(numTrailingObjects( + OverloadToken<FoldingSetPlaceholder<TypedefType>>{}) == 1); + return getTrailingObjects<FoldingSetPlaceholder<TypedefType>>(); + } + +public: + NestedNameSpecifier getQualifier() const { + return TypedefBits.hasQualifier ? *getTrailingObjects<NestedNameSpecifier>() + : 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<AttributedType>(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<TypeOfKind>(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<TypeOfKind>(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<PackIndexingType, QualType> { + 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<QualType> 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<QualType> 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<QualType> Expansions); + +private: + const QualType *getExpansionsPtr() const { return getTrailingObjects(); } + + static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr, + ArrayRef<QualType> 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<TemplateArgument> 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<TagType *>(reinterpret_cast<char *>(this + 1) + + getOffset()); + } + const TagType *getTagType() const { + return const_cast<TagTypeFoldingSetPlaceholder *>(this)->getTagType(); + } + static TagTypeFoldingSetPlaceholder *fromTagType(TagType *T) { + return reinterpret_cast<TagTypeFoldingSetPlaceholder *>( + reinterpret_cast<char *>(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<RecordDecl *>(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<EnumDecl *>(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<CXXRecordDecl *>(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<Kind>(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<NullabilityKind> 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<NullabilityKind> 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<uint32_t>(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<HLSLInlineSpirvType, SpirvOperand> { + 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<SpirvOperand> 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<SpirvOperand> 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<SpirvOperand> 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<SubstTemplateTypeParmType, QualType> { + friend class ASTContext; + friend class llvm::TrailingObjects<SubstTemplateTypeParmType, QualType>; + + 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<Decl *, 1, bool> 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<TemplateArgument> TypeConstraintArgs); + +public: + ArrayRef<TemplateArgument> getTypeConstraintArguments() const { + return {reinterpret_cast<const TemplateArgument *>(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<TemplateArgument> Arguments); + + static bool classof(const Type *T) { + return T->getTypeClass() == Auto; + } +}; + +/// Represents a C++17 deduced template specialization type. +class DeducedTemplateSpecializationType : public KeywordWrapper<DeducedType>, + 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<int> will refer to a tag type for +/// the instantiation \c std::vector<int, std::allocator<int>> +/// +/// 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<TemplateArgument> 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<TemplateArgumentLoc> Args, + ArrayRef<TemplateArgument> Converted); + static bool + anyDependentTemplateArguments(const TemplateArgumentListInfo &, + ArrayRef<TemplateArgument> Converted); + static bool anyInstantiationDependentTemplateArguments( + ArrayRef<TemplateArgumentLoc> Args); + + /// True if this template specialization type matches a current + /// instantiation in the context in which it is found. + bool isCurrentInstantiation() const { + return isa<InjectedClassNameType>(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<typename T, typename U, typename V> struct S; + /// template<typename T, typename U> using A = S<T, int, U>; + /// template<typename... Ts> struct X { + /// typedef A<Ts...> 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<TemplateArgument> template_arguments() const { + return {reinterpret_cast<const TemplateArgument *>(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<TemplateArgument> 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<TemplateArgument> Args, + const PrintingPolicy &Policy, + const TemplateParameterList *TPL = nullptr); + +void printTemplateArgumentList(raw_ostream &OS, + ArrayRef<TemplateArgumentLoc> 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<TemplateArgument> 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<T>::template B<T> +class DependentTemplateSpecializationType : public TypeWithKeyword { + friend class ASTContext; // ASTContext creates these + + DependentTemplateStorage Name; + + DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + const DependentTemplateStorage &Name, + ArrayRef<TemplateArgument> Args, + QualType Canon); + +public: + const DependentTemplateStorage &getDependentTemplateName() const { + return Name; + } + + ArrayRef<TemplateArgument> template_arguments() const { + return {reinterpret_cast<const TemplateArgument *>(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<TemplateArgument> 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<typename ...Types> struct tuple; +/// +/// template<typename ...Types> +/// struct tuple_of_references { +/// typedef tuple<Types&...> 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 T> +class ObjCProtocolQualifiers { +protected: + ObjCProtocolQualifiers() = default; + + ObjCProtocolDecl * const *getProtocolStorage() const { + return const_cast<ObjCProtocolQualifiers*>(this)->getProtocolStorage(); + } + + ObjCProtocolDecl **getProtocolStorage() { + return static_cast<T*>(this)->getProtocolStorageImpl(); + } + + void setNumProtocols(unsigned N) { + static_cast<T*>(this)->setNumProtocolsImpl(N); + } + + void initialize(ArrayRef<ObjCProtocolDecl *> 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_iterator>; + + 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<const T*>(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<ObjCProtocolDecl *> getProtocols() const { + return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols()); + } +}; + +/// Represents a type parameter type in Objective C. It can take +/// a list of protocols. +class ObjCTypeParamType : public Type, + public ObjCProtocolQualifiers<ObjCTypeParamType>, + public llvm::FoldingSetNode { + friend class ASTContext; + friend class ObjCProtocolQualifiers<ObjCTypeParamType>; + + /// 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<ObjCProtocolDecl *> 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<ObjCProtocolDecl *> 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<T>; +/// \@protocol P; +/// \endcode +/// +/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType +/// with base C and no protocols. +/// +/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P]. +/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no +/// protocol list. +/// 'C<C*><P>' 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<P>' 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<ObjCObjectType> { + friend class ObjCProtocolQualifiers<ObjCObjectType>; + + // 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<const ObjCObjectType *, 1, bool> + CachedSuperClassType; + + QualType *getTypeArgStorage(); + const QualType *getTypeArgStorage() const { + return const_cast<ObjCObjectType *>(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<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> 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<BuiltinType>()) + 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<QualType> getTypeArgs() const; + + /// Retrieve the type arguments of this object type as they were + /// written. + ArrayRef<QualType> 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<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf) + : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols, + bool isKindOf); +}; + +inline QualType *ObjCObjectType::getTypeArgStorage() { + return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1); +} + +inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { + return reinterpret_cast<ObjCProtocolDecl**>( + getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); +} + +inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { + return reinterpret_cast<ObjCProtocolDecl**>( + static_cast<ObjCTypeParamType*>(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<NSCopyable, NSAmazing>`. +/// +/// 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 <class T> friend class serialization::AbstractTypeReader; + + ObjCInterfaceDecl *Decl; + + ObjCInterfaceType(const ObjCInterfaceDecl *D) + : ObjCObjectType(Nonce_ObjCInterface), + Decl(const_cast<ObjCInterfaceDecl*>(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<ObjCObjectType>()) { + if (const auto *T = dyn_cast<ObjCInterfaceType>(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<P>' +/// and 'Class<P>' 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<P> AP; + /// typedef A A1; + /// typedef A1<P> A1P; + /// typedef A1P<Q> A1PQ; + /// \endcode + /// For 'A*', getObjectType() will return 'A'. + /// For 'A<P>*', getObjectType() will return 'A<P>'. + /// For 'AP*', getObjectType() will return 'A<P>'. + /// For 'A1*', getObjectType() will return 'A'. + /// For 'A1<P>*', getObjectType() will return 'A1<P>'. + /// For 'A1P*', getObjectType() will return 'A1<P>'. + /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because + /// adding protocols to a protocol-qualified base discards the + /// old qualifiers (for now). But if it didn't, getObjectType() + /// would return 'A1P<Q>' (and we'd have to make iterating over + /// qualifiers more complicated). + const ObjCObjectType *getObjectType() const { + return PointeeType->castAs<ObjCObjectType>(); + } + + /// 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<P>' for some non-empty set of + /// protocols. + bool isObjCQualifiedIdType() const { + return getObjectType()->isObjCQualifiedId(); + } + + /// True if this is equivalent to 'Class<P>' 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<QualType> getTypeArgs() const { + return getObjectType()->getTypeArgs(); + } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> 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_iterator>; + + 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<Expr*, 1, bool> 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<FunctionProtoType>()) + 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<FunctionType>(T) && + (!isa<ArrayType>(T) || isa<ArrayParameterType>(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<PointerType>()) { + if (const auto *FT = PT->getPointeeType()->getAs<FunctionType>()) + return FT->getExtInfo(); + } else if (const auto *FT = t.getAs<FunctionType>()) + 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<ReferenceType>()) + 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<FunctionType>(CanonicalType); +} + +inline bool Type::isPointerType() const { + return isa<PointerType>(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<BlockPointerType>(CanonicalType); +} + +inline bool Type::isReferenceType() const { + return isa<ReferenceType>(CanonicalType); +} + +inline bool Type::isLValueReferenceType() const { + return isa<LValueReferenceType>(CanonicalType); +} + +inline bool Type::isRValueReferenceType() const { + return isa<RValueReferenceType>(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<PointerType>()) + return !T->getPointeeType()->isFunctionType(); + else + return false; +} + +inline bool Type::isCFIUncheckedCalleeFunctionType() const { + if (const auto *Fn = getAs<FunctionProtoType>()) + return Fn->hasCFIUncheckedCallee(); + return false; +} + +inline bool Type::hasPointeeToToCFIUncheckedCalleeFunctionType() const { + QualType Pointee; + if (const auto *PT = getAs<PointerType>()) + Pointee = PT->getPointeeType(); + else if (const auto *RT = getAs<ReferenceType>()) + Pointee = RT->getPointeeType(); + else if (const auto *MPT = getAs<MemberPointerType>()) + Pointee = MPT->getPointeeType(); + else if (const auto *DT = getAs<DecayedType>()) + Pointee = DT->getPointeeType(); + else + return false; + return Pointee->isCFIUncheckedCalleeFunctionType(); +} + +inline bool Type::isFunctionPointerType() const { + if (const auto *T = getAs<PointerType>()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} + +inline bool Type::isFunctionReferenceType() const { + if (const auto *T = getAs<ReferenceType>()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} + +inline bool Type::isMemberPointerType() const { + return isa<MemberPointerType>(CanonicalType); +} + +inline bool Type::isMemberFunctionPointerType() const { + if (const auto *T = getAs<MemberPointerType>()) + return T->isMemberFunctionPointer(); + else + return false; +} + +inline bool Type::isMemberDataPointerType() const { + if (const auto *T = getAs<MemberPointerType>()) + return T->isMemberDataPointer(); + else + return false; +} + +inline bool Type::isArrayType() const { + return isa<ArrayType>(CanonicalType); +} + +inline bool Type::isConstantArrayType() const { + return isa<ConstantArrayType>(CanonicalType); +} + +inline bool Type::isIncompleteArrayType() const { + return isa<IncompleteArrayType>(CanonicalType); +} + +inline bool Type::isVariableArrayType() const { + return isa<VariableArrayType>(CanonicalType); +} + +inline bool Type::isArrayParameterType() const { + return isa<ArrayParameterType>(CanonicalType); +} + +inline bool Type::isDependentSizedArrayType() const { + return isa<DependentSizedArrayType>(CanonicalType); +} + +inline bool Type::isBuiltinType() const { + return isa<BuiltinType>(CanonicalType); +} + +inline bool Type::isRecordType() const { + return isa<RecordType>(CanonicalType); +} + +inline bool Type::isEnumeralType() const { + return isa<EnumType>(CanonicalType); +} + +inline bool Type::isAnyComplexType() const { + return isa<ComplexType>(CanonicalType); +} + +inline bool Type::isVectorType() const { + return isa<VectorType>(CanonicalType); +} + +inline bool Type::isExtVectorType() const { + return isa<ExtVectorType>(CanonicalType); +} + +inline bool Type::isExtVectorBoolType() const { + if (!isExtVectorType()) + return false; + return cast<ExtVectorType>(CanonicalType)->getElementType()->isBooleanType(); +} + +inline bool Type::isSubscriptableVectorType() const { + return isVectorType() || isSveVLSBuiltinType(); +} + +inline bool Type::isMatrixType() const { + return isa<MatrixType>(CanonicalType); +} + +inline bool Type::isConstantMatrixType() const { + return isa<ConstantMatrixType>(CanonicalType); +} + +inline bool Type::isDependentAddressSpaceType() const { + return isa<DependentAddressSpaceType>(CanonicalType); +} + +inline bool Type::isObjCObjectPointerType() const { + return isa<ObjCObjectPointerType>(CanonicalType); +} + +inline bool Type::isObjCObjectType() const { + return isa<ObjCObjectType>(CanonicalType); +} + +inline bool Type::isObjCObjectOrInterfaceType() const { + return isa<ObjCInterfaceType>(CanonicalType) || + isa<ObjCObjectType>(CanonicalType); +} + +inline bool Type::isAtomicType() const { + return isa<AtomicType>(CanonicalType); +} + +inline bool Type::isUndeducedAutoType() const { + return isa<AutoType>(CanonicalType); +} + +inline bool Type::isObjCQualifiedIdType() const { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedIdType(); + return false; +} + +inline bool Type::isObjCQualifiedClassType() const { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedClassType(); + return false; +} + +inline bool Type::isObjCIdType() const { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCIdType(); + return false; +} + +inline bool Type::isObjCClassType() const { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCClassType(); + return false; +} + +inline bool Type::isObjCSelType() const { + if (const auto *OPT = getAs<PointerType>()) + return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); + return false; +} + +inline bool Type::isObjCBuiltinType() const { + return isObjCIdType() || isObjCClassType() || isObjCSelType(); +} + +inline bool Type::isDecltypeType() const { + return isa<DecltypeType>(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<PipeType>(CanonicalType); +} + +inline bool Type::isBitIntType() const { + return isa<BitIntType>(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<HLSLAttributedResourceType>(this); +} + +inline bool Type::isHLSLInlineSpirvType() const { + return isa<HLSLInlineSpirvType>(this); +} + +inline bool Type::isTemplateTypeParmType() const { + return isa<TemplateTypeParmType>(CanonicalType); +} + +inline bool Type::isSpecificBuiltinType(unsigned K) const { + if (const BuiltinType *BT = getAs<BuiltinType>()) { + return BT->getKind() == static_cast<BuiltinType::Kind>(K); + } + return false; +} + +inline bool Type::isPlaceholderType() const { + if (const auto *BT = dyn_cast<BuiltinType>(this)) + return BT->isPlaceholderType(); + return false; +} + +inline const BuiltinType *Type::getAsPlaceholderType() const { + if (const auto *BT = dyn_cast<BuiltinType>(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<BuiltinType>(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<BuiltinType>(CanonicalType)) + return BT->isInteger(); + if (const EnumType *ET = dyn_cast<EnumType>(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<BuiltinType>(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<BuiltinType>(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<BuiltinType>(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<BuiltinType>(CanonicalType)) + return BT->getKind() > BuiltinType::Void && + BT->getKind() <= BuiltinType::NullPtr; + if (const EnumType *ET = dyn_cast<EnumType>(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<PointerType>(CanonicalType) || + isa<BlockPointerType>(CanonicalType) || + isa<MemberPointerType>(CanonicalType) || + isa<ComplexType>(CanonicalType) || + isa<ObjCObjectPointerType>(CanonicalType) || + isBitIntType(); +} + +inline bool Type::isIntegralOrEnumerationType() const { + if (const auto *BT = dyn_cast<BuiltinType>(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<EnumType>(CanonicalType)) + return IsEnumDeclComplete(ET->getOriginalDecl()); + + return isBitIntType(); +} + +inline bool Type::isBooleanType() const { + if (const auto *BT = dyn_cast<BuiltinType>(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<TypedefType>()) + return true; + if (auto *TST = getAs<TemplateSpecializationType>()) + 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<uint64_t>(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 <typename T> +using TypeIsArrayType = + std::integral_constant<bool, std::is_same<T, ArrayType>::value || + std::is_base_of<ArrayType, T>::value>; + +// Member-template getAs<specific type>'. +template <typename T> const T *Type::getAs() const { + static_assert(!TypeIsArrayType<T>::value, + "ArrayType cannot be used with getAs!"); + + // If this is directly a T type, return it. + if (const auto *Ty = dyn_cast<T>(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<T>(CanonicalType)) + return nullptr; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<T>(getUnqualifiedDesugaredType()); +} + +template <typename T> const T *Type::getAsAdjusted() const { + static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!"); + + // If this is directly a T type, return it. + if (const auto *Ty = dyn_cast<T>(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<T>(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<AttributedType>(Ty)) + Ty = A->getModifiedType().getTypePtr(); + else if (const auto *A = dyn_cast<BTFTagAttributedType>(Ty)) + Ty = A->getWrappedType().getTypePtr(); + else if (const auto *A = dyn_cast<HLSLAttributedResourceType>(Ty)) + Ty = A->getWrappedType().getTypePtr(); + else if (const auto *P = dyn_cast<ParenType>(Ty)) + Ty = P->desugar().getTypePtr(); + else if (const auto *A = dyn_cast<AdjustedType>(Ty)) + Ty = A->desugar().getTypePtr(); + else if (const auto *M = dyn_cast<MacroQualifiedType>(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<T>(Ty); +} + +inline const ArrayType *Type::getAsArrayTypeUnsafe() const { + // If this is directly an array type, return it. + if (const auto *arr = dyn_cast<ArrayType>(this)) + return arr; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) + return nullptr; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + +template <typename T> const T *Type::castAs() const { + static_assert(!TypeIsArrayType<T>::value, + "ArrayType cannot be used with castAs!"); + + if (const auto *ty = dyn_cast<T>(this)) return ty; + assert(isa<T>(CanonicalType)); + return cast<T>(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::castAsArrayTypeUnsafe() const { + assert(isa<ArrayType>(CanonicalType)); + if (const auto *arr = dyn_cast<ArrayType>(this)) return arr; + return cast<ArrayType>(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<PointerType>(Adjusted)); +#endif +} + +QualType DecayedType::getPointeeType() const { + QualType Decayed = getDecayedType(); + (void)AttributedType::stripOuterNullability(Decayed); + return cast<PointerType>(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<char> &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<FunctionProtoType>()) + 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 52ef7ac..d52e104 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -16,9 +16,9 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/DeclarationName.h" -#include "clang/AST/NestedNameSpecifier.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" @@ -193,6 +193,21 @@ public: /// Get the SourceLocation of the template keyword (if any). SourceLocation getTemplateKeywordLoc() const; + /// If this type represents a qualified-id, this returns it's 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. + NestedNameSpecifierLoc getPrefix() const; + + /// This returns the position of the type after any elaboration, such as the + /// 'struct' keyword, and name qualifiers. This will the 'template' keyword if + /// present, or the name location otherwise. + SourceLocation getNonPrefixBeginLoc() const; + + /// This returns the position of the type after any elaboration, such as the + /// 'struct' keyword. This may be the position of the name qualifiers, + /// 'template' keyword, or the name location otherwise. + SourceLocation getNonElaboratedBeginLoc() const; + /// Initializes this to state that every location in this /// type is the given location. /// @@ -679,62 +694,164 @@ public: } }; -/// Wrapper for source info for types used via transparent aliases. -class UsingTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - UsingTypeLoc, UsingType> { -public: - QualType getUnderlyingType() const { - return getTypePtr()->getUnderlyingType(); +struct ElaboratedNameLocInfo { + SourceLocation NameLoc; + SourceLocation ElaboratedKeywordLoc; + + ElaboratedNameLocInfo() = default; + ElaboratedNameLocInfo(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation NameLoc) + : NameLoc(NameLoc), ElaboratedKeywordLoc(ElaboratedKeywordLoc), + QualifierData(QualifierLoc.getOpaqueData()) {} + ElaboratedNameLocInfo(ASTContext &Context, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, SourceLocation Loc) + : NameLoc(Loc), + ElaboratedKeywordLoc( + Keyword != ElaboratedTypeKeyword::None ? Loc : SourceLocation()), + QualifierData(getTrivialQualifierData(Context, Qualifier, Loc)) {} + + NestedNameSpecifierLoc getQualifierLoc(NestedNameSpecifier Qualifier) const { + assert(!Qualifier == !QualifierData); + return NestedNameSpecifierLoc(Qualifier, QualifierData); + } + + SourceRange getLocalSourceRange(NestedNameSpecifier Qualifier) const { + SourceLocation BeginLoc = ElaboratedKeywordLoc; + if (NestedNameSpecifierLoc QualifierLoc = getQualifierLoc(Qualifier); + BeginLoc.isInvalid() && Qualifier) + BeginLoc = QualifierLoc.getBeginLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = NameLoc; + return SourceRange(BeginLoc, NameLoc); } - UsingShadowDecl *getFoundDecl() const { return getTypePtr()->getFoundDecl(); } -}; -/// Wrapper for source info for typedefs. -class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - TypedefTypeLoc, - TypedefType> { -public: - TypedefNameDecl *getTypedefNameDecl() const { - return getTypePtr()->getDecl(); +private: + void *QualifierData; + + static void *getTrivialQualifierData(ASTContext &Context, + NestedNameSpecifier Qualifier, + SourceLocation Loc) { + if (!Qualifier) + return nullptr; + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + return Builder.getWithLocInContext(Context).getOpaqueData(); } }; -/// Wrapper for source info for injected class names of class -/// templates. -class InjectedClassNameTypeLoc : - public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - InjectedClassNameTypeLoc, - InjectedClassNameType> { +template <class TL, class T> +class ElaboratedNameTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, TL, T, ElaboratedNameLocInfo> { public: - CXXRecordDecl *getDecl() const { - return getTypePtr()->getDecl(); + auto *getDecl() const { return this->getTypePtr()->getDecl(); } + + void set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation NameLoc) { + assert(QualifierLoc.getNestedNameSpecifier() == + this->getTypePtr()->getQualifier()); + *this->getLocalData() = + ElaboratedNameLocInfo(ElaboratedKeywordLoc, QualifierLoc, NameLoc); + } + + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKeywordLoc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + return this->getLocalData()->getQualifierLoc( + this->getTypePtr()->getQualifier()); + } + + SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; } + + SourceRange getLocalSourceRange() const { + return this->getLocalData()->getLocalSourceRange( + this->getTypePtr()->getQualifier()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + const auto *Ptr = this->getTypePtr(); + *this->getLocalData() = ElaboratedNameLocInfo(Context, Ptr->getKeyword(), + Ptr->getQualifier(), Loc); } }; +/// Wrapper for source info for typedefs. +class TypedefTypeLoc + : public ElaboratedNameTypeLoc<TypedefTypeLoc, TypedefType> {}; + /// Wrapper for source info for unresolved typename using decls. -class UnresolvedUsingTypeLoc : - public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - UnresolvedUsingTypeLoc, - UnresolvedUsingType> { -public: - UnresolvedUsingTypenameDecl *getDecl() const { - return getTypePtr()->getDecl(); - } +class UnresolvedUsingTypeLoc + : public ElaboratedNameTypeLoc<UnresolvedUsingTypeLoc, + UnresolvedUsingType> {}; + +/// Wrapper for source info for types used via transparent aliases. +class UsingTypeLoc : public ElaboratedNameTypeLoc<UsingTypeLoc, UsingType> {}; + +struct TagTypeLocInfo { + SourceLocation NameLoc; + SourceLocation ElaboratedKWLoc; + void *QualifierData; }; -/// Wrapper for source info for tag types. Note that this only -/// records source info for the name itself; a type written 'struct foo' -/// should be represented as an ElaboratedTypeLoc. We currently -/// only do that when C++ is enabled because of the expense of -/// creating an ElaboratedType node for so many type references in C. -class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - TagTypeLoc, - TagType> { +class TagTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, TagTypeLoc, TagType, + TagTypeLocInfo> { public: - TagDecl *getDecl() const { return getTypePtr()->getDecl(); } + TagDecl *getOriginalDecl() const { return getTypePtr()->getOriginalDecl(); } /// True if the tag was defined in this type specifier. bool isDefinition() const; + + SourceLocation getElaboratedKeywordLoc() const { + return getLocalData()->ElaboratedKWLoc; + } + + void setElaboratedKeywordLoc(SourceLocation Loc) { + getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + NestedNameSpecifier Qualifier = getTypePtr()->getQualifier(); + void *QualifierData = getLocalData()->QualifierData; + assert(!Qualifier == !QualifierData); + return NestedNameSpecifierLoc(Qualifier, QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr()->getQualifier()); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceLocation getNameLoc() const { return getLocalData()->NameLoc; } + + void setNameLoc(SourceLocation Loc) { getLocalData()->NameLoc = Loc; } + + SourceRange getLocalSourceRange() const { + SourceLocation BeginLoc = getElaboratedKeywordLoc(); + if (NestedNameSpecifierLoc Qualifier = getQualifierLoc(); + BeginLoc.isInvalid() && Qualifier) + BeginLoc = Qualifier.getBeginLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = getNameLoc(); + return SourceRange(BeginLoc, getNameLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setElaboratedKeywordLoc(getTypePtr()->getKeyword() != + ElaboratedTypeKeyword::None + ? Loc + : SourceLocation()); + if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + } else { + getLocalData()->QualifierData = nullptr; + } + setNameLoc(Loc); + } }; /// Wrapper for source info for record types. @@ -742,7 +859,9 @@ class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, RecordTypeLoc, RecordType> { public: - RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } + RecordDecl *getOriginalDecl() const { + return getTypePtr()->getOriginalDecl(); + } }; /// Wrapper for source info for enum types. @@ -750,7 +869,18 @@ class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, EnumTypeLoc, EnumType> { public: - EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } + EnumDecl *getOriginalDecl() const { return getTypePtr()->getOriginalDecl(); } +}; + +/// Wrapper for source info for injected class names of class +/// templates. +class InjectedClassNameTypeLoc + : public InheritingConcreteTypeLoc<TagTypeLoc, InjectedClassNameTypeLoc, + InjectedClassNameType> { +public: + CXXRecordDecl *getOriginalDecl() const { + return getTypePtr()->getOriginalDecl(); + } }; /// Wrapper for template type parameters. @@ -859,12 +989,22 @@ class SubstTemplateTypeParmTypeLoc : SubstTemplateTypeParmType> { }; - /// Wrapper for substituted template type parameters. -class SubstTemplateTypeParmPackTypeLoc : - public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - SubstTemplateTypeParmPackTypeLoc, - SubstTemplateTypeParmPackType> { -}; +/// Abstract type representing delayed type pack expansions. +class SubstPackTypeLoc + : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, SubstPackTypeLoc, + SubstPackType> {}; + +/// Wrapper for substituted template type parameters. +class SubstTemplateTypeParmPackTypeLoc + : public InheritingConcreteTypeLoc<SubstPackTypeLoc, + SubstTemplateTypeParmPackTypeLoc, + SubstTemplateTypeParmPackType> {}; + +/// Wrapper for substituted template type parameters. +class SubstBuiltinTemplatePackTypeLoc + : public InheritingConcreteTypeLoc<SubstPackTypeLoc, + SubstBuiltinTemplatePackTypeLoc, + SubstBuiltinTemplatePackType> {}; struct AttributedLocInfo { const Attr *TypeAttr; @@ -1405,7 +1545,7 @@ public: void initializeLocal(ASTContext &Context, SourceLocation Loc) { setSigilLoc(Loc); - if (auto *Qualifier = getTypePtr()->getQualifier()) { + if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) { NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, Qualifier, Loc); setQualifierLoc(Builder.getWithLocInContext(Context)); @@ -1701,9 +1841,11 @@ struct TemplateNameLocInfo { }; struct TemplateSpecializationLocInfo : TemplateNameLocInfo { + SourceRange SR; + SourceLocation ElaboratedKWLoc; SourceLocation TemplateKWLoc; SourceLocation LAngleLoc; - SourceLocation RAngleLoc; + void *QualifierData; }; class TemplateSpecializationTypeLoc : @@ -1712,54 +1854,52 @@ class TemplateSpecializationTypeLoc : TemplateSpecializationType, TemplateSpecializationLocInfo> { public: - SourceLocation getTemplateKeywordLoc() const { - return getLocalData()->TemplateKWLoc; - } + void set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, SourceLocation NameLoc, + SourceLocation LAngleLoc, SourceLocation RAngleLoc); - void setTemplateKeywordLoc(SourceLocation Loc) { - getLocalData()->TemplateKWLoc = Loc; - } + void set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, SourceLocation NameLoc, + const TemplateArgumentListInfo &TAL); - SourceLocation getLAngleLoc() const { - return getLocalData()->LAngleLoc; + SourceLocation getElaboratedKeywordLoc() const { + return getLocalData()->ElaboratedKWLoc; } - void setLAngleLoc(SourceLocation Loc) { - getLocalData()->LAngleLoc = Loc; - } + NestedNameSpecifierLoc getQualifierLoc() const { + if (!getLocalData()->QualifierData) + return NestedNameSpecifierLoc(); - SourceLocation getRAngleLoc() const { - return getLocalData()->RAngleLoc; + NestedNameSpecifier Qualifier = + getTypePtr()->getTemplateName().getQualifier(); + assert(Qualifier && "missing qualification"); + return NestedNameSpecifierLoc(Qualifier, getLocalData()->QualifierData); } - void setRAngleLoc(SourceLocation Loc) { - getLocalData()->RAngleLoc = Loc; + SourceLocation getTemplateKeywordLoc() const { + return getLocalData()->TemplateKWLoc; } + SourceLocation getTemplateNameLoc() const { return getLocalData()->NameLoc; } + + SourceLocation getLAngleLoc() const { return getLocalData()->LAngleLoc; } + unsigned getNumArgs() const { return getTypePtr()->template_arguments().size(); } - void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { - getArgInfos()[i] = AI; - } - - TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { - return getArgInfos()[i]; + MutableArrayRef<TemplateArgumentLocInfo> getArgLocInfos() { + return {getArgInfos(), getNumArgs()}; } TemplateArgumentLoc getArgLoc(unsigned i) const { return TemplateArgumentLoc(getTypePtr()->template_arguments()[i], - getArgLocInfo(i)); - } - - SourceLocation getTemplateNameLoc() const { - return getLocalData()->NameLoc; + getArgInfos()[i]); } - void setTemplateNameLoc(SourceLocation Loc) { - getLocalData()->NameLoc = Loc; - } + SourceLocation getRAngleLoc() const { return getLocalData()->SR.getEnd(); } /// - Copy the location information from the given info. void copy(TemplateSpecializationTypeLoc Loc) { @@ -1773,21 +1913,9 @@ public: memcpy(Data, Loc.Data, size); } - SourceRange getLocalSourceRange() const { - if (getTemplateKeywordLoc().isValid()) - return SourceRange(getTemplateKeywordLoc(), getRAngleLoc()); - else - return SourceRange(getTemplateNameLoc(), getRAngleLoc()); - } + SourceRange getLocalSourceRange() const { return getLocalData()->SR; } - void initializeLocal(ASTContext &Context, SourceLocation Loc) { - setTemplateKeywordLoc(SourceLocation()); - setTemplateNameLoc(Loc); - setLAngleLoc(Loc); - setRAngleLoc(Loc); - initializeArgLocs(Context, getTypePtr()->template_arguments(), - getArgInfos(), Loc); - } + void initializeLocal(ASTContext &Context, SourceLocation Loc); static void initializeArgLocs(ASTContext &Context, ArrayRef<TemplateArgument> Args, @@ -2346,99 +2474,73 @@ public: void initializeLocal(ASTContext &Context, SourceLocation Loc); }; -class DeducedTemplateSpecializationTypeLoc - : public InheritingConcreteTypeLoc<DeducedTypeLoc, - DeducedTemplateSpecializationTypeLoc, - DeducedTemplateSpecializationType> { -public: - SourceLocation getTemplateNameLoc() const { - return getNameLoc(); - } - - void setTemplateNameLoc(SourceLocation Loc) { - setNameLoc(Loc); - } -}; - -struct ElaboratedLocInfo { +struct DeducedTemplateSpecializationLocInfo : TypeSpecLocInfo { SourceLocation ElaboratedKWLoc; - /// Data associated with the nested-name-specifier location. void *QualifierData; }; -class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, - ElaboratedTypeLoc, - ElaboratedType, - ElaboratedLocInfo> { +class DeducedTemplateSpecializationTypeLoc + : public ConcreteTypeLoc<DeducedTypeLoc, + DeducedTemplateSpecializationTypeLoc, + DeducedTemplateSpecializationType, + DeducedTemplateSpecializationLocInfo> { public: SourceLocation getElaboratedKeywordLoc() const { - return !isEmpty() ? getLocalData()->ElaboratedKWLoc : SourceLocation(); + return getLocalData()->ElaboratedKWLoc; } void setElaboratedKeywordLoc(SourceLocation Loc) { - if (isEmpty()) { - assert(Loc.isInvalid()); - return; - } getLocalData()->ElaboratedKWLoc = Loc; } + SourceLocation getTemplateNameLoc() const { return getNameLoc(); } + + void setTemplateNameLoc(SourceLocation Loc) { setNameLoc(Loc); } + NestedNameSpecifierLoc getQualifierLoc() const { - return !isEmpty() ? NestedNameSpecifierLoc(getTypePtr()->getQualifier(), - getLocalData()->QualifierData) - : NestedNameSpecifierLoc(); + void *Data = getLocalData()->QualifierData; + if (!Data) + return NestedNameSpecifierLoc(); + NestedNameSpecifier Qualifier = + getTypePtr()->getTemplateName().getQualifier(); + assert(Qualifier && "missing qualification"); + return NestedNameSpecifierLoc(Qualifier, Data); } void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { - assert(QualifierLoc.getNestedNameSpecifier() == - getTypePtr()->getQualifier() && - "Inconsistent nested-name-specifier pointer"); - if (isEmpty()) { - assert(!QualifierLoc.hasQualifier()); + if (!QualifierLoc) { + // Even if we have a nested-name-specifier in the dependent + // template specialization type, we won't record the nested-name-specifier + // location information when this type-source location information is + // part of a nested-name-specifier. + getLocalData()->QualifierData = nullptr; return; } + + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr()->getTemplateName().getQualifier() && + "Inconsistent nested-name-specifier pointer"); getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); } SourceRange getLocalSourceRange() const { - if (getElaboratedKeywordLoc().isValid()) - if (getQualifierLoc()) - return SourceRange(getElaboratedKeywordLoc(), - getQualifierLoc().getEndLoc()); - else - return SourceRange(getElaboratedKeywordLoc()); - else - return getQualifierLoc().getSourceRange(); + SourceLocation BeginLoc = getElaboratedKeywordLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = getQualifierLoc().getBeginLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = getNameLoc(); + return {BeginLoc, getNameLoc()}; } void initializeLocal(ASTContext &Context, SourceLocation Loc); +}; - TypeLoc getNamedTypeLoc() const { return getInnerTypeLoc(); } - - QualType getInnerType() const { return getTypePtr()->getNamedType(); } - - bool isEmpty() const { - return getTypePtr()->getKeyword() == ElaboratedTypeKeyword::None && - !getTypePtr()->getQualifier(); - } - - unsigned getLocalDataAlignment() const { - // FIXME: We want to return 1 here in the empty case, but - // there are bugs in how alignment is handled in TypeLocs - // that prevent this from working. - return ConcreteTypeLoc::getLocalDataAlignment(); - } - - unsigned getLocalDataSize() const { - return !isEmpty() ? ConcreteTypeLoc::getLocalDataSize() : 0; - } +struct ElaboratedLocInfo { + SourceLocation ElaboratedKWLoc; - void copy(ElaboratedTypeLoc Loc) { - unsigned size = getFullDataSize(); - assert(size == Loc.getFullDataSize()); - memcpy(Data, Loc.Data, size); - } + /// Data associated with the nested-name-specifier location. + void *QualifierData; }; // This is exactly the structure of an ElaboratedTypeLoc whose inner @@ -2749,8 +2851,6 @@ inline T TypeLoc::getAsAdjusted() const { Cur = ATL.getWrappedLoc(); else if (auto ATL = Cur.getAs<HLSLAttributedResourceTypeLoc>()) Cur = ATL.getWrappedLoc(); - else if (auto ETL = Cur.getAs<ElaboratedTypeLoc>()) - Cur = ETL.getNamedTypeLoc(); else if (auto ATL = Cur.getAs<AdjustedTypeLoc>()) Cur = ATL.getOriginalLoc(); else if (auto MQL = Cur.getAs<MacroQualifiedTypeLoc>()) diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 3373e96..185a968 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -379,38 +379,59 @@ let Class = AtomicType in { } let Class = UnresolvedUsingType in { - def : Property<"declaration", DeclRef> { - let Read = [{ node->getDecl() }]; + def : Property<"IsCanonical", Bool> { + let Read = [{ node->isCanonicalUnqualified() }]; } - + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getKeyword() }]; + } + def : Property<"Qualifier", NestedNameSpecifier> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getQualifier() }]; + } + def : Property<"D", DeclRef> { let Read = [{ node->getDecl() }]; } def : Creator<[{ - return ctx.getUnresolvedUsingType(cast<UnresolvedUsingTypenameDecl>(declaration)); + auto *UD = cast<UnresolvedUsingTypenameDecl>(D); + return IsCanonical ? ctx.getCanonicalUnresolvedUsingType(UD) : ctx.getUnresolvedUsingType(*Keyword, *Qualifier, UD); }]>; } let Class = UsingType in { - def : Property<"foundDeclaration", UsingShadowDeclRef> { - let Read = [{ node->getFoundDecl() }]; + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; } - def : Property<"underlyingType", QualType> { - let Read = [{ node->getUnderlyingType() }]; + def : Property<"Qualifier", NestedNameSpecifier> { + let Read = [{ node->getQualifier() }]; + } + def : Property<"D", UsingShadowDeclRef> { let Read = [{ node->getDecl() }]; } + def : Property<"UnderlyingType", QualType> { + let Read = [{ node->desugar() }]; } - def : Creator<[{ - return ctx.getUsingType(foundDeclaration, underlyingType); + return ctx.getUsingType(Keyword, Qualifier, D, UnderlyingType); }]>; } let Class = TypedefType in { + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; + } + def : Property<"Qualifier", NestedNameSpecifier> { + let Read = [{ node->getQualifier() }]; + } def : Property<"declaration", DeclRef> { let Read = [{ node->getDecl() }]; } - def : Property<"underlyingType", QualType> { + def : Property<"UnderlyingType", QualType> { let Read = [{ node->desugar() }]; } + def : Property<"TypeMatchesDecl", Bool> { + let Read = [{ node->typeMatchesDecl() }]; + } def : Creator<[{ - return ctx.getTypedefType(cast<TypedefNameDecl>(declaration), underlyingType); + return ctx.getTypedefType(Keyword, Qualifier, cast<TypedefNameDecl>(declaration), UnderlyingType, TypeMatchesDecl); }]>; } @@ -520,6 +541,9 @@ let Class = AutoType in { } let Class = DeducedTemplateSpecializationType in { + def : Property<"keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; + } def : Property<"templateName", Optional<TemplateName>> { let Read = [{ makeOptionalFromNullable(node->getTemplateName()) }]; } @@ -533,97 +557,42 @@ let Class = DeducedTemplateSpecializationType in { } def : Creator<[{ - return ctx.getDeducedTemplateSpecializationType( + return ctx.getDeducedTemplateSpecializationType(keyword, makeNullableFromOptional(templateName), deducedType, dependent); }]>; } let Class = TagType in { - def : Property<"dependent", Bool> { - let Read = [{ node->isDependentType() }]; + def : Property<"IsCanonical", Bool> { + let Read = [{ node->isCanonicalUnqualified() }]; } - def : Property<"declaration", DeclRef> { - // We don't know which declaration was originally referenced here, and we - // cannot reference a declaration that follows the use (because that can - // introduce deserialization cycles), so conservatively generate a - // reference to the first declaration. - // FIXME: If this is a reference to a class template specialization, that - // can still introduce a deserialization cycle. - let Read = [{ node->getDecl()->getCanonicalDecl() }]; + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getKeyword() }]; } + def : Property<"Qualifier", NestedNameSpecifier> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getQualifier() }]; + } + def : Property<"TD", TagDeclRef> { let Read = [{ node->getOriginalDecl() }]; } } let Class = EnumType in { + def : Property<"OwnsTag", Bool> { let Read = [{ node->isTagOwned() }]; } def : Creator<[{ - QualType result = ctx.getEnumType(cast<EnumDecl>(declaration)); - if (dependent) - const_cast<Type *>(result.getTypePtr()) - ->addDependence(TypeDependence::DependentInstantiation); - return result; + return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, OwnsTag); }]>; } - let Class = RecordType in { + def : Property<"OwnsTag", Bool> { let Read = [{ node->isTagOwned() }]; } def : Creator<[{ - auto record = cast<RecordDecl>(declaration); - QualType result = ctx.getRecordType(record); - if (dependent) - const_cast<Type *>(result.getTypePtr()) - ->addDependence(TypeDependence::DependentInstantiation); - return result; - }]>; -} - -let Class = ElaboratedType in { - def : Property<"keyword", ElaboratedTypeKeyword> { - let Read = [{ node->getKeyword() }]; - } - def : Property<"qualifier", NestedNameSpecifier> { - let Read = [{ node->getQualifier() }]; - } - def : Property<"namedType", QualType> { - let Read = [{ node->getNamedType() }]; - } - def : Property<"ownedTag", Optional<TagDeclRef>> { - let Read = [{ makeOptionalFromPointer( - const_cast<const TagDecl *>(node->getOwnedTagDecl())) }]; - } - - def : Creator<[{ - return ctx.getElaboratedType(keyword, qualifier, namedType, - makePointerFromOptional(ownedTag)); + return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, OwnsTag); }]>; } - let Class = InjectedClassNameType in { - def : Property<"declaration", DeclRef> { - // FIXME: drilling down to the canonical declaration is what the - // existing serialization code was doing, but it's not clear why. - let Read = [{ node->getDecl()->getCanonicalDecl() }]; - } - def : Property<"injectedSpecializationType", QualType> { - let Read = [{ node->getInjectedSpecializationType() }]; - } - def : Creator<[{ - // FIXME: ASTContext::getInjectedClassNameType is not currently suitable - // for AST reading, too much interdependencies. - const Type *T = nullptr; - auto typeDecl = cast<CXXRecordDecl>(declaration); - for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl()) { - if (const Type *existing = DI->getTypeForDecl()) { - T = existing; - break; - } - } - if (!T) { - T = new (ctx, TypeAlignment) - InjectedClassNameType(typeDecl, injectedSpecializationType); - for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl()) - DI->setTypeForDecl(T); - } - return QualType(T, 0); + return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, /*OwnsTag=*/false); }]>; } @@ -741,6 +710,9 @@ let Class = DependentAddressSpaceType in { } let Class = TemplateSpecializationType in { + def : Property<"keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; + } def : Property<"templateName", TemplateName> { let Read = [{ node->getTemplateName() }]; } @@ -753,7 +725,7 @@ let Class = TemplateSpecializationType in { } def : Creator<[{ - return ctx.getTemplateSpecializationType(templateName, args, {}, UnderlyingType); + return ctx.getTemplateSpecializationType(keyword, templateName, args, {}, UnderlyingType); }]>; } @@ -848,6 +820,12 @@ let Class = PackExpansionType in { }]>; } +let Class = SubstPackType in { + def : Property<"replacementPack", TemplateArgument> { + let Read = [{ node->getArgumentPack() }]; + } +} + let Class = SubstTemplateTypeParmPackType in { def : Property<"associatedDecl", DeclRef> { let Read = [{ node->getAssociatedDecl() }]; @@ -855,12 +833,7 @@ let Class = SubstTemplateTypeParmPackType in { def : Property<"Index", UInt32> { let Read = [{ node->getIndex() }]; } - def : Property<"Final", Bool> { - let Read = [{ node->getFinal() }]; - } - def : Property<"replacementPack", TemplateArgument> { - let Read = [{ node->getArgumentPack() }]; - } + def : Property<"Final", Bool> { let Read = [{ node->getFinal() }]; } def : Creator<[{ return ctx.getSubstTemplateTypeParmPackType( @@ -868,6 +841,12 @@ let Class = SubstTemplateTypeParmPackType in { }]>; } +let Class = SubstBuiltinTemplatePackType in { + def : Creator<[{ + return ctx.getSubstBuiltinTemplatePack(replacementPack); + }]>; +} + let Class = BuiltinType in { def : Property<"kind", BuiltinTypeKind> { let Read = [{ node->getKind() }]; diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h index 73cbcf1..2d36e8c 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -135,10 +135,15 @@ public: llvm::StringMap<llvm::TimeRecord> &Records; }; + MatchFinderOptions() {} + /// Enables per-check timers. /// /// It prints a report after match. std::optional<Profiling> CheckProfiling; + + /// Avoids matching declarations in system headers. + bool IgnoreSystemHeaders{false}; }; MatchFinder(MatchFinderOptions Options = MatchFinderOptions()); diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 08c898f..f1d88a9 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -222,6 +222,19 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl> extern const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl; +/// \brief Matches shadow declarations introduced into a scope by a +/// (resolved) using declaration. +/// +/// Given +/// \code +/// namespace n { int f; } +/// namespace declToImport { using n::f; } +/// \endcode +/// usingShadowDecl() +/// matches \code f \endcode +extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingShadowDecl> + usingShadowDecl; + /// Matches type alias template declarations. /// /// typeAliasTemplateDecl() matches @@ -3740,7 +3753,7 @@ extern const internal::VariadicOperatorMatcherFunc<1, 1> unless; /// Matcher<MemberExpr>, Matcher<QualType>, Matcher<RecordType>, /// Matcher<TagType>, Matcher<TemplateSpecializationType>, /// Matcher<TemplateTypeParmType>, Matcher<TypedefType>, -/// Matcher<UnresolvedUsingType> +/// Matcher<UnresolvedUsingType>, Matcher<UsingType> inline internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher<Decl>> @@ -4375,7 +4388,13 @@ AST_POLYMORPHIC_MATCHER_P(throughUsingDecl, AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, UsingType), internal::Matcher<UsingShadowDecl>, Inner) { - const NamedDecl *FoundDecl = Node.getFoundDecl(); + const NamedDecl *FoundDecl; + if constexpr (std::is_same_v<NodeType, UsingType>) { + FoundDecl = Node.getDecl(); + } else { + static_assert(std::is_same_v<NodeType, DeclRefExpr>); + FoundDecl = Node.getFoundDecl(); + } if (const UsingShadowDecl *UsingDecl = dyn_cast<UsingShadowDecl>(FoundDecl)) return Inner.matches(*UsingDecl, Finder, Builder); return false; @@ -5642,8 +5661,8 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement, return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder); } -/// Matches the condition expression of an if statement, for loop, -/// switch statement or conditional operator. +/// Matches the condition expression of an if statement, for loop, while loop, +/// do-while loop, switch statement or conditional operator. /// /// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true)))) /// \code @@ -5720,16 +5739,29 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, return Builder->removeBindings(Predicate); } -/// Matches the condition variable statement in an if statement. +/// Matches a declaration if it declares the same entity as the node previously +/// bound to \p ID. +AST_MATCHER_P(Decl, declaresSameEntityAsBoundNode, std::string, ID) { + return Builder->removeBindings([&](const internal::BoundNodesMap &Nodes) { + return !clang::declaresSameEntity(&Node, Nodes.getNodeAs<Decl>(ID)); + }); +} + +/// Matches the condition variable statement in an if statement, for loop, +/// while loop or switch statement. /// /// Given /// \code /// if (A* a = GetAPointer()) {} +/// for (; A* a = GetAPointer(); ) {} /// \endcode /// hasConditionVariableStatement(...) -/// matches 'A* a = GetAPointer()'. -AST_MATCHER_P(IfStmt, hasConditionVariableStatement, - internal::Matcher<DeclStmt>, InnerMatcher) { +/// matches both 'A* a = GetAPointer()'. +AST_POLYMORPHIC_MATCHER_P(hasConditionVariableStatement, + AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt, + WhileStmt, + SwitchStmt), + internal::Matcher<DeclStmt>, InnerMatcher) { const DeclStmt* const DeclarationStatement = Node.getConditionVariableDeclStmt(); return DeclarationStatement != nullptr && @@ -7004,37 +7036,6 @@ AST_POLYMORPHIC_MATCHER_P2( InnerMatcher.matches(Args[Index], Finder, Builder); } -/// Matches C or C++ elaborated `TypeLoc`s. -/// -/// Given -/// \code -/// struct s {}; -/// struct s ss; -/// \endcode -/// elaboratedTypeLoc() -/// matches the `TypeLoc` of the variable declaration of `ss`. -extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc> - elaboratedTypeLoc; - -/// Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching -/// `InnerMatcher`. -/// -/// Given -/// \code -/// template <typename T> -/// class C {}; -/// class C<int> c; -/// -/// class D {}; -/// class D d; -/// \endcode -/// elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())); -/// matches the `TypeLoc` of the variable declaration of `c`, but not `d`. -AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, internal::Matcher<TypeLoc>, - InnerMatcher) { - return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder); -} - /// Matches type \c bool. /// /// Given @@ -7301,7 +7302,7 @@ extern const AstTypeMatcher<DecltypeType> decltypeType; AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, AST_POLYMORPHIC_SUPPORTED_TYPES(AutoType)); -/// Matches \c DecltypeType or \c UsingType nodes to find the underlying type. +/// Matches \c QualType nodes to find the underlying type. /// /// Given /// \code @@ -7311,10 +7312,13 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, /// decltypeType(hasUnderlyingType(isInteger())) /// matches the type of "a" /// -/// Usable as: Matcher<DecltypeType>, Matcher<UsingType> -AST_TYPE_TRAVERSE_MATCHER(hasUnderlyingType, getUnderlyingType, - AST_POLYMORPHIC_SUPPORTED_TYPES(DecltypeType, - UsingType)); +/// Usable as: Matcher<QualType> +AST_MATCHER_P(Type, hasUnderlyingType, internal::Matcher<QualType>, Inner) { + QualType QT = Node.getLocallyUnqualifiedSingleStepDesugaredType(); + if (QT == QualType(&Node, 0)) + return false; + return Inner.matches(QT, Finder, Builder); +} /// Matches \c FunctionType nodes. /// @@ -7593,27 +7597,7 @@ extern const AstTypeMatcher<RecordType> recordType; /// and \c c. extern const AstTypeMatcher<TagType> tagType; -/// Matches types specified with an elaborated type keyword or with a -/// qualified name. -/// -/// Given -/// \code -/// namespace N { -/// namespace M { -/// class D {}; -/// } -/// } -/// class C {}; -/// -/// class C c; -/// N::M::D d; -/// \endcode -/// -/// \c elaboratedType() matches the type of the variable declarations of both -/// \c c and \c d. -extern const AstTypeMatcher<ElaboratedType> elaboratedType; - -/// Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier, +/// Matches Types whose qualifier, a NestedNameSpecifier, /// matches \c InnerMatcher if the qualifier exists. /// /// Given @@ -7628,34 +7612,14 @@ extern const AstTypeMatcher<ElaboratedType> elaboratedType; /// /// \c elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))) /// matches the type of the variable declaration of \c d. -AST_MATCHER_P(ElaboratedType, hasQualifier, - internal::Matcher<NestedNameSpecifier>, InnerMatcher) { - if (const NestedNameSpecifier *Qualifier = Node.getQualifier()) - return InnerMatcher.matches(*Qualifier, Finder, Builder); +AST_MATCHER_P(Type, hasQualifier, internal::Matcher<NestedNameSpecifier>, + InnerMatcher) { + if (NestedNameSpecifier Qualifier = Node.getPrefix()) + return InnerMatcher.matches(Qualifier, Finder, Builder); return false; } -/// Matches ElaboratedTypes whose named type matches \c InnerMatcher. -/// -/// Given -/// \code -/// namespace N { -/// namespace M { -/// class D {}; -/// } -/// } -/// N::M::D d; -/// \endcode -/// -/// \c elaboratedType(namesType(recordType( -/// hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable -/// declaration of \c d. -AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>, - InnerMatcher) { - return InnerMatcher.matches(Node.getNamedType(), Finder, Builder); -} - /// Matches types specified through a using declaration. /// /// Given @@ -7824,7 +7788,7 @@ AST_MATCHER_FUNCTION_P_OVERLOAD( /// matches "A::" AST_MATCHER_P(NestedNameSpecifier, specifiesType, internal::Matcher<QualType>, InnerMatcher) { - if (!Node.getAsType()) + if (Node.getKind() != NestedNameSpecifier::Kind::Type) return false; return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder); } @@ -7842,8 +7806,12 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType, /// matches "A::" AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc, internal::Matcher<TypeLoc>, InnerMatcher) { - return Node && Node.getNestedNameSpecifier()->getAsType() && - InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder); + if (!Node) + return false; + TypeLoc TL = Node.getAsTypeLoc(); + if (!TL) + return false; + return InnerMatcher.matches(TL, Finder, Builder); } /// Matches on the prefix of a \c NestedNameSpecifier. @@ -7858,10 +7826,21 @@ AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc, AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix, internal::Matcher<NestedNameSpecifier>, InnerMatcher, 0) { - const NestedNameSpecifier *NextNode = Node.getPrefix(); + NestedNameSpecifier NextNode = std::nullopt; + switch (Node.getKind()) { + case NestedNameSpecifier::Kind::Namespace: + NextNode = Node.getAsNamespaceAndPrefix().Prefix; + break; + case NestedNameSpecifier::Kind::Type: + NextNode = Node.getAsType()->getPrefix(); + break; + default: + break; + } + if (!NextNode) return false; - return InnerMatcher.matches(*NextNode, Finder, Builder); + return InnerMatcher.matches(NextNode, Finder, Builder); } /// Matches on the prefix of a \c NestedNameSpecifierLoc. @@ -7876,7 +7855,12 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix, AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix, internal::Matcher<NestedNameSpecifierLoc>, InnerMatcher, 1) { - NestedNameSpecifierLoc NextNode = Node.getPrefix(); + NestedNameSpecifierLoc NextNode; + if (TypeLoc TL = Node.getAsTypeLoc()) + NextNode = TL.getPrefix(); + else + NextNode = Node.getAsNamespaceAndPrefix().Prefix; + if (!NextNode) return false; return InnerMatcher.matches(NextNode, Finder, Builder); @@ -7894,9 +7878,13 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix, /// matches "ns::" AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace, internal::Matcher<NamespaceDecl>, InnerMatcher) { - if (auto *NS = dyn_cast_if_present<NamespaceDecl>(Node.getAsNamespace())) - return InnerMatcher.matches(*NS, Finder, Builder); - return false; + if (Node.getKind() != NestedNameSpecifier::Kind::Namespace) + return false; + const auto *Namespace = + dyn_cast<NamespaceDecl>(Node.getAsNamespaceAndPrefix().Namespace); + if (!Namespace) + return false; + return InnerMatcher.matches(*Namespace, Finder, Builder); } /// Matches attributes. @@ -8835,7 +8823,7 @@ AST_MATCHER(OMPDefaultClause, isFirstPrivateKind) { /// #pragma omp for /// \endcode /// -/// `ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches +/// ``ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches /// ``omp parallel`` and ``omp parallel for``. /// /// If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 5df2294..1ab6f11 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1017,10 +1017,7 @@ private: // First, for any types that have a declaration, extract the declaration and // match on it. if (const auto *S = dyn_cast<TagType>(&Node)) { - return matchesDecl(S->getDecl(), Finder, Builder); - } - if (const auto *S = dyn_cast<InjectedClassNameType>(&Node)) { - return matchesDecl(S->getDecl(), Finder, Builder); + return matchesDecl(S->getOriginalDecl(), Finder, Builder); } if (const auto *S = dyn_cast<TemplateTypeParmType>(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); @@ -1031,6 +1028,9 @@ private: if (const auto *S = dyn_cast<UnresolvedUsingType>(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } + if (const auto *S = dyn_cast<UsingType>(&Node)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } if (const auto *S = dyn_cast<ObjCObjectType>(&Node)) { return matchesDecl(S->getInterface(), Finder, Builder); } @@ -1066,12 +1066,6 @@ private: Builder); } - // FIXME: We desugar elaborated types. This makes the assumption that users - // do never want to match on whether a type is elaborated - there are - // arguments for both sides; for now, continue desugaring. - if (const auto *S = dyn_cast<ElaboratedType>(&Node)) { - return matchesSpecialized(S->desugar(), Finder, Builder); - } // Similarly types found via using declarations. // These are *usually* meaningless sugar, and this matches the historical // behavior prior to the introduction of UsingType. @@ -1211,8 +1205,8 @@ using AdaptativeDefaultToTypes = /// All types that are supported by HasDeclarationMatcher above. using HasDeclarationSupportedTypes = TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType, - ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr, - MemberExpr, QualType, RecordType, TagType, + InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr, + QualType, RecordType, TagType, UsingType, TemplateSpecializationType, TemplateTypeParmType, TypedefType, UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>; @@ -1789,7 +1783,7 @@ public: private: static DynTypedNode extract(const NestedNameSpecifierLoc &Loc) { - return DynTypedNode::create(*Loc.getNestedNameSpecifier()); + return DynTypedNode::create(Loc.getNestedNameSpecifier()); } }; diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h index 1c00558..7e1bfc9 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h @@ -19,14 +19,35 @@ #define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableSet.h" #include "llvm/ADT/StringMap.h" #include <memory> namespace clang::lifetimes { +/// Enum to track the confidence level of a potential error. +enum class Confidence { + None, + Maybe, // Reported as a potential error (-Wlifetime-safety-strict) + Definite // Reported as a definite error (-Wlifetime-safety-permissive) +}; + +class LifetimeSafetyReporter { +public: + LifetimeSafetyReporter() = default; + virtual ~LifetimeSafetyReporter() = default; + + virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr, + SourceLocation FreeLoc, + Confidence Confidence) {} +}; + /// The main entry point for the analysis. -void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC); +void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, + LifetimeSafetyReporter *Reporter); namespace internal { // Forward declarations of internal types. @@ -53,6 +74,7 @@ template <typename Tag> struct ID { IDBuilder.AddInteger(Value); } }; + template <typename Tag> inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) { return OS << ID.Value; @@ -78,7 +100,8 @@ using ProgramPoint = const Fact *; /// encapsulates the various dataflow analyses. class LifetimeSafetyAnalysis { public: - LifetimeSafetyAnalysis(AnalysisDeclContext &AC); + LifetimeSafetyAnalysis(AnalysisDeclContext &AC, + LifetimeSafetyReporter *Reporter); ~LifetimeSafetyAnalysis(); void run(); @@ -87,7 +110,7 @@ public: LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const; /// Returns the set of loans that have expired at a specific program point. - LoanSet getExpiredLoansAtPoint(ProgramPoint PP) const; + std::vector<LoanID> getExpiredLoansAtPoint(ProgramPoint PP) const; /// Finds the OriginID for a given declaration. /// Returns a null optional if not found. @@ -110,6 +133,7 @@ public: private: AnalysisDeclContext &AC; + LifetimeSafetyReporter *Reporter; std::unique_ptr<LifetimeFactory> Factory; std::unique_ptr<FactManager> FactMgr; std::unique_ptr<LoanPropagationAnalysis> LoanPropagation; @@ -118,4 +142,25 @@ private: } // namespace internal } // namespace clang::lifetimes +namespace llvm { +template <typename Tag> +struct DenseMapInfo<clang::lifetimes::internal::ID<Tag>> { + using ID = clang::lifetimes::internal::ID<Tag>; + + static inline ID getEmptyKey() { + return {DenseMapInfo<uint32_t>::getEmptyKey()}; + } + + static inline ID getTombstoneKey() { + return {DenseMapInfo<uint32_t>::getTombstoneKey()}; + } + + static unsigned getHashValue(const ID &Val) { + return DenseMapInfo<uint32_t>::getHashValue(Val.Value); + } + + static bool isEqual(const ID &LHS, const ID &RHS) { return LHS == RHS; } +}; +} // namespace llvm + #endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h index 8c7ee86..a404b06 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h +++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h @@ -112,8 +112,14 @@ public: // fields that are only used in these. // Note: The operand of the `noexcept` operator is an unevaluated operand, but // nevertheless it appears in the Clang CFG, so we don't exclude it here. - bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) override { return true; } - bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) override { return true; } + bool TraverseDecltypeTypeLoc(DecltypeTypeLoc, + bool TraverseQualifier) override { + return true; + } + bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc, + bool TraverseQualifier) override { + return true; + } bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) override { if (TIE->isPotentiallyEvaluated()) return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(TIE); diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index 5be4a11..11042e8 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -42,6 +42,18 @@ struct ContextSensitiveOptions { unsigned Depth = 2; }; +/// A simple representation of essential elements of the logical context used in +/// environments. Designed for import/export for applications requiring +/// serialization support. +struct SimpleLogicalContext { + // Global invariant that applies for all definitions in the context. + const Formula *Invariant; + // Flow-condition tokens in the context. + llvm::DenseMap<Atom, const Formula *> TokenDefs; + // Dependencies between flow-condition definitions. + llvm::DenseMap<Atom, llvm::DenseSet<Atom>> TokenDeps; +}; + /// Owns objects that encompass the state of a program and stores context that /// is used during dataflow analysis. class DataflowAnalysisContext { @@ -140,6 +152,15 @@ public: /// Adds `Constraint` to the flow condition identified by `Token`. void addFlowConditionConstraint(Atom Token, const Formula &Constraint); + /// Adds `Deps` to the dependencies of the flow condition identified by + /// `Token`. Intended for use in deserializing contexts. The formula alone + /// doesn't have enough information to indicate its deps. + void addFlowConditionDeps(Atom Token, const llvm::DenseSet<Atom> &Deps) { + // Avoid creating an entry for `Token` with an empty set. + if (!Deps.empty()) + FlowConditionDeps[Token].insert(Deps.begin(), Deps.end()); + } + /// Creates a new flow condition with the same constraints as the flow /// condition identified by `Token` and returns its token. Atom forkFlowCondition(Atom Token); @@ -207,6 +228,14 @@ public: return {}; } + /// Export the logical-context portions of `AC`, limited to the given target + /// flow-condition tokens. + SimpleLogicalContext + exportLogicalContext(llvm::DenseSet<dataflow::Atom> TargetTokens) const; + + /// Initializes this context's "logical" components with `LC`. + void initLogicalContext(SimpleLogicalContext LC); + private: friend class Environment; @@ -228,6 +257,11 @@ private: DataflowAnalysisContext(Solver &S, std::unique_ptr<Solver> &&OwnedSolver, Options Opts); + /// Computes the transitive closure of dependencies of (flow-condition) + /// `Tokens`. That is, the set of flow-condition tokens reachable from + /// `Tokens` in the dependency graph. + llvm::DenseSet<Atom> collectDependencies(llvm::DenseSet<Atom> Tokens) const; + // Extends the set of modeled field declarations. void addModeledFields(const FieldSet &Fields); diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 097ff2b..0767144 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -157,10 +157,18 @@ public: }; /// Creates an environment that uses `DACtx` to store objects that encompass - /// the state of a program. + /// the state of a program. `FlowConditionToken` sets the flow condition + /// associated with the environment. Generally, new environments should be + /// initialized with a fresh token, by using one of the other + /// constructors. This constructor is for specialized use, including + /// deserialization and delegation from other constructors. + Environment(DataflowAnalysisContext &DACtx, Atom FlowConditionToken) + : DACtx(&DACtx), FlowConditionToken(FlowConditionToken) {} + + /// Creates an environment that uses `DACtx` to store objects that encompass + /// the state of a program. Populates a fresh atom as flow condition token. explicit Environment(DataflowAnalysisContext &DACtx) - : DACtx(&DACtx), - FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} + : Environment(DACtx, DACtx.arena().makeFlowConditionToken()) {} /// Creates an environment that uses `DACtx` to store objects that encompass /// the state of a program, with `S` as the statement to analyze. diff --git a/clang/include/clang/Analysis/FlowSensitive/Formula.h b/clang/include/clang/Analysis/FlowSensitive/Formula.h index 0e63524..3959bc9 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Formula.h +++ b/clang/include/clang/Analysis/FlowSensitive/Formula.h @@ -85,21 +85,17 @@ public: } using AtomNames = llvm::DenseMap<Atom, std::string>; - // Produce a stable human-readable representation of this formula. - // For example: (V3 | !(V1 & V2)) - // If AtomNames is provided, these override the default V0, V1... names. + /// Produces a stable human-readable representation of this formula. + /// For example: (V3 | !(V1 & V2)) + /// If AtomNames is provided, these override the default V0, V1... names. void print(llvm::raw_ostream &OS, const AtomNames * = nullptr) const; - // Allocate Formulas using Arena rather than calling this function directly. + /// Allocates Formulas using Arena rather than calling this function directly. static const Formula &create(llvm::BumpPtrAllocator &Alloc, Kind K, ArrayRef<const Formula *> Operands, unsigned Value = 0); -private: - Formula() = default; - Formula(const Formula &) = delete; - Formula &operator=(const Formula &) = delete; - + /// Count of operands (sub-formulas) associated with Formulas of kind `K`. static unsigned numOperands(Kind K) { switch (K) { case AtomRef: @@ -116,6 +112,11 @@ private: llvm_unreachable("Unhandled Formula::Kind enum"); } +private: + Formula() = default; + Formula(const Formula &) = delete; + Formula &operator=(const Formula &) = delete; + Kind FormulaKind; // Some kinds of formula have scalar values, e.g. AtomRef's atom number. unsigned Value; diff --git a/clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h b/clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h new file mode 100644 index 0000000..119f93e --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h @@ -0,0 +1,40 @@ +//=== FormulaSerialization.h - Formula De/Serialization support -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_FORMULA_SERIALIZATION_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_FORMULA_SERIALIZATION_H + +#include "clang/Analysis/FlowSensitive/Arena.h" +#include "clang/Analysis/FlowSensitive/Formula.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <string> + +namespace clang::dataflow { + +/// Prints `F` to `OS` in a compact format, optimized for easy parsing +/// (deserialization) rather than human use. +void serializeFormula(const Formula &F, llvm::raw_ostream &OS); + +/// Parses `Str` to build a serialized Formula. +/// @returns error on parse failure or if parsing does not fully consume `Str`. +/// @param A used to construct the formula components. +/// @param AtomMap maps serialized Atom identifiers (unsigned ints) to Atoms. +/// This map is provided by the caller to enable consistency across +/// multiple formulas in a single file. +llvm::Expected<const Formula *> +parseFormula(llvm::StringRef Str, Arena &A, + llvm::DenseMap<unsigned, Atom> &AtomMap); + +} // namespace clang::dataflow +#endif diff --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h index 8fcc6a4..534b9a0 100644 --- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h +++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" #include <cassert> @@ -152,6 +153,11 @@ public: return {SyntheticFields.begin(), SyntheticFields.end()}; } + /// Add a synthetic field, if none by that name is already present. + void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) { + SyntheticFields.insert({Name, &Loc}); + } + /// Changes the child storage location for a field `D` of reference type. /// All other fields cannot change their storage location and always retain /// the storage location passed to the `RecordStorageLocation` constructor. @@ -164,6 +170,11 @@ public: Children[&D] = Loc; } + /// Add a child storage location for a field `D`, if not already present. + void addChild(const ValueDecl &D, StorageLocation *Loc) { + Children.insert({&D, Loc}); + } + llvm::iterator_range<FieldToLoc::const_iterator> children() const { return {Children.begin(), Children.end()}; } diff --git a/clang/include/clang/Basic/ABIVersions.def b/clang/include/clang/Basic/ABIVersions.def new file mode 100644 index 0000000..f6524bc --- /dev/null +++ b/clang/include/clang/Basic/ABIVersions.def @@ -0,0 +1,135 @@ +//===--- ABIVersions.def - Clang ABI Versions Database ----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file enumerates Clang ABI versions. +// +//===----------------------------------------------------------------------===// +// +/// @file ABIVersions.def +/// +/// In this file, each of the Clang ABI Versions is enumerated +/// ABI_VER_MAJOR_MINOR, ABI_VER_MAJOR, or ABI_VER_LATEST macro. +/// +/// ABI_VER_MAJOR is used when the minor version is 0 or can be omitted. +/// +/// The first argument of ABI_VER_MAJOR_MINOR and ABI_VER_MAJOR is the major +/// version. +/// +/// The second argument of ABI_VER_MAJOR_MINOR is the minor version. +/// +/// The first argument of ABI_VER_LATEST is an identifier `Latest`. + +#if defined(ABI_VER_MAJOR_MINOR) != defined(ABI_VER_MAJOR) || \ + defined(ABI_VER_MAJOR) != defined(ABI_VER_LATEST) +# error ABI_VER_MAJOR_MINOR, ABI_VER_MAJOR and ABI_VER_LATEST should be defined simultaneously +#endif + +#ifndef ABI_VER_MAJOR_MINOR +# define ABI_VER_MAJOR_MINOR(Major, Minor) +#endif + +#ifndef ABI_VER_MAJOR +# define ABI_VER_MAJOR(Major) +#endif + +#ifndef ABI_VER_LATEST +# define ABI_VER_LATEST(Latest) +#endif + +/// Attempt to be ABI-compatible with code generated by Clang 3.8.x +/// (SVN r257626). This causes <1 x long long> to be passed in an integer +/// register instead of an SSE register on x64_64. +ABI_VER_MAJOR_MINOR(3, 8) + +/// Attempt to be ABI-compatible with code generated by Clang 4.0.x +/// (SVN r291814). This causes move operations to be ignored when determining +/// whether a class type can be passed or returned directly. +ABI_VER_MAJOR(4) + +/// Attempt to be ABI-compatible with code generated by Clang 6.0.x +/// (SVN r321711). This causes determination of whether a type is +/// standard-layout to ignore collisions between empty base classes and between +/// base classes and member subobjects, which affects whether we reuse base +/// class tail padding in some ABIs. +ABI_VER_MAJOR(6) + +/// Attempt to be ABI-compatible with code generated by Clang 7.0.x +/// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be compatible +/// with __alignof (i.e., return the preferred alignment) rather than returning +/// the required alignment. +ABI_VER_MAJOR(7) + +/// Attempt to be ABI-compatible with code generated by Clang 9.0.x +/// (SVN r351319). This causes vectors of __int128 to be passed in memory +/// instead of passing in multiple scalar registers on x86_64 on Linux and +/// NetBSD. +ABI_VER_MAJOR(9) + +/// Attempt to be ABI-compatible with code generated by Clang 11.0.x +/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit vector +/// member on the stack instead of using registers, to not properly mangle +/// substitutions for template names in some cases, and to mangle declaration +/// template arguments without a cast to the parameter type even when that can +/// lead to mangling collisions. +ABI_VER_MAJOR(11) + +/// Attempt to be ABI-compatible with code generated by Clang 12.0.x +/// (git 8e464dd76bef). This causes clang to mangle lambdas within global-scope +/// inline variables incorrectly. +ABI_VER_MAJOR(12) + +/// Attempt to be ABI-compatible with code generated by Clang 14.0.x. +/// This causes clang to: +/// - mangle dependent nested names incorrectly. +/// - make trivial only those defaulted copy constructors with a +/// parameter-type-list equivalent to the parameter-type-list of an implicit +/// declaration. +ABI_VER_MAJOR(14) + +/// Attempt to be ABI-compatible with code generated by Clang 15.0.x. +/// This causes clang to: +/// - Reverse the implementation for CWG692, CWG1395 and CWG1432. +/// - pack non-POD members of packed structs. +/// - consider classes with defaulted special member functions non-pod. +ABI_VER_MAJOR(15) + +/// Attempt to be ABI-compatible with code generated by Clang 17.0.x. +/// This causes clang to revert some fixes to its implementation of the Itanium +/// name mangling scheme, with the consequence that overloaded function +/// templates are mangled the same if they differ only by: +/// - constraints +/// - whether a non-type template parameter has a deduced type +/// - the parameter list of a template template parameter +ABI_VER_MAJOR(17) + +/// Attempt to be ABI-compatible with code generated by Clang 18.0.x. +/// This causes clang to revert some fixes to the mangling of lambdas in the +/// initializers of members of local classes. +ABI_VER_MAJOR(18) + +/// Attempt to be ABI-compatible with code generated by Clang 19.0.x. +/// This causes clang to: +/// - Incorrectly mangle the 'base type' substitutions of the CXX construction +/// vtable because it hasn't added 'type' as a substitution. +/// - Skip mangling enclosing class templates of member-like friend function +/// templates. +/// - Ignore empty struct arguments in C++ mode for ARM, instead of passing +/// them as if they had a size of 1 byte. +ABI_VER_MAJOR(19) + +/// Attempt to be ABI-compatible with code generated by Clang 20.0.x. +/// This causes clang to: +/// - Incorrectly return C++ records in AVX registers on x86_64. +ABI_VER_MAJOR(20) + +/// Conform to the underlying platform's C and C++ ABIs as closely as we can. +ABI_VER_LATEST(Latest) + +#undef ABI_VER_MAJOR_MINOR +#undef ABI_VER_MAJOR +#undef ABI_VER_LATEST diff --git a/clang/include/clang/Basic/AllDiagnosticKinds.inc b/clang/include/clang/Basic/AllDiagnosticKinds.inc index a946b4a..2d08bb0 100644 --- a/clang/include/clang/Basic/AllDiagnosticKinds.inc +++ b/clang/include/clang/Basic/AllDiagnosticKinds.inc @@ -30,4 +30,5 @@ #include "clang/Basic/DiagnosticAnalysisKinds.inc" #include "clang/Basic/DiagnosticRefactoringKinds.inc" #include "clang/Basic/DiagnosticInstallAPIKinds.inc" +#include "clang/Basic/DiagnosticTrapKinds.inc" // clang-format on diff --git a/clang/include/clang/Basic/AllDiagnostics.h b/clang/include/clang/Basic/AllDiagnostics.h index e64634c..78e5428 100644 --- a/clang/include/clang/Basic/AllDiagnostics.h +++ b/clang/include/clang/Basic/AllDiagnostics.h @@ -23,20 +23,21 @@ #include "clang/Basic/DiagnosticInstallAPI.h" #include "clang/Basic/DiagnosticLex.h" #include "clang/Basic/DiagnosticParse.h" +#include "clang/Basic/DiagnosticRefactoring.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/DiagnosticSerialization.h" -#include "clang/Basic/DiagnosticRefactoring.h" +#include "clang/Basic/DiagnosticTrap.h" namespace clang { -template <size_t SizeOfStr, typename FieldType> -class StringSizerHelper { +template <size_t SizeOfStr, typename FieldType> class StringSizerHelper { static_assert(SizeOfStr <= FieldType(~0U), "Field too small!"); + public: enum { Size = SizeOfStr }; }; } // end namespace clang -#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \ - fieldTy>::Size +#define STR_SIZE(str, fieldTy) \ + clang::StringSizerHelper<sizeof(str) - 1, fieldTy>::Size #endif diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 30efb9f..29364c5 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1632,6 +1632,13 @@ def DeviceKernel : DeclOrTypeAttr { }]; } +def SYCLExternal : InheritableAttr { + let Spellings = [CXX11<"clang", "sycl_external">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let LangOpts = [SYCLHost, SYCLDevice]; + let Documentation = [SYCLExternalDocs]; +} + def SYCLKernelEntryPoint : InheritableAttr { let Spellings = [CXX11<"clang", "sycl_kernel_entry_point">]; let Args = [ @@ -3922,6 +3929,14 @@ def CFICanonicalJumpTable : InheritableAttr { let SimpleHandler = 1; } +def CFISalt : TypeAttr { + let Spellings = [Clang<"cfi_salt">]; + let Args = [StringArgument<"Salt">]; + let Subjects = SubjectList<[FunctionLike], ErrorDiag>; + let Documentation = [CFISaltDocs]; + let LangOpts = [COnly]; +} + // C/C++ Thread safety attributes (e.g. for deadlock, data race checking) // Not all of these attributes will be given a [[]] spelling. The attributes // which require access to function parameter names cannot use the [[]] spelling @@ -4932,6 +4947,7 @@ def HLSLResourceBinding: InheritableAttr { return SpaceNumber; } void setImplicitBindingOrderID(uint32_t Value) { + assert(!hasImplicitBindingOrderID() && "attribute already has implicit binding order id"); ImplicitBindingOrderID = Value; } bool hasImplicitBindingOrderID() const { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 2b095ab..2504841 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -476,6 +476,47 @@ The SYCL kernel in the previous code sample meets these expectations. }]; } +def SYCLExternalDocs : Documentation { + let Category = DocCatFunction; + let Heading = "sycl_external"; + let Content = [{ +The ``sycl_external`` attribute indicates that a function defined in another +translation unit may be called by a device function defined in the current +translation unit or, if defined in the current translation unit, the function +may be called by device functions defined in other translation units. +The attribute is intended for use in the implementation of the ``SYCL_EXTERNAL`` +macro as specified in section 5.10.1, "SYCL functions and member functions +linkage", of the SYCL 2020 specification. + +The attribute only appertains to functions and only those that meet the +following requirements: + +* Has external linkage +* Is not explicitly defined as deleted (the function may be an explicitly + defaulted function that is defined as deleted) + +The attribute shall be present on the first declaration of a function and +may optionally be present on subsequent declarations. + +When compiling for a SYCL device target that does not support the generic +address space, the function shall not specify a raw pointer or reference type +as the return type or as a parameter type. +See section 5.10, "SYCL offline linking", of the SYCL 2020 specification. +The following examples demonstrate the use of this attribute: + +.. code-block:: c++ + + [[clang::sycl_external]] void Foo(); // Ok. + + [[clang::sycl_external]] void Bar() { /* ... */ } // Ok. + + [[clang::sycl_external]] extern void Baz(); // Ok. + + [[clang::sycl_external]] static void Quux() { /* ... */ } // error: Quux() has internal linkage. + + }]; +} + def SYCLKernelEntryPointDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -932,6 +973,21 @@ An example of how to use ``alloc_size`` assert(__builtin_object_size(a, 0) == 100); } +When ``-Walloc-size`` is enabled, this attribute allows the compiler to +diagnose cases when the allocated memory is insufficient for the size of the +type the returned pointer is cast to. + +.. code-block:: c + + void *my_malloc(int a) __attribute__((alloc_size(1))); + void consumer_func(int *); + + int main() { + int *ptr = my_malloc(sizeof(int)); // no warning + int *w = my_malloc(1); // warning: allocation of insufficient size '1' for type 'int' with size '4' + consumer_func(my_malloc(1)); // warning: allocation of insufficient size '1' for type 'int' with size '4' + } + .. Note:: This attribute works differently in clang than it does in GCC. Specifically, clang will only trace ``const`` pointers (as above); we give up on pointers that are not marked as ``const``. In the vast majority of cases, @@ -3646,6 +3702,99 @@ make the function's CFI jump table canonical. See :ref:`the CFI documentation }]; } +def CFISaltDocs : Documentation { + let Category = DocCatFunction; + let Heading = "cfi_salt"; + let Label = "langext-cfi_salt"; + let Content = [{ +The ``cfi_salt`` attribute specifies a string literal that is used as a salt +for Control-Flow Integrity (CFI) checks to distinguish between functions with +the same type signature. This attribute can be applied to function declarations, +function definitions, and function pointer typedefs. + +The attribute prevents function pointers from being replaced with pointers to +functions that have a compatible type, which can be a CFI bypass vector. + +**Syntax:** + +* GNU-style: ``__attribute__((cfi_salt("<salt_string>")))`` +* C++11-style: ``[[clang::cfi_salt("<salt_string>")]]`` + +**Usage:** + +The attribute takes a single string literal argument that serves as the salt. +Functions or function types with different salt values will have different CFI +hashes, even if they have identical type signatures. + +**Motivation:** + +In large codebases like the Linux kernel, there are often hundreds of functions +with identical type signatures that are called indirectly: + +.. code-block:: + + 1662 functions with void (*)(void) + 1179 functions with int (*)(void) + ... + +By salting the CFI hashes, you can make CFI more robust by ensuring that +functions intended for different purposes have distinct CFI identities. + +**Type Compatibility:** + +* Functions with different salt values are considered to have incompatible types +* Function pointers with different salt values cannot be assigned to each other +* All declarations of the same function must use the same salt value + +**Example:** + +.. code-block:: c + + // Header file - define convenience macros + #define __cfi_salt(s) __attribute__((cfi_salt(s))) + + // Typedef for regular function pointers + typedef int (*fptr_t)(void); + + // Typedef for salted function pointers + typedef int (*fptr_salted_t)(void) __cfi_salt("pepper"); + + struct widget_ops { + fptr_t init; // Regular CFI + fptr_salted_t exec; // Salted CFI + fptr_t cleanup; // Regular CFI + }; + + // Function implementations + static int widget_init(void) { return 0; } + static int widget_exec(void) __cfi_salt("pepper") { return 1; } + static int widget_cleanup(void) { return 0; } + + static struct widget_ops ops = { + .init = widget_init, // OK - compatible types + .exec = widget_exec, // OK - both use "pepper" salt + .cleanup = widget_cleanup // OK - compatible types + }; + + // Using C++11 attribute syntax + void secure_callback(void) [[clang::cfi_salt("secure")]]; + + // This would cause a compilation error: + // fptr_t bad_ptr = widget_exec; // Error: incompatible types + +**Notes:** + +* The salt string can contain non-NULL ASCII characters, including spaces and + quotes +* This attribute only applies to function types; using it on non-function + types will generate a warning +* All declarations and definitions of the same function must use identical + salt values +* The attribute affects type compatibility during compilation and CFI hash + generation during code generation + }]; +} + def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> { let Content = [{ Clang supports additional attributes to enable checking type safety properties diff --git a/clang/include/clang/Basic/BuiltinTemplates.td b/clang/include/clang/Basic/BuiltinTemplates.td index 5b9672b..504405a 100644 --- a/clang/include/clang/Basic/BuiltinTemplates.td +++ b/clang/include/clang/Basic/BuiltinTemplates.td @@ -62,3 +62,7 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate< // typename ...Operands> def __hlsl_spirv_type : HLSLBuiltinTemplate< [Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>; + +// template <class ...Args> +def __builtin_dedup_pack + : CPlusPlusBuiltinTemplate<[Class<"Args", /*is_variadic=*/1>]>; diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index c81714e..af0e824 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1232,6 +1232,30 @@ def ConvertVector : Builtin { let Prototype = "void(...)"; } +def MaskedLoad : Builtin { + let Spellings = ["__builtin_masked_load"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def MaskedStore : Builtin { + let Spellings = ["__builtin_masked_store"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def MaskedExpandLoad : Builtin { + let Spellings = ["__builtin_masked_expand_load"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def MaskedCompressStore : Builtin { + let Spellings = ["__builtin_masked_compress_store"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; +} + def AllocaUninitialized : Builtin { let Spellings = ["__builtin_alloca_uninitialized"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow]; @@ -1264,7 +1288,7 @@ def NondetermenisticValue : Builtin { def ElementwiseAbs : Builtin { let Spellings = ["__builtin_elementwise_abs"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } @@ -1300,13 +1324,13 @@ def ElementwiseBitreverse : Builtin { def ElementwiseMax : Builtin { let Spellings = ["__builtin_elementwise_max"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } def ElementwiseMin : Builtin { let Spellings = ["__builtin_elementwise_min"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } @@ -1498,7 +1522,7 @@ def ElementwiseCopysign : Builtin { def ElementwiseFma : Builtin { let Spellings = ["__builtin_elementwise_fma"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } @@ -1514,6 +1538,30 @@ def ElementwiseSubSat : Builtin { let Prototype = "void(...)"; } +def ElementwiseFshl : Builtin { + let Spellings = ["__builtin_elementwise_fshl"]; + let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def ElementwiseFshr : Builtin { + let Spellings = ["__builtin_elementwise_fshr"]; + let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def ElementwiseCtlz : Builtin { + let Spellings = ["__builtin_elementwise_ctlz"]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; + let Prototype = "void(...)"; +} + +def ElementwiseCttz : Builtin { + let Spellings = ["__builtin_elementwise_cttz"]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; + let Prototype = "void(...)"; +} + def ReduceMax : Builtin { let Spellings = ["__builtin_reduce_max"]; let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index b16d4a2..6f5d1e0 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -183,6 +183,9 @@ TARGET_BUILTIN(__builtin_amdgcn_struct_ptr_buffer_load_lds, "vQbv*3IUiiiiIiIi", TARGET_BUILTIN(__builtin_amdgcn_ballot_w32, "ZUib", "nc", "wavefrontsize32") BUILTIN(__builtin_amdgcn_ballot_w64, "WUib", "nc") +TARGET_BUILTIN(__builtin_amdgcn_inverse_ballot_w32, "bZUi", "nc", "wavefrontsize32") +TARGET_BUILTIN(__builtin_amdgcn_inverse_ballot_w64, "bWUi", "nc", "wavefrontsize64") + // Deprecated intrinsics in favor of __builtin_amdgn_ballot_{w32|w64} BUILTIN(__builtin_amdgcn_uicmp, "WUiUiUiIi", "nc") BUILTIN(__builtin_amdgcn_uicmpl, "WUiWUiWUiIi", "nc") @@ -503,6 +506,9 @@ TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal, "vIi", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_var, "vv*i", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_barrier_wait, "vIs", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst, "bIi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_init, "vv*i", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vv*", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "vIs", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_get_named_barrier_state, "Uiv*", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_prefetch_data, "vvC*Ui", "nc", "gfx12-insts") diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index e7d6741..22926b6 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -580,6 +580,8 @@ TARGET_BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "", "isa-v207-instructions") // P9 Binary-coded decimal (BCD) builtins. +TARGET_BUILTIN(__builtin_ppc_bcdcopysign, "V16UcV16UcV16Uc", "", "power9-vector") +TARGET_BUILTIN(__builtin_ppc_bcdsetsign, "V16UcV16UcUc", "t", "power9-vector") TARGET_BUILTIN(__builtin_ppc_national2packed, "V16UcV16UcUc", "t", "power9-vector") TARGET_BUILTIN(__builtin_ppc_packed2national, "V16UcV16Uc", "", "power9-vector") TARGET_BUILTIN(__builtin_ppc_packed2zoned, "V16UcV16UcUc", "t", "power9-vector") @@ -1098,6 +1100,10 @@ UNALIASED_CUSTOM_BUILTIN(mma_dmmr, "vW1024*W1024*", false, "mma,isa-future-instructions") UNALIASED_CUSTOM_BUILTIN(mma_dmxor, "vW1024*W1024*", true, "mma,isa-future-instructions") +UNALIASED_CUSTOM_BUILTIN(mma_disassemble_dmr, "vv*W1024*", false, + "mma,isa-future-instructions") +UNALIASED_CUSTOM_BUILTIN(mma_build_dmr, "vW1024*VVVVVVVV", false, + "mma,isa-future-instructions") // MMA builtins with positive/negative multiply/accumulate. UNALIASED_CUSTOM_MMA_BUILTIN(mma_xvf16ger2, "vW512*VV", diff --git a/clang/include/clang/Basic/BuiltinsX86.td b/clang/include/clang/Basic/BuiltinsX86.td index a4acc72..acd8f70 100644 --- a/clang/include/clang/Basic/BuiltinsX86.td +++ b/clang/include/clang/Basic/BuiltinsX86.td @@ -93,13 +93,11 @@ let Attributes = [Const, NoThrow, RequiredVectorWidth<128>] in { } let Features = "sse2" in { - def pmulhw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; def pavgb128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">; def pavgw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; def packsswb128 : X86Builtin<"_Vector<16, char>(_Vector<8, short>, _Vector<8, short>)">; def packssdw128 : X86Builtin<"_Vector<8, short>(_Vector<4, int>, _Vector<4, int>)">; def packuswb128 : X86Builtin<"_Vector<16, char>(_Vector<8, short>, _Vector<8, short>)">; - def pmulhuw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; def vec_ext_v2di : X86Builtin<"long long int(_Vector<2, long long int>, _Constant int)">; def vec_ext_v4si : X86Builtin<"int(_Vector<4, int>, _Constant int)">; def vec_ext_v4sf : X86Builtin<"float(_Vector<4, float>, _Constant int)">; @@ -107,6 +105,11 @@ let Attributes = [Const, NoThrow, RequiredVectorWidth<128>] in { def vec_set_v8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, short, _Constant int)">; } + let Features = "sse2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def pmulhw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; + def pmulhuw128 : X86Builtin<"_Vector<8, unsigned short>(_Vector<8, unsigned short>, _Vector<8, unsigned short>)">; + } + let Features = "sse3" in { foreach Op = ["addsub", "hadd", "hsub"] in { def Op#ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>)">; @@ -265,7 +268,6 @@ let Header = "emmintrin.h", Attributes = [NoThrow, RequireDeclaration] in { } let Features = "sse2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def pmuludq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">; def psraw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; def psrad128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; def psrlw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; @@ -274,17 +276,25 @@ let Features = "sse2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] i def psllw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; def pslld128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; def psllq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; + def pmaddwd128 : X86Builtin<"_Vector<4, int>(_Vector<8, short>, _Vector<8, short>)">; + def pslldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; + def psrldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; +} + +let Features = "sse2", + Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def pmuludq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">; + def psllwi128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, int)">; def pslldi128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int)">; def psllqi128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, int)">; + def psrlwi128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, int)">; def psrldi128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int)">; def psrlqi128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, int)">; + def psrawi128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, int)">; def psradi128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int)">; - def pmaddwd128 : X86Builtin<"_Vector<4, int>(_Vector<8, short>, _Vector<8, short>)">; - def pslldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; - def psrldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; } let Features = "sse3", Attributes = [NoThrow] in { @@ -309,7 +319,6 @@ let Features = "sse4.1", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] def blendvpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, double>)">; def blendvps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>)">; def packusdw128 : X86Builtin<"_Vector<8, short>(_Vector<4, int>, _Vector<4, int>)">; - def pmuldq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">; def roundps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Constant int)">; def roundss : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Constant int)">; def roundsd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Constant int)">; @@ -326,6 +335,10 @@ let Features = "sse4.1", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] def vec_set_v4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int, _Constant int)">; } +let Features = "sse4.1", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def pmuldq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">; +} + let Features = "sse4.2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def pcmpistrm128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>, _Constant char)">; def pcmpistri128 : X86Builtin<"int(_Vector<16, char>, _Vector<16, char>, _Constant char)">; @@ -526,28 +539,22 @@ let Features = "avx", Attributes = [NoThrow] in { let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<256>] in { def lddqu256 : X86Builtin<"_Vector<32, char>(char const *)">; -} -let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def maskloadpd : X86Builtin<"_Vector<2, double>(_Vector<2, double const *>, _Vector<2, long long int>)">; - def maskloadps : X86Builtin<"_Vector<4, float>(_Vector<4, float const *>, _Vector<4, int>)">; -} - -let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<256>] in { def maskloadpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double const *>, _Vector<4, long long int>)">; def maskloadps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float const *>, _Vector<8, int>)">; + + def maskstorepd256 : X86Builtin<"void(_Vector<4, double *>, _Vector<4, long long int>, _Vector<4, double>)">; + def maskstoreps256 : X86Builtin<"void(_Vector<8, float *>, _Vector<8, int>, _Vector<8, float>)">; } let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<128>] in { + def maskloadpd : X86Builtin<"_Vector<2, double>(_Vector<2, double const *>, _Vector<2, long long int>)">; + def maskloadps : X86Builtin<"_Vector<4, float>(_Vector<4, float const *>, _Vector<4, int>)">; + def maskstorepd : X86Builtin<"void(_Vector<2, double *>, _Vector<2, long long int>, _Vector<2, double>)">; def maskstoreps : X86Builtin<"void(_Vector<4, float *>, _Vector<4, int>, _Vector<4, float>)">; } -let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def maskstorepd256 : X86Builtin<"void(_Vector<4, double *>, _Vector<4, long long int>, _Vector<4, double>)">; - def maskstoreps256 : X86Builtin<"void(_Vector<8, float *>, _Vector<8, int>, _Vector<8, float>)">; -} - let Features = "avx", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { def vec_ext_v32qi : X86Builtin<"char(_Vector<32, char>, _Constant int)">; def vec_ext_v16hi : X86Builtin<"short(_Vector<16, short>, _Constant int)">; @@ -577,11 +584,7 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i def pmaddubsw256 : X86Builtin<"_Vector<16, short>(_Vector<32, char>, _Vector<32, char>)">; def pmaddwd256 : X86Builtin<"_Vector<8, int>(_Vector<16, short>, _Vector<16, short>)">; def pmovmskb256 : X86Builtin<"int(_Vector<32, char>)">; - def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">; def pmulhrsw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">; - def pmulhuw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">; - def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">; - def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">; def psadbw256 : X86Builtin<"_Vector<4, long long int>(_Vector<32, char>, _Vector<32, char>)">; def pshufb256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>)">; def pshufd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">; @@ -590,23 +593,15 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i def psignb256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>)">; def psignw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">; def psignd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; - def psllwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">; def psllw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<8, short>)">; def pslldqi256_byteshift : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">; - def pslldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">; def pslld256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<4, int>)">; - def psllqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">; def psllq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>)">; - def psrawi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">; def psraw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<8, short>)">; - def psradi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">; def psrad256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<4, int>)">; def psrldqi256_byteshift : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">; - def psrlwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">; def psrlw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<8, short>)">; - def psrldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">; def psrld256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<4, int>)">; - def psrlqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">; def psrlq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>)">; def pblendd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Constant int)">; def pblendd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>, _Constant int)">; @@ -619,128 +614,73 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i def insert128i256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>, _Constant int)">; } -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def maskloadd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int const *>, _Vector<8, int>)">; - def maskloadq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int const *>, _Vector<4, long long int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def maskloadd : X86Builtin<"_Vector<4, int>(_Vector<4, int const *>, _Vector<4, int>)">; - def maskloadq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int const *>, _Vector<2, long long int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def maskstored256 : X86Builtin<"void(_Vector<8, int *>, _Vector<8, int>, _Vector<8, int>)">; - def maskstoreq256 : X86Builtin<"void(_Vector<4, long long int *>, _Vector<4, long long int>, _Vector<4, long long int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def maskstored : X86Builtin<"void(_Vector<4, int *>, _Vector<4, int>, _Vector<4, int>)">; - def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">; -} +let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { + def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">; + def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">; -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; -} + def psllwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">; + def pslldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">; + def psllqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">; -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; -} + def psrlwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">; + def psrldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">; + def psrlqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">; -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">; -} + def psrawi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">; + def psradi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">; -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; -} + def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">; + def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">; -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { + def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; -} - -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { + def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">; def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">; } -let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; + def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; + def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; + def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; } -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">; -} - let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def gatherd_pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, double const *, _Vector<4, int>, _Vector<4, double>, _Constant char)">; -} + def maskloadd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int const *>, _Vector<8, int>)">; + def maskloadq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int const *>, _Vector<4, long long int>)">; -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherq_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<2, long long int>, _Vector<2, double>, _Constant char)">; -} + def maskstored256 : X86Builtin<"void(_Vector<8, int *>, _Vector<8, int>, _Vector<8, int>)">; + def maskstoreq256 : X86Builtin<"void(_Vector<4, long long int *>, _Vector<4, long long int>, _Vector<4, long long int>)">; -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { + def gatherd_pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, double const *, _Vector<4, int>, _Vector<4, double>, _Constant char)">; def gatherq_pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, double const *, _Vector<4, long long int>, _Vector<4, double>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherd_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<4, int>, _Vector<4, float>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { def gatherd_ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, float const *, _Vector<8, int>, _Vector<8, float>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherq_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<2, long long int>, _Vector<4, float>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { def gatherq_ps256 : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<4, long long int>, _Vector<4, float>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherd_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<4, int>, _Vector<2, long long int>, _Constant char)">; -} -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { def gatherd_q256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, long long int const *, _Vector<4, int>, _Vector<4, long long int>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherq_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<2, long long int>, _Vector<2, long long int>, _Constant char)">; -} - -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { def gatherq_q256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, long long int const *, _Vector<4, long long int>, _Vector<4, long long int>, _Constant char)">; + def gatherd_d256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int const *, _Vector<8, int>, _Vector<8, int>, _Constant char)">; + def gatherq_d256 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, long long int>, _Vector<4, int>, _Constant char)">; } let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherd_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, int>, _Vector<4, int>, _Constant char)">; -} + def maskloadd : X86Builtin<"_Vector<4, int>(_Vector<4, int const *>, _Vector<4, int>)">; + def maskloadq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int const *>, _Vector<2, long long int>)">; -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def gatherd_d256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int const *, _Vector<8, int>, _Vector<8, int>, _Constant char)">; -} + def maskstored : X86Builtin<"void(_Vector<4, int *>, _Vector<4, int>, _Vector<4, int>)">; + def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">; -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def gatherq_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<2, long long int>, _Vector<4, int>, _Constant char)">; -} + def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">; + def gatherq_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<2, long long int>, _Vector<2, double>, _Constant char)">; + def gatherd_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<4, int>, _Vector<4, float>, _Constant char)">; + def gatherq_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<2, long long int>, _Vector<4, float>, _Constant char)">; -let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def gatherq_d256 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, long long int>, _Vector<4, int>, _Constant char)">; + def gatherd_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<4, int>, _Vector<2, long long int>, _Constant char)">; + def gatherq_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<2, long long int>, _Vector<2, long long int>, _Constant char)">; + def gatherd_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, int>, _Vector<4, int>, _Constant char)">; + def gatherq_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<2, long long int>, _Vector<4, int>, _Constant char)">; } let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { @@ -751,14 +691,6 @@ let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i def vcvtps2ph256 : X86Builtin<"_Vector<8, short>(_Vector<8, float>, _Constant int)">; } -let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vcvtph2ps : X86Builtin<"_Vector<4, float>(_Vector<8, short>)">; -} - -let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vcvtph2ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, short>)">; -} - let Features = "rdrnd", Attributes = [NoThrow] in { def rdrand16_step : X86Builtin<"unsigned int(unsigned short *)">; def rdrand32_step : X86Builtin<"unsigned int(unsigned int *)">; @@ -878,11 +810,6 @@ let Features = "sha", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in def sha256msg2 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; } -let Features = "fma|fma4", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vfmaddps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>)">; - def vfmaddpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, double>)">; -} - let Features = "fma", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def vfmaddss3 : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>)">; def vfmaddsd3 : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, double>)">; @@ -899,8 +826,6 @@ let Features = "fma|fma4", Attributes = [NoThrow, Const, RequiredVectorWidth<128 } let Features = "fma|fma4", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vfmaddps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, float>)">; - def vfmaddpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, double>)">; def vfmaddsubps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, float>)">; def vfmaddsubpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, double>)">; } @@ -953,14 +878,6 @@ let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in def vphsubwd : X86Builtin<"_Vector<4, int>(_Vector<8, short>)">; def vphsubdq : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>)">; def vpperm : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>, _Vector<16, char>)">; - def vprotb : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">; - def vprotw : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; - def vprotd : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; - def vprotq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; - def vprotbi : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Constant char)">; - def vprotwi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant char)">; - def vprotdi : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant char)">; - def vprotqi : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant char)">; def vpshlb : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">; def vpshlw : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; def vpshld : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; @@ -978,28 +895,23 @@ let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in def vpcomd : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Constant char)">; def vpcomq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>, _Constant char)">; def vpermil2pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, long long int>, _Constant char)">; -} - -let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpermil2pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, long long int>, _Constant char)">; -} - -let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def vpermil2ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, int>, _Constant char)">; -} - -let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpermil2ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, int>, _Constant char)">; -} - -let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def vfrczss : X86Builtin<"_Vector<4, float>(_Vector<4, float>)">; def vfrczsd : X86Builtin<"_Vector<2, double>(_Vector<2, double>)">; def vfrczps : X86Builtin<"_Vector<4, float>(_Vector<4, float>)">; def vfrczpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>)">; } +let Features = "xop", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def vprotbi : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Constant char)">; + def vprotwi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant char)">; + def vprotdi : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant char)">; + def vprotqi : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant char)">; +} + let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { + def vpermil2pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, long long int>, _Constant char)">; + def vpermil2ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, int>, _Constant char)">; def vfrczps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>)">; def vfrczpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>)">; } @@ -1090,6 +1002,9 @@ let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWi def cvtpd2ps512_mask : X86Builtin<"_Vector<8, float>(_Vector<8, double>, _Vector<8, float>, unsigned char, _Constant int)">; def vcvtps2ph512_mask : X86Builtin<"_Vector<16, short>(_Vector<16, float>, _Constant int, _Vector<16, short>, unsigned short)">; def vcvtph2ps512_mask : X86Builtin<"_Vector<16, float>(_Vector<16, short>, _Vector<16, float>, unsigned short, _Constant int)">; +} + +let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def pmuldq512 : X86Builtin<"_Vector<8, long long int>(_Vector<16, int>, _Vector<16, int>)">; def pmuludq512 : X86Builtin<"_Vector<8, long long int>(_Vector<16, int>, _Vector<16, int>)">; } @@ -1411,8 +1326,6 @@ let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVector let Features = "avx512cd,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { def vpconflictdi_512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>)">; def vpconflictsi_512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>)">; - def vplzcntd_512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>)">; - def vplzcntq_512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>)">; } let Features = "avx512vl,avx512bitalg", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { @@ -1429,7 +1342,10 @@ let Features = "avx512bitalg,evex512", Attributes = [NoThrow, Const, RequiredVec let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { def pmulhrsw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">; - def pmulhuw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">; +} + +let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { + def pmulhuw512 : X86Builtin<"_Vector<32, unsigned short>(_Vector<32, unsigned short>, _Vector<32, unsigned short>)">; def pmulhw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">; } @@ -1888,78 +1804,6 @@ let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVect } let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vpshldvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Vector<4, int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpshldvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>, _Vector<8, int>)">; -} - -let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def vpshldvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>, _Vector<16, int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vpshldvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>, _Vector<2, long long int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpshldvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>, _Vector<4, long long int>)">; -} - -let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def vpshldvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>, _Vector<8, long long int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vpshldvw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>, _Vector<8, short>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpshldvw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>, _Vector<16, short>)">; -} - -let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def vpshldvw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>, _Vector<32, short>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vpshrdvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Vector<4, int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpshrdvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>, _Vector<8, int>)">; -} - -let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def vpshrdvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>, _Vector<16, int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vpshrdvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>, _Vector<2, long long int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpshrdvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>, _Vector<4, long long int>)">; -} - -let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def vpshrdvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>, _Vector<8, long long int>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vpshrdvw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>, _Vector<8, short>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vpshrdvw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>, _Vector<16, short>)">; -} - -let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def vpshrdvw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>, _Vector<32, short>)">; -} - -let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def vpshrdd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Constant int)">; } @@ -2148,93 +1992,32 @@ let Features = "avx512dq,evex512", Attributes = [NoThrow, Const, RequiredVectorW def reduceps512_mask : X86Builtin<"_Vector<16, float>(_Vector<16, float>, _Constant int, _Vector<16, float>, unsigned short, _Constant int)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def prold512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">; - def prolq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def prold128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prold256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def prolq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prolq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">; -} - -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def prolvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">; - def prolvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">; def prord512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">; + def prolq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">; def prorq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def prolvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prolvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def prolvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prolvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def prold128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">; def prord128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prord256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { + def prolq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; def prorq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { + def prold256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">; + def prord256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">; + def prolq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">; def prorq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def prorvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">; - def prorvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def prorvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prorvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def prorvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">; -} - -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def prorvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">; -} - let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { def pshufhw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int)">; def pshuflw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int)">; def psllv32hi : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">; def psllw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">; - def psllwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">; } let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { @@ -2245,7 +2028,9 @@ let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVector def psllv8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", + Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { + def psllwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">; def pslldi512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, int)">; def psllqi512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, int)">; } @@ -2262,7 +2047,9 @@ let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVector def psrlv8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", + Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { + def psrlwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">; def psrldi512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, int)">; def psrlqi512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, int)">; } @@ -2288,10 +2075,10 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256 } let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { - def psraw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">; - def psrawi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">; - def psrlw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">; - def psrlwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">; + def psraw512 + : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">; + def psrlw512 + : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">; def pslldqi512_byteshift : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">; def psrldqi512_byteshift : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">; } @@ -2574,22 +2361,6 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256 def rcp14ps256_mask : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, unsigned char)">; } -let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vplzcntd_128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>)">; -} - -let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vplzcntd_256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>)">; -} - -let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vplzcntq_128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>)">; -} - -let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vplzcntq_256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>)">; -} - let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def vcvtsd2si32 : X86Builtin<"int(_Vector<2, double>, _Constant int)">; def vcvtsd2usi32 : X86Builtin<"unsigned int(_Vector<2, double>, _Constant int)">; @@ -2623,7 +2394,9 @@ let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<128> def scalefss_round_mask : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>, unsigned char, _Constant int)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", + Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { + def psrawi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">; def psradi512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, int)">; def psraqi512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, int)">; } @@ -2636,11 +2409,13 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256 def psraq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512vl", + Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def psraqi128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, int)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512vl", + Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def psraqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">; } @@ -4140,14 +3915,6 @@ let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVecto def vcvtps2phx512_mask : X86Builtin<"_Vector<16, _Float16>(_Vector<16, float>, _Vector<16, _Float16>, unsigned short, _Constant int)">; } -let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vfmaddph : X86Builtin<"_Vector<8, _Float16>(_Vector<8, _Float16>, _Vector<8, _Float16>, _Vector<8, _Float16>)">; -} - -let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vfmaddph256 : X86Builtin<"_Vector<16, _Float16>(_Vector<16, _Float16>, _Vector<16, _Float16>, _Vector<16, _Float16>)">; -} - let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { def vfmaddph512_mask : X86Builtin<"_Vector<32, _Float16>(_Vector<32, _Float16>, _Vector<32, _Float16>, _Vector<32, _Float16>, unsigned int, _Constant int)">; def vfmaddph512_mask3 : X86Builtin<"_Vector<32, _Float16>(_Vector<32, _Float16>, _Vector<32, _Float16>, _Vector<32, _Float16>, unsigned int, _Constant int)">; @@ -4246,99 +4013,99 @@ let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVecto def vfcmulcph512_mask : X86Builtin<"_Vector<16, float>(_Vector<16, float>, _Vector<16, float>, _Vector<16, float>, unsigned short, _Constant int)">; } -let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectb_128 : X86Builtin<"_Vector<16, char>(unsigned short, _Vector<16, char>, _Vector<16, char>)">; } -let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectb_256 : X86Builtin<"_Vector<32, char>(unsigned int, _Vector<32, char>, _Vector<32, char>)">; } -let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectb_512 : X86Builtin<"_Vector<64, char>(unsigned long long int, _Vector<64, char>, _Vector<64, char>)">; } -let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectw_128 : X86Builtin<"_Vector<8, short>(unsigned char, _Vector<8, short>, _Vector<8, short>)">; } -let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectw_256 : X86Builtin<"_Vector<16, short>(unsigned short, _Vector<16, short>, _Vector<16, short>)">; } -let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectw_512 : X86Builtin<"_Vector<32, short>(unsigned int, _Vector<32, short>, _Vector<32, short>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectd_128 : X86Builtin<"_Vector<4, int>(unsigned char, _Vector<4, int>, _Vector<4, int>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectd_256 : X86Builtin<"_Vector<8, int>(unsigned char, _Vector<8, int>, _Vector<8, int>)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectd_512 : X86Builtin<"_Vector<16, int>(unsigned short, _Vector<16, int>, _Vector<16, int>)">; } -let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectph_128 : X86Builtin<"_Vector<8, _Float16>(unsigned char, _Vector<8, _Float16>, _Vector<8, _Float16>)">; } -let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectph_256 : X86Builtin<"_Vector<16, _Float16>(unsigned short, _Vector<16, _Float16>, _Vector<16, _Float16>)">; } -let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectph_512 : X86Builtin<"_Vector<32, _Float16>(unsigned int, _Vector<32, _Float16>, _Vector<32, _Float16>)">; } -let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectpbf_128 : X86Builtin<"_Vector<8, __bf16>(unsigned char, _Vector<8, __bf16>, _Vector<8, __bf16>)">; } -let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectpbf_256 : X86Builtin<"_Vector<16, __bf16>(unsigned short, _Vector<16, __bf16>, _Vector<16, __bf16>)">; } -let Features = "avx512bf16,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512bf16,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectpbf_512 : X86Builtin<"_Vector<32, __bf16>(unsigned int, _Vector<32, __bf16>, _Vector<32, __bf16>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectq_128 : X86Builtin<"_Vector<2, long long int>(unsigned char, _Vector<2, long long int>, _Vector<2, long long int>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectq_256 : X86Builtin<"_Vector<4, long long int>(unsigned char, _Vector<4, long long int>, _Vector<4, long long int>)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectq_512 : X86Builtin<"_Vector<8, long long int>(unsigned char, _Vector<8, long long int>, _Vector<8, long long int>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectps_128 : X86Builtin<"_Vector<4, float>(unsigned char, _Vector<4, float>, _Vector<4, float>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectps_256 : X86Builtin<"_Vector<8, float>(unsigned char, _Vector<8, float>, _Vector<8, float>)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectps_512 : X86Builtin<"_Vector<16, float>(unsigned short, _Vector<16, float>, _Vector<16, float>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def selectpd_128 : X86Builtin<"_Vector<2, double>(unsigned char, _Vector<2, double>, _Vector<2, double>)">; } -let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def selectpd_256 : X86Builtin<"_Vector<4, double>(unsigned char, _Vector<4, double>, _Vector<4, double>)">; } -let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { +let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def selectpd_512 : X86Builtin<"_Vector<8, double>(unsigned char, _Vector<8, double>, _Vector<8, double>)">; } @@ -5373,13 +5140,4 @@ let Features = "avx10.2-256", Attributes = [NoThrow, Const, RequiredVectorWidth< let Features = "avx10.2-512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in { def vsqrtbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>)">; - def vfmaddbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>, _Vector<32, __bf16>, _Vector<32, __bf16>)">; -} - -let Features = "avx10.2-256", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in { - def vfmaddbf16256 : X86Builtin<"_Vector<16, __bf16>(_Vector<16, __bf16>, _Vector<16, __bf16>, _Vector<16, __bf16>)">; -} - -let Features = "avx10.2-256", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { - def vfmaddbf16128 : X86Builtin<"_Vector<8, __bf16>(_Vector<8, __bf16>, _Vector<8, __bf16>, _Vector<8, __bf16>)">; } diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 0cf661a..8173600 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -33,6 +33,7 @@ clang_diag_gen(Parse) clang_diag_gen(Refactoring) clang_diag_gen(Sema) clang_diag_gen(Serialization) +clang_diag_gen(Trap) clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups SOURCE Diagnostic.td TARGET ClangDiagnosticGroups) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 423b696..fda0da9 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -58,7 +58,7 @@ ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None, Benig ENUM_CODEGENOPT(ExceptionHandling, ExceptionHandlingKind, 3, ExceptionHandlingKind::None, NotCompatible) -CODEGENOPT(ClearASTBeforeBackend , 1, 0, Benign) ///< Free the AST before running backend code generation. Only works with -disable-free. +CODEGENOPT(ClearASTBeforeBackend , 1, 0, Benign) ///< Free the AST before running backend code generation. CODEGENOPT(DisableFree , 1, 0, Benign) ///< Don't free memory. CODEGENOPT(DiscardValueNames , 1, 0, Benign) ///< Discard Value Names from the IR (LLVMContext flag) CODEGENOPT(DisableLLVMPasses , 1, 0, Benign) ///< Don't run any LLVM IR passes to get @@ -307,7 +307,7 @@ CODEGENOPT(SanitizeBinaryMetadataAtomics, 1, 0, Benign) ///< Emit PCs for atomic CODEGENOPT(SanitizeBinaryMetadataUAR, 1, 0, Benign) ///< Emit PCs for start of functions ///< that are subject for use-after-return checking. CODEGENOPT(SanitizeStats , 1, 0, Benign) ///< Collect statistics for sanitizers. -CODEGENOPT(SanitizeDebugTrapReasons, 1, 1 , Benign) ///< Enable UBSan trapping messages +ENUM_CODEGENOPT(SanitizeDebugTrapReasons, SanitizeDebugTrapReasonKind, 2, SanitizeDebugTrapReasonKind::Detailed, Benign) ///< Control how "trap reasons" are emitted in debug info CODEGENOPT(SimplifyLibCalls , 1, 1, Benign) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0, Benign) ///< -soft-float. CODEGENOPT(SpeculativeLoadHardening, 1, 0, Benign) ///< Enable speculative load hardening. diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index cdeedd5..5d5cf25 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -198,6 +198,16 @@ public: Forced, }; + enum SanitizeDebugTrapReasonKind { + None, ///< Trap Messages are omitted. This offers the smallest debug info + ///< size but at the cost of making traps hard to debug. + Basic, ///< Trap Message is fixed per SanitizerKind. Produces smaller debug + ///< info than `Detailed` but is not as helpful for debugging. + Detailed, ///< Trap Message includes more context (e.g. the expression being + ///< overflowed). This is more helpful for debugging but produces + ///< larger debug info than `Basic`. + }; + /// The code model to use (-mcmodel). std::string CodeModel; diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index cee5bed..af26a04 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -23,6 +23,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" @@ -1259,10 +1260,13 @@ class DiagnosticBuilder : public StreamingDiagnostic { DiagnosticBuilder() = default; +protected: DiagnosticBuilder(DiagnosticsEngine *DiagObj, SourceLocation DiagLoc, unsigned DiagID); -protected: + DiagnosticsEngine *getDiagnosticsEngine() const { return DiagObj; } + unsigned getDiagID() const { return DiagID; } + /// Clear out the current diagnostic. void Clear() const { DiagObj = nullptr; diff --git a/clang/include/clang/Basic/Diagnostic.td b/clang/include/clang/Basic/Diagnostic.td index 65b19f3..53b1db2 100644 --- a/clang/include/clang/Basic/Diagnostic.td +++ b/clang/include/clang/Basic/Diagnostic.td @@ -30,6 +30,7 @@ def CLASS_REMARK : DiagClass; def CLASS_WARNING : DiagClass; def CLASS_EXTENSION : DiagClass; def CLASS_ERROR : DiagClass; +def CLASS_TRAP : DiagClass; // Responses to a diagnostic in a SFINAE context. class SFINAEResponse; @@ -144,7 +145,8 @@ class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>; class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>; // Notes can provide supplementary information on errors, warnings, and remarks. class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>; - +// Trap messages attached to traps in debug info. +class Trap<string str> : Diagnostic<str, CLASS_TRAP, SEV_Fatal/*ignored*/>; class DefaultIgnore { Severity DefaultSeverity = SEV_Ignored; } class DefaultWarn { Severity DefaultSeverity = SEV_Warning; } @@ -235,3 +237,4 @@ include "DiagnosticParseKinds.td" include "DiagnosticRefactoringKinds.td" include "DiagnosticSemaKinds.td" include "DiagnosticSerializationKinds.td" +include "DiagnosticTrapKinds.td" diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 46d04b0..a63bd80 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -400,6 +400,9 @@ def note_constexpr_non_const_vectorelements : Note< "cannot determine number of elements for sizeless vectors in a constant expression">; def note_constexpr_assumption_failed : Note< "assumption evaluated to false">; +def note_constexpr_countzeroes_zero : Note< + "evaluation of %select{__builtin_elementwise_ctlz|__builtin_elementwise_cttz}0 " + "with a zero value is undefined">; def err_experimental_clang_interp_failed : Error< "the experimental clang interpreter failed to evaluate an expression">; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 0f17f4a..b8c7c6e 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -581,6 +581,13 @@ def err_drv_reduced_module_output_overrided : Warning< "please consider use '-fmodule-output=' to specify the output file for reduced BMI explicitly">, InGroup<DiagGroup<"reduced-bmi-output-overrided">>; +def remark_found_cxx20_module_usage : Remark< + "found C++20 module usage in file '%0'">, + InGroup<ModulesDriver>; +def remark_performing_driver_managed_module_build : Remark< + "performing driver managed module build">, + InGroup<ModulesDriver>; + def warn_drv_delayed_template_parsing_after_cxx20 : Warning< "-fdelayed-template-parsing is deprecated after C++20">, InGroup<DiagGroup<"delayed-template-parsing-in-cxx20">>; @@ -878,4 +885,9 @@ def warn_drv_openacc_without_cir : Warning<"OpenACC directives will result in no runtime behavior; use " "-fclangir to enable runtime effect">, InGroup<SourceUsesOpenACC>; + +def warn_drv_gcc_install_dir_libstdcxx : Warning< + "future releases of the clang compiler will prefer GCC installations " + "containing libstdc++ include directories; '%0' would be chosen over '%1'">, + InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>; } diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8a8db27..b7e27d8 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -287,6 +287,10 @@ def err_function_needs_feature : Error< "always_inline function %1 requires target feature '%2', but would " "be inlined into function %0 that is compiled without support for '%2'">; +def err_flatten_function_needs_feature : Error< + "flatten function %0 calls %1 which requires target feature '%2', but the " + "caller is compiled without support for '%2'">; + let CategoryName = "Codegen ABI Check" in { def err_function_always_inline_attribute_mismatch : Error< "always_inline function %1 and its caller %0 have mismatching %2 attributes">; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index ccb18aa..0c994e0 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -533,7 +533,14 @@ def Dangling : DiagGroup<"dangling", [DanglingAssignment, DanglingGsl, ReturnStackAddress]>; -def LifetimeSafety : DiagGroup<"experimental-lifetime-safety">; +def LifetimeSafetyPermissive : DiagGroup<"experimental-lifetime-safety-permissive">; +def LifetimeSafetyStrict : DiagGroup<"experimental-lifetime-safety-strict">; +def LifetimeSafety : DiagGroup<"experimental-lifetime-safety", + [LifetimeSafetyPermissive, LifetimeSafetyStrict]> { + code Documentation = [{ + Experimental warnings to detect use-after-free and related temporal safety bugs based on lifetime safety analysis. + }]; +} def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; def DllexportExplicitInstantiationDecl : DiagGroup<"dllexport-explicit-instantiation-decl">; @@ -628,6 +635,7 @@ def ModuleConflict : DiagGroup<"module-conflict">; def ModuleFileExtension : DiagGroup<"module-file-extension">; def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">; def ModuleMap : DiagGroup<"module-map">; +def ModulesDriver : DiagGroup<"modules-driver">; def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">; def NewlineEOF : DiagGroup<"newline-eof">; def Nullability : DiagGroup<"nullability">; @@ -644,6 +652,7 @@ def NonNull : DiagGroup<"nonnull">; def NonPODVarargs : DiagGroup<"non-pod-varargs">; def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>; def : DiagGroup<"nonportable-cfstrings">; +def NonPortableSYCL : DiagGroup<"nonportable-sycl">; def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; def GNUNullPointerArithmetic : DiagGroup<"gnu-null-pointer-arithmetic">; def NullPointerArithmetic diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index b21a3b6..06446cf 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -23,76 +23,80 @@ #include <vector> namespace clang { - class DiagnosticsEngine; - class DiagnosticBuilder; - class LangOptions; - class SourceLocation; - - // Import the diagnostic enums themselves. - namespace diag { - enum class Group; - - // Size of each of the diagnostic categories. - enum { - DIAG_SIZE_COMMON = 300, - DIAG_SIZE_DRIVER = 400, - DIAG_SIZE_FRONTEND = 200, - DIAG_SIZE_SERIALIZATION = 120, - DIAG_SIZE_LEX = 500, - DIAG_SIZE_PARSE = 800, - DIAG_SIZE_AST = 300, - DIAG_SIZE_COMMENT = 100, - DIAG_SIZE_CROSSTU = 100, - DIAG_SIZE_SEMA = 5000, - DIAG_SIZE_ANALYSIS = 100, - DIAG_SIZE_REFACTORING = 1000, - DIAG_SIZE_INSTALLAPI = 100, - }; - // Start position for diagnostics. - enum { - DIAG_START_COMMON = 0, - DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON), - DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER), - DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND), - DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION), - DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX), - DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE), - DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST), - DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT), - DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU), - DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA), - DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS), - DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING), - DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI) - }; - - class CustomDiagInfo; - - /// All of the diagnostics that can be emitted by the frontend. - typedef unsigned kind; - - /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs - /// to either Ignore (nothing), Remark (emit a remark), Warning - /// (emit a warning) or Error (emit as an error). It allows clients to - /// map ERRORs to Error or Fatal (stop emitting diagnostics after this one). - enum class Severity : uint8_t { - // NOTE: 0 means "uncomputed". - Ignored = 1, ///< Do not present this diagnostic, ignore it. - Remark = 2, ///< Present this diagnostic as a remark. - Warning = 3, ///< Present this diagnostic as a warning. - Error = 4, ///< Present this diagnostic as an error. - Fatal = 5 ///< Present this diagnostic as a fatal error. - }; - - /// Flavors of diagnostics we can emit. Used to filter for a particular - /// kind of diagnostic (for instance, for -W/-R flags). - enum class Flavor { - WarningOrError, ///< A diagnostic that indicates a problem or potential - ///< problem. Can be made fatal by -Werror. - Remark ///< A diagnostic that indicates normal progress through - ///< compilation. - }; - } // end namespace diag +class DiagnosticsEngine; +class DiagnosticBuilder; +class LangOptions; +class SourceLocation; + +// Import the diagnostic enums themselves. +namespace diag { +enum class Group; + +// Size of each of the diagnostic categories. +enum { + DIAG_SIZE_COMMON = 300, + DIAG_SIZE_DRIVER = 400, + DIAG_SIZE_FRONTEND = 200, + DIAG_SIZE_SERIALIZATION = 120, + DIAG_SIZE_LEX = 500, + DIAG_SIZE_PARSE = 800, + DIAG_SIZE_AST = 300, + DIAG_SIZE_COMMENT = 100, + DIAG_SIZE_CROSSTU = 100, + DIAG_SIZE_SEMA = 5000, + DIAG_SIZE_ANALYSIS = 100, + DIAG_SIZE_REFACTORING = 1000, + DIAG_SIZE_INSTALLAPI = 100, + DIAG_SIZE_TRAP = 100, +}; +// Start position for diagnostics. +// clang-format off +enum { + DIAG_START_COMMON = 0, + DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON), + DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER), + DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND), + DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION), + DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX), + DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE), + DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST), + DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT), + DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU), + DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA), + DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS), + DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING), + DIAG_START_TRAP = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI), + DIAG_UPPER_LIMIT = DIAG_START_TRAP + static_cast<int>(DIAG_SIZE_TRAP) +}; +// clang-format on + +class CustomDiagInfo; + +/// All of the diagnostics that can be emitted by the frontend. +typedef unsigned kind; + +/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs +/// to either Ignore (nothing), Remark (emit a remark), Warning +/// (emit a warning) or Error (emit as an error). It allows clients to +/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one). +enum class Severity : uint8_t { + // NOTE: 0 means "uncomputed". + Ignored = 1, ///< Do not present this diagnostic, ignore it. + Remark = 2, ///< Present this diagnostic as a remark. + Warning = 3, ///< Present this diagnostic as a warning. + Error = 4, ///< Present this diagnostic as an error. + Fatal = 5 ///< Present this diagnostic as a fatal error. +}; + +/// Flavors of diagnostics we can emit. Used to filter for a particular +/// kind of diagnostic (for instance, for -W/-R flags). +enum class Flavor { + WarningOrError, ///< A diagnostic that indicates a problem or potential + ///< problem. Can be made fatal by -Werror. + Remark ///< A diagnostic that indicates normal progress through + ///< compilation. +}; +} // end namespace diag } // end namespace clang // This has to be included *after* the DIAG_START_ enums above are defined. @@ -173,7 +177,8 @@ public: /// Used for handling and querying diagnostic IDs. /// -/// Can be used and shared by multiple Diagnostics for multiple translation units. +/// Can be used and shared by multiple Diagnostics for multiple translation +/// units. class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> { public: /// The level of the diagnostic, after it has been through mapping. @@ -186,7 +191,8 @@ public: CLASS_REMARK = 0x02, CLASS_WARNING = 0x03, CLASS_EXTENSION = 0x04, - CLASS_ERROR = 0x05 + CLASS_ERROR = 0x05, + CLASS_TRAP = 0x06 }; static bool IsCustomDiag(diag::kind Diag) { @@ -360,6 +366,10 @@ public: /// bool isExtensionDiag(unsigned DiagID, bool &EnabledByDefault) const; + bool isTrapDiag(unsigned DiagID) const { + return getDiagClass(DiagID) == CLASS_TRAP; + } + /// Given a group ID, returns the flag that toggles the group. /// For example, for Group::DeprecatedDeclarations, returns /// "deprecated-declarations". @@ -498,6 +508,6 @@ private: friend class DiagnosticsEngine; }; -} // end namespace clang +} // end namespace clang #endif diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index c7fe6e1d..c03c403 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -912,6 +912,11 @@ def err_mmap_nested_submodule_id : Error< "qualified module name can only be used to define modules at the top level">; def err_mmap_expected_feature : Error<"expected a feature name">; def err_mmap_expected_attribute : Error<"expected an attribute name">; +def warn_mmap_link_redeclaration : Warning<"redeclaration of link library '%0'">, + InGroup<DiagGroup<"module-link-redeclaration">>, DefaultError; +def note_mmap_prev_link_declaration : Note<"previously declared here">; +def err_mmap_submodule_link_decl + : Error<"link declaration is not allowed in submodules">; def warn_mmap_unknown_attribute : Warning<"unknown attribute '%0'">, InGroup<IgnoredAttributes>; def warn_mmap_mismatched_private_submodule : Warning< diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 0042afc..ff506fb 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -830,6 +830,9 @@ def err_ms_property_expected_comma_or_rparen : Error< "expected ',' or ')' at end of property accessor list">; def err_ms_property_initializer : Error< "property declaration cannot have a default member initializer">; +def ext_invalid_attribute_argument + : Extension<"'%0' is not allowed in an attribute argument list">, + InGroup<DiagGroup<"attribute-preprocessor-tokens">>; def err_assume_attr_expects_cond_expr : Error< "use of this expression in an %0 attribute requires parentheses">; @@ -1503,8 +1506,8 @@ def err_omp_unexpected_directive : Error< "unexpected OpenMP directive %select{|'#pragma omp %1'}0">; def err_omp_expected_punc : Error< "expected ',' or ')' in '%0' %select{clause|directive}1">; -def warn_clause_expected_string : Warning< - "expected string literal in 'clause %0' - ignoring">, InGroup<IgnoredPragmas>; +def warn_clause_expected_string: Warning< + "expected string %select{|literal }1in 'clause %0' - ignoring">, InGroup<IgnoredPragmas>; def err_omp_unexpected_clause : Error< "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; def err_omp_unexpected_clause_extension_only : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f903b7f..c934fed 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1772,7 +1772,8 @@ def note_unsatisfied_trait "%Replaceable{replaceable}|" "%TriviallyCopyable{trivially copyable}|" "%Empty{empty}|" - "%StandardLayout{standard-layout}" + "%StandardLayout{standard-layout}|" + "%Final{final}" "}1">; def note_unsatisfied_trait_reason @@ -1815,7 +1816,9 @@ def note_unsatisfied_trait_reason "%sub{select_special_member_kind}1}|" "%FunctionType{is a function type}|" "%CVVoidType{is a cv void type}|" - "%IncompleteArrayType{is an incomplete array type}" + "%IncompleteArrayType{is an incomplete array type}|" + "%NotClassOrUnion{is not a class or union type}|" + "%NotMarkedFinal{is not marked 'final'}" "}0">; def warn_consteval_if_always_true : Warning< @@ -3684,6 +3687,10 @@ def warn_alloca_align_alignof : Warning< "second argument to __builtin_alloca_with_align is supposed to be in bits">, InGroup<DiagGroup<"alloca-with-align-alignof">>; +def warn_alloc_size : Warning< + "allocation of insufficient size '%0' for type %1 with size '%2'">, + InGroup<DiagGroup<"alloc-size">>; + def err_alignment_too_small : Error< "requested alignment must be %0 or greater">; def err_alignment_too_big : Error< @@ -4404,6 +4411,11 @@ def warn_impcast_different_enum_types : Warning< def warn_impcast_int_to_enum : Warning< "implicit conversion from %0 to enumeration type %1 is invalid in C++">, InGroup<ImplicitIntToEnumCast>, DefaultIgnore; + +def note_no_implicit_conversion_for_scoped_enum + : Note<"no implicit conversion for scoped enum; consider casting to " + "underlying type">; + def warn_impcast_bool_to_null_pointer : Warning< "initialization of pointer of type %0 to null from a constant boolean " "expression">, InGroup<BoolConversion>; @@ -6074,6 +6086,13 @@ def warn_cxx23_pack_indexing : Warning< def err_pack_outside_template : Error< "pack declaration outside of template">; +def err_builtin_pack_outside_template + : Error<"%0 cannot be used outside of template">; + +def err_unsupported_builtin_template_pack_expansion + : Error<"expansions of %0 are not supported here. Only expansions in " + "template arguments and class bases are supported">; + def err_fold_expression_packs_both_sides : Error< "binary fold expression has unexpanded parameter packs in both operands">; def err_fold_expression_empty : Error< @@ -10423,9 +10442,10 @@ def warn_format_conversion_argument_type_mismatch : Warning< def warn_format_conversion_argument_type_mismatch_pedantic : Extension< warn_format_conversion_argument_type_mismatch.Summary>, InGroup<FormatPedantic>; -def warn_format_conversion_argument_type_mismatch_signedness : Warning< - warn_format_conversion_argument_type_mismatch.Summary>, - InGroup<FormatSignedness>, DefaultIgnore; +def warn_format_conversion_argument_type_mismatch_signedness: Warning< + "format specifies type %0 but the argument has %select{type|underlying " + "type}2 %1, which differs in signedness" > + , InGroup<FormatSignedness>, DefaultIgnore; def warn_format_conversion_argument_type_mismatch_confusion : Warning< warn_format_conversion_argument_type_mismatch.Summary>, InGroup<FormatTypeConfusion>, DefaultIgnore; @@ -10537,8 +10557,10 @@ def warn_format_cmp_sensitivity_mismatch : Warning< "it should be %select{unspecified|private|public|sensitive}1">, InGroup<Format>; def warn_format_cmp_specifier_mismatch : Warning< "format specifier '%0' is incompatible with '%1'">, InGroup<Format>; -def warn_format_cmp_specifier_sign_mismatch : Warning< - "signedness of format specifier '%0' is incompatible with '%1'">, InGroup<Format>; +def warn_format_cmp_specifier_sign_mismatch + : Warning<"signedness of format specifier '%0' is incompatible with '%1'">, + InGroup<FormatSignedness>, + DefaultIgnore; def warn_format_cmp_specifier_mismatch_pedantic : Extension< warn_format_cmp_specifier_sign_mismatch.Summary>, InGroup<FormatPedantic>; def note_format_cmp_with : Note< @@ -10668,9 +10690,15 @@ def warn_dangling_reference_captured_by_unknown : Warning< "object whose reference is captured will be destroyed at the end of " "the full-expression">, InGroup<DanglingCapture>; -def warn_experimental_lifetime_safety_dummy_warning : Warning< - "todo: remove this warning after we have atleast one warning based on the lifetime analysis">, - InGroup<LifetimeSafety>, DefaultIgnore; +// Diagnostics based on the Lifetime safety analysis. +def warn_lifetime_safety_loan_expires_permissive : Warning< + "object whose reference is captured does not live long enough">, + InGroup<LifetimeSafetyPermissive>, DefaultIgnore; +def warn_lifetime_safety_loan_expires_strict : Warning< + "object whose reference is captured may not live long enough">, + InGroup<LifetimeSafetyStrict>, DefaultIgnore; +def note_lifetime_safety_used_here : Note<"later used here">; +def note_lifetime_safety_destroyed_here : Note<"destroyed here">; // For non-floating point, expressions of the form x == x or x != x // should result in a warning, since these always evaluate to a constant. @@ -10985,10 +11013,15 @@ def err_block_on_vm : Error< def err_sizeless_nonlocal : Error< "non-local variable with sizeless type %0">; +def err_vec_masked_load_store_ptr : Error< + "%ordinal0 argument must be a %1">; +def err_vec_masked_load_store_size : Error< + "all arguments to %0 must have the same number of elements (was %1 and %2)">; + def err_vec_builtin_non_vector : Error< "%select{first two|all}1 arguments to %0 must be vectors">; def err_vec_builtin_incompatible_vector : Error< - "%select{first two|all}1 arguments to %0 must have the same type">; + "%select{first two|all|last two}1 arguments to %0 must have the same type">; def err_vsx_builtin_nonconstant_argument : Error< "argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">; @@ -12585,7 +12618,7 @@ def warn_zero_as_null_pointer_constant : Warning< InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore; def warn_not_eliding_copy_on_return : Warning< - "not eliding copy on return">, + "not eliding copy on return">, InGroup<DiagGroup<"nrvo">>, DefaultIgnore; def err_nullability_cs_multilevel : Error< @@ -12850,7 +12883,7 @@ def err_builtin_invalid_arg_type: Error< "%plural{0:|: }1" // Second component: integer-like types "%select{|integer|signed integer|unsigned integer|'int'|" - "pointer to a valid matrix element}2" + "pointer to a valid matrix element|boolean}2" // A space after a non-empty second component "%plural{0:|: }2" // An 'or' if non-empty second and third components are combined @@ -12942,6 +12975,17 @@ def err_sycl_special_type_num_init_method : Error< "types with 'sycl_special_class' attribute must have one and only one '__init' " "method defined">; +// SYCL external attribute diagnostics +def err_sycl_external_invalid_linkage : Error< + "%0 can only be applied to functions with external linkage">; +def err_sycl_external_invalid_main : Error< + "%0 cannot be applied to the 'main' function">; +def err_sycl_external_invalid_deleted_function : Error< + "%0 cannot be applied to an explicitly deleted function">; +def warn_sycl_external_missing_on_first_decl : Warning< + "%0 attribute does not appear on the first declaration">, + InGroup<NonPortableSYCL>; + // SYCL kernel entry point diagnostics def err_sycl_entry_point_invalid : Error< "the %0 attribute cannot be applied to a" @@ -12956,7 +13000,7 @@ def err_sycl_kernel_name_conflict : Error< "the %0 kernel name argument conflicts with a previous declaration">; def warn_sycl_kernel_name_not_a_class_type : Warning< "%0 is not a valid SYCL kernel name type; a non-union class type is required">, - InGroup<DiagGroup<"nonportable-sycl">>, DefaultError; + InGroup<NonPortableSYCL>, DefaultError; def warn_sycl_entry_point_redundant_declaration : Warning< "redundant %0 attribute">, InGroup<RedundantAttribute>; def err_sycl_entry_point_after_definition : Error< @@ -13234,9 +13278,9 @@ def err_wasm_builtin_arg_must_match_table_element_type : Error < "%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">; def err_wasm_builtin_arg_must_be_integer_type : Error < "%ordinal0 argument must be an integer">; -def err_wasm_builtin_test_fp_sig_cannot_include_reference_type - : Error<"not supported for " - "function pointers with a reference type %select{return " +def err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union + : Error<"not supported with the multivalue ABI for " + "function pointers with a struct/union as %select{return " "value|parameter}0">; // OpenACC diagnostics. @@ -13359,16 +13403,23 @@ def err_acc_reduction_num_gangs_conflict "appear on a '%2' construct " "with a '%3' clause%select{ with more than 1 argument|}0">; def err_acc_reduction_type - : Error<"OpenACC 'reduction' variable must be of scalar type, aggregate, " - "sub-array, or a composite of scalar types;%select{| sub-array " - "base}1 type is %0">; -def err_acc_reduction_composite_type - : Error<"OpenACC 'reduction' variable must be a composite of scalar types; " - "%1 %select{is not a class or struct|is incomplete|is not an " - "aggregate}0">; -def err_acc_reduction_composite_member_type :Error< - "OpenACC 'reduction' composite variable must not have non-scalar field">; -def note_acc_reduction_composite_member_loc : Note<"invalid field is here">; + : Error<"invalid type %0 used in OpenACC 'reduction' variable reference; " + "type is %enum_select<OACCReductionTy>{%NotScalar{not a scalar " + "value, or array of scalars, or composite of " + "scalars}|%MemberNotScalar{not a scalar value}|%NotAgg{not an " + "aggregate}|%NotComplete{not a complete type}|%NotClassStruct{not " + "a class or struct}}1">; +def note_acc_reduction_array + : Note<"used as element type of " + "%enum_select<OACCReductionArray>{%Section{sub-array" + "}|%Subscript{array}|%ArrayTy{array}}0 type %1">; +def note_acc_reduction_member_of_composite + : Note<"used as field '%0' of composite '%1'">; +def note_acc_reduction_type_summary + : Note<"OpenACC 'reduction' variable reference must be a scalar variable " + "or a " + "composite of scalars, or an array, sub-array, or element of scalar " + "types">; def err_acc_loop_not_for_loop : Error<"OpenACC '%0' construct can only be applied to a 'for' loop">; def note_acc_construct_here : Note<"'%0' construct is here">; @@ -13529,8 +13580,13 @@ def err_acc_invalid_modifier def err_acc_invalid_default_type : Error<"invalid value %0 in '%1' clause; valid values are %2">; def err_acc_device_type_multiple_archs - : Error<"OpenACC 'device_type' clause on a 'set' construct only permits " + : Error<"OpenACC 'device_type' clause on a '%0' construct only permits " "one architecture">; +def warn_acc_var_referenced_non_const_array + : Warning<"variable of array type %0 referenced in OpenACC '%1' clause " + "does not have constant bounds; initialization will happen after " + "decay to pointer">, + InGroup<DiagGroup<"openacc-var-non-const-array">>; def warn_acc_var_referenced_lacks_op : Warning<"variable of type %0 referenced in OpenACC '%1' clause does not " "have a %enum_select<AccVarReferencedReason>{%DefCtor{default " diff --git a/clang/include/clang/Basic/DiagnosticTrap.h b/clang/include/clang/Basic/DiagnosticTrap.h new file mode 100644 index 0000000..da8bd25 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticTrap.h @@ -0,0 +1,14 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_DIAGNOSTICTRAP_H +#define LLVM_CLANG_BASIC_DIAGNOSTICTRAP_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticTrapInterface.inc" + +#endif diff --git a/clang/include/clang/Basic/DiagnosticTrapKinds.td b/clang/include/clang/Basic/DiagnosticTrapKinds.td new file mode 100644 index 0000000..c17a88d --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticTrapKinds.td @@ -0,0 +1,30 @@ +//==--- DiagnosticTrapKinds.td ------------------------ -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Trap Diagnostics +// +// These are diagnostics that are emitted into `TrapReason` objects using the +// `TrapReasonBuilder` class. These `TrapReason` objects are then encoded into +// debug info during codegen, rather than to the traditional diagnostic +// consumers like the terminal. Their primary purpose is to make debugging traps +// (e.g. `-fsanitize-trap=undefined`) easier by attaching a trap category and +// message to the trap instruction that tools like a debugger can show. +// +//===----------------------------------------------------------------------===// +let Component = "Trap" in { +let CategoryName = "Undefined Behavior Sanitizer" in { + +def trap_ubsan_arith_overflow : Trap< + "%select{unsigned|signed}0 integer " + "%enum_select<UBSanArithKind>{" + "%Add{addition}|" + "%Sub{subtraction}|" + "%Mul{multiplication}" + "}1 overflow in %2">; + +} +} diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 72f2361..0e91b42a 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -128,6 +128,7 @@ FEATURE(attribute_overloadable, true) FEATURE(attribute_unavailable_with_message, true) FEATURE(attribute_unused_on_fields, true) FEATURE(attribute_diagnose_if_objc, true) +FEATURE(ext_vector_type_boolean, true) FEATURE(blocks, LangOpts.Blocks) FEATURE(c_thread_safety_attributes, true) FEATURE(cxx_exceptions, LangOpts.CXXExceptions) @@ -147,14 +148,17 @@ FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type)) FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) -FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics) -EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics) +FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics && + PP.getTargetInfo().getTriple().isOSDarwin()) +FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics && + PP.getTargetInfo().getTriple().isOSDarwin()) FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls) FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns) FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination) FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination) FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination) FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls) +FEATURE(ptrauth_signed_block_descriptors, LangOpts.PointerAuthBlockDescriptorPointers) FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination) FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos) FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini) @@ -163,7 +167,7 @@ FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT) FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa) FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel) -FEATURE(ptrauth_objc_signable_class, true) +FEATURE(ptrauth_objc_signable_class, LangOpts.PointerAuthIntrinsics) FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls) EXTENSION(swiftcc, @@ -303,6 +307,14 @@ FEATURE(is_trivially_assignable, LangOpts.CPlusPlus) FEATURE(is_trivially_constructible, LangOpts.CPlusPlus) FEATURE(is_trivially_copyable, LangOpts.CPlusPlus) FEATURE(is_union, LangOpts.CPlusPlus) +FEATURE(cfi_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::CFI)) +FEATURE(cfi_cast_strict_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFICastStrict)) +FEATURE(cfi_derived_cast_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast)) +FEATURE(cfi_icall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIICall)) +FEATURE(cfi_mfcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIMFCall)) +FEATURE(cfi_unrelated_cast_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast)) +FEATURE(cfi_nvcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFINVCall)) +FEATURE(cfi_vcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIVCall)) FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI)) FEATURE(kcfi_arity, LangOpts.Sanitize.has(SanitizerKind::KCFI)) FEATURE(modules, LangOpts.Modules) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 08d98a7..e0a5351 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -136,6 +136,8 @@ LANGOPT(PointerAuthObjcInterfaceSel, 1, 0, NotCompatible, "authentication of SEL LANGOPT(PointerAuthObjcInterfaceSelKey, 16, 0, NotCompatible, "authentication key for SEL fields of ObjC interfaces") LANGOPT(PointerAuthObjcClassROPointers, 1, 0, Benign, "class_ro_t pointer authentication") +LANGOPT(PointerAuthBlockDescriptorPointers, 1, 0, NotCompatible, "enable signed block descriptors") + LANGOPT(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes extension for all language standard modes") LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes") @@ -239,6 +241,7 @@ LANGOPT(HLSL, 1, 0, NotCompatible, "HLSL") ENUM_LANGOPT(HLSLVersion, HLSLLangStd, 16, HLSL_Unset, NotCompatible, "HLSL Version") LANGOPT(HLSLStrictAvailability, 1, 0, NotCompatible, "Strict availability diagnostic mode for HLSL built-in functions.") +LANGOPT(HLSLSpvUseUnknownImageFormat, 1, 0, NotCompatible, "For storage images and texel buffers, sets the default format to 'Unknown' when not specified via the `vk::image_format` attribute. If this option is not used, the format is inferred from the resource's data type.") LANGOPT(CUDAIsDevice , 1, 0, NotCompatible, "compiling for CUDA device") LANGOPT(CUDAAllowVariadicFunctions, 1, 0, NotCompatible, "allowing variadic functions in CUDA device code") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 0407897..a8943df 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -186,95 +186,10 @@ public: /// Clang versions with different platform ABI conformance. enum class ClangABI { - /// Attempt to be ABI-compatible with code generated by Clang 3.8.x - /// (SVN r257626). This causes <1 x long long> to be passed in an - /// integer register instead of an SSE register on x64_64. - Ver3_8, - - /// Attempt to be ABI-compatible with code generated by Clang 4.0.x - /// (SVN r291814). This causes move operations to be ignored when - /// determining whether a class type can be passed or returned directly. - Ver4, - - /// Attempt to be ABI-compatible with code generated by Clang 6.0.x - /// (SVN r321711). This causes determination of whether a type is - /// standard-layout to ignore collisions between empty base classes - /// and between base classes and member subobjects, which affects - /// whether we reuse base class tail padding in some ABIs. - Ver6, - - /// Attempt to be ABI-compatible with code generated by Clang 7.0.x - /// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be - /// compatible with __alignof (i.e., return the preferred alignment) - /// rather than returning the required alignment. - Ver7, - - /// Attempt to be ABI-compatible with code generated by Clang 9.0.x - /// (SVN r351319). This causes vectors of __int128 to be passed in memory - /// instead of passing in multiple scalar registers on x86_64 on Linux and - /// NetBSD. - Ver9, - - /// Attempt to be ABI-compatible with code generated by Clang 11.0.x - /// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit - /// vector member on the stack instead of using registers, to not properly - /// mangle substitutions for template names in some cases, and to mangle - /// declaration template arguments without a cast to the parameter type - /// even when that can lead to mangling collisions. - Ver11, - - /// Attempt to be ABI-compatible with code generated by Clang 12.0.x - /// (git 8e464dd76bef). This causes clang to mangle lambdas within - /// global-scope inline variables incorrectly. - Ver12, - - /// Attempt to be ABI-compatible with code generated by Clang 14.0.x. - /// This causes clang to: - /// - mangle dependent nested names incorrectly. - /// - make trivial only those defaulted copy constructors with a - /// parameter-type-list equivalent to the parameter-type-list of an - /// implicit declaration. - Ver14, - - /// Attempt to be ABI-compatible with code generated by Clang 15.0.x. - /// This causes clang to: - /// - Reverse the implementation for DR692, DR1395 and DR1432. - /// - pack non-POD members of packed structs. - /// - consider classes with defaulted special member functions non-pod. - Ver15, - - /// Attempt to be ABI-compatible with code generated by Clang 17.0.x. - /// This causes clang to revert some fixes to its implementation of the - /// Itanium name mangling scheme, with the consequence that overloaded - /// function templates are mangled the same if they differ only by: - /// - constraints - /// - whether a non-type template parameter has a deduced type - /// - the parameter list of a template template parameter - Ver17, - - /// Attempt to be ABI-compatible with code generated by Clang 18.0.x. - /// This causes clang to revert some fixes to the mangling of lambdas - /// in the initializers of members of local classes. - Ver18, - - /// Attempt to be ABI-compatible with code generated by Clang 19.0.x. - /// This causes clang to: - /// - Incorrectly mangle the 'base type' substitutions of the CXX - /// construction vtable because it hasn't added 'type' as a substitution. - /// - Skip mangling enclosing class templates of member-like friend - /// function templates. - /// - Ignore empty struct arguments in C++ mode for ARM, instead of - /// passing them as if they had a size of 1 byte. - Ver19, - - /// Attempt to be ABI-compatible with code generated by Clang 20.0.x. - /// This causes clang to: - /// - Incorrectly return C++ records in AVX registers on x86_64. - Ver20, - - /// Conform to the underlying platform's C and C++ ABIs as closely - /// as we can. - Latest +#define ABI_VER_MAJOR_MINOR(Major, Minor) Ver##Major##_##Minor, +#define ABI_VER_MAJOR(Major) Ver##Major, +#define ABI_VER_LATEST(Latest) Latest +#include "clang/Basic/ABIVersions.def" }; enum class CoreFoundationABI { @@ -637,6 +552,10 @@ public: llvm::dxbc::RootSignatureVersion HLSLRootSigVer = llvm::dxbc::RootSignatureVersion::V1_1; + /// The HLSL root signature that will be used to overide the root signature + /// used for the shader entry point. + std::string HLSLRootSigOverride; + // Indicates if the wasm-opt binary must be ignored in the case of a // WebAssembly target. bool NoWasmOpt = false; diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index fb6dddf..2b92025 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -23,6 +23,10 @@ namespace clang { +/// Constant discriminator to be used with block descriptor pointers. The value +/// is ptrauth_string_discriminator("block_descriptor") +constexpr uint16_t BlockDescriptorConstantDiscriminator = 0xC0BB; + /// Constant discriminator to be used with function pointers in .init_array and /// .fini_array. The value is ptrauth_string_discriminator("init_fini") constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4; @@ -223,6 +227,18 @@ struct PointerAuthOptions { /// The ABI for function addresses in .init_array and .fini_array PointerAuthSchema InitFiniPointers; + /// The ABI for block invocation function pointers. + PointerAuthSchema BlockInvocationFunctionPointers; + + /// The ABI for block object copy/destroy function pointers. + PointerAuthSchema BlockHelperFunctionPointers; + + /// The ABI for __block variable copy/destroy function pointers. + PointerAuthSchema BlockByrefHelperFunctionPointers; + + /// The ABI for pointers to block descriptors. + PointerAuthSchema BlockDescriptorPointers; + /// The ABI for Objective-C method lists. PointerAuthSchema ObjCMethodListFunctionPointers; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index ce4677e..25b6862 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -233,8 +233,9 @@ protected: bool TLSSupported; bool VLASupported; bool NoAsmVariants; // True if {|} are normal characters. - bool HasLegalHalfType; // True if the backend supports operations on the half - // LLVM IR type. + bool HasFastHalfType; // True if the backend has native half float support, + // and performing calculations in float instead does + // not have a performance advantage. bool HalfArgsAndReturns; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) type. bool HasFloat128; bool HasFloat16; @@ -700,8 +701,9 @@ public: return 128; } - /// Determine whether _Float16 is supported on this target. - virtual bool hasLegalHalfType() const { return HasLegalHalfType; } + /// Determine whether the target has fast native support for operations + /// on half types. + virtual bool hasFastHalfType() const { return HasFastHalfType; } /// Whether half args and returns are supported. virtual bool allowHalfArgsAndReturns() const { return HalfArgsAndReturns; } diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h index 1b133dd..d84f359 100644 --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -95,10 +95,20 @@ inline bool isStringLiteral(TokenKind K) { /// Return true if this is a "literal" kind, like a numeric /// constant, string, etc. inline bool isLiteral(TokenKind K) { - return K == tok::numeric_constant || K == tok::char_constant || - K == tok::wide_char_constant || K == tok::utf8_char_constant || - K == tok::utf16_char_constant || K == tok::utf32_char_constant || - isStringLiteral(K) || K == tok::header_name || K == tok::binary_data; + const bool isInLiteralRange = + K >= tok::numeric_constant && K <= tok::utf32_string_literal; + +#if !NDEBUG + const bool isLiteralExplicit = + K == tok::numeric_constant || K == tok::char_constant || + K == tok::wide_char_constant || K == tok::utf8_char_constant || + K == tok::utf16_char_constant || K == tok::utf32_char_constant || + isStringLiteral(K) || K == tok::header_name || K == tok::binary_data; + assert(isInLiteralRange == isLiteralExplicit && + "TokenKind literals should be contiguous"); +#endif + + return isInLiteralRange; } /// Return true if this is any of tok::annot_* kinds. diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 971ce54..fb6862b 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -37,21 +37,12 @@ class NeverCanonical {} /// canonical types can ignore these nodes. class NeverCanonicalUnlessDependent {} -/// A type node which never has component type structure. Some code may be -/// able to operate on leaf types faster than they can on non-leaf types. -/// -/// For example, the function type `void (int)` is not a leaf type because it -/// is structurally composed of component types (`void` and `int`). -/// -/// A struct type is a leaf type because its field types are not part of its -/// type-expression. -/// -/// Nodes like `TypedefType` which are syntactically leaves but can desugar -/// to types that may not be leaves should not declare this. -class LeafType {} +/// A type node which is always a canonical type, that is, types for which +/// `T.getCanonicalType() == T` always holds. +class AlwaysCanonical {} def Type : TypeNode<?, 1>; -def BuiltinType : TypeNode<Type>, LeafType; +def BuiltinType : TypeNode<Type>, AlwaysCanonical; def ComplexType : TypeNode<Type>; def PointerType : TypeNode<Type>; def BlockPointerType : TypeNode<Type>; @@ -88,28 +79,29 @@ def TypeOfType : TypeNode<Type>, NeverCanonicalUnlessDependent; def DecltypeType : TypeNode<Type>, NeverCanonicalUnlessDependent; def UnaryTransformType : TypeNode<Type>, NeverCanonicalUnlessDependent; def TagType : TypeNode<Type, 1>; -def RecordType : TypeNode<TagType>, LeafType; -def EnumType : TypeNode<TagType>, LeafType; -def ElaboratedType : TypeNode<Type>, NeverCanonical; +def RecordType : TypeNode<TagType>; +def EnumType : TypeNode<TagType>; +def InjectedClassNameType : TypeNode<TagType>, AlwaysDependent; def AttributedType : TypeNode<Type>, NeverCanonical; def BTFTagAttributedType : TypeNode<Type>, NeverCanonical; def HLSLAttributedResourceType : TypeNode<Type>; def HLSLInlineSpirvType : TypeNode<Type>; -def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType; +def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent; def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical; -def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent; +def SubstPackType : TypeNode<Type, 1>; +def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent; +def SubstBuiltinTemplatePackType : TypeNode<SubstPackType>, AlwaysDependent; def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent; def DeducedType : TypeNode<Type, 1>; def AutoType : TypeNode<DeducedType>; def DeducedTemplateSpecializationType : TypeNode<DeducedType>; -def InjectedClassNameType : TypeNode<Type>, AlwaysDependent, LeafType; def DependentNameType : TypeNode<Type>, AlwaysDependent; def DependentTemplateSpecializationType : TypeNode<Type>, AlwaysDependent; def PackExpansionType : TypeNode<Type>, AlwaysDependent; def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent; def ObjCTypeParamType : TypeNode<Type>, NeverCanonical; def ObjCObjectType : TypeNode<Type>; -def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType; +def ObjCInterfaceType : TypeNode<ObjCObjectType>, AlwaysCanonical; def ObjCObjectPointerType : TypeNode<Type>; def BoundsAttributedType : TypeNode<Type, 1>; def CountAttributedType : TypeNode<BoundsAttributedType>, NeverCanonical; diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td index c491eb0..a4eb92e 100644 --- a/clang/include/clang/Basic/arm_sme.td +++ b/clang/include/clang/Basic/arm_sme.td @@ -21,23 +21,21 @@ let SVETargetGuard = InvalidMode in { // Loads multiclass ZALoad<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> { - let SMETargetGuard = "sme" in { - def NAME # _H : MInst<"svld1_hor_" # n_suffix, "vimPQ", t, - [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], - MemEltTyDefault, i_prefix # "_horiz", ch>; - - def NAME # _H_VNUM : MInst<"svld1_hor_vnum_" # n_suffix, "vimPQl", t, - [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], - MemEltTyDefault, i_prefix # "_horiz", ch>; - - def NAME # _V : MInst<"svld1_ver_" # n_suffix, "vimPQ", t, - [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], - MemEltTyDefault, i_prefix # "_vert", ch>; - - def NAME # _V_VNUM : MInst<"svld1_ver_vnum_" # n_suffix, "vimPQl", t, - [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], - MemEltTyDefault, i_prefix # "_vert", ch>; - } + def NAME # _H : MInst<"svld1_hor_" # n_suffix, "vimPQ", t, + [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], + MemEltTyDefault, i_prefix # "_horiz", ch>; + + def NAME # _H_VNUM : MInst<"svld1_hor_vnum_" # n_suffix, "vimPQl", t, + [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], + MemEltTyDefault, i_prefix # "_horiz", ch>; + + def NAME # _V : MInst<"svld1_ver_" # n_suffix, "vimPQ", t, + [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], + MemEltTyDefault, i_prefix # "_vert", ch>; + + def NAME # _V_VNUM : MInst<"svld1_ver_vnum_" # n_suffix, "vimPQl", t, + [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], + MemEltTyDefault, i_prefix # "_vert", ch>; } defm SVLD1_ZA8 : ZALoad<"za8", "c", "aarch64_sme_ld1b", [ImmCheck<0, ImmCheck0_0>]>; @@ -46,7 +44,6 @@ defm SVLD1_ZA32 : ZALoad<"za32", "i", "aarch64_sme_ld1w", [ImmCheck<0, ImmCheck0 defm SVLD1_ZA64 : ZALoad<"za64", "l", "aarch64_sme_ld1d", [ImmCheck<0, ImmCheck0_7>]>; defm SVLD1_ZA128 : ZALoad<"za128", "q", "aarch64_sme_ld1q", [ImmCheck<0, ImmCheck0_15>]>; -let SMETargetGuard = "sme" in { def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "", [IsOverloadNone, IsStreamingCompatible, IsInOutZA], MemEltTyDefault, "aarch64_sme_ldr">; @@ -54,29 +51,26 @@ def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "", def SVLDR_ZA : MInst<"svldr_za", "vmQ", "", [IsOverloadNone, IsStreamingCompatible, IsInOutZA], MemEltTyDefault, "aarch64_sme_ldr", []>; -} //////////////////////////////////////////////////////////////////////////////// // Stores multiclass ZAStore<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> { - let SMETargetGuard = "sme" in { - def NAME # _H : MInst<"svst1_hor_" # n_suffix, "vimP%", t, - [IsStore, IsOverloadNone, IsStreaming, IsInZA], - MemEltTyDefault, i_prefix # "_horiz", ch>; - - def NAME # _H_VNUM : MInst<"svst1_hor_vnum_" # n_suffix, "vimP%l", t, - [IsStore, IsOverloadNone, IsStreaming, IsInZA], - MemEltTyDefault, i_prefix # "_horiz", ch>; - - def NAME # _V : MInst<"svst1_ver_" # n_suffix, "vimP%", t, - [IsStore, IsOverloadNone, IsStreaming, IsInZA], - MemEltTyDefault, i_prefix # "_vert", ch>; - - def NAME # _V_VNUM : MInst<"svst1_ver_vnum_" # n_suffix, "vimP%l", t, - [IsStore, IsOverloadNone, IsStreaming, IsInZA], - MemEltTyDefault, i_prefix # "_vert", ch>; - } + def NAME # _H : MInst<"svst1_hor_" # n_suffix, "vimP%", t, + [IsStore, IsOverloadNone, IsStreaming, IsInZA], + MemEltTyDefault, i_prefix # "_horiz", ch>; + + def NAME # _H_VNUM : MInst<"svst1_hor_vnum_" # n_suffix, "vimP%l", t, + [IsStore, IsOverloadNone, IsStreaming, IsInZA], + MemEltTyDefault, i_prefix # "_horiz", ch>; + + def NAME # _V : MInst<"svst1_ver_" # n_suffix, "vimP%", t, + [IsStore, IsOverloadNone, IsStreaming, IsInZA], + MemEltTyDefault, i_prefix # "_vert", ch>; + + def NAME # _V_VNUM : MInst<"svst1_ver_vnum_" # n_suffix, "vimP%l", t, + [IsStore, IsOverloadNone, IsStreaming, IsInZA], + MemEltTyDefault, i_prefix # "_vert", ch>; } defm SVST1_ZA8 : ZAStore<"za8", "c", "aarch64_sme_st1b", [ImmCheck<0, ImmCheck0_0>]>; @@ -85,7 +79,6 @@ defm SVST1_ZA32 : ZAStore<"za32", "i", "aarch64_sme_st1w", [ImmCheck<0, ImmCheck defm SVST1_ZA64 : ZAStore<"za64", "l", "aarch64_sme_st1d", [ImmCheck<0, ImmCheck0_7>]>; defm SVST1_ZA128 : ZAStore<"za128", "q", "aarch64_sme_st1q", [ImmCheck<0, ImmCheck0_15>]>; -let SMETargetGuard = "sme" in { def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "", [IsOverloadNone, IsStreamingCompatible, IsInZA], MemEltTyDefault, "aarch64_sme_str">; @@ -93,21 +86,18 @@ def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "", def SVSTR_ZA : MInst<"svstr_za", "vm%", "", [IsOverloadNone, IsStreamingCompatible, IsInZA], MemEltTyDefault, "aarch64_sme_str", []>; -} //////////////////////////////////////////////////////////////////////////////// // Read horizontal/vertical ZA slices multiclass ZARead<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> { - let SMETargetGuard = "sme" in { - def NAME # _H : SInst<"svread_hor_" # n_suffix # "[_{d}]", "ddPim", t, - MergeOp1, i_prefix # "_horiz", - [IsReadZA, IsStreaming, IsInZA], ch>; - - def NAME # _V : SInst<"svread_ver_" # n_suffix # "[_{d}]", "ddPim", t, - MergeOp1, i_prefix # "_vert", - [IsReadZA, IsStreaming, IsInZA], ch>; - } + def NAME # _H : SInst<"svread_hor_" # n_suffix # "[_{d}]", "ddPim", t, + MergeOp1, i_prefix # "_horiz", + [IsReadZA, IsStreaming, IsInZA], ch>; + + def NAME # _V : SInst<"svread_ver_" # n_suffix # "[_{d}]", "ddPim", t, + MergeOp1, i_prefix # "_vert", + [IsReadZA, IsStreaming, IsInZA], ch>; } defm SVREAD_ZA8 : ZARead<"za8", "cUcm", "aarch64_sme_read", [ImmCheck<2, ImmCheck0_0>]>; @@ -120,15 +110,13 @@ defm SVREAD_ZA128 : ZARead<"za128", "csilUcUsUiUlmhbfd", "aarch64_sme_readq", [I // Write horizontal/vertical ZA slices multiclass ZAWrite<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> { - let SMETargetGuard = "sme" in { - def NAME # _H : SInst<"svwrite_hor_" # n_suffix # "[_{d}]", "vimPd", t, - MergeOp1, i_prefix # "_horiz", - [IsWriteZA, IsStreaming, IsInOutZA], ch>; - - def NAME # _V : SInst<"svwrite_ver_" # n_suffix # "[_{d}]", "vimPd", t, - MergeOp1, i_prefix # "_vert", - [IsWriteZA, IsStreaming, IsInOutZA], ch>; - } + def NAME # _H : SInst<"svwrite_hor_" # n_suffix # "[_{d}]", "vimPd", t, + MergeOp1, i_prefix # "_horiz", + [IsWriteZA, IsStreaming, IsInOutZA], ch>; + + def NAME # _V : SInst<"svwrite_ver_" # n_suffix # "[_{d}]", "vimPd", t, + MergeOp1, i_prefix # "_vert", + [IsWriteZA, IsStreaming, IsInOutZA], ch>; } defm SVWRITE_ZA8 : ZAWrite<"za8", "cUcm", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_0>]>; @@ -140,13 +128,11 @@ defm SVWRITE_ZA128 : ZAWrite<"za128", "csilUcUsUiUlmhbfd", "aarch64_sme_writeq", //////////////////////////////////////////////////////////////////////////////// // SME - Zero -let SMETargetGuard = "sme" in { - def SVZERO_MASK_ZA : SInst<"svzero_mask_za", "vi", "", MergeNone, "aarch64_sme_zero", - [IsOverloadNone, IsStreamingCompatible, IsInOutZA], - [ImmCheck<0, ImmCheck0_255>]>; - def SVZERO_ZA : SInst<"svzero_za", "vv", "", MergeNone, "aarch64_sme_zero", - [IsOverloadNone, IsStreamingCompatible, IsOutZA]>; -} +def SVZERO_MASK_ZA : SInst<"svzero_mask_za", "vi", "", MergeNone, "aarch64_sme_zero", + [IsOverloadNone, IsStreamingCompatible, IsInOutZA], + [ImmCheck<0, ImmCheck0_255>]>; +def SVZERO_ZA : SInst<"svzero_za", "vv", "", MergeNone, "aarch64_sme_zero", + [IsOverloadNone, IsStreamingCompatible, IsOutZA]>; let SMETargetGuard = "sme2p1" in { def SVZERO_ZA64_VG1x2 : SInst<"svzero_za64_vg1x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x2", @@ -171,11 +157,9 @@ let SMETargetGuard = "sme2p1" in { // SME - Counting elements in a streaming vector multiclass ZACount<string n_suffix> { - let SMETargetGuard = "sme" in { - def NAME : SInst<"sv" # n_suffix, "nv", "", MergeNone, - "aarch64_sme_" # n_suffix, - [IsOverloadNone, IsStreamingCompatible]>; - } + def NAME : SInst<"sv" # n_suffix, "nv", "", MergeNone, + "aarch64_sme_" # n_suffix, + [IsOverloadNone, IsStreamingCompatible]>; } defm SVCNTSB : ZACount<"cntsb">; @@ -187,11 +171,9 @@ defm SVCNTSD : ZACount<"cntsd">; // SME - ADDHA/ADDVA multiclass ZAAdd<string n_suffix> { - let SMETargetGuard = "sme" in { - def NAME # _ZA32: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPd", "iUi", MergeOp1, - "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA], - [ImmCheck<0, ImmCheck0_3>]>; - } + def NAME # _ZA32: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPd", "iUi", MergeOp1, + "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA], + [ImmCheck<0, ImmCheck0_3>]>; let SMETargetGuard = "sme-i16i64" in { def NAME # _ZA64: SInst<"sv" # n_suffix # "_za64[_{d}]", "viPPd", "lUl", MergeOp1, @@ -207,13 +189,11 @@ defm SVADDVA : ZAAdd<"addva">; // SME - SMOPA, SMOPS, UMOPA, UMOPS multiclass ZAIntOuterProd<string n_suffix1, string n_suffix2> { - let SMETargetGuard = "sme" in { - def NAME # _ZA32_B: SInst<"sv" # n_suffix2 # "_za32[_{d}]", - "viPPdd", !cond(!eq(n_suffix1, "s") : "", true: "U") # "c", - MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide", - [IsStreaming, IsInOutZA], - [ImmCheck<0, ImmCheck0_3>]>; - } + def NAME # _ZA32_B: SInst<"sv" # n_suffix2 # "_za32[_{d}]", + "viPPdd", !cond(!eq(n_suffix1, "s") : "", true: "U") # "c", + MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide", + [IsStreaming, IsInOutZA], + [ImmCheck<0, ImmCheck0_3>]>; let SMETargetGuard = "sme-i16i64" in { def NAME # _ZA64_H: SInst<"sv" # n_suffix2 # "_za64[_{d}]", @@ -233,14 +213,12 @@ defm SVUMOPS : ZAIntOuterProd<"u", "mops">; // SME - SUMOPA, SUMOPS, USMOPA, USMOPS multiclass ZAIntOuterProdMixedSigns<string n_suffix1, string n_suffix2> { - let SMETargetGuard = "sme" in { - def NAME # _ZA32_B: SInst<"sv" # n_suffix1 # n_suffix2 # "_za32[_{d}]", - "viPPd" # !cond(!eq(n_suffix1, "su") : "u", true: "x"), - !cond(!eq(n_suffix1, "su") : "", true: "U") # "c", - MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide", - [IsStreaming, IsInOutZA], - [ImmCheck<0, ImmCheck0_3>]>; - } + def NAME # _ZA32_B: SInst<"sv" # n_suffix1 # n_suffix2 # "_za32[_{d}]", + "viPPd" # !cond(!eq(n_suffix1, "su") : "u", true: "x"), + !cond(!eq(n_suffix1, "su") : "", true: "U") # "c", + MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide", + [IsStreaming, IsInOutZA], + [ImmCheck<0, ImmCheck0_3>]>; let SMETargetGuard = "sme-i16i64" in { def NAME # _ZA64_H: SInst<"sv" # n_suffix1 # n_suffix2 # "_za64[_{d}]", @@ -261,22 +239,20 @@ defm SVUSMOPS : ZAIntOuterProdMixedSigns<"us", "mops">; // SME - FMOPA, FMOPS multiclass ZAFPOuterProd<string n_suffix> { - let SMETargetGuard = "sme" in { - def NAME # _ZA32_B: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "h", - MergeOp1, "aarch64_sme_" # n_suffix # "_wide", - [IsStreaming, IsInOutZA], - [ImmCheck<0, ImmCheck0_3>]>; + def NAME # _ZA32_B: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "h", + MergeOp1, "aarch64_sme_" # n_suffix # "_wide", + [IsStreaming, IsInOutZA], + [ImmCheck<0, ImmCheck0_3>]>; - def NAME # _ZA32_H: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "b", - MergeOp1, "aarch64_sme_" # n_suffix # "_wide", - [IsStreaming, IsInOutZA], - [ImmCheck<0, ImmCheck0_3>]>; + def NAME # _ZA32_H: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "b", + MergeOp1, "aarch64_sme_" # n_suffix # "_wide", + [IsStreaming, IsInOutZA], + [ImmCheck<0, ImmCheck0_3>]>; - def NAME # _ZA32_S: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "f", - MergeOp1, "aarch64_sme_" # n_suffix, - [IsStreaming, IsInOutZA], - [ImmCheck<0, ImmCheck0_3>]>; - } + def NAME # _ZA32_S: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "f", + MergeOp1, "aarch64_sme_" # n_suffix, + [IsStreaming, IsInOutZA], + [ImmCheck<0, ImmCheck0_3>]>; let SMETargetGuard = "sme-f64f64" in { def NAME # _ZA64_D: SInst<"sv" # n_suffix # "_za64[_{d}]", "viPPdd", "d", diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index 07786c6..b8b0f7f 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -36,7 +36,7 @@ def SVLD1UH_VNUM : MInst<"svld1uh_vnum_{d}", "dPXl", "ilUiUl", [IsLoa def SVLD1SW_VNUM : MInst<"svld1sw_vnum_{d}", "dPUl", "lUl", [IsLoad, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">; def SVLD1UW_VNUM : MInst<"svld1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">; -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { // Load one vector (vector base) def SVLD1_GATHER_BASES_U : MInst<"svld1_gather[_{2}base]_{d}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ld1_gather_scalar_offset">; def SVLD1SB_GATHER_BASES_U : MInst<"svld1sb_gather[_{2}base]_{d}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ld1_gather_scalar_offset">; @@ -134,7 +134,7 @@ def SVLDFF1SW_VNUM : MInst<"svldff1sw_vnum_{d}", "dPUl", "lUl", [I def SVLDFF1UW_VNUM : MInst<"svldff1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn], MemEltTyInt32, "aarch64_sve_ldff1">; } -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { // First-faulting load one vector (vector base) def SVLDFF1_GATHER_BASES_U : MInst<"svldff1_gather[_{2}base]_{d}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ldff1_gather_scalar_offset">; def SVLDFF1SB_GATHER_BASES_U : MInst<"svldff1sb_gather[_{2}base]_{d}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ldff1_gather_scalar_offset">; @@ -251,15 +251,15 @@ def SVLD3_VNUM : SInst<"svld3_vnum[_{2}]", "3Pcl", "csilUcUsUiUlhfdbm", MergeNon def SVLD4_VNUM : SInst<"svld4_vnum[_{2}]", "4Pcl", "csilUcUsUiUlhfdbm", MergeNone, "aarch64_sve_ld4_sret", [IsStructLoad, VerifyRuntimeMode]>; // Load one octoword and replicate (scalar base) -let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in { +let SVETargetGuard = "f64mm", SMETargetGuard = InvalidMode in { def SVLD1RO : SInst<"svld1ro[_{2}]", "dPc", "csilUcUsUiUlhfdbm", MergeNone, "aarch64_sve_ld1ro">; } -let SVETargetGuard = "sve,bf16", SMETargetGuard = InvalidMode in { +let SVETargetGuard = "bf16", SMETargetGuard = InvalidMode in { def SVBFMMLA : SInst<"svbfmmla[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmmla", [IsOverloadNone]>; } -let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { +let SVETargetGuard = "bf16", SMETargetGuard = "bf16" in { def SVBFDOT : SInst<"svbfdot[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfdot", [IsOverloadNone, VerifyRuntimeMode]>; def SVBFMLALB : SInst<"svbfmlalb[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmlalb", [IsOverloadNone, VerifyRuntimeMode]>; def SVBFMLALT : SInst<"svbfmlalt[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmlalt", [IsOverloadNone, VerifyRuntimeMode]>; @@ -326,7 +326,7 @@ def SVST1H_VNUM_U : MInst<"svst1h_vnum[_{d}]", "vPFld", "UiUl", [Is def SVST1W_VNUM_S : MInst<"svst1w_vnum[_{d}]", "vPCld", "l", [IsStore, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_st1">; def SVST1W_VNUM_U : MInst<"svst1w_vnum[_{d}]", "vPGld", "Ul", [IsStore, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_st1">; -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { // Store one vector (vector base) def SVST1_SCATTER_BASES_U : MInst<"svst1_scatter[_{2}base_{d}]", "vPud", "ilUiUlfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1_scatter_scalar_offset">; def SVST1B_SCATTER_BASES_U : MInst<"svst1b_scatter[_{2}base_{d}]", "vPud", "ilUiUl", [IsScatterStore], MemEltTyInt8, "aarch64_sve_st1_scatter_scalar_offset">; @@ -464,7 +464,7 @@ def SVPRFH_VNUM : MInst<"svprfh_vnum", "vPQlJ", "s", [IsPrefetch, VerifyRuntimeM def SVPRFW_VNUM : MInst<"svprfw_vnum", "vPQlJ", "i", [IsPrefetch, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_prf">; def SVPRFD_VNUM : MInst<"svprfd_vnum", "vPQlJ", "l", [IsPrefetch, VerifyRuntimeMode], MemEltTyInt64, "aarch64_sve_prf">; -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { // Prefetch (Vector bases) def SVPRFB_GATHER_BASES : MInst<"svprfb_gather[_{2}base]", "vPdJ", "UiUl", [IsGatherPrefetch], MemEltTyInt8, "aarch64_sve_prfb_gather_scalar_offset">; def SVPRFH_GATHER_BASES : MInst<"svprfh_gather[_{2}base]", "vPdJ", "UiUl", [IsGatherPrefetch], MemEltTyInt16, "aarch64_sve_prfh_gather_scalar_offset">; @@ -502,7 +502,7 @@ def SVPRFD_GATHER_BASES_OFFSET : MInst<"svprfd_gather[_{2}base]_index", "vPdlJ" //////////////////////////////////////////////////////////////////////////////// // Address calculations -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { def SVADRB : SInst<"svadrb[_{0}base]_[{2}]offset", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrb">; def SVADRH : SInst<"svadrh[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrh">; def SVADRW : SInst<"svadrw[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrw">; @@ -778,11 +778,11 @@ defm SVRINTX : SInstZPZ<"svrintx", "hfd", "aarch64_sve_frintx">; defm SVRINTZ : SInstZPZ<"svrintz", "hfd", "aarch64_sve_frintz">; defm SVSQRT : SInstZPZ<"svsqrt", "hfd", "aarch64_sve_fsqrt">; -let SVETargetGuard = "sve", SMETargetGuard = "sme2,ssve-fexpa" in { +let SMETargetGuard = "sme2,ssve-fexpa" in { def SVEXPA : SInst<"svexpa[_{d}]", "du", "hfd", MergeNone, "aarch64_sve_fexpa_x", [VerifyRuntimeMode]>; } -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { def SVTMAD : SInst<"svtmad[_{d}]", "dddi", "hfd", MergeNone, "aarch64_sve_ftmad_x", [], [ImmCheck<2, ImmCheck0_7>]>; def SVTSMUL : SInst<"svtsmul[_{d}]", "ddu", "hfd", MergeNone, "aarch64_sve_ftsmul_x">; def SVTSSEL : SInst<"svtssel[_{d}]", "ddu", "hfd", MergeNone, "aarch64_sve_ftssel_x">; @@ -825,7 +825,7 @@ def SVRSQRTS : SInst<"svrsqrts[_{d}]", "ddd", "hfd", MergeNone, "aarch64_sve_frs //////////////////////////////////////////////////////////////////////////////// // Floating-point reductions -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { def SVFADDA : SInst<"svadda[_{d}]", "sPsd", "hfd", MergeNone, "aarch64_sve_fadda">; } @@ -946,14 +946,14 @@ defm SVFCVT_F32_F64 : SInstCvtMXZ<"svcvt_f32[_f64]", "MMPd", "MPd", "d", "aarc defm SVFCVT_F64_F16 : SInstCvtMXZ<"svcvt_f64[_f16]", "ddPO", "dPO", "d", "aarch64_sve_fcvt_f64f16">; defm SVFCVT_F64_F32 : SInstCvtMXZ<"svcvt_f64[_f32]", "ddPM", "dPM", "d", "aarch64_sve_fcvt_f64f32">; -let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { +let SVETargetGuard = "bf16", SMETargetGuard = "bf16" in { defm SVCVT_BF16_F32 : SInstCvtMXZ<"svcvt_bf16[_f32]", "$$Pd", "$Pd", "f", "aarch64_sve_fcvt_bf16f32_v2">; def SVCVTNT_BF16_F32 : SInst<"svcvtnt_bf16[_f32]", "$$Pd", "f", MergeOp1, "aarch64_sve_fcvtnt_bf16f32_v2", [IsOverloadNone, VerifyRuntimeMode]>; // SVCVTNT_X_BF16_F32 : Implemented as macro by SveEmitter.cpp } -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { defm SVCVTLT_F32_F16 : SInstCvtMX<"svcvtlt_f32[_f16]", "ddPh", "dPh", "f", "aarch64_sve_fcvtlt_f32f16">; defm SVCVTLT_F64_F32 : SInstCvtMX<"svcvtlt_f64[_f32]", "ddPh", "dPh", "d", "aarch64_sve_fcvtlt_f64f32">; @@ -980,8 +980,8 @@ defm SVCLASTA_N : SVEPerm<"svclasta[_n_{d}]", "sPsd", "aarch64_sve_clasta_n">; defm SVCLASTB : SVEPerm<"svclastb[_{d}]", "dPdd", "aarch64_sve_clastb">; defm SVCLASTB_N : SVEPerm<"svclastb[_n_{d}]", "sPsd", "aarch64_sve_clastb_n">; -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { -def SVCOMPACT : SInst<"svcompact[_{d}]", "dPd", "ilUiUlfd", MergeNone, "aarch64_sve_compact">; +let SMETargetGuard = "sme2p2" in { +def SVCOMPACT : SInst<"svcompact[_{d}]", "dPd", "ilUiUlfd", MergeNone, "aarch64_sve_compact", [VerifyRuntimeMode]>; } // Note: svdup_lane is implemented using the intrinsic for TBL to represent a @@ -1088,7 +1088,7 @@ def SVPTEST_LAST : SInst<"svptest_last", "sPP", "Pc", MergeNone, "aarch64_sve_ //////////////////////////////////////////////////////////////////////////////// // FFR manipulation -let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { +let SMETargetGuard = InvalidMode in { def SVRDFFR : SInst<"svrdffr", "Pv", "Pc", MergeNone, "", [IsOverloadNone]>; def SVRDFFR_Z : SInst<"svrdffr_z", "PP", "Pc", MergeNone, "", [IsOverloadNone]>; def SVSETFFR : SInst<"svsetffr", "vv", "", MergeNone, "", [IsOverloadNone]>; @@ -1173,13 +1173,13 @@ def SVQINCP_N_S64 : SInst<"svqincp[_n_s64]_{d}", "llP", "PcPsPiPl", MergeNone, " def SVQINCP_N_U32 : SInst<"svqincp[_n_u32]_{d}", "mmP", "PcPsPiPl", MergeNone, "aarch64_sve_uqincp_n32", [VerifyRuntimeMode]>; def SVQINCP_N_U64 : SInst<"svqincp[_n_u64]_{d}", "nnP", "PcPsPiPl", MergeNone, "aarch64_sve_uqincp_n64", [VerifyRuntimeMode]>; -let SVETargetGuard = "sve,i8mm", SMETargetGuard = InvalidMode in { +let SVETargetGuard = "i8mm", SMETargetGuard = InvalidMode in { def SVMLLA_S32 : SInst<"svmmla[_s32]", "ddqq","i", MergeNone, "aarch64_sve_smmla">; def SVMLLA_U32 : SInst<"svmmla[_u32]", "ddqq","Ui", MergeNone, "aarch64_sve_ummla">; def SVUSMLLA_S32 : SInst<"svusmmla[_s32]", "ddbq","i", MergeNone, "aarch64_sve_usmmla">; } -let SVETargetGuard = "sve,i8mm", SMETargetGuard = "sme,i8mm"in { +let SVETargetGuard = "i8mm", SMETargetGuard = "i8mm"in { def SVUSDOT_S : SInst<"svusdot[_s32]", "ddbq", "i", MergeNone, "aarch64_sve_usdot", [VerifyRuntimeMode]>; def SVUSDOT_N_S : SInst<"svusdot[_n_s32]", "ddbr", "i", MergeNone, "aarch64_sve_usdot", [VerifyRuntimeMode]>; def SVSUDOT_S : SInst<"svsudot[_s32]", "ddqb", "i", MergeNone, "aarch64_sve_usdot", [ReverseUSDOT, VerifyRuntimeMode]>; @@ -1189,11 +1189,11 @@ def SVUSDOT_LANE_S : SInst<"svusdot_lane[_s32]", "ddbqi", "i", MergeNone, "aarc def SVSUDOT_LANE_S : SInst<"svsudot_lane[_s32]", "ddqbi", "i", MergeNone, "aarch64_sve_sudot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>; } -let SVETargetGuard = "sve,f32mm", SMETargetGuard = InvalidMode in { +let SVETargetGuard = "f32mm", SMETargetGuard = InvalidMode in { def SVMLLA_F32 : SInst<"svmmla[_f32]", "dddd","f", MergeNone, "aarch64_sve_fmmla">; } -let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in { +let SVETargetGuard = "f64mm", SMETargetGuard = InvalidMode in { def SVMLLA_F64 : SInst<"svmmla[_f64]", "dddd", "d", MergeNone, "aarch64_sve_fmmla">; def SVTRN1Q : SInst<"svtrn1q[_{d}]", "ddd", "csilUcUsUiUlhfdb", MergeNone, "aarch64_sve_trn1q">; @@ -1243,7 +1243,7 @@ let SVETargetGuard = "sve2p1|sme2", SMETargetGuard = "sve2p1|sme2" in { //////////////////////////////////////////////////////////////////////////////// // SVE2 WhileGE/GT -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; @@ -1268,7 +1268,7 @@ let SVETargetGuard = "sve2p1|sme2", SMETargetGuard = "sve2p1|sme2" in { //////////////////////////////////////////////////////////////////////////////// // SVE2 - Uniform DSP operations -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { defm SVQADD_S : SInstZPZZ<"svqadd", "csli", "aarch64_sve_sqadd", "aarch64_sve_sqadd">; defm SVQADD_U : SInstZPZZ<"svqadd", "UcUsUiUl", "aarch64_sve_uqadd", "aarch64_sve_uqadd">; defm SVHADD_S : SInstZPZZ<"svhadd", "csli", "aarch64_sve_shadd", "aarch64_sve_shadd">; @@ -1303,7 +1303,7 @@ multiclass SInstZPZxZ<string name, string types, string pat_v, string pat_n, str def _N_Z : SInst<name # "[_n_{d}]", pat_n, types, MergeZero, intrinsic, flags>; } -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { defm SVQRSHL_S : SInstZPZxZ<"svqrshl", "csil", "dPdx", "dPdK", "aarch64_sve_sqrshl", [VerifyRuntimeMode]>; defm SVQRSHL_U : SInstZPZxZ<"svqrshl", "UcUsUiUl", "dPdx", "dPdK", "aarch64_sve_uqrshl", [VerifyRuntimeMode]>; defm SVQSHL_S : SInstZPZxZ<"svqshl", "csil", "dPdx", "dPdK", "aarch64_sve_sqshl", [VerifyRuntimeMode]>; @@ -1357,7 +1357,7 @@ multiclass SInstPairwise<string name, string types, string intrinsic, list<FlagT def _X : SInst<name # "[_{d}]", "dPdd", types, MergeAny, intrinsic, flags>; } -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { defm SVADDP : SInstPairwise<"svaddp", "csliUcUsUiUl", "aarch64_sve_addp", [VerifyRuntimeMode]>; defm SVADDP_F : SInstPairwise<"svaddp", "hfd", "aarch64_sve_faddp", [VerifyRuntimeMode]>; defm SVMAXNMP : SInstPairwise<"svmaxnmp", "hfd", "aarch64_sve_fmaxnmp", [VerifyRuntimeMode]>; @@ -1373,7 +1373,7 @@ defm SVMINP_U : SInstPairwise<"svminp", "UcUsUiUl", "aarch64_sve_uminp", [ //////////////////////////////////////////////////////////////////////////////// // SVE2 - Widening pairwise arithmetic -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVADALP_S_M : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeOp1, "aarch64_sve_sadalp", [VerifyRuntimeMode]>; def SVADALP_S_X : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeAny, "aarch64_sve_sadalp", [VerifyRuntimeMode]>; def SVADALP_S_Z : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeZero, "aarch64_sve_sadalp", [VerifyRuntimeMode]>; @@ -1387,7 +1387,7 @@ def SVADALP_U_Z : SInst<"svadalp[_{d}]", "dPdh", "UsUiUl", MergeZero, "aarch64_s // SVE2 - Bitwise ternary logical instructions // -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVBCAX : SInst<"svbcax[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bcax", [VerifyRuntimeMode]>; def SVBSL : SInst<"svbsl[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bsl", [VerifyRuntimeMode]>; def SVBSL1N : SInst<"svbsl1n[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bsl1n", [VerifyRuntimeMode]>; @@ -1407,7 +1407,7 @@ def SVXAR_N : SInst<"svxar[_n_{d}]", "dddi", "csilUcUsUiUl", MergeNone, "aar //////////////////////////////////////////////////////////////////////////////// // SVE2 - Large integer arithmetic -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVADCLB : SInst<"svadclb[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_adclb", [VerifyRuntimeMode]>; def SVADCLT : SInst<"svadclt[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_adclt", [VerifyRuntimeMode]>; def SVSBCLB : SInst<"svsbclb[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_sbclb", [VerifyRuntimeMode]>; @@ -1422,7 +1422,7 @@ def SVSBCLT_N : SInst<"svsbclt[_n_{d}]", "ddda", "UiUl", MergeNone, "aarch64_sve //////////////////////////////////////////////////////////////////////////////// // SVE2 - Multiplication by indexed elements -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVMLA_LANE_2 : SInst<"svmla_lane[_{d}]", "ddddi", "silUsUiUl", MergeNone, "aarch64_sve_mla_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>; def SVMLS_LANE_2 : SInst<"svmls_lane[_{d}]", "ddddi", "silUsUiUl", MergeNone, "aarch64_sve_mls_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>; def SVMUL_LANE_2 : SInst<"svmul_lane[_{d}]", "dddi", "silUsUiUl", MergeNone, "aarch64_sve_mul_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckLaneIndex, 1>]>; @@ -1430,7 +1430,7 @@ def SVMUL_LANE_2 : SInst<"svmul_lane[_{d}]", "dddi", "silUsUiUl", MergeNone, "a //////////////////////////////////////////////////////////////////////////////// // SVE2 - Uniform complex integer arithmetic -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVCADD : SInst<"svcadd[_{d}]", "dddi", "csilUcUsUiUl", MergeNone, "aarch64_sve_cadd_x", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckComplexRot90_270>]>; def SVSQCADD : SInst<"svqcadd[_{d}]", "dddi", "csil", MergeNone, "aarch64_sve_sqcadd_x", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckComplexRot90_270>]>; def SVCMLA : SInst<"svcmla[_{d}]", "ddddi", "csilUcUsUiUl", MergeNone, "aarch64_sve_cmla_x", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckComplexRotAll90>]>; @@ -1457,7 +1457,7 @@ multiclass SInstWideDSPWide<string name, string types, string intrinsic> { def _N : SInst<name # "[_n_{d}]", "ddR", types, MergeNone, intrinsic, [VerifyRuntimeMode]>; } -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { defm SVABALB_S : SInstWideDSPAcc<"svabalb", "sil", "aarch64_sve_sabalb">; defm SVABALB_U : SInstWideDSPAcc<"svabalb", "UsUiUl", "aarch64_sve_uabalb">; defm SVABALT_S : SInstWideDSPAcc<"svabalt", "sil", "aarch64_sve_sabalt">; @@ -1536,7 +1536,7 @@ def SVQDMULLT_LANE : SInst<"svqdmullt_lane[_{d}]", "dhhi", "il", MergeNone, " //////////////////////////////////////////////////////////////////////////////// // SVE2 - Narrowing DSP operations -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVADDHNB : SInst<"svaddhnb[_{d}]", "hdd", "silUsUiUl", MergeNone, "aarch64_sve_addhnb", [VerifyRuntimeMode]>; def SVADDHNT : SInst<"svaddhnt[_{d}]", "hhdd", "silUsUiUl", MergeNone, "aarch64_sve_addhnt", [VerifyRuntimeMode]>; def SVRADDHNB : SInst<"svraddhnb[_{d}]", "hdd", "silUsUiUl", MergeNone, "aarch64_sve_raddhnb", [VerifyRuntimeMode]>; @@ -1576,7 +1576,7 @@ def SVQRSHRNT_U : SInst<"svqrshrnt[_n_{d}]", "hhdi", "UsUiUl", MergeNone, "a //////////////////////////////////////////////////////////////////////////////// // SVE2 - Unary narrowing operations -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVQXTNB_S : SInst<"svqxtnb[_{d}]", "hd", "sil", MergeNone, "aarch64_sve_sqxtnb", [VerifyRuntimeMode]>; def SVQXTNB_U : SInst<"svqxtnb[_{d}]", "hd", "UsUiUl", MergeNone, "aarch64_sve_uqxtnb", [VerifyRuntimeMode]>; def SVQXTUNB_S : SInst<"svqxtunb[_{d}]", "ed", "sil", MergeNone, "aarch64_sve_sqxtunb", [VerifyRuntimeMode]>; @@ -1589,7 +1589,7 @@ def SVQXTUNT_S : SInst<"svqxtunt[_{d}]", "eed", "sil", MergeNone, "aarch64_sv //////////////////////////////////////////////////////////////////////////////// // SVE2 - Widening complex integer arithmetic -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { defm SVADDLBT : SInstWideDSPLong<"svaddlbt", "sil", "aarch64_sve_saddlbt">; defm SVSUBLBT : SInstWideDSPLong<"svsublbt", "sil", "aarch64_sve_ssublbt">; defm SVSUBLTB : SInstWideDSPLong<"svsubltb", "sil", "aarch64_sve_ssubltb">; @@ -1723,7 +1723,7 @@ def SVSTNT1W_SCATTER_INDEX_S : MInst<"svstnt1w_scatter[_{2}base]_index[_{d}]", " //////////////////////////////////////////////////////////////////////////////// // SVE2 - Polynomial arithmetic -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVEORBT : SInst<"sveorbt[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorbt", [VerifyRuntimeMode]>; def SVEORBT_N : SInst<"sveorbt[_n_{d}]", "ddda", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorbt", [VerifyRuntimeMode]>; def SVEORTB : SInst<"sveortb[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eortb", [VerifyRuntimeMode]>; @@ -1744,7 +1744,7 @@ def SVPMULLT_PAIR_N : SInst<"svpmullt_pair[_n_{d}]", "dda", "UcUi", MergeNone, //////////////////////////////////////////////////////////////////////////////// // SVE2 - Complex integer dot product -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVCDOT : SInst<"svcdot[_{d}]", "ddqqi", "il", MergeNone, "aarch64_sve_cdot", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckComplexRotAll90>]>; def SVCDOT_LANE : SInst<"svcdot_lane[_{d}]", "ddqqii", "il", MergeNone, "aarch64_sve_cdot_lane", [VerifyRuntimeMode], [ImmCheck<4, ImmCheckComplexRotAll90>, ImmCheck<3, ImmCheckLaneIndexDot, 2>]>; } @@ -1752,7 +1752,7 @@ def SVCDOT_LANE : SInst<"svcdot_lane[_{d}]", "ddqqii", "il", MergeNone, "aarch //////////////////////////////////////////////////////////////////////////////// // SVE2 - Floating-point widening multiply-accumulate -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVMLALB_F : SInst<"svmlalb[_{d}]", "ddhh", "f", MergeNone, "aarch64_sve_fmlalb", [VerifyRuntimeMode]>; def SVMLALB_F_N : SInst<"svmlalb[_n_{d}]", "ddhR", "f", MergeNone, "aarch64_sve_fmlalb", [VerifyRuntimeMode]>; def SVMLALB_F_LANE : SInst<"svmlalb_lane[_{d}]", "ddhhi", "f", MergeNone, "aarch64_sve_fmlalb_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>; @@ -1770,7 +1770,7 @@ def SVMLSLT_F_LANE : SInst<"svmlslt_lane[_{d}]", "ddhhi", "f", MergeNone, "aarch //////////////////////////////////////////////////////////////////////////////// // SVE2 - Floating-point integer binary logarithm -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVLOGB_M : SInst<"svlogb[_{d}]", "xxPd", "hfd", MergeOp1, "aarch64_sve_flogb", [VerifyRuntimeMode]>; def SVLOGB_X : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeAnyExp, "aarch64_sve_flogb", [VerifyRuntimeMode]>; def SVLOGB_Z : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeZeroExp, "aarch64_sve_flogb", [VerifyRuntimeMode]>; @@ -1794,7 +1794,7 @@ def SVNMATCH : SInst<"svnmatch[_{d}]", "PPdd", "csUcUs", MergeNone, "aarch64_sve //////////////////////////////////////////////////////////////////////////////// // SVE2 - Contiguous conflict detection -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVWHILERW_B : SInst<"svwhilerw[_{1}]", "Pcc", "cUc", MergeNone, "aarch64_sve_whilerw_b", [IsOverloadWhileRW, VerifyRuntimeMode]>; def SVWHILERW_H : SInst<"svwhilerw[_{1}]", "Pcc", "sUshb", MergeNone, "aarch64_sve_whilerw_h", [IsOverloadWhileRW, VerifyRuntimeMode]>; def SVWHILERW_S : SInst<"svwhilerw[_{1}]", "Pcc", "iUif", MergeNone, "aarch64_sve_whilerw_s", [IsOverloadWhileRW, VerifyRuntimeMode]>; @@ -1808,7 +1808,7 @@ def SVWHILEWR_D : SInst<"svwhilewr[_{1}]", "Pcc", "lUld", MergeNone, "aarch64_sv //////////////////////////////////////////////////////////////////////////////// // SVE2 - Extended table lookup/permute -let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { +let SVETargetGuard = "sve2" in { def SVTBL2 : SInst<"svtbl2[_{d}]", "d2u", "csilUcUsUiUlhfdb", MergeNone, "", [VerifyRuntimeMode]>; def SVTBX : SInst<"svtbx[_{d}]", "dddu", "csilUcUsUiUlhfdb", MergeNone, "aarch64_sve_tbx", [VerifyRuntimeMode]>; } @@ -1828,17 +1828,17 @@ let SVETargetGuard = "sve2,lut", SMETargetGuard = "sme2,lut" in { //////////////////////////////////////////////////////////////////////////////// // SVE2 - Optional -let SVETargetGuard = "sve2,sve-aes", SMETargetGuard = InvalidMode in { -def SVAESD : SInst<"svaesd[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aesd", [IsOverloadNone]>; -def SVAESIMC : SInst<"svaesimc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesimc", [IsOverloadNone]>; -def SVAESE : SInst<"svaese[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aese", [IsOverloadNone]>; -def SVAESMC : SInst<"svaesmc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesmc", [IsOverloadNone]>; +let SVETargetGuard = "sve2,sve-aes", SMETargetGuard = "ssve-aes" in { +def SVAESD : SInst<"svaesd[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aesd", [IsOverloadNone, VerifyRuntimeMode]>; +def SVAESIMC : SInst<"svaesimc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesimc", [IsOverloadNone, VerifyRuntimeMode]>; +def SVAESE : SInst<"svaese[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aese", [IsOverloadNone, VerifyRuntimeMode]>; +def SVAESMC : SInst<"svaesmc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesmc", [IsOverloadNone, VerifyRuntimeMode]>; -def SVPMULLB_PAIR_U64 : SInst<"svpmullb_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullb_pair">; -def SVPMULLB_PAIR_N_U64 : SInst<"svpmullb_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullb_pair">; +def SVPMULLB_PAIR_U64 : SInst<"svpmullb_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullb_pair", [VerifyRuntimeMode]>; +def SVPMULLB_PAIR_N_U64 : SInst<"svpmullb_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullb_pair", [VerifyRuntimeMode]>; -def SVPMULLT_PAIR_U64 : SInst<"svpmullt_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullt_pair">; -def SVPMULLT_PAIR_N_U64 : SInst<"svpmullt_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullt_pair">; +def SVPMULLT_PAIR_U64 : SInst<"svpmullt_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullt_pair", [VerifyRuntimeMode]>; +def SVPMULLT_PAIR_N_U64 : SInst<"svpmullt_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullt_pair", [VerifyRuntimeMode]>; } let SVETargetGuard = "sve-sha3", SMETargetGuard = "sve-sha3,sme2p1" in { @@ -1850,7 +1850,7 @@ def SVSM4E : SInst<"svsm4e[_{d}]", "ddd", "Ui", MergeNone, "aarch64_sve_sm def SVSM4EKEY : SInst<"svsm4ekey[_{d}]", "ddd", "Ui", MergeNone, "aarch64_sve_sm4ekey", [IsOverloadNone]>; } -let SVETargetGuard = "sve2,sve-bitperm", SMETargetGuard = "sme,ssve-bitperm" in { +let SVETargetGuard = "sve2,sve-bitperm", SMETargetGuard = "ssve-bitperm" in { def SVBDEP : SInst<"svbdep[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sve_bdep_x", [VerifyRuntimeMode]>; def SVBDEP_N : SInst<"svbdep[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bdep_x", [VerifyRuntimeMode]>; def SVBEXT : SInst<"svbext[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sve_bext_x", [VerifyRuntimeMode]>; @@ -1859,7 +1859,7 @@ def SVBGRP : SInst<"svbgrp[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sv def SVBGRP_N : SInst<"svbgrp[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bgrp_x", [VerifyRuntimeMode]>; } -let SVETargetGuard = "sve2p1|sme", SMETargetGuard = "sve2p1|sme" in { +let SVETargetGuard = "sve2p1|sme" in { def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [VerifyRuntimeMode], []>; def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [VerifyRuntimeMode], []>; def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [VerifyRuntimeMode], []>; @@ -1965,7 +1965,7 @@ def SVDOT_LANE_X2_F : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "f", MergeNone, "a def SVFCLAMP : SInst<"svclamp[_{d}]", "dddd", "hfd", MergeNone, "aarch64_sve_fclamp", [VerifyRuntimeMode], []>; } -let SVETargetGuard = "sve2p1|sme", SMETargetGuard = "sve2p1|sme" in { +let SVETargetGuard = "sve2p1|sme" in { def SVSCLAMP : SInst<"svclamp[_{d}]", "dddd", "csil", MergeNone, "aarch64_sve_sclamp", [VerifyRuntimeMode], []>; def SVUCLAMP : SInst<"svclamp[_{d}]", "dddd", "UcUsUiUl", MergeNone, "aarch64_sve_uclamp", [VerifyRuntimeMode], []>; @@ -2340,7 +2340,7 @@ let SVETargetGuard = "sve2,fp8", SMETargetGuard = "sme2,fp8" in { def SVFCVTNT : SInst<"svcvtnt_mf8[_f32_x2]", "~~2>", "f", MergeNone, "aarch64_sve_fp8_cvtnt", [VerifyRuntimeMode]>; } -let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in { +let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="ssve-fp8dot2" in { // 8-bit floating-point dot product to half-precision (vectors) def SVFDOT_2WAY : SInst<"svdot[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; def SVFDOT_N_2WAY : SInst<"svdot[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; @@ -2349,7 +2349,7 @@ let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in { def SVFDOT_LANE_2WAY : SInst<"svdot_lane[_f16_mf8]", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; } -let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in { +let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="ssve-fp8dot4" in { // 8-bit floating-point dot product to single-precision (vectors) def SVFDOT_4WAY : SInst<"svdot[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; def SVFDOT_N_4WAY : SInst<"svdot[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; @@ -2358,7 +2358,7 @@ let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in { def SVFDOT_LANE_4WAY : SInst<"svdot_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_3>]>; } -let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "sme,ssve-fp8fma" in { +let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "ssve-fp8fma" in { // 8-bit floating-point multiply-add long to half-precision (bottom) def SVFMLALB : SInst<"svmlalb[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode]>; def SVFMLALB_N : SInst<"svmlalb[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode]>; diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td index 275bb2b..cc5ab38 100644 --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -56,34 +56,8 @@ multiclass RVVVLEFFBuiltin<list<string> types> { SupportOverloading = false, UnMaskedPolicyScheme = HasPassthruOperand, ManualCodegen = [{ - { - if (IsMasked) { - // Move mask to right before vl. - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - IntrinsicTypes = {ResultType, Ops[4]->getType(), Ops[2]->getType()}; - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - IntrinsicTypes = {ResultType, Ops[3]->getType(), Ops[1]->getType()}; - } - Value *NewVL = Ops[2]; - Ops.erase(Ops.begin() + 2); - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); - llvm::Value *V = Builder.CreateExtractValue(LoadValue, {0}); - // Store new_vl. - clang::CharUnits Align; - if (IsMasked) - Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(E->getNumArgs()-2)->getType()); - else - Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(1)->getType()); - llvm::Value *Val = Builder.CreateExtractValue(LoadValue, {1}); - Builder.CreateStore(Val, Address(NewVL, Val->getType(), Align)); - return V; - } + return emitRVVVLEFFBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach type = types in { def : RVVBuiltin<"v", "vPCePz", type>; @@ -139,17 +113,8 @@ multiclass RVVIndexedLoad<string op> { let HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - if (IsMasked) { - // Builtin: (mask, ptr, value, vl). Intrinsic: (value, ptr, mask, vl) - std::swap(Ops[0], Ops[2]); - } else { - // Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl) - std::swap(Ops[0], Ops[1]); - } - if (IsMasked) - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()}; + return emitRVVVSEMaskBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { class RVVVSEMaskBuiltin : RVVBuiltin<"m", "0PUem", "c"> { let Name = "vsm_v"; @@ -177,17 +142,8 @@ multiclass RVVVSSEBuiltin<list<string> types> { HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - if (IsMasked) { - // Builtin: (mask, ptr, stride, value, vl). Intrinsic: (value, ptr, stride, mask, vl) - std::swap(Ops[0], Ops[3]); - } else { - // Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl) - std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); - } - if (IsMasked) - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()}; + return emitRVVVSSEBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach type = types in { def : RVVBuiltin<"v", "0Petv", type>; @@ -202,17 +158,8 @@ multiclass RVVIndexedStore<string op> { let HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - if (IsMasked) { - // Builtin: (mask, ptr, index, value, vl). Intrinsic: (value, ptr, index, mask, vl) - std::swap(Ops[0], Ops[3]); - } else { - // Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl) - std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); - } - if (IsMasked) - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[4]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[3]->getType()}; + return emitRVVIndexedStoreBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach type = TypeList in { foreach eew_list = EEWList[0-2] in { @@ -367,28 +314,8 @@ multiclass RVVPseudoUnaryBuiltin<string IR, string type_range> { MaskedIRName = IR # "_mask", UnMaskedPolicyScheme = HasPassthruOperand, ManualCodegen = [{ - { - if (IsMasked) { - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } - auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType(); - Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy)); - - if (IsMasked) { - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - // maskedoff, op1, op2, mask, vl, policy - IntrinsicTypes = {ResultType, ElemTy, Ops[4]->getType()}; - } else { - // passthru, op1, op2, vl - IntrinsicTypes = {ResultType, ElemTy, Ops[3]->getType()}; - } - break; - } + return emitRVVPseudoUnaryBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"v", "vv", type_range>; } @@ -400,32 +327,8 @@ multiclass RVVPseudoVNotBuiltin<string IR, string type_range> { MaskedIRName = IR # "_mask", UnMaskedPolicyScheme = HasPassthruOperand, ManualCodegen = [{ - { - if (IsMasked) { - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } - auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType(); - Ops.insert(Ops.begin() + 2, - llvm::Constant::getAllOnesValue(ElemTy)); - if (IsMasked) { - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - // maskedoff, op1, po2, mask, vl, policy - IntrinsicTypes = {ResultType, - ElemTy, - Ops[4]->getType()}; - } else { - // passthru, op1, op2, vl - IntrinsicTypes = {ResultType, - ElemTy, - Ops[3]->getType()}; - } - break; - } + return emitRVVPseudoVNotBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"v", "vv", type_range>; def : RVVBuiltin<"Uv", "UvUv", type_range>; @@ -437,13 +340,8 @@ multiclass RVVPseudoMaskBuiltin<string IR, string type_range> { IRName = IR, HasMasked = false, ManualCodegen = [{ - { - // op1, vl - IntrinsicTypes = {ResultType, - Ops[1]->getType()}; - Ops.insert(Ops.begin() + 1, Ops[0]); - break; - } + return emitRVVPseudoMaskBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"m", "mm", type_range>; } @@ -455,28 +353,8 @@ multiclass RVVPseudoVFUnaryBuiltin<string IR, string type_range> { MaskedIRName = IR # "_mask", UnMaskedPolicyScheme = HasPassthruOperand, ManualCodegen = [{ - { - if (IsMasked) { - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - Ops.insert(Ops.begin() + 2, Ops[1]); - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - // maskedoff, op1, op2, mask, vl - IntrinsicTypes = {ResultType, - Ops[2]->getType(), - Ops.back()->getType()}; - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - // op1, po2, vl - IntrinsicTypes = {ResultType, - Ops[1]->getType(), Ops[2]->getType()}; - Ops.insert(Ops.begin() + 2, Ops[1]); - break; - } - break; - } + return emitRVVPseudoVFUnaryBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"v", "vv", type_range>; } @@ -490,33 +368,8 @@ multiclass RVVPseudoVWCVTBuiltin<string IR, string MName, string type_range, MaskedIRName = IR # "_mask", UnMaskedPolicyScheme = HasPassthruOperand, ManualCodegen = [{ - { - if (IsMasked) { - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } - auto ElemTy = cast<llvm::VectorType>(Ops[1]->getType())->getElementType(); - Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy)); - if (IsMasked) { - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - // maskedoff, op1, op2, mask, vl, policy - IntrinsicTypes = {ResultType, - Ops[1]->getType(), - ElemTy, - Ops[4]->getType()}; - } else { - // passtru, op1, op2, vl - IntrinsicTypes = {ResultType, - Ops[1]->getType(), - ElemTy, - Ops[3]->getType()}; - } - break; - } + return emitRVVPseudoVWCVTBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach s_p = suffixes_prototypes in { def : RVVBuiltin<s_p[0], s_p[1], type_range>; @@ -532,32 +385,8 @@ multiclass RVVPseudoVNCVTBuiltin<string IR, string MName, string type_range, MaskedIRName = IR # "_mask", UnMaskedPolicyScheme = HasPassthruOperand, ManualCodegen = [{ - { - if (IsMasked) { - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - } - Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(Ops.back()->getType())); - if (IsMasked) { - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - // maskedoff, op1, xlen, mask, vl - IntrinsicTypes = {ResultType, - Ops[1]->getType(), - Ops[4]->getType(), - Ops[4]->getType()}; - } else { - // passthru, op1, xlen, vl - IntrinsicTypes = {ResultType, - Ops[1]->getType(), - Ops[3]->getType(), - Ops[3]->getType()}; - } - break; - } + return emitRVVPseudoVNCVTBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach s_p = suffixes_prototypes in { def : RVVBuiltin<s_p[0], s_p[1], type_range>; @@ -575,17 +404,8 @@ let HasBuiltinAlias = false, HasVL = false, HasMasked = false, UnMaskedPolicyScheme = NonePolicy, MaskedPolicyScheme = NonePolicy, Log2LMUL = [0], IRName = "", ManualCodegen = [{ - { - LLVMContext &Context = CGM.getLLVMContext(); - llvm::MDBuilder MDHelper(Context); - - llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "vlenb")}; - llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops); - llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName); - llvm::Function *F = - CGM.getIntrinsic(llvm::Intrinsic::read_register, {SizeTy}); - return Builder.CreateCall(F, Metadata); - } + return emitRVVVlenbBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { def vlenb : RVVBuiltin<"", "u", "i">; @@ -660,7 +480,10 @@ let HasBuiltinAlias = false, HasMasked = false, MaskedPolicyScheme = NonePolicy, Log2LMUL = [0], - ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type + ManualCodegen = [{ + return emitRVVVsetvliBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); + }] in // Set XLEN type { def vsetvli : RVVBuiltin<"", "zzKzKz", "i">; def vsetvlimax : RVVBuiltin<"", "zKzKz", "i">; @@ -720,43 +543,10 @@ multiclass RVVUnitStridedSegLoadTuple<string op> { MaskedIRName = op # nf # "_mask", NF = nf, ManualCodegen = [{ - { - SmallVector<llvm::Value*, 6> Operands; - - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[0]->getType(), Ops.back()->getType()}; - else - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()}; - - if (NoPassthru) { // Push poison into passthru - Operands.push_back(llvm::PoisonValue::get(ResultType)); - } else { // Push intrinsics operands into passthru - llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0]; - Operands.push_back(PassthruOperand); - } - - Operands.push_back(Ops[Offset]); // Ptr - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 1]); // VL - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - - llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - if (ReturnValue.isNull()) - return LoadValue; - else - return Builder.CreateStore(LoadValue, ReturnValue.getValue()); - } - }] in { + return emitRVVUnitStridedSegLoadTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, + IsMasked, SegInstSEW); + }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCe", type>; if !not(IsFloat<type>.val) then { @@ -784,31 +574,10 @@ multiclass RVVUnitStridedSegStoreTuple<string op> { NF = nf, HasMaskedOffOperand = false, ManualCodegen = [{ - { - // Masked - // Builtin: (mask, ptr, v_tuple, vl) - // Intrinsic: (tuple, ptr, mask, vl) - // Unmasked - // Builtin: (ptr, v_tuple, vl) - // Intrinsic: (tuple, ptr, vl) - unsigned Offset = IsMasked ? 1 : 0; - - SmallVector<llvm::Value*, 5> Operands; - Operands.push_back(Ops[Offset + 1]); // tuple - Operands.push_back(Ops[Offset]); // Ptr - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 2]); // VL - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[0]->getType(), Operands.back()->getType()}; - else - IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Operands.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); - } - }] in { + return emitRVVUnitStridedSegStoreTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, + IsMasked, SegInstSEW); + }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", "0Pe" # T # "v", type>; if !not(IsFloat<type>.val) then { @@ -835,52 +604,9 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> { MaskedIRName = op # nf # "ff_mask", NF = nf, ManualCodegen = [{ - { - SmallVector<llvm::Value*, 6> Operands; - - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType(), Ops[0]->getType()}; - else - IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType()}; - - if (NoPassthru) { // Push poison into passthru - Operands.push_back(llvm::PoisonValue::get(ResultType)); - } else { // Push intrinsics operands into passthru - llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0]; - Operands.push_back(PassthruOperand); - } - - Operands.push_back(Ops[Offset]); // Ptr - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 2]); // vl - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - - llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - // Get alignment from the new vl operand - clang::CharUnits Align = - CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType()); - - llvm::Value *ReturnTuple = Builder.CreateExtractValue(LoadValue, 0); - - // Store new_vl - llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1); - Builder.CreateStore(V, Address(Ops[Offset + 1], V->getType(), Align)); - - if (ReturnValue.isNull()) - return ReturnTuple; - else - return Builder.CreateStore(ReturnTuple, ReturnValue.getValue()); - } + return emitRVVUnitStridedSegLoadFFTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCePz", type>; @@ -908,43 +634,9 @@ multiclass RVVStridedSegLoadTuple<string op> { MaskedIRName = op # nf # "_mask", NF = nf, ManualCodegen = [{ - { - SmallVector<llvm::Value*, 7> Operands; - - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType(), Ops[0]->getType()}; - else - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()}; - - if (NoPassthru) { // Push poison into passthru - Operands.push_back(llvm::PoisonValue::get(ResultType)); - } else { // Push intrinsics operands into passthru - llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0]; - Operands.push_back(PassthruOperand); - } - - Operands.push_back(Ops[Offset]); // Ptr - Operands.push_back(Ops[Offset + 1]); // Stride - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 2]); // VL - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - - if (ReturnValue.isNull()) - return LoadValue; - else - return Builder.CreateStore(LoadValue, ReturnValue.getValue()); - } + return emitRVVStridedSegLoadTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCet", type>; @@ -974,31 +666,9 @@ multiclass RVVStridedSegStoreTuple<string op> { HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - // Masked - // Builtin: (mask, ptr, stride, v_tuple, vl) - // Intrinsic: (tuple, ptr, stride, mask, vl) - // Unmasked - // Builtin: (ptr, stride, v_tuple, vl) - // Intrinsic: (tuple, ptr, stride, vl) - unsigned Offset = IsMasked ? 1 : 0; - - SmallVector<llvm::Value*, 6> Operands; - Operands.push_back(Ops[Offset + 2]); // tuple - Operands.push_back(Ops[Offset]); // Ptr - Operands.push_back(Ops[Offset + 1]); // Stride - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 3]); // VL - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType(), Ops[0]->getType()}; - else - IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); - } + return emitRVVStridedSegStoreTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", "0Pet" # T # "v", type>; @@ -1021,47 +691,9 @@ multiclass RVVIndexedSegLoadTuple<string op> { MaskedIRName = op # nf # "_mask", NF = nf, ManualCodegen = [{ - { - SmallVector<llvm::Value*, 7> Operands; - - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (NoPassthru) { // Push poison into passthru - Operands.push_back(llvm::PoisonValue::get(ResultType)); - } else { // Push intrinsics operands into passthru - llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0]; - Operands.push_back(PassthruOperand); - } - - Operands.push_back(Ops[Offset]); // Ptr - Operands.push_back(Ops[Offset + 1]); // Idx - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 2]); // VL - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), - Ops[Offset + 1]->getType(), - Ops[0]->getType(), - Ops.back()->getType()}; - else - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), - Ops[Offset + 1]->getType(), - Ops.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - - if (ReturnValue.isNull()) - return LoadValue; - else - return Builder.CreateStore(LoadValue, ReturnValue.getValue()); - } + return emitRVVIndexedSegLoadTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCe" # eew_type # "Uv", type>; @@ -1087,34 +719,9 @@ multiclass RVVIndexedSegStoreTuple<string op> { HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - // Masked - // Builtin: (mask, ptr, index, v_tuple, vl) - // Intrinsic: (tuple, ptr, index, mask, vl) - // Unmasked - // Builtin: (ptr, index, v_tuple, vl) - // Intrinsic: (tuple, ptr, index, vl) - unsigned Offset = IsMasked ? 1 : 0; - - SmallVector<llvm::Value*, 6> Operands; - Operands.push_back(Ops[Offset + 2]); // tuple - Operands.push_back(Ops[Offset]); // Ptr - Operands.push_back(Ops[Offset + 1]); // Idx - if (IsMasked) - Operands.push_back(Ops[0]); - Operands.push_back(Ops[Offset + 3]); // VL - Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(), - Ops[0]->getType(), - Operands.back()->getType()}; - else - IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(), - Operands.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); - } + return emitRVVIndexedSegStoreTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", "0Pe" # eew_type # "Uv" # T # "v", type>; @@ -1355,37 +962,8 @@ defm vssub : RVVSignedBinBuiltinSet; let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy) - - SmallVector<llvm::Value*, 7> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - Operands.push_back(Ops[Offset + 2]); // vxrm - Operands.push_back(Ops[Offset + 3]); // vl - - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(), Ops.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVAveragingBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); } }] in { // 12.2. Vector Single-Width Averaging Add and Subtract @@ -1404,38 +982,8 @@ let ManualCodegen = [{ let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy) - - SmallVector<llvm::Value*, 7> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - Operands.push_back(Ops[Offset + 2]); // vxrm - Operands.push_back(Ops[Offset + 3]); // vl - - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(), - Ops.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVNarrowingClipBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { // 12.5. Vector Narrowing Fixed-Point Clip Instructions @@ -1459,47 +1007,8 @@ enum __RISCV_FRM { let UnMaskedPolicyScheme = HasPassthruOperand in { let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) - - SmallVector<llvm::Value*, 7> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - bool HasRoundModeOp = IsMasked ? - (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) : - (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4); - - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 2]); // frm - Operands.push_back(Ops[Offset + 3]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } - - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(), - Operands.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVFloatingPointBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = true in { @@ -1536,47 +1045,9 @@ let ManualCodegen = [{ let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) - - SmallVector<llvm::Value*, 7> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - bool HasRoundModeOp = IsMasked ? - (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) : - (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4); - - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 2]); // frm - Operands.push_back(Ops[Offset + 3]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } - - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(), - Ops.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVWideningFloatingPointBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); } }] in { let HasFRMRoundModeOp = true in { @@ -1618,39 +1089,8 @@ let ManualCodegen = [{ let UnMaskedPolicyScheme = HasPolicyOperand in { let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) - - SmallVector<llvm::Value*, 7> Operands; - bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5; - - unsigned Offset = IsMasked ? 2 : 1; - - Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 2]); // frm - Operands.push_back(Ops[Offset + 3]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } - - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), - Operands.back()->getType()}; - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - - return Builder.CreateCall(F, Operands, ""); + return emitRVVFMABuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1677,39 +1117,8 @@ let ManualCodegen = [{ let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) - - SmallVector<llvm::Value*, 7> Operands; - bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5; - - unsigned Offset = IsMasked ? 2 : 1; - - Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 2]); // frm - Operands.push_back(Ops[Offset + 3]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } - - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(), - Operands.back()->getType()}; - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - - return Builder.CreateCall(F, Operands, ""); + return emitRVVWideningFMABuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1747,45 +1156,8 @@ let ManualCodegen = [{ let UnMaskedPolicyScheme = HasPassthruOperand in { let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, round_mode, vl) - // Masked: (passthru, op0, mask, frm, vl, policy) - - SmallVector<llvm::Value*, 6> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - bool HasRoundModeOp = IsMasked ? - (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) : - (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3); - - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 1]); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 1]); // vl - } - - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Operands.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVFloatingUnaryBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1947,45 +1319,8 @@ def vfwcvtbf16_f_f_v : RVVConvBuiltin<"Fw", "Fwv", "y", "vfwcvtbf16_f">; let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, frm, vl) - // Masked: (passthru, op0, mask, frm, vl, policy) - SmallVector<llvm::Value*, 6> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - bool HasRoundModeOp = IsMasked ? - (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) : - (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3); - - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 1]); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 1]); // vl - } - - if (IsMasked) - Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), - Operands.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVFloatingConvBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -2151,44 +1486,9 @@ defm vfredmax : RVVFloatingReductionBuiltin; defm vfredmin : RVVFloatingReductionBuiltin; let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) - - SmallVector<llvm::Value*, 6> Operands; - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - bool HasRoundModeOp = IsMasked ? - (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) : - (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4); - - unsigned Offset = IsMasked ? - (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0); - - if (!HasMaskedOff) - Operands.push_back(llvm::PoisonValue::get(ResultType)); - else - Operands.push_back(Ops[IsMasked ? 1 : 0]); - - Operands.push_back(Ops[Offset]); // op0 - Operands.push_back(Ops[Offset + 1]); // op1 - - if (IsMasked) - Operands.push_back(Ops[0]); // mask - - if (HasRoundModeOp) { - Operands.push_back(Ops[Offset + 2]); // frm - Operands.push_back(Ops[Offset + 3]); // vl - } else { - Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm - Operands.push_back(Ops[Offset + 2]); // vl - } - - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), - Ops.back()->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - return Builder.CreateCall(F, Operands, ""); + return emitRVVFloatingReductionBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -2346,37 +1646,8 @@ let HasMasked = false, let HasMasked = false, HasVL = false, IRName = "" in { let Name = "vreinterpret_v", MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - if (ResultType->isIntOrIntVectorTy(1) || - Ops[0]->getType()->isIntOrIntVectorTy(1)) { - assert(isa<ScalableVectorType>(ResultType) && - isa<ScalableVectorType>(Ops[0]->getType())); - - LLVMContext &Context = CGM.getLLVMContext(); - ScalableVectorType *Boolean64Ty = - ScalableVectorType::get(llvm::Type::getInt1Ty(Context), 64); - - if (ResultType->isIntOrIntVectorTy(1)) { - // Casting from m1 vector integer -> vector boolean - // Ex: <vscale x 8 x i8> - // --(bitcast)--------> <vscale x 64 x i1> - // --(vector_extract)-> <vscale x 8 x i1> - llvm::Value *BitCast = Builder.CreateBitCast(Ops[0], Boolean64Ty); - return Builder.CreateExtractVector(ResultType, BitCast, - ConstantInt::get(Int64Ty, 0)); - } else { - // Casting from vector boolean -> m1 vector integer - // Ex: <vscale x 1 x i1> - // --(vector_insert)-> <vscale x 64 x i1> - // --(bitcast)-------> <vscale x 8 x i8> - llvm::Value *Boolean64Val = - Builder.CreateInsertVector(Boolean64Ty, - llvm::PoisonValue::get(Boolean64Ty), - Ops[0], - ConstantInt::get(Int64Ty, 0)); - return Builder.CreateBitCast(Boolean64Val, ResultType); - } - } - return Builder.CreateBitCast(Ops[0], ResultType); + return emitRVVReinterpretBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { // Reinterpret between different type under the same SEW and LMUL def vreinterpret_i_u : RVVBuiltin<"Uvv", "vUv", "csil", "v">; @@ -2502,25 +1773,8 @@ let HasMasked = false, HasVL = false, IRName = "" in { let Name = "vget_v", MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - auto *VecTy = cast<ScalableVectorType>(ResultType); - if (auto *OpVecTy = dyn_cast<ScalableVectorType>(Ops[0]->getType())) { - unsigned MaxIndex = OpVecTy->getMinNumElements() / VecTy->getMinNumElements(); - assert(isPowerOf2_32(MaxIndex)); - // Mask to only valid indices. - Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty()); - Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1); - Ops[1] = Builder.CreateMul(Ops[1], - ConstantInt::get(Ops[1]->getType(), - VecTy->getMinNumElements())); - return Builder.CreateExtractVector(ResultType, Ops[0], Ops[1]); - } - - return Builder.CreateIntrinsic(Intrinsic::riscv_tuple_extract, - {ResultType, Ops[0]->getType()}, - {Ops[0], Builder.CreateTrunc(Ops[1], - Builder.getInt32Ty())}); - } + return emitRVVGetBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach dst_lmul = ["(SFixedLog2LMUL:0)", "(SFixedLog2LMUL:1)", "(SFixedLog2LMUL:2)"] in { def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "vvKz", "csilxfdy", dst_lmul # "v">; @@ -2535,25 +1789,8 @@ let HasMasked = false, HasVL = false, IRName = "" in { let Name = "vset_v", MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - if (auto *ResVecTy = dyn_cast<ScalableVectorType>(ResultType)) { - auto *VecTy = cast<ScalableVectorType>(Ops[2]->getType()); - unsigned MaxIndex = ResVecTy->getMinNumElements() / VecTy->getMinNumElements(); - assert(isPowerOf2_32(MaxIndex)); - // Mask to only valid indices. - Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty()); - Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1); - Ops[1] = Builder.CreateMul(Ops[1], - ConstantInt::get(Ops[1]->getType(), - VecTy->getMinNumElements())); - return Builder.CreateInsertVector(ResultType, Ops[0], Ops[2], Ops[1]); - } - - return Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert, - {ResultType, Ops[2]->getType()}, - {Ops[0], Ops[2], - Builder.CreateTrunc(Ops[1],Builder.getInt32Ty())}); - } + return emitRVVSetBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in { def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfdy">; @@ -2571,26 +1808,8 @@ let HasMasked = false, HasVL = false, IRName = "" in { MaskedPolicyScheme = NonePolicy, SupportOverloading = false, ManualCodegen = [{ - { - llvm::Value *ReturnVector = llvm::PoisonValue::get(ResultType); - auto *VecTy = cast<ScalableVectorType>(Ops[0]->getType()); - for (unsigned I = 0, N = Ops.size(); I < N; ++I) { - if (isa<ScalableVectorType>(ResultType)) { - llvm::Value *Idx = ConstantInt::get(Builder.getInt64Ty(), - VecTy->getMinNumElements() * I); - ReturnVector = - Builder.CreateInsertVector(ResultType, ReturnVector, Ops[I], Idx); - } else { - llvm::Value *Idx = ConstantInt::get(Builder.getInt32Ty(), I); - ReturnVector = - Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert, - {ResultType, Ops[I]->getType()}, - {ReturnVector, Ops[I], Idx}); - } - - } - return ReturnVector; - } + return emitRVVCreateBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { // Since the vcreate_v uses LFixedLog2LMUL, setting the Log2LMUL to [-3] can diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index b26e558..96f55f5 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -19,7 +19,6 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinAttributes.h" -#include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Location.h" #include "mlir/IR/Types.h" @@ -63,11 +62,11 @@ public: mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, const llvm::APInt &val) { - return create<cir::ConstantOp>(loc, cir::IntAttr::get(typ, val)); + return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(typ, val)); } cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) { - return create<cir::ConstantOp>(loc, attr); + return cir::ConstantOp::create(*this, loc, attr); } cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, @@ -119,7 +118,7 @@ public: } cir::ConstantOp getBool(bool state, mlir::Location loc) { - return create<cir::ConstantOp>(loc, getCIRBoolAttr(state)); + return cir::ConstantOp::create(*this, loc, getCIRBoolAttr(state)); } cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); } cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); } @@ -144,21 +143,37 @@ public: mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real, mlir::Value imag) { auto resultComplexTy = cir::ComplexType::get(real.getType()); - return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag); + return cir::ComplexCreateOp::create(*this, loc, resultComplexTy, real, + imag); } mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) { auto operandTy = mlir::cast<cir::ComplexType>(operand.getType()); - return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand); + return cir::ComplexRealOp::create(*this, loc, operandTy.getElementType(), + operand); } mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) { auto operandTy = mlir::cast<cir::ComplexType>(operand.getType()); - return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand); + return cir::ComplexImagOp::create(*this, loc, operandTy.getElementType(), + operand); + } + + cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr, + uint64_t alignment = 0) { + mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment); + assert(!cir::MissingFeatures::opLoadStoreVolatile()); + return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false, + alignmentAttr, cir::MemOrderAttr{}); + } + + mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr, + uint64_t alignment) { + return createLoad(loc, ptr, alignment); } mlir::Value createNot(mlir::Value value) { - return create<cir::UnaryOp>(value.getLoc(), value.getType(), + return cir::UnaryOp::create(*this, value.getLoc(), value.getType(), cir::UnaryOpKind::Not, value); } @@ -167,7 +182,7 @@ public: mlir::Location loc, llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) { - return create<cir::DoWhileOp>(loc, condBuilder, bodyBuilder); + return cir::DoWhileOp::create(*this, loc, condBuilder, bodyBuilder); } /// Create a while operation. @@ -175,7 +190,7 @@ public: mlir::Location loc, llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) { - return create<cir::WhileOp>(loc, condBuilder, bodyBuilder); + return cir::WhileOp::create(*this, loc, condBuilder, bodyBuilder); } /// Create a for operation. @@ -184,22 +199,23 @@ public: llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder, llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder) { - return create<cir::ForOp>(loc, condBuilder, bodyBuilder, stepBuilder); + return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder, + stepBuilder); } /// Create a break operation. cir::BreakOp createBreak(mlir::Location loc) { - return create<cir::BreakOp>(loc); + return cir::BreakOp::create(*this, loc); } /// Create a continue operation. cir::ContinueOp createContinue(mlir::Location loc) { - return create<cir::ContinueOp>(loc); + return cir::ContinueOp::create(*this, loc); } mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind, mlir::Value operand) { - return create<cir::UnaryOp>(loc, kind, operand); + return cir::UnaryOp::create(*this, loc, kind, operand); } mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) { @@ -209,13 +225,21 @@ public: mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, mlir::Type type, llvm::StringRef name, mlir::IntegerAttr alignment) { - return create<cir::AllocaOp>(loc, addrType, type, name, alignment); + return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment); + } + + /// Get constant address of a global variable as an MLIR attribute. + cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type, + cir::GlobalOp globalOp, + mlir::ArrayAttr indices = {}) { + auto symbol = mlir::FlatSymbolRefAttr::get(globalOp.getSymNameAttr()); + return cir::GlobalViewAttr::get(type, symbol, indices); } mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) { assert(!cir::MissingFeatures::addressSpace()); - return create<cir::GetGlobalOp>(loc, getPointerTo(global.getSymType()), - global.getSymName()); + return cir::GetGlobalOp::create( + *this, loc, getPointerTo(global.getSymType()), global.getSymName()); } mlir::Value createGetGlobal(cir::GlobalOp global) { @@ -223,36 +247,39 @@ public: } cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst, - mlir::IntegerAttr align = {}) { - return create<cir::StoreOp>(loc, val, dst, align); + bool isVolatile = false, + mlir::IntegerAttr align = {}, + cir::MemOrderAttr order = {}) { + return cir::StoreOp::create(*this, loc, val, dst, align, order); } [[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc, mlir::StringRef name, - mlir::Type type, + mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage) { mlir::OpBuilder::InsertionGuard guard(*this); setInsertionPointToStart(mlirModule.getBody()); - return create<cir::GlobalOp>(loc, name, type, linkage); + return cir::GlobalOp::create(*this, loc, name, type, isConstant, linkage); } cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy, mlir::Value base, llvm::StringRef name, unsigned index) { - return create<cir::GetMemberOp>(loc, resultTy, base, name, index); + return cir::GetMemberOp::create(*this, loc, resultTy, base, name, index); } mlir::Value createDummyValue(mlir::Location loc, mlir::Type type, clang::CharUnits alignment) { mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment); auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr); - return create<cir::LoadOp>(loc, addr, /*isDeref=*/false, alignmentAttr); + return cir::LoadOp::create(*this, loc, addr, /*isDeref=*/false, + alignmentAttr, /*mem_order=*/{}); } cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride) { - return create<cir::PtrStrideOp>(loc, base.getType(), base, stride); + return cir::PtrStrideOp::create(*this, loc, base.getType(), base, stride); } //===--------------------------------------------------------------------===// @@ -262,7 +289,7 @@ public: cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) { - auto op = create<cir::CallOp>(loc, callee, returnType, operands); + auto op = cir::CallOp::create(*this, loc, callee, returnType, operands); op->setAttrs(attrs); return op; } @@ -285,6 +312,25 @@ public: resOperands, attrs); } + cir::CallOp createTryCallOp( + mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(), + mlir::Type returnType = cir::VoidType(), + mlir::ValueRange operands = mlir::ValueRange(), + [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) { + assert(!cir::MissingFeatures::opCallCallConv()); + assert(!cir::MissingFeatures::opCallSideEffect()); + return createCallOp(loc, callee, returnType, operands); + } + + cir::CallOp createTryCallOp( + mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands, + [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) { + assert(!cir::MissingFeatures::opCallCallConv()); + assert(!cir::MissingFeatures::opCallSideEffect()); + return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee), + callee.getFunctionType().getReturnType(), operands); + } + //===--------------------------------------------------------------------===// // Cast/Conversion Operators //===--------------------------------------------------------------------===// @@ -293,7 +339,7 @@ public: mlir::Value src, mlir::Type newTy) { if (newTy == src.getType()) return src; - return create<cir::CastOp>(loc, newTy, kind, src); + return cir::CastOp::create(*this, loc, newTy, kind, src); } mlir::Value createCast(cir::CastKind kind, mlir::Value src, @@ -343,7 +389,7 @@ public: mlir::Value createBinop(mlir::Location loc, mlir::Value lhs, cir::BinOpKind kind, mlir::Value rhs) { - return create<cir::BinOp>(loc, lhs.getType(), kind, lhs, rhs); + return cir::BinOp::create(*this, loc, lhs.getType(), kind, lhs, rhs); } mlir::Value createLowBitsSet(mlir::Location loc, unsigned size, @@ -365,8 +411,8 @@ public: mlir::Value trueValue, mlir::Value falseValue) { assert(trueValue.getType() == falseValue.getType() && "trueValue and falseValue should have the same type"); - return create<cir::SelectOp>(loc, trueValue.getType(), condition, trueValue, - falseValue); + return cir::SelectOp::create(*this, loc, trueValue.getType(), condition, + trueValue, falseValue); } mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs, @@ -381,8 +427,8 @@ public: mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob = OverflowBehavior::None) { - auto op = - create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs); + auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Mul, + lhs, rhs); op.setNoUnsignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap)); op.setNoSignedWrap( @@ -400,8 +446,8 @@ public: mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob = OverflowBehavior::Saturated) { - auto op = - create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs); + auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Sub, + lhs, rhs); op.setNoUnsignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap)); op.setNoSignedWrap( @@ -422,8 +468,8 @@ public: mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, OverflowBehavior ob = OverflowBehavior::None) { - auto op = - create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs); + auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Add, + lhs, rhs); op.setNoUnsignedWrap( llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap)); op.setNoSignedWrap( @@ -444,7 +490,7 @@ public: cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs) { - return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs); + return cir::CmpOp::create(*this, loc, getBoolTy(), kind, lhs, rhs); } mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) { @@ -453,7 +499,8 @@ public: mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, bool isShiftLeft) { - return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft); + return cir::ShiftOp::create(*this, loc, lhs.getType(), lhs, rhs, + isShiftLeft); } mlir::Value createShift(mlir::Location loc, mlir::Value lhs, @@ -496,8 +543,7 @@ public: static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block) { auto last = std::find_if(block->rbegin(), block->rend(), [](mlir::Operation &op) { - // TODO: Add LabelOp missing feature here - return mlir::isa<cir::AllocaOp>(&op); + return mlir::isa<cir::AllocaOp, cir::LabelOp>(&op); }); if (last != block->rend()) @@ -532,12 +578,12 @@ public: /// Create a loop condition. cir::ConditionOp createCondition(mlir::Value condition) { - return create<cir::ConditionOp>(condition.getLoc(), condition); + return cir::ConditionOp::create(*this, condition.getLoc(), condition); } /// Create a yield operation. cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) { - return create<cir::YieldOp>(loc, value); + return cir::YieldOp::create(*this, loc, value); } }; diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 588fb0d..16b818f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -51,6 +51,45 @@ class CIR_UnitAttr<string name, string attrMnemonic, list<Trait> traits = []> } //===----------------------------------------------------------------------===// +// SourceLanguageAttr +//===----------------------------------------------------------------------===// + +// TODO: Add cases for other languages that Clang supports. + +def CIR_SourceLanguage : CIR_I32EnumAttr<"SourceLanguage", "source language", [ + I32EnumAttrCase<"C", 1, "c">, + I32EnumAttrCase<"CXX", 2, "cxx"> +]> { + // The enum attr class is defined in `CIR_SourceLanguageAttr` below, + // so that it can define extra class methods. + let genSpecializedAttr = 0; +} + +def CIR_SourceLanguageAttr : CIR_EnumAttr<CIR_SourceLanguage, "lang"> { + + let summary = "Module source language"; + let description = [{ + Represents the source language used to generate the module. + + Example: + ``` + // Module compiled from C. + module attributes {cir.lang = cir.lang<c>} {} + // Module compiled from C++. + module attributes {cir.lang = cir.lang<cxx>} {} + ``` + + Module source language attribute name is `cir.lang` is defined by + `getSourceLanguageAttrName` method in CIRDialect class. + }]; + + let extraClassDeclaration = [{ + bool isC() const { return getValue() == SourceLanguage::C; } + bool isCXX() const { return getValue() == SourceLanguage::CXX; } + }]; +} + +//===----------------------------------------------------------------------===// // OptInfoAttr //===----------------------------------------------------------------------===// @@ -342,6 +381,44 @@ def CIR_ConstVectorAttr : CIR_Attr<"ConstVector", "const_vector", [ } //===----------------------------------------------------------------------===// +// ConstRecordAttr +//===----------------------------------------------------------------------===// + +def CIR_ConstRecordAttr : CIR_Attr<"ConstRecord", "const_record", [ + TypedAttrInterface +]> { + let summary = "Represents a constant record"; + let description = [{ + Effectively supports "struct-like" constants. It's must be built from + an `mlir::ArrayAttr` instance where each element is a typed attribute + (`mlir::TypedAttribute`). + + Example: + ``` + cir.global external @rgb2 = #cir.const_record<{0 : i8, + 5 : i64, #cir.null : !cir.ptr<i8> + }> : !cir.record<"", i8, i64, !cir.ptr<i8>> + ``` + }]; + + let parameters = (ins AttributeSelfTypeParameter<"">:$type, + "mlir::ArrayAttr":$members); + + let builders = [ + AttrBuilderWithInferredContext<(ins "cir::RecordType":$type, + "mlir::ArrayAttr":$members), [{ + return $_get(type.getContext(), type, members); + }]> + ]; + + let assemblyFormat = [{ + `<` custom<RecordMembers>($members) `>` + }]; + + let genVerifyDecl = 1; +} + +//===----------------------------------------------------------------------===// // ConstPtrAttr //===----------------------------------------------------------------------===// @@ -371,6 +448,160 @@ def CIR_ConstPtrAttr : CIR_Attr<"ConstPtr", "ptr", [TypedAttrInterface]> { } //===----------------------------------------------------------------------===// +// GlobalViewAttr +//===----------------------------------------------------------------------===// + +def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [ + TypedAttrInterface +]> { + let summary = "Provides constant access to a global address"; + let description = [{ + Get constant address of global `symbol` and optionally apply offsets to + access existing subelements. It provides a way to access globals from other + global and always produces a pointer. + + The type of the input symbol can be different from `#cir.global_view` + output type, since a given view of the global might require a static + cast for initializing other globals. + + A list of indices can be optionally passed and each element subsequently + indexes underlying types. For `symbol` types like `!cir.array` + and `!cir.record`, it leads to the constant address of sub-elements, while + for `!cir.ptr`, an offset is applied. The first index is relative to the + original symbol type, not the produced one. + + The result type of this attribute may be an integer type. In such a case, + the pointer to the referenced global is casted to an integer and this + attribute represents the casted result. + + Example: + + ``` + cir.global external @s = @".str2": !cir.ptr<i8> + cir.global external @x = #cir.global_view<@s> : !cir.ptr<i8> + cir.global external @s_addr = #cir.global_view<@s> : !s64i + + cir.global external @rgb = #cir.const_array<[0 : i8, -23 : i8, 33 : i8] + : !cir.array<i8 x 3>> + cir.global external @elt_ptr = #cir.global_view<@rgb, [1]> : !cir.ptr<i8> + ``` + + Note, that unlike LLVM IR's gep instruction, CIR doesn't add the leading + zero index when it's known to be constant zero, e.g. for pointers, i.e. we + use indexes exactly to access sub elements or for the offset. The leading + zero index is added later in the lowering. + + Example: + ``` + struct A { + int a; + }; + + struct B: virtual A { + int b; + }; + ``` + VTT for B in CIR: + ``` + cir.global linkonce_odr @_ZTT1B = #cir.const_array<[ + #cir.global_view<@_ZTV1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>]> + : !cir.array<!cir.ptr<!u8i> x 1> + ``` + VTT for B in LLVM IR: + ``` + @_ZTT1B = linkonce_odr global [1 x ptr] [ptr getelementptr inbounds + ({ [3 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)], align 8 + ``` + }]; + + let parameters = (ins AttributeSelfTypeParameter<"">:$type, + "mlir::FlatSymbolRefAttr":$symbol, + OptionalParameter<"mlir::ArrayAttr">:$indices); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + "mlir::FlatSymbolRefAttr":$symbol, + CArg<"mlir::ArrayAttr", "{}">:$indices), [{ + return $_get(type.getContext(), type, symbol, indices); + }]> + ]; + + // let genVerifyDecl = 1; + let assemblyFormat = [{ + `<` + $symbol + (`,` $indices^)? + `>` + }]; +} + +//===----------------------------------------------------------------------===// +// VTableAttr +//===----------------------------------------------------------------------===// + +def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> { + let summary = "Represents a C++ vtable"; + let description = [{ + Wraps a #cir.const_record containing one or more vtable arrays. + + In most cases, the anonymous record type wrapped by this attribute will + contain a single array corresponding to the vtable for one class. However, + in the case of multiple inheritence, the anonymous structure may contain + multiple arrays, each of which is a vtable. + + Example 1 (single vtable): + ```mlir + cir.global linkonce_odr @_ZTV6Mother = + #cir.vtable<{ + #cir.const_array<[ + #cir.ptr<null> : !cir.ptr<!u8i>, + #cir.global_view<@_ZTI6Mother> : !cir.ptr<!u8i>, + #cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr<!u8i>, + #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i> + ]> : !cir.array<!cir.ptr<!u8i> x 4> + }> : !rec_anon_struct1 + ``` + + Example 2 (multiple vtables): + ```mlir + cir.global linkonce_odr @_ZTV5Child = + #cir.vtable<{ + #cir.const_array<[ + #cir.ptr<null> : !cir.ptr<!u8i>, + #cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>, + #cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr<!u8i>, + #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i> + ]> : !cir.array<!cir.ptr<!u8i> x 4>, + #cir.const_array<[ + #cir.ptr<-8 : i64> : !cir.ptr<!u8i>, + #cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>, + #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr<!u8i> + ]> : !cir.array<!cir.ptr<!u8i> x 3> + }> : !rec_anon_struct2 + ``` + }]; + + // `data` is a const record with one element, containing an array of + // vtable information. + let parameters = (ins + AttributeSelfTypeParameter<"">:$type, + "mlir::ArrayAttr":$data + ); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + "mlir::ArrayAttr":$data), [{ + return $_get(type.getContext(), type, data); + }]> + ]; + + let genVerifyDecl = 1; + let assemblyFormat = [{ + `<` custom<RecordMembers>($data) `>` + }]; +} + +//===----------------------------------------------------------------------===// // ConstComplexAttr //===----------------------------------------------------------------------===// @@ -516,4 +747,36 @@ def CIR_BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { ]; } +//===----------------------------------------------------------------------===// +// AddressPointAttr +//===----------------------------------------------------------------------===// + +def CIR_AddressPointAttr : CIR_Attr<"AddressPoint", "address_point"> { + let summary = "Address point attribute"; + + let description = [{ + Attribute specifying the address point within a C++ virtual table (vtable). + + The `index` (vtable index) parameter identifies which vtable to use within a + vtable group, while the `offset` (address point index) specifies the offset + within that vtable where the address begins. + + Example: + ```mlir + cir.global linkonce_odr @_ZTV1B = ... + ... + %3 = cir.vtable.address_point(@_ZTV1B, + address_point = <index = 0, offset = 2>) + : !cir.vptr + ``` + }]; + + let parameters = (ins "int32_t":$index, + "int32_t":$offset); + + let assemblyFormat = [{ + `<` struct($index, $offset) `>` + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h index 8ef565d..ecc681e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h @@ -34,6 +34,41 @@ public: void reset(mlir::DataLayoutSpecInterface spec); bool isBigEndian() const { return bigEndian; } + + /// Internal helper method that returns requested alignment for type. + llvm::Align getAlignment(mlir::Type ty, bool abiOrPref) const; + + llvm::Align getABITypeAlign(mlir::Type ty) const { + return getAlignment(ty, true); + } + + /// Returns the maximum number of bytes that may be overwritten by + /// storing the specified type. + /// + /// If Ty is a scalable vector type, the scalable property will be set and + /// the runtime size will be a positive integer multiple of the base size. + /// + /// For example, returns 5 for i36 and 10 for x86_fp80. + llvm::TypeSize getTypeStoreSize(mlir::Type ty) const { + llvm::TypeSize baseSize = getTypeSizeInBits(ty); + return {llvm::divideCeil(baseSize.getKnownMinValue(), 8), + baseSize.isScalable()}; + } + + /// Returns the offset in bytes between successive objects of the + /// specified type, including alignment padding. + /// + /// If Ty is a scalable vector type, the scalable property will be set and + /// the runtime size will be a positive integer multiple of the base size. + /// + /// This is the amount that alloca reserves for this type. For example, + /// returns 12 or 16 for x86_fp80, depending on alignment. + llvm::TypeSize getTypeAllocSize(mlir::Type ty) const { + // Round up to the next alignment boundary. + return llvm::alignTo(getTypeStoreSize(ty), getABITypeAlign(ty).value()); + } + + llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const; }; } // namespace cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index 3fdbf65..15d5fa0 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -35,11 +35,13 @@ def CIR_Dialect : Dialect { let hasConstantMaterializer = 1; let extraClassDeclaration = [{ + static llvm::StringRef getSourceLanguageAttrName() { return "cir.lang"; } static llvm::StringRef getTripleAttrName() { return "cir.triple"; } static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; } static llvm::StringRef getCalleeAttrName() { return "callee"; } static llvm::StringRef getNoThrowAttrName() { return "nothrow"; } static llvm::StringRef getSideEffectAttrName() { return "side_effect"; } + static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; } void registerAttributes(); void registerTypes(); diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 72841a1..982533f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -300,6 +300,20 @@ def CIR_ConstantOp : CIR_Op<"const", [ } //===----------------------------------------------------------------------===// +// C/C++ memory order definitions +//===----------------------------------------------------------------------===// + +def CIR_MemOrder : CIR_I32EnumAttr< + "MemOrder", "Memory order according to C++11 memory model", [ + I32EnumAttrCase<"Relaxed", 0, "relaxed">, + I32EnumAttrCase<"Consume", 1, "consume">, + I32EnumAttrCase<"Acquire", 2, "acquire">, + I32EnumAttrCase<"Release", 3, "release">, + I32EnumAttrCase<"AcquireRelease", 4, "acq_rel">, + I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst"> +]>; + +//===----------------------------------------------------------------------===// // AllocaOp //===----------------------------------------------------------------------===// @@ -408,13 +422,14 @@ def CIR_LoadOp : CIR_Op<"load", [ let arguments = (ins Arg<CIR_PointerType, "the address to load from", [MemRead]>:$addr, UnitAttr:$isDeref, - OptionalAttr<I64Attr>:$alignment - ); + OptionalAttr<I64Attr>:$alignment, + OptionalAttr<CIR_MemOrder>:$mem_order); let results = (outs CIR_AnyType:$result); let assemblyFormat = [{ (`deref` $isDeref^)? (`align` `(` $alignment^ `)`)? + (`atomic` `(` $mem_order^ `)`)? $addr `:` qualified(type($addr)) `,` type($result) attr-dict }]; @@ -451,10 +466,12 @@ def CIR_StoreOp : CIR_Op<"store", [ let arguments = (ins CIR_AnyType:$value, Arg<CIR_PointerType, "the address to store the value", [MemWrite]>:$addr, - OptionalAttr<I64Attr>:$alignment); + OptionalAttr<I64Attr>:$alignment, + OptionalAttr<CIR_MemOrder>:$mem_order); let assemblyFormat = [{ (`align` `(` $alignment^ `)`)? + (`atomic` `(` $mem_order^ `)`)? $value `,` $addr attr-dict `:` type($value) `,` qualified(type($addr)) }]; @@ -1061,6 +1078,77 @@ def CIR_BrOp : CIR_Op<"br",[ } //===----------------------------------------------------------------------===// +// GotoOp +//===----------------------------------------------------------------------===// + +def CIR_GotoOp : CIR_Op<"goto", [Terminator]> { + let description = [{ + + Transfers control to the specified `label`. This requires a corresponding + `cir.label` to exist and is used by to represent source level `goto`s + that jump across region boundaries. Alternatively, `cir.br` is used to + construct goto's that don't violate such boundaries. + + `cir.goto` is completely symbolic (i.e. it "jumps" on a label that isn't + yet materialized) and should be taken into account by passes and analysis + when deciding if it's safe to make some assumptions about a given region + or basic block. + + Example: + ```C++ + int test(int x) { + if (x) + goto label; + { + x = 10; + label: + return x; + } + } + ``` + + ```mlir + cir.scope { // REGION #1 + %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i + %3 = cir.cast(int_to_bool, %2 : !s32i), !cir.bool + cir.if %3 { + cir.goto "label" + } + } + cir.scope { // REGION #2 + %2 = cir.const #cir.int<10> : !s32i + cir.store %2, %0 : !s32i, !cir.ptr<!s32i> + cir.br ^bb1 + ^bb1: // pred: ^bb0 + cir.label "label" + %3 = cir.load %0 : !cir.ptr<!s32i>, !s32i + cir.store %3, %1 : !s32i, !cir.ptr<!s32i> + %4 = cir.load %1 : !cir.ptr<!s32i>, !s32i + cir.return %4 : !s32i + } + cir.unreachable + ``` + }]; + let arguments = (ins StrAttr:$label); + let assemblyFormat = [{ $label attr-dict }]; +} + +//===----------------------------------------------------------------------===// +// LabelOp +//===----------------------------------------------------------------------===// + +// The LabelOp has AlwaysSpeculatable trait in order to not to be swept +// by canonicalizer +def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> { + let description = [{ + An identifier which may be referred by cir.goto operation + }]; + let arguments = (ins StrAttr:$label); + let assemblyFormat = [{ $label attr-dict }]; + let hasVerifier = 1; +} + +//===----------------------------------------------------------------------===// // UnaryOp //===----------------------------------------------------------------------===// @@ -1631,12 +1719,14 @@ def CIR_GlobalOp : CIR_Op<"global", [ CIR_GlobalLinkageKind:$linkage, OptionalAttr<AnyAttr>:$initial_value, UnitAttr:$comdat, + UnitAttr:$constant, UnitAttr:$dso_local, OptionalAttr<I64Attr>:$alignment); let assemblyFormat = [{ ($sym_visibility^)? (`` $global_visibility^)? + (`constant` $constant^)? $linkage (`comdat` $comdat^)? (`dso_local` $dso_local^)? @@ -1655,6 +1745,7 @@ def CIR_GlobalOp : CIR_Op<"global", [ let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name, "mlir::Type":$sym_type, + CArg<"bool", "false">:$isConstant, // CIR defaults to external linkage. CArg<"cir::GlobalLinkageKind", "cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>]; @@ -1692,6 +1783,194 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [ } //===----------------------------------------------------------------------===// +// VTableAddrPointOp +//===----------------------------------------------------------------------===// + +def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [ + Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface> +]> { + let summary = "Get the vtable (global variable) address point"; + let description = [{ + The `vtable.address_point` operation retrieves the "effective" address + (address point) of a C++ virtual table. An object internal `__vptr` + gets initializated on top of the value returned by this operation. + + `address_point.index` (vtable index) provides the appropriate vtable within + the vtable group (as specified by Itanium ABI), and `address_point.offset` + (address point index) the actual address point within that vtable. + + The return type is always `!cir.vptr`. + + Example: + ```mlir + cir.global linkonce_odr @_ZTV1B = ... + ... + %3 = cir.vtable.address_point(@_ZTV1B, + address_point = <index = 0, offset = 2>) : !cir.vptr + ``` + }]; + + let arguments = (ins + FlatSymbolRefAttr:$name, + CIR_AddressPointAttr:$address_point + ); + + let results = (outs Res<CIR_VPtrType, "", []>:$addr); + + let assemblyFormat = [{ + `(` + $name `,` `address_point` `=` $address_point + `)` + `:` qualified(type($addr)) attr-dict + }]; +} + +//===----------------------------------------------------------------------===// +// VTableGetVPtr +//===----------------------------------------------------------------------===// + +def CIR_VTableGetVPtrOp : CIR_Op<"vtable.get_vptr", [Pure]> { + let summary = "Get a the address of the vtable pointer for an object"; + let description = [{ + The `vtable.get_vptr` operation retrieves the address of the vptr for a + C++ object. This operation requires that the object pointer points to + the start of a complete object. (TODO: Describe how we get that). + The vptr will always be at offset zero in the object, but this operation + is more explicit about what is being retrieved than a direct bitcast. + + The return type is always `!cir.ptr<!cir.vptr>`. + + Example: + ```mlir + %2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C> + %3 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr> + ``` + }]; + + let arguments = (ins + Arg<CIR_PointerType, "the vptr address", [MemRead]>:$src + ); + + let results = (outs CIR_PtrToVPtr:$result); + + let assemblyFormat = [{ + $src `:` qualified(type($src)) `->` qualified(type($result)) attr-dict + }]; +} + +//===----------------------------------------------------------------------===// +// VTableGetVirtualFnAddrOp +//===----------------------------------------------------------------------===// + +def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ + Pure +]> { + let summary = "Get a the address of a virtual function pointer"; + let description = [{ + The `vtable.get_virtual_fn_addr` operation retrieves the address of a + virtual function pointer from an object's vtable (__vptr). + This is an abstraction to perform the basic pointer arithmetic to get + the address of the virtual function pointer, which can then be loaded and + called. + + The `vptr` operand must be a `!cir.ptr<!cir.vptr>` value, which would + have been returned by a previous call to `cir.vatble.get_vptr`. The + `index` operand is an index of the virtual function in the vtable. + + The return type is a pointer-to-pointer to the function type. + + Example: + ```mlir + %2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C> + %3 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr> + %4 = cir.load %3 : !cir.ptr<!cir.vptr>, !cir.vptr + %5 = cir.vtable.get_virtual_fn_addr %4[2] : !cir.vptr + -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>> + %6 = cir.load align(8) %5 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) + -> !s32i>>>, + !cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>> + %7 = cir.call %6(%2) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>, + !cir.ptr<!rec_C>) -> !s32i + ``` + }]; + + let arguments = (ins + Arg<CIR_VPtrType, "vptr", [MemRead]>:$vptr, + I64Attr:$index); + + let results = (outs CIR_PointerType:$result); + + let assemblyFormat = [{ + $vptr `[` $index `]` attr-dict + `:` qualified(type($vptr)) `->` qualified(type($result)) + }]; +} + +//===----------------------------------------------------------------------===// +// VTTAddrPointOp +//===----------------------------------------------------------------------===// + +def CIR_VTTAddrPointOp : CIR_Op<"vtt.address_point", [ + Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface> +]> { + let summary = "Get the VTT address point"; + let description = [{ + The `vtt.address_point` operation retrieves an element from the virtual + table table (VTT), which is the address point of a C++ vtable. In virtual + inheritance, a set of internal `__vptr` members for an object are + initialized by this operation, which assigns an element from the VTT. The + initialization order is as follows: + + The complete object constructors and destructors find the VTT, + via the mangled name of the VTT global variable. They pass the address of + the subobject's sub-VTT entry in the VTT as a second parameter + when calling the base object constructors and destructors. + The base object constructors and destructors use the address passed to + initialize the primary virtual pointer and virtual pointers that point to + the classes which either have virtual bases or override virtual functions + with a virtual step. + + The first parameter is either the mangled name of VTT global variable + or the address of the subobject's sub-VTT entry in the VTT. + The second parameter `offset` provides a virtual step to adjust to + the actual address point of the vtable. + + The return type is always a `!cir.ptr<!cir.ptr<void>>`. + + Example: + ```mlir + cir.global linkonce_odr @_ZTV1B = ... + ... + %3 = cir.base_class_addr(%1 : !cir.ptr<!rec_D> nonnull) [0] + -> !cir.ptr<!rec_B> + %4 = cir.vtt.address_point @_ZTT1D, offset = 1 + -> !cir.ptr<!cir.ptr<!void>> + cir.call @_ZN1BC2Ev(%3, %4) + ``` + Or: + ```mlir + %7 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1 + -> !cir.ptr<!cir.ptr<!void>> + ``` + }]; + + let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name, + Optional<CIR_AnyType>:$sym_addr, + I32Attr:$offset); + let results = (outs CIR_PointerType:$addr); + + let assemblyFormat = [{ + ($name^)? + ($sym_addr^ `:` type($sym_addr))? + `,` + `offset` `=` $offset + `->` qualified(type($addr)) attr-dict + }]; + + let hasVerifier = 1; +} + +//===----------------------------------------------------------------------===// // SetBitfieldOp //===----------------------------------------------------------------------===// @@ -2153,6 +2432,68 @@ def CIR_CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> { } //===----------------------------------------------------------------------===// +// ReturnAddrOp and FrameAddrOp +//===----------------------------------------------------------------------===// + +class CIR_FuncAddrBuiltinOp<string mnemonic> : CIR_Op<mnemonic, []> { + let arguments = (ins CIR_UInt32:$level); + let results = (outs CIR_VoidPtrType:$result); + let assemblyFormat = [{ + `(` $level `)` attr-dict + }]; +} + +def CIR_ReturnAddrOp : CIR_FuncAddrBuiltinOp<"return_address"> { + let summary = + "The return address of the current function, or of one of its callers"; + + let description = [{ + Represents a call to builtin function ` __builtin_return_address` in CIR. + This builtin function returns the return address of the current function, + or of one of its callers. + + The `level` argument is number of frames to scan up the call stack. + For instance, value of 0 yields the return address of the current function, + value of 1 yields the return address of the caller of the current function, + and so forth. + + Examples: + + ```mlir + %p = return_address(%level) -> !cir.ptr<!void> + ``` + }]; +} + +def CIR_FrameAddrOp : CIR_FuncAddrBuiltinOp<"frame_address"> { + let summary = + "The frame address of the current function, or of one of its callers"; + + let description = [{ + Represents a call to builtin function ` __builtin_frame_address` in CIR. + This builtin function returns the frame address of the current function, + or of one of its callers. The frame is the area on the stack that holds + local variables and saved registers. The frame address is normally the + address of the first word pushed on to the stack by the function. + However, the exact definition depends upon the processor and the calling + convention. If the processor has a dedicated frame pointer register, and + the function has a frame, then __builtin_frame_address returns the value of + the frame pointer register. + + The `level` argument is number of frames to scan up the call stack. + For instance, value of 0 yields the frame address of the current function, + value of 1 yields the frame address of the caller of the current function, + and so forth. + + Examples: + + ```mlir + %p = frame_address(%level) -> !cir.ptr<!void> + ``` + }]; +} + +//===----------------------------------------------------------------------===// // StackSaveOp & StackRestoreOp //===----------------------------------------------------------------------===// @@ -2197,6 +2538,87 @@ def CIR_StackRestoreOp : CIR_Op<"stackrestore"> { } //===----------------------------------------------------------------------===// +// InlineAsmOp +//===----------------------------------------------------------------------===// + +def CIR_AsmFlavor : CIR_I32EnumAttr<"AsmFlavor", "ATT or Intel", + [I32EnumAttrCase<"x86_att", 0>, + I32EnumAttrCase<"x86_intel", 1>]>; + +def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> { + let description = [{ + The `cir.asm` operation represents C/C++ asm inline. + + CIR constraints strings follow the same rules that are established for + the C level assembler constraints with several differences caused by + clang::AsmStmt processing. + + Thus, numbers that appears in the constraint string may also refer to: + - the output variable index referenced by the input operands. + - the index of early-clobber operand + + Operand attributes are a storage, where each element corresponds to the + operand with the same index. The first index relates to the operation + result (if any). + The operands themselves are stored as VariadicOfVariadic in the following + order: output, input and then in/out operands. When several output operands + are present, the result type may be represented as an anonymous record type. + + Example: + ```C++ + __asm__("foo" : : : ); + __asm__("bar $42 %[val]" : [val] "=r" (x), "+&r"(x)); + __asm__("baz $42 %[val]" : [val] "=r" (x), "+&r"(x) : "[val]"(y)); + ``` + + ```mlir + !rec_22anon2E022 = !cir.record<struct "anon.0" {!cir.int<s, 32>, !cir.int<s, 32>}> + !rec_22anon2E122 = !cir.record<struct "anon.1" {!cir.int<s, 32>, !cir.int<s, 32>}> + ... + %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] + %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] + ... + %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i + %3 = cir.load %1 : !cir.ptr<!s32i>, !s32i + + cir.asm(x86_att, + out = [], + in = [], + in_out = [], + {"foo" "~{dirflag},~{fpsr},~{flags}"}) side_effects + + cir.asm(x86_att, + out = [], + in = [], + in_out = [%2 : !s32i], + {"bar $$42 $0" "=r,=&r,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E022 + + cir.asm(x86_att, + out = [], + in = [%3 : !s32i], + in_out = [%2 : !s32i], + {"baz $$42 $0" "=r,=&r,0,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E122 + ``` + }]; + + let results = (outs Optional<CIR_AnyType>:$res); + + let arguments = + (ins VariadicOfVariadic<AnyType, "operands_segments">:$asm_operands, + StrAttr:$asm_string, StrAttr:$constraints, UnitAttr:$side_effects, + CIR_AsmFlavor:$asm_flavor, ArrayAttr:$operand_attrs, + DenseI32ArrayAttr:$operands_segments); + + let builders = [OpBuilder<(ins + "llvm::ArrayRef<mlir::ValueRange>":$asmOperands, + "llvm::StringRef":$asmString, "llvm::StringRef":$constraints, + "bool":$sideEffects, "AsmFlavor":$asmFlavor, + "llvm::ArrayRef<mlir::Attribute>":$operandAttrs)>]; + + let hasCustomAssemblyFormat = 1; +} + +//===----------------------------------------------------------------------===// // UnreachableOp //===----------------------------------------------------------------------===// @@ -2827,7 +3249,7 @@ def CIR_ComplexSubOp : CIR_Op<"complex.sub", [ } //===----------------------------------------------------------------------===// -// ComplexMulOp +// ComplexMulOp & ComplexDivOp //===----------------------------------------------------------------------===// def CIR_ComplexRangeKind : CIR_I32EnumAttr< @@ -2846,12 +3268,13 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [ The `cir.complex.mul` operation takes two complex numbers and returns their product. - Range is used to select the implementation used when the operation - is lowered to the LLVM dialect. For multiplication, 'improved', - 'promoted', and 'basic' are all handled equivalently, producing the - algebraic formula with no special handling for NaN value. If 'full' is - used, a runtime-library function is called if one of the intermediate - calculations produced a NaN value. + For complex types with floating-point components, the `range` attribute + specifies the algorithm to be used when the operation is lowered to + the LLVM dialect. For multiplication, 'improved', 'promoted', and 'basic' + are all handled equivalently, producing the algebraic formula with no + special handling for NaN value. If 'full' is used, a runtime-library + function is called if one of the intermediate calculations produced + a NaN value. Example: @@ -2874,6 +3297,48 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [ }]; } +def CIR_ComplexDivOp : CIR_Op<"complex.div", [ + Pure, SameOperandsAndResultType +]> { + let summary = "Complex division"; + let description = [{ + The `cir.complex.div` operation takes two complex numbers and returns + their quotient. + + For complex types with floating-point components, the `range` attribute + specifies the algorithm to be used when the operation is lowered to + the LLVM dialect. For division, 'improved' produces Smith's algorithms for + Complex division with no additional handling for NaN values. If 'promoted' + is used, the values are promoted to a higher precision type, if possible, + and the calculation is performed using the algebraic formula, with + no additional handling for NaN values. We fall back on Smith's algorithm + when the target doesn't support a higher precision type. If 'full' is used, + a runtime-library function is called if one of the intermediate + calculations produced a NaN value. and for 'basic' algebraic formula with + no additional handling for the NaN value will be used. For integers types + `range` attribute will be ignored. + + Example: + + ```mlir + %2 = cir.complex.div %0, %1 range(basic) : !cir.complex<!cir.float> + %2 = cir.complex.div %0, %1 range(full) : !cir.complex<!cir.float> + ``` + }]; + + let arguments = (ins + CIR_ComplexType:$lhs, + CIR_ComplexType:$rhs, + CIR_ComplexRangeKind:$range + ); + + let results = (outs CIR_ComplexType:$result); + + let assemblyFormat = [{ + $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict + }]; +} + //===----------------------------------------------------------------------===// // Bit Manipulation Operations //===----------------------------------------------------------------------===// @@ -3143,6 +3608,56 @@ def CIR_AssumeOp : CIR_Op<"assume"> { }]; } +def CIR_AssumeAlignedOp : CIR_Op<"assume_aligned", [ + Pure, AllTypesMatch<["pointer", "result"]> +]> { + let summary = "Tell the optimizer that a pointer is aligned"; + let description = [{ + The `cir.assume_aligned` operation takes two or three arguments. The first + argument `pointer` gives the pointer value whose alignment is to be assumed, + and the second argument `align` is an integer attribute that gives the + assumed alignment. + + The `offset` argument is optional. If given, it represents misalignment + offset. When it's present, this operation tells the optimizer that the + pointer is always misaligned to the alignment by `offset` bytes, a.k.a. the + pointer yielded by `(char *)pointer - offset` is aligned to the specified + alignment. Note that the `offset` argument is an SSA value rather than an + attribute, which means that you could pass a dynamically determined value + as the mialignment offset. + + The result of this operation has the same value as the `pointer` argument, + but it additionally carries any alignment information indicated by this + operation. + + This operation corresponds to the `__builtin_assume_aligned` builtin + function. + + Example: + + ```mlir + // Assume that %0 is a CIR pointer value of type !cir.ptr<!s32i> + %1 = cir.assume_aligned %0 alignment 16 : !cir.ptr<!s32i> + + // With a misalignment offset of 4 bytes: + %2 = cir.const #cir.int<4> : !u64i + %3 = cir.assume_aligned %0 alignment 16 [offset %2 : !u64i] : !cir.ptr<!s32i> + ``` + }]; + + let arguments = (ins CIR_PointerType:$pointer, + I64Attr:$alignment, + Optional<CIR_IntType>:$offset); + let results = (outs CIR_PointerType:$result); + + let assemblyFormat = [{ + $pointer + `alignment` $alignment + (`[` `offset` $offset^ `:` type($offset) `]`)? + `:` qualified(type($pointer)) attr-dict + }]; +} + def CIR_AssumeSepStorageOp : CIR_Op<"assume_separate_storage", [ SameTypeOperands ]> { @@ -3202,4 +3717,210 @@ def CIR_ExpectOp : CIR_Op<"expect", [ }]; } +//===----------------------------------------------------------------------===// +// Floating Point Ops +//===----------------------------------------------------------------------===// + +class CIR_UnaryFPToFPBuiltinOp<string mnemonic, string llvmOpName> + : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> +{ + let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src); + let results = (outs CIR_AnyFloatOrVecOfFloatType:$result); + + let assemblyFormat = "$src `:` type($src) attr-dict"; + + let llvmOp = llvmOpName; +} + +def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> { + let summary = "Computes the floating-point absolute value"; + let description = [{ + `cir.fabs` computes the absolute value of a floating-point operand + and returns a result of the same type, ignoring floating-point + exceptions. It does not set `errno`. + }]; +} + +//===----------------------------------------------------------------------===// +// Variadic Operations +//===----------------------------------------------------------------------===// + +def CIR_VAStartOp : CIR_Op<"va_start"> { + let summary = "Starts a variable argument list"; + let description = [{ + The cir.va_start operation models the C/C++ va_start macro by + initializing a variable argument list at the given va_list storage + location. + + The first operand must be a pointer to the target's `va_list` + representation. This operation has no results and produces its effect by + mutating the storage referenced by the pointer operand. The second operand + must be an integer value that contains the expected number of arguments in + that list. + + Each `cir.va_start` must be paired with a corresponding `cir.va_end` + on the same logical `va_list` object along all control-flow paths. After + `cir.va_end`, the `va_list` must not be accessed unless reinitialized + with another `cir.va_start`. + + Lowering maps this to the LLVM intrinsic `llvm.va_start`, passing the + appropriately decayed pointer to the underlying `va_list` storage. + + Example: + + ```mlir + // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> + %p = cir.cast(array_to_ptrdecay, %args + : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), + !cir.ptr<!rec___va_list_tag> + %count = cir.load %0 : !cir.ptr<!s32i>, !s32i + cir.va_start %p %count : !cir.ptr<!rec___va_list_tag>, !s32i + ``` + }]; + let arguments = (ins + CIR_PointerType:$arg_list, + CIR_AnyFundamentalIntType:$count + ); + + let assemblyFormat = [{ + $arg_list $count attr-dict `:` type(operands) + }]; +} + +def CIR_VAEndOp : CIR_Op<"va_end"> { + let summary = "Ends a variable argument list"; + let description = [{ + The `cir.va_end` operation models the C/C++ va_end macro by finalizing + and cleaning up a variable argument list previously initialized with + `cir.va_start`. + + The operand must be a pointer to the target's `va_list` representation. + This operation has no results and produces its effect by mutating the + storage referenced by the pointer operand. + + `cir.va_end` must only be called after a matching `cir.va_start` on the + same `va_list` along all control-flow paths. After `cir.va_end`, the + `va_list` is invalid and must not be accessed unless reinitialized. + + Lowering typically maps this to the LLVM intrinsic `llvm.va_end`, + passing the appropriately decayed pointer to the underlying `va_list` + storage. + + Example: + ```mlir + // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> + %p = cir.cast(array_to_ptrdecay, %args + : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), + !cir.ptr<!rec___va_list_tag> + cir.va_end %p : !cir.ptr<!rec___va_list_tag> + ``` + }]; + + let arguments = (ins CIR_PointerType:$arg_list); + + let assemblyFormat = [{ + $arg_list attr-dict `:` type(operands) + }]; +} + +def CIR_VAArgOp : CIR_Op<"va_arg"> { + let summary = "Fetches next variadic element as a given type"; + let description = [{ + The `cir.va_arg` operation models the C/C++ `va_arg` macro by reading the + next argument from an active variable argument list and producing it as a + value of a specified result type. + + The operand must be a pointer to the target's `va_list` representation. + The operation advances the `va_list` state as a side effect and returns + the fetched value as the result, whose type is chosen by the user of the + operation. + + A `cir.va_arg` must only be used on a `va_list` that has been initialized + with `cir.va.start` and not yet finalized by `cir.va.end`. The semantics + (including alignment and promotion rules) follow the platform ABI; the + frontend is responsible for providing a `va_list` pointer that matches the + target representation. + + Example: + ```mlir + // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> + %p = cir.cast(array_to_ptrdecay, %args + : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), + !cir.ptr<!rec___va_list_tag> + cir.va.start %p : !cir.ptr<!rec___va_list_tag> + + // Fetch an `int` from the vararg list. + %v = cir.va_arg %p : (!cir.ptr<!rec___va_list_tag>) -> !s32i + + cir.va.end %p : !cir.ptr<!rec___va_list_tag> + ``` + }]; + + let arguments = (ins CIR_PointerType:$arg_list); + let results = (outs CIR_AnyType:$result); + + let assemblyFormat = [{ + $arg_list attr-dict `:` functional-type(operands, $result) + }]; +} + +//===----------------------------------------------------------------------===// +// ThrowOp +//===----------------------------------------------------------------------===// + +def CIR_ThrowOp : CIR_Op<"throw"> { + let summary = "(Re)Throws an exception"; + let description = [{ + This operation is equivalent to either __cxa_throw or __cxa_rethrow, + depending on the arguments. + + The absense of arguments for `cir.throw` means it rethrows. + + For the no-rethrow version, it must have at least two operands, the RTTI + information, a pointer to the exception object (likely allocated via + `cir.alloc_exception`) and finally an optional dtor, which might run as + part of this operation. + + Example: + + ```mlir + // re-throw; + cir.throw + + // if (b == 0) + // throw "Division by zero condition!"; + + // Type info for char const* + cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i> + cir.if %cond { + %exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void> + ... + // Store string addr for "Division by zero condition!" + cir.store %string_addr, %exception_addr : !cir.ptr<!s8i>, + !cir.ptr<!cir.ptr<!s8i>> + cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>, + @_ZTIPKc + ``` + }]; + + let arguments = (ins + Optional<CIR_PointerType>:$exception_ptr, + OptionalAttr<FlatSymbolRefAttr>:$type_info, + OptionalAttr<FlatSymbolRefAttr>:$dtor + ); + + let assemblyFormat = [{ + ($exception_ptr^ `:` type($exception_ptr))? + (`,` $type_info^)? + (`,` $dtor^)? + attr-dict + }]; + + let extraClassDeclaration = [{ + bool rethrows() { return getNumOperands() == 0; } + }]; + + let hasVerifier = 1; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h index fead572..17fddae 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h +++ b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h @@ -113,6 +113,18 @@ LLVM_ATTRIBUTE_UNUSED static bool isValidLinkage(GlobalLinkageKind gl) { isLinkOnceLinkage(gl); } +bool operator<(cir::MemOrder, cir::MemOrder) = delete; +bool operator>(cir::MemOrder, cir::MemOrder) = delete; +bool operator<=(cir::MemOrder, cir::MemOrder) = delete; +bool operator>=(cir::MemOrder, cir::MemOrder) = delete; + +// Validate an integral value which isn't known to fit within the enum's range +// is a valid AtomicOrderingCABI. +template <typename Int> inline bool isValidCIRAtomicOrderingCABI(Int value) { + return static_cast<Int>(cir::MemOrder::Relaxed) <= value && + value <= static_cast<Int>(cir::MemOrder::SequentiallyConsistent); +} + } // namespace cir #endif // CLANG_CIR_DIALECT_IR_CIROPSENUMS_H diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index d7d55df..82f6e1d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -290,6 +290,14 @@ def CIR_AnyFloatOrVecOfFloatType } //===----------------------------------------------------------------------===// +// VPtr type predicates +//===----------------------------------------------------------------------===// + +def CIR_AnyVPtrType : CIR_TypeBase<"::cir::VPtrType", "vptr type">; + +def CIR_PtrToVPtr : CIR_PtrToType<CIR_AnyVPtrType>; + +//===----------------------------------------------------------------------===// // Scalar Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index a258df7..312d0a9 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -296,10 +296,10 @@ def CIR_VPtrType : CIR_Type<"VPtr", "vptr", [ access to the vptr. This type will be the element type of the 'vptr' member of structures that - require a vtable pointer. A pointer to this type is returned by the - `cir.vtable.address_point` and `cir.vtable.get_vptr` operations, and this - pointer may be passed to the `cir.vtable.get_virtual_fn_addr` operation to - get the address of a virtual function pointer. + require a vtable pointer. The `cir.vtable.address_point` operation returns + this type. The `cir.vtable.get_vptr` operations returns a pointer to this + type. This pointer may be passed to the `cir.vtable.get_virtual_fn_addr` + operation to get the address of a virtual function pointer. The pointer may also be cast to other pointer types in order to perform pointer arithmetic based on information encoded in the AST layout to get diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h index 7a202b1..32c3e27 100644 --- a/clang/include/clang/CIR/Dialect/Passes.h +++ b/clang/include/clang/CIR/Dialect/Passes.h @@ -26,6 +26,7 @@ std::unique_ptr<Pass> createCIRSimplifyPass(); std::unique_ptr<Pass> createHoistAllocasPass(); std::unique_ptr<Pass> createLoweringPreparePass(); std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx); +std::unique_ptr<Pass> createGotoSolverPass(); void populateCIRPreLoweringPasses(mlir::OpPassManager &pm); diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td index 7d5ec2f..0f57839 100644 --- a/clang/include/clang/CIR/Dialect/Passes.td +++ b/clang/include/clang/CIR/Dialect/Passes.td @@ -72,6 +72,16 @@ def CIRFlattenCFG : Pass<"cir-flatten-cfg"> { let dependentDialects = ["cir::CIRDialect"]; } +def GotoSolver : Pass<"cir-goto-solver"> { + let summary = "Replaces goto operations with branches"; + let description = [{ + This pass transforms CIR and replaces goto-s with branch + operations to the proper blocks. + }]; + let constructor = "mlir::createGotoSolverPass()"; + let dependentDialects = ["cir::CIRDialect"]; +} + def LoweringPrepare : Pass<"cir-lowering-prepare"> { let summary = "Lower to more fine-grained CIR operations before lowering to " "other dialects"; diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 27dd181..6a8bab2 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -27,9 +27,6 @@ struct MissingFeatures { // Address space related static bool addressSpace() { return false; } - // CIRGenFunction implementation details - static bool cgfSymbolTable() { return false; } - // Unhandled global/linkage information. static bool opGlobalThreadLocal() { return false; } static bool opGlobalConstant() { return false; } @@ -52,7 +49,6 @@ struct MissingFeatures { static bool opLoadEmitScalarRangeCheck() { return false; } static bool opLoadBooleanRepresentation() { return false; } static bool opLoadStoreTbaa() { return false; } - static bool opLoadStoreMemOrder() { return false; } static bool opLoadStoreVolatile() { return false; } static bool opLoadStoreAtomic() { return false; } static bool opLoadStoreObjC() { return false; } @@ -87,7 +83,6 @@ struct MissingFeatures { static bool setFunctionAttributes() { return false; } // CallOp handling - static bool opCallPseudoDtor() { return false; } static bool opCallAggregateArgs() { return false; } static bool opCallPaddingArgs() { return false; } static bool opCallABIExtendArg() { return false; } @@ -98,8 +93,8 @@ struct MissingFeatures { static bool opCallReturn() { return false; } static bool opCallArgEvaluationOrder() { return false; } static bool opCallCallConv() { return false; } + static bool opCallSideEffect() { return false; } static bool opCallMustTail() { return false; } - static bool opCallVirtual() { return false; } static bool opCallInAlloca() { return false; } static bool opCallAttrs() { return false; } static bool opCallSurroundingTry() { return false; } @@ -162,6 +157,15 @@ struct MissingFeatures { static bool addressIsKnownNonNull() { return false; } static bool addressPointerAuthInfo() { return false; } + // Atomic + static bool atomicExpr() { return false; } + static bool atomicInfo() { return false; } + static bool atomicInfoGetAtomicPointer() { return false; } + static bool atomicInfoGetAtomicAddress() { return false; } + static bool atomicUseLibCall() { return false; } + static bool atomicScope() { return false; } + static bool atomicSyncScopeID() { return false; } + // Misc static bool abiArgInfo() { return false; } static bool addHeapAllocSiteMetadata() { return false; } @@ -173,7 +177,12 @@ struct MissingFeatures { static bool aggValueSlotVolatile() { return false; } static bool alignCXXRecordDecl() { return false; } static bool armComputeVolatileBitfields() { return false; } + static bool asmGoto() { return false; } + static bool asmInputOperands() { return false; } static bool asmLabelAttr() { return false; } + static bool asmMemoryEffects() { return false; } + static bool asmOutputOperands() { return false; } + static bool asmUnwindClobber() { return false; } static bool assignMemcpyizer() { return false; } static bool astVarDeclInterface() { return false; } static bool attributeBuiltin() { return false; } @@ -187,18 +196,26 @@ struct MissingFeatures { static bool cirgenABIInfo() { return false; } static bool cleanupAfterErrorDiags() { return false; } static bool cleanupsToDeactivate() { return false; } + static bool constEmitterAggILE() { return false; } static bool constEmitterArrayILE() { return false; } static bool constEmitterVectorILE() { return false; } static bool constantFoldSwitchStatement() { return false; } static bool constructABIArgDirectExtend() { return false; } static bool coverageMapping() { return false; } + static bool createInvariantGroup() { return false; } static bool createProfileWeightsForLoop() { return false; } static bool ctorMemcpyizer() { return false; } static bool cudaSupport() { return false; } static bool cxxRecordStaticMembers() { return false; } + static bool dataLayoutTypeIsSized() { return false; } static bool dataLayoutTypeAllocSize() { return false; } + static bool dataLayoutTypeStoreSize() { return false; } static bool deferredCXXGlobalInit() { return false; } + static bool devirtualizeMemberFunction() { return false; } static bool ehCleanupFlags() { return false; } + static bool ehCleanupScope() { return false; } + static bool ehCleanupScopeRequiresEHCleanup() { return false; } + static bool ehCleanupBranchFixups() { return false; } static bool ehstackBranches() { return false; } static bool emitCheckedInBoundsGEP() { return false; } static bool emitCondLikelihoodViaExpectIntrinsic() { return false; } @@ -206,12 +223,16 @@ struct MissingFeatures { static bool emitLValueAlignmentAssumption() { return false; } static bool emitNullabilityCheck() { return false; } static bool emitTypeCheck() { return false; } + static bool emitTypeMetadataCodeForVCall() { return false; } static bool fastMathFlags() { return false; } static bool fpConstraints() { return false; } static bool generateDebugInfo() { return false; } + static bool globalViewIndices() { return false; } + static bool globalViewIntLowering() { return false; } static bool hip() { return false; } static bool implicitConstructorArgs() { return false; } static bool incrementProfileCounter() { return false; } + static bool innermostEHScope() { return false; } static bool insertBuiltinUnpredictable() { return false; } static bool instrumentation() { return false; } static bool intrinsics() { return false; } @@ -231,8 +252,8 @@ struct MissingFeatures { static bool objCBlocks() { return false; } static bool objCGC() { return false; } static bool objCLifetime() { return false; } + static bool openCL() { return false; } static bool openMP() { return false; } - static bool opGlobalViewAttr() { return false; } static bool opTBAA() { return false; } static bool peepholeProtection() { return false; } static bool pgoUse() { return false; } @@ -245,6 +266,7 @@ struct MissingFeatures { static bool setNonGC() { return false; } static bool setObjCGCLValueClass() { return false; } static bool setTargetAttributes() { return false; } + static bool sourceLanguageCases() { return false; } static bool stackBase() { return false; } static bool stackSaveOp() { return false; } static bool targetCIRGenInfoArch() { return false; } @@ -258,7 +280,10 @@ struct MissingFeatures { static bool appleKext() { return false; } static bool dtorCleanups() { return false; } static bool vtableInitialization() { return false; } + static bool vtableEmitMetadata() { return false; } + static bool vtableRelativeLayout() { return false; } static bool msvcBuiltins() { return false; } + static bool vaArgABILowering() { return false; } static bool vlas() { return false; } // Missing types diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index 50be517..713b52a 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -77,6 +77,11 @@ public: /// Array elements in the type are assumed to be padding and skipped. CoerceAndExpand, + /// TargetSpecific - Some argument types are passed as target specific types + /// such as RISC-V's tuple type, these need to be handled in the target + /// hook. + TargetSpecific, + /// InAlloca - Pass the argument directly using the LLVM inalloca attribute. /// This is similar to indirect with byval, except it only applies to /// arguments stored in memory and forbids any implicit copies. When @@ -120,7 +125,7 @@ private: bool canHavePaddingType() const { return isDirect() || isExtend() || isIndirect() || isIndirectAliased() || - isExpand(); + isExpand() || isTargetSpecific(); } void setPaddingType(llvm::Type *T) { assert(canHavePaddingType()); @@ -291,6 +296,20 @@ public: return AI; } + static ABIArgInfo getTargetSpecific(llvm::Type *T = nullptr, + unsigned Offset = 0, + llvm::Type *Padding = nullptr, + bool CanBeFlattened = true, + unsigned Align = 0) { + auto AI = ABIArgInfo(TargetSpecific); + AI.setCoerceToType(T); + AI.setPaddingType(Padding); + AI.setDirectOffset(Offset); + AI.setDirectAlign(Align); + AI.setCanBeFlattened(CanBeFlattened); + return AI; + } + static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) { return eltType->isArrayTy() && eltType->getArrayElementType()->isIntegerTy(8); @@ -305,27 +324,33 @@ public: bool isIndirectAliased() const { return TheKind == IndirectAliased; } bool isExpand() const { return TheKind == Expand; } bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; } + bool isTargetSpecific() const { return TheKind == TargetSpecific; } bool canHaveCoerceToType() const { - return isDirect() || isExtend() || isCoerceAndExpand(); + return isDirect() || isExtend() || isCoerceAndExpand() || + isTargetSpecific(); } // Direct/Extend accessors unsigned getDirectOffset() const { - assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + assert((isDirect() || isExtend() || isTargetSpecific()) && + "Not a direct or extend or target specific kind"); return DirectAttr.Offset; } void setDirectOffset(unsigned Offset) { - assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + assert((isDirect() || isExtend() || isTargetSpecific()) && + "Not a direct or extend or target specific kind"); DirectAttr.Offset = Offset; } unsigned getDirectAlign() const { - assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + assert((isDirect() || isExtend() || isTargetSpecific()) && + "Not a direct or extend or target specific kind"); return DirectAttr.Align; } void setDirectAlign(unsigned Align) { - assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + assert((isDirect() || isExtend() || isTargetSpecific()) && + "Not a direct or extend or target specific kind"); DirectAttr.Align = Align; } @@ -394,12 +419,14 @@ public: } bool getInReg() const { - assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); + assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) && + "Invalid kind!"); return InReg; } void setInReg(bool IR) { - assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); + assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) && + "Invalid kind!"); InReg = IR; } @@ -481,12 +508,12 @@ public: } bool getCanBeFlattened() const { - assert(isDirect() && "Invalid kind!"); + assert((isDirect() || isTargetSpecific()) && "Invalid kind!"); return CanBeFlattened; } void setCanBeFlattened(bool Flatten) { - assert(isDirect() && "Invalid kind!"); + assert((isDirect() || isTargetSpecific()) && "Invalid kind!"); CanBeFlattened = Flatten; } diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h index 836fdd7..16f39b991 100644 --- a/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -32,6 +32,7 @@ namespace llvm { class AttrBuilder; class Constant; +class ConstantInt; class Function; class FunctionType; class Type; @@ -126,6 +127,12 @@ uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD); uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM, QualType FunctionType); +/// Return a signed constant pointer. +llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM, + llvm::Constant *Pointer, unsigned Key, + llvm::Constant *StorageAddress, + llvm::ConstantInt *OtherDiscriminator); + /// Given the language and code-generation options that Clang was configured /// with, set the default LLVM IR attributes for a function definition. /// The attributes set here are mostly global target-configuration and diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index 7aecfd8..dbf1187 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -76,9 +76,10 @@ public: StaticLibJobClass, BinaryAnalyzeJobClass, BinaryTranslatorJobClass, + ObjcopyJobClass, JobClassFirst = PreprocessJobClass, - JobClassLast = BinaryTranslatorJobClass + JobClassLast = ObjcopyJobClass }; // The offloading kind determines if this action is binded to a particular @@ -687,6 +688,17 @@ public: } }; +class ObjcopyJobAction : public JobAction { + void anchor() override; + +public: + ObjcopyJobAction(Action *Input, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == ObjcopyJobClass; + } +}; + } // namespace driver } // namespace clang diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 9802962d..1464ce4 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -85,6 +85,8 @@ const char *RelocationModelName(llvm::Reloc::Model Model); std::tuple<llvm::Reloc::Model, unsigned, bool> ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); +bool getStaticPIE(const llvm::opt::ArgList &Args, const ToolChain &TC); + unsigned ParseFunctionAlignment(const ToolChain &TC, const llvm::opt::ArgList &Args); diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 4d32552..b9b187a 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -512,6 +512,9 @@ public: /// BuildActions - Construct the list of actions to perform for the /// given arguments, which are only done for a single architecture. + /// If the compilation is an explicit module build, delegates to + /// BuildDriverManagedModuleBuildActions. Otherwise, BuildDefaultActions is + /// used. /// /// \param C - The compilation that is being built. /// \param Args - The input arguments. @@ -796,6 +799,35 @@ private: /// compilation based on which -f(no-)?lto(=.*)? option occurs last. void setLTOMode(const llvm::opt::ArgList &Args); + /// BuildDefaultActions - Constructs the list of actions to perform + /// for the provided arguments, which are only done for a single architecture. + /// + /// \param C - The compilation that is being built. + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildDefaultActions(Compilation &C, llvm::opt::DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions) const; + + /// BuildDriverManagedModuleBuildActions - Performs a dependency + /// scan and constructs the list of actions to perform for dependency order + /// and the provided arguments. This is only done for a single a architecture. + /// + /// \param C - The compilation that is being built. + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildDriverManagedModuleBuildActions(Compilation &C, + llvm::opt::DerivedArgList &Args, + const InputList &Inputs, + ActionList &Actions) const; + + /// Scans the leading lines of the C++ source inputs to detect C++20 module + /// usage. + /// + /// \returns True if module usage is detected, false otherwise, or an error on + /// read failure. + llvm::ErrorOr<bool> + ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const; + /// Retrieves a ToolChain for a particular \p Target triple. /// /// Will cache ToolChains for the life of the driver object, and create them diff --git a/clang/include/clang/Driver/OffloadBundler.h b/clang/include/clang/Driver/OffloadBundler.h index 667156a..e7306ce 100644 --- a/clang/include/clang/Driver/OffloadBundler.h +++ b/clang/include/clang/Driver/OffloadBundler.h @@ -120,7 +120,7 @@ public: static llvm::Expected<CompressedBundleHeader> tryParse(llvm::StringRef); }; - static inline const uint16_t DefaultVersion = 2; + static inline const uint16_t DefaultVersion = 3; static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 6aab43c..f507968d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1851,7 +1851,7 @@ defm pseudo_probe_for_profiling CodeGenOpts<"PseudoProbeForProfiling">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption], "Emit">, NegFlag<SetFalse, [], [ClangOption], "Do not emit">, - BothFlags<[], [ClangOption, CC1Option], + BothFlags<[], [ClangOption, CC1Option, CLOption], " pseudo probes for sample profiling">>; def fprofile_list_EQ : Joined<["-"], "fprofile-list=">, Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, @@ -2612,16 +2612,27 @@ def fsanitize_undefined_trap_on_error def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group<f_clang_Group>, Alias<fno_sanitize_trap_EQ>, AliasArgs<["undefined"]>; -defm sanitize_debug_trap_reasons - : BoolFOption< - "sanitize-debug-trap-reasons", - CodeGenOpts<"SanitizeDebugTrapReasons">, DefaultTrue, - PosFlag<SetTrue, [], [ClangOption, CC1Option], - "Annotate trap blocks in debug info with UBSan trap reasons">, - NegFlag<SetFalse, [], [ClangOption, CC1Option], - "Do not annotate trap blocks in debug info with UBSan trap " - "reasons">>; - +def fsanitize_debug_trap_reasons_EQ + : Joined<["-"], "fsanitize-debug-trap-reasons=">, Group<f_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Set how trap reasons are emitted. " + "`none` - Not emitted. This gives the smallest debug info; " + "`basic` - Emit a fixed trap message per check type. This increases the " + "debug info size but not as much as `detailed`; " + "`detailed` - Emit a more detailed trap message. This increases the " + "debug info size the most. Default is `detailed`.">, + Values<"none,basic,detailed">, + NormalizedValuesScope<"CodeGenOptions::SanitizeDebugTrapReasonKind">, + NormalizedValues<["None", "Basic", "Detailed"]>, + MarshallingInfoEnum<CodeGenOpts<"SanitizeDebugTrapReasons">, "Detailed">; +def fsanitize_debug_trap_reasons + : Flag<["-"], "fsanitize-debug-trap-reasons">, Group<f_clang_Group>, + Alias<fsanitize_debug_trap_reasons_EQ>, AliasArgs<["detailed"]>, + HelpText<"Alias for -fsanitize-debug-trap-reasons=detailed">; +def fno_sanitize_debug_trap_reasons + : Flag<["-"], "fno-sanitize-debug-trap-reasons">, Group<f_clang_Group>, + Alias<fsanitize_debug_trap_reasons_EQ>, AliasArgs<["none"]>, + HelpText<"Alias for -fsanitize-debug-trap-reasons=none">; defm sanitize_minimal_runtime : BoolOption<"f", "sanitize-minimal-runtime", CodeGenOpts<"SanitizeMinimalRuntime">, DefaultFalse, PosFlag<SetTrue>, @@ -3296,6 +3307,13 @@ defm modules_reduced_bmi : BoolOption<"f", "modules-reduced-bmi", PosFlag<SetTrue, [], [ClangOption, CC1Option], "Generate the reduced BMI">>; +def fmodules_driver : Flag<["-"], "fmodules-driver">, + Group<f_Group>, Visibility<[ClangOption]>, + HelpText<"Enable support for driver managed module builds (experimental)">; +def fno_modules_driver : Flag<["-"], "fno-modules-driver">, + Group<f_Group>, Visibility<[ClangOption]>, + HelpText<"Disable support for driver managed module builds (experimental)">; + def experimental_modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>, Alias<fmodules_reduced_bmi>; @@ -3731,14 +3749,20 @@ def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">, def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">, Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>; -def fopenmp_simd : Flag<["-"], "fopenmp-simd">, Group<f_Group>, - Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Emit OpenMP code only for SIMD-based constructs.">; +def fopenmp_simd : Flag<["-"], "fopenmp-simd">, + Group<f_Group>, + Flags<[NoArgumentUnused]>, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, + HelpText<"Emit OpenMP code only for SIMD-based constructs.">; def fopenmp_enable_irbuilder : Flag<["-"], "fopenmp-enable-irbuilder">, Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>, HelpText<"Use the experimental OpenMP-IR-Builder codegen path.">; -def fno_openmp_simd : Flag<["-"], "fno-openmp-simd">, Group<f_Group>, - Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>; +def fno_openmp_simd + : Flag<["-"], "fno-openmp-simd">, + Group<f_Group>, + Flags<[NoArgumentUnused]>, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, + HelpText<"Do not emit code for any OpenMP constructs.">; def fopenmp_cuda_mode : Flag<["-"], "fopenmp-cuda-mode">, Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>; def fno_openmp_cuda_mode : Flag<["-"], "fno-openmp-cuda-mode">, Group<f_Group>, @@ -4540,6 +4564,7 @@ defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", defm ptrauth_objc_isa : OptInCC1FFlag<"ptrauth-objc-isa", "Enable signing and authentication of Objective-C object's 'isa' field">; defm ptrauth_objc_interface_sel : OptInCC1FFlag<"ptrauth-objc-interface-sel", "Enable signing and authentication of Objective-C object's 'SEL' fields">; defm ptrauth_objc_class_ro : OptInCC1FFlag<"ptrauth-objc-class-ro", "Enable signing and authentication for ObjC class_ro pointers">; +defm ptrauth_block_descriptor_pointers : OptInCC1FFlag<"ptrauth-block-descriptor-pointers", "Enable signing and authentication of block descriptors">; } def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>, @@ -5589,7 +5614,8 @@ def mno_outline_atomics : Flag<["-"], "mno-outline-atomics">, Group<f_clang_Grou HelpText<"Don't generate local calls to out-of-line atomic operations">; def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>, HelpText<"Don't generate implicit floating point or vector instructions">; -def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>; +def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>, + HelpText<"Generate implicit floating point or vector instructions">; def mrecip : Flag<["-"], "mrecip">, Group<m_Group>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Equivalent to '-mrecip=all'">; @@ -6805,10 +6831,10 @@ def mapx_features_EQ : CommaJoined<["-"], "mapx-features=">, Group<m_x86_Feature def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group<m_x86_Features_Group>, HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu">, Visibility<[ClangOption, CLOption, FlangOption]>; def mapxf : Flag<["-"], "mapxf">, Alias<mapx_features_EQ>, - AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","cf","zu"]>, + AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","zu"]>, Group<m_x86_Features_Group>; def mno_apxf : Flag<["-"], "mno-apxf">, Alias<mno_apx_features_EQ>, - AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","cf","zu"]>, + AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","zu"]>, Group<m_x86_Features_Group>; def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group<m_Group>, HelpText<"Enable use of GPR32 in inline assembly for APX">; @@ -6979,7 +7005,6 @@ def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group // "f" options with values for gfortran. def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>; def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>; -def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>; def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>; def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>; def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>; @@ -8688,6 +8713,15 @@ def fopenmp_host_ir_file_path : Separate<["-"], "fopenmp-host-ir-file-path">, } // let Visibility = [CC1Option, FC1Option] //===----------------------------------------------------------------------===// +// Coarray Options +//===----------------------------------------------------------------------===// + +def fcoarray : Flag<["-"], "fcoarray">, + Group<f_Group>, + Visibility<[FlangOption, FC1Option]>, + HelpText<"Enable Coarray features">; + +//===----------------------------------------------------------------------===// // SYCL Options //===----------------------------------------------------------------------===// @@ -9381,6 +9415,11 @@ def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>, Visibility<[DXCOption, ClangOption, CC1Option]>, HelpText<"Assume that UAVs/SRVs may alias">, MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>; +def dxc_strip_rootsignature : + Option<["/", "-"], "Qstrip-rootsignature", KIND_FLAG>, + Group<dxc_Group>, + Visibility<[DXCOption]>, + HelpText<"Omit the root signature from produced DXContainer">; def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">, HelpText<"Set target profile">, Values<"ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7," @@ -9413,6 +9452,18 @@ def dxc_rootsig_ver : Alias<fdx_rootsignature_version>, Group<dxc_Group>, Visibility<[DXCOption]>; +def fdx_rootsignature_define : + Joined<["-"], "fdx-rootsignature-define=">, + Group<dxc_Group>, + Visibility<[ClangOption, CC1Option]>, + MarshallingInfoString<LangOpts<"HLSLRootSigOverride">, "\"\"">, + HelpText<"Override entry function root signature with root signature at " + "given macro name.">; +def dxc_rootsig_define : + Separate<["-"], "rootsig-define">, + Alias<fdx_rootsignature_define>, + Group<dxc_Group>, + Visibility<[DXCOption]>; def hlsl_entrypoint : Option<["-"], "hlsl-entry", KIND_SEPARATE>, Group<dxc_Group>, Visibility<[ClangOption, CC1Option]>, @@ -9445,8 +9496,12 @@ def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<dxc_Group>, def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<dxc_Group>, - HelpText<"Specify the available SPIR-V extensions. If this option is not " - "specified, then all extensions are available.">; + HelpText< + "Specify the available SPIR-V extensions. If this option is not " + "specified, then all extensions are available. If KHR is specified, " + "then all KHR extensions will be available. If DXC is specifided, " + "then all extensions implemented by the DirectX Shader compiler will " + "be available. This option is useful for moving from DXC to Clang.">; def fvk_use_dx_layout : DXCFlag<"fvk-use-dx-layout">, HelpText<"Use DirectX memory layout for Vulkan resources.">; @@ -9457,6 +9512,16 @@ def fvk_use_scalar_layout : DXCFlag<"fvk-use-scalar-layout">, HelpText<"Use scalar memory layout for Vulkan resources.">; +def fhlsl_spv_use_unknown_image_format + : Flag<["-"], "fspv-use-unknown-image-format">, + Group<dxc_Group>, + Visibility<[CC1Option, DXCOption]>, + HelpText<"For storage images and texel buffers, sets the default format " + "to 'Unknown' when not specified via the `vk::image_format` " + "attribute. If this option is not used, the format is inferred " + "from the resource's data type.">, + MarshallingInfoFlag<LangOpts<"HLSLSpvUseUnknownImageFormat">>; + def no_wasm_opt : Flag<["--"], "no-wasm-opt">, Group<m_Group>, HelpText<"Disable the wasm-opt optimizer">, diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 2430563..1425714 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -224,9 +224,6 @@ protected: static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path); - static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const Twine &Path); static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path); @@ -246,6 +243,9 @@ protected: ///@} public: + static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); virtual ~ToolChain(); // Accessors diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index 4ac7444..4859225 100644 --- a/clang/include/clang/ExtractAPI/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -440,9 +440,8 @@ private: DeclarationFragments &); /// Build DeclarationFragments for a NestedNameSpecifier. - static DeclarationFragments getFragmentsForNNS(const NestedNameSpecifier *, - ASTContext &, - DeclarationFragments &); + static DeclarationFragments + getFragmentsForNNS(NestedNameSpecifier, ASTContext &, DeclarationFragments &); /// Build DeclarationFragments for Qualifiers. static DeclarationFragments getFragmentsForQualifiers(const Qualifiers quals); diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 31582a4..5dfdb23 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4813,14 +4813,45 @@ struct FormatStyle { /// \version 7 bool SpaceBeforeRangeBasedForLoopColon; - /// If ``true``, spaces will be inserted into ``{}``. - /// \code - /// true: false: - /// void f() { } vs. void f() {} - /// while (true) { } while (true) {} - /// \endcode + /// This option is **deprecated**. See ``Block`` of ``SpaceInEmptyBraces``. /// \version 10 - bool SpaceInEmptyBlock; + // bool SpaceInEmptyBlock; + + /// Style of when to insert a space in empty braces. + enum SpaceInEmptyBracesStyle : int8_t { + /// Always insert a space in empty braces. + /// \code + /// void f() { } + /// class Unit { }; + /// auto a = [] { }; + /// int x{ }; + /// \endcode + SIEB_Always, + /// Only insert a space in empty blocks. + /// \code + /// void f() { } + /// class Unit { }; + /// auto a = [] { }; + /// int x{}; + /// \endcode + SIEB_Block, + /// Never insert a space in empty braces. + /// \code + /// void f() {} + /// class Unit {}; + /// auto a = [] {}; + /// int x{}; + /// \endcode + SIEB_Never + }; + + /// Specifies when to insert a space in empty braces. + /// \note + /// This option doesn't apply to initializer braces if + /// ``Cpp11BracedListStyle`` is set to ``true``. + /// \endnote + /// \version 22 + SpaceInEmptyBracesStyle SpaceInEmptyBraces; /// If ``true``, spaces may be inserted into ``()``. /// This option is **deprecated**. See ``InEmptyParentheses`` of @@ -5494,7 +5525,7 @@ struct FormatStyle { SpaceBeforeRangeBasedForLoopColon == R.SpaceBeforeRangeBasedForLoopColon && SpaceBeforeSquareBrackets == R.SpaceBeforeSquareBrackets && - SpaceInEmptyBlock == R.SpaceInEmptyBlock && + SpaceInEmptyBraces == R.SpaceInEmptyBraces && SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && SpacesInAngles == R.SpacesInAngles && SpacesInContainerLiterals == R.SpacesInContainerLiterals && diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index a5dfb77..73308c0 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -329,6 +329,18 @@ public: : ModuleName(ModuleName) {} }; +//===----------------------------------------------------------------------===// +// HLSL Specific Actions +//===----------------------------------------------------------------------===// + +class HLSLFrontendAction : public WrapperFrontendAction { +protected: + void ExecuteAction() override; + +public: + HLSLFrontendAction(std::unique_ptr<FrontendAction> WrappedAction); +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Index/IndexSymbol.h b/clang/include/clang/Index/IndexSymbol.h index 59e90fc..deb9337 100644 --- a/clang/include/clang/Index/IndexSymbol.h +++ b/clang/include/clang/Index/IndexSymbol.h @@ -27,6 +27,7 @@ enum class SymbolKind : uint8_t { Namespace, NamespaceAlias, Macro, + IncludeDirective, Enum, Struct, diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 83d2962..8c124aa 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -37,7 +37,6 @@ class ThreadSafeContext; namespace clang { class CompilerInstance; -class CodeGenerator; class CXXRecordDecl; class Decl; class IncrementalExecutor; @@ -110,10 +109,6 @@ class Interpreter { // printing happens, it's in an invalid state. Value LastValue; - /// When CodeGen is created the first llvm::Module gets cached in many places - /// and we must keep it alive. - std::unique_ptr<llvm::Module> CachedInCodeGenModule; - /// Compiler instance performing the incremental compilation. std::unique_ptr<CompilerInstance> CI; @@ -175,15 +170,9 @@ public: llvm::Expected<llvm::orc::ExecutorAddr> getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; - std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr); - PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU, - std::unique_ptr<llvm::Module> M = {}, - IncrementalAction *Action = nullptr); - private: size_t getEffectivePTUSize() const; void markUserCodeStart(); - llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E); // A cache for the compiled destructors used to for de-allocation of managed // clang::Values. @@ -206,11 +195,6 @@ private: // This function forces emission of the needed dtor. llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD) const; - - /// @} - /// @name Code generation - /// @{ - CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const; }; } // namespace clang diff --git a/clang/include/clang/Lex/DependencyDirectivesScanner.h b/clang/include/clang/Lex/DependencyDirectivesScanner.h index f9fec39..c0b742d 100644 --- a/clang/include/clang/Lex/DependencyDirectivesScanner.h +++ b/clang/include/clang/Lex/DependencyDirectivesScanner.h @@ -135,6 +135,13 @@ void printDependencyDirectivesAsSource( ArrayRef<dependency_directives_scan::Directive> Directives, llvm::raw_ostream &OS); +/// Scan an input source buffer for C++20 named module usage. +/// +/// \param Source The input source buffer. +/// +/// \returns true if any C++20 named modules related directive was found. +bool scanInputForCXX20ModulesUsage(StringRef Source); + /// Functor that returns the dependency directives for a given file. class DependencyDirectivesGetter { public: diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index 06971ff..423f2ff 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -143,9 +143,6 @@ class Lexer : public PreprocessorLexer { /// True if this is the first time we're lexing the input file. bool IsFirstTimeLexingFile; - /// True if current lexing token is the first pp-token. - bool IsFirstPPToken; - // NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n', // it also points to '\n.' const char *NewLinePtr; diff --git a/clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h b/clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h new file mode 100644 index 0000000..9ab3c6a --- /dev/null +++ b/clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h @@ -0,0 +1,310 @@ +//===--- NoTrivialPPDirectiveTracer.h ---------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the NoTrivialPPDirectiveTracer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H +#define LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H + +#include "clang/Lex/PPCallbacks.h" + +namespace clang { +class Preprocessor; + +/// Consider the following code: +/// +/// # 1 __FILE__ 1 3 +/// export module a; +/// +/// According to the wording in +/// [P1857R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1857r3.html): +/// +/// A module directive may only appear as the first preprocessing tokens in a +/// file (excluding the global module fragment.) +/// +/// and the wording in +/// [[cpp.pre]](https://eel.is/c++draft/cpp.pre#nt:module-file): +/// module-file: +/// pp-global-module-fragment[opt] pp-module group[opt] +/// pp-private-module-fragment[opt] +/// +/// `#` is the first pp-token in the translation unit, and it was rejected by +/// clang, but they really should be exempted from this rule. The goal is to not +/// allow any preprocessor conditionals or most state changes, but these don't +/// fit that. +/// +/// State change would mean most semantically observable preprocessor state, +/// particularly anything that is order dependent. Global flags like being a +/// system header/module shouldn't matter. +/// +/// We should exempt a brunch of directives, even though it violates the current +/// standard wording. +/// +/// This class used to trace 'no-trivial' pp-directives in main file, which may +/// change the preprocessing state. +/// +/// FIXME: Once the wording of the standard is revised, we need to follow the +/// wording of the standard. Currently this is just a workaround +class NoTrivialPPDirectiveTracer : public PPCallbacks { + Preprocessor &PP; + + /// Whether preprocessing main file. We only focus on the main file. + bool InMainFile = true; + + /// Whether one or more conditional, include or other 'no-trivial' + /// pp-directives has seen before. + bool SeenNoTrivialPPDirective = false; + + void setSeenNoTrivialPPDirective(); + +public: + NoTrivialPPDirectiveTracer(Preprocessor &P) : PP(P) {} + + bool hasSeenNoTrivialPPDirective() const; + + /// Callback invoked whenever the \p Lexer moves to a different file for + /// lexing. Unlike \p FileChanged line number directives and other related + /// pragmas do not trigger callbacks to \p LexedFileChanged. + /// + /// \param FID The \p FileID that the \p Lexer moved to. + /// + /// \param Reason Whether the \p Lexer entered a new file or exited one. + /// + /// \param FileType The \p CharacteristicKind of the file the \p Lexer moved + /// to. + /// + /// \param PrevFID The \p FileID the \p Lexer was using before the change. + /// + /// \param Loc The location where the \p Lexer entered a new file from or the + /// location that the \p Lexer moved into after exiting a file. + void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, FileID PrevFID, + SourceLocation Loc) override; + + /// Callback invoked whenever an embed directive has been processed, + /// regardless of whether the embed will actually find a file. + /// + /// \param HashLoc The location of the '#' that starts the embed directive. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param File The actual file that may be included by this embed directive. + /// + /// \param Params The parameters used by the directive. + void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled, + OptionalFileEntryRef File, + const LexEmbedParametersResult &Params) override { + setSeenNoTrivialPPDirective(); + } + + /// Callback invoked whenever an inclusion directive of + /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless + /// of whether the inclusion will actually result in an inclusion. + /// + /// \param HashLoc The location of the '#' that starts the inclusion + /// directive. + /// + /// \param IncludeTok The token that indicates the kind of inclusion + /// directive, e.g., 'include' or 'import'. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param FilenameRange The character range of the quotes or angle brackets + /// for the written file name. + /// + /// \param File The actual file that may be included by this inclusion + /// directive. + /// + /// \param SearchPath Contains the search path which was used to find the file + /// in the file system. If the file was found via an absolute include path, + /// SearchPath will be empty. For framework includes, the SearchPath and + /// RelativePath will be split up. For example, if an include of "Some/Some.h" + /// is found via the framework path + /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be + /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be + /// "Some.h". + /// + /// \param RelativePath The path relative to SearchPath, at which the include + /// file was found. This is equal to FileName except for framework includes. + /// + /// \param SuggestedModule The module suggested for this header, if any. + /// + /// \param ModuleImported Whether this include was translated into import of + /// \p SuggestedModule. + /// + /// \param FileType The characteristic kind, indicates whether a file or + /// directory holds normal user code, system code, or system code which is + /// implicitly 'extern "C"' in C++ mode. + /// + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, + OptionalFileEntryRef File, StringRef SearchPath, + StringRef RelativePath, const Module *SuggestedModule, + bool ModuleImported, + SrcMgr::CharacteristicKind FileType) override { + setSeenNoTrivialPPDirective(); + } + + /// Callback invoked whenever there was an explicit module-import + /// syntax. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Imported The imported module; can be null if importing failed. + /// + void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, + const Module *Imported) override { + setSeenNoTrivialPPDirective(); + } + + /// Callback invoked when the end of the main file is reached. + /// + /// No subsequent callbacks will be made. + void EndOfMainFile() override { setSeenNoTrivialPPDirective(); } + + /// Callback invoked when start reading any pragma directive. + void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) override {} + + /// Called by Preprocessor::HandleMacroExpandedIdentifier when a + /// macro invocation is found. + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override; + + /// Hook called whenever a macro definition is seen. + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever a macro \#undef is seen. + /// \param MacroNameTok The active Token + /// \param MD A MacroDefinition for the named macro. + /// \param Undef New MacroDirective if the macro was defined, null otherwise. + /// + /// MD is released immediately following this callback. + void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, + const MacroDirective *Undef) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever the 'defined' operator is seen. + /// \param MD The MacroDirective if the name was a macro, null otherwise. + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#if is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param ConditionValue The evaluated value of the condition. + /// + // FIXME: better to pass in a list (or tree!) of Tokens. + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#elif is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param ConditionValue The evaluated value of the condition. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#ifdef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#elifdef branch is taken. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + void Elifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + setSeenNoTrivialPPDirective(); + } + /// Hook called whenever an \#elifdef is skipped. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + void Elifdef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#ifndef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefiniton if the name was a macro, null otherwise. + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#elifndef branch is taken. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDefinition if the name was a macro, null otherwise. + void Elifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + setSeenNoTrivialPPDirective(); + } + /// Hook called whenever an \#elifndef is skipped. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + void Elifndef(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#else is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + void Else(SourceLocation Loc, SourceLocation IfLoc) override { + setSeenNoTrivialPPDirective(); + } + + /// Hook called whenever an \#endif is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + void Endif(SourceLocation Loc, SourceLocation IfLoc) override { + setSeenNoTrivialPPDirective(); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 71b0f8e..3975484 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -82,6 +82,7 @@ class PreprocessorLexer; class PreprocessorOptions; class ScratchBuffer; class TargetInfo; +class NoTrivialPPDirectiveTracer; namespace Builtin { class Context; @@ -353,6 +354,11 @@ private: /// First pp-token source location in current translation unit. SourceLocation FirstPPTokenLoc; + /// A preprocessor directive tracer to trace whether the preprocessing + /// state changed. These changes would mean most semantically observable + /// preprocessor state, particularly anything that is order dependent. + NoTrivialPPDirectiveTracer *DirTracer = nullptr; + /// A position within a C++20 import-seq. class StdCXXImportSeq { public: @@ -609,6 +615,8 @@ private: return State == NamedModuleImplementation && !getName().contains(':'); } + bool isNotAModuleDecl() const { return State == NotAModuleDecl; } + StringRef getName() const { assert(isNamedModule() && "Can't get name from a non named module"); return Name; @@ -3091,6 +3099,10 @@ public: bool setDeserializedSafeBufferOptOutMap( const SmallVectorImpl<SourceLocation> &SrcLocSeqs); + /// Whether we've seen pp-directives which may have changed the preprocessing + /// state. + bool hasSeenNoTrivialPPDirective() const; + private: /// Helper functions to forward lexing to the actual lexer. They all share the /// same signature. diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index fc43e72..d9dc5a5 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -86,12 +86,12 @@ public: // macro stringizing or charizing operator. CommaAfterElided = 0x200, // The comma following this token was elided (MS). IsEditorPlaceholder = 0x400, // This identifier is a placeholder. - - IsReinjected = 0x800, // A phase 4 token that was produced before and - // re-added, e.g. via EnterTokenStream. Annotation - // tokens are *not* reinjected. - FirstPPToken = 0x1000, // This token is the first pp token in the - // translation unit. + IsReinjected = 0x800, // A phase 4 token that was produced before and + // re-added, e.g. via EnterTokenStream. Annotation + // tokens are *not* reinjected. + HasSeenNoTrivialPPDirective = + 0x1000, // Whether we've seen any 'no-trivial' pp-directives before + // current position. }; tok::TokenKind getKind() const { return Kind; } @@ -321,8 +321,9 @@ public: /// lexer uses identifier tokens to represent placeholders. bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); } - /// Returns true if this token is the first pp-token. - bool isFirstPPToken() const { return getFlag(FirstPPToken); } + bool hasSeenNoTrivialPPDirective() const { + return getFlag(HasSeenNoTrivialPPDirective); + } }; /// Information about the conditional stack (\#if directives) diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index a49bdfd..c87e6637c 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -236,6 +236,10 @@ private: RootSignatureToken CurToken; }; +IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, + llvm::dxbc::RootSignatureVersion Version, + StringLiteral *Signature); + } // namespace hlsl } // namespace clang diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index 2dd2759..c26f4e3 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -162,7 +162,8 @@ SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T); /// Determine the type that this declaration will have if it is used /// as a type or in an expression. -QualType getDeclUsageType(ASTContext &C, const NamedDecl *ND); +QualType getDeclUsageType(ASTContext &C, NestedNameSpecifier Qualifier, + const NamedDecl *ND); /// Determine the priority to be given to a macro code completion result /// with the given name. @@ -867,7 +868,7 @@ public: /// If the result should have a nested-name-specifier, this is it. /// When \c QualifierIsInformative, the nested-name-specifier is /// informative rather than required. - NestedNameSpecifier *Qualifier = nullptr; + NestedNameSpecifier Qualifier = std::nullopt; /// If this Decl was unshadowed by using declaration, this can store a /// pointer to the UsingShadowDecl which was used in the unshadowing process. @@ -882,7 +883,7 @@ public: /// Build a result that refers to a declaration. CodeCompletionResult(const NamedDecl *Declaration, unsigned Priority, - NestedNameSpecifier *Qualifier = nullptr, + NestedNameSpecifier Qualifier = std::nullopt, bool QualifierIsInformative = false, bool Accessible = true, std::vector<FixItHint> FixIts = std::vector<FixItHint>()) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index e568081..c1a99a1 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -91,12 +91,11 @@ public: } /// Retrieve the representation of the nested-name-specifier. - NestedNameSpecifier *getScopeRep() const { + NestedNameSpecifier getScopeRep() const { return Builder.getRepresentation(); } - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'type::'. + /// Make a nested-name-specifier of the form 'type::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. @@ -106,21 +105,7 @@ public: /// \param TL The TypeLoc that describes the type preceding the '::'. /// /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'identifier::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Identifier The identifier. - /// - /// \param IdentifierLoc The location of the identifier. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); + void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); /// Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'namespace::'. @@ -154,8 +139,9 @@ public: /// name. /// /// \param ColonColonLoc The location of the trailing '::'. - void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, - SourceLocation SuperLoc, SourceLocation ColonColonLoc); + void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc); /// Make a new nested-name-specifier from incomplete source-location /// information. @@ -163,7 +149,7 @@ public: /// FIXME: This routine should be used very, very rarely, in cases where we /// need to synthesize a nested-name-specifier. Most code should instead use /// \c Adopt() with a proper \c NestedNameSpecifierLoc. - void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, SourceRange R); /// Adopt an existing nested-name-specifier (with source-range @@ -189,14 +175,14 @@ public: SourceLocation getLastQualifierNameLoc() const; /// No scope specifier. - bool isEmpty() const { return Range.isInvalid() && getScopeRep() == nullptr; } + bool isEmpty() const { return Range.isInvalid() && !getScopeRep(); } /// A scope specifier is present, but may be valid or invalid. bool isNotEmpty() const { return !isEmpty(); } /// An error occurred during parsing of the scope specifier. - bool isInvalid() const { return Range.isValid() && getScopeRep() == nullptr; } + bool isInvalid() const { return Range.isValid() && !getScopeRep(); } /// A scope specifier is present, and it refers to a real scope. - bool isValid() const { return getScopeRep() != nullptr; } + bool isValid() const { return bool(getScopeRep()); } /// Indicate that this nested-name-specifier is invalid. void SetInvalid(SourceRange R) { @@ -209,7 +195,7 @@ public: /// Deprecated. Some call sites intend isNotEmpty() while others intend /// isValid(). - bool isSet() const { return getScopeRep() != nullptr; } + bool isSet() const { return bool(getScopeRep()); } void clear() { Range = SourceRange(); diff --git a/clang/include/clang/Sema/HeuristicResolver.h b/clang/include/clang/Sema/HeuristicResolver.h index e193c0b..71588be 100644 --- a/clang/include/clang/Sema/HeuristicResolver.h +++ b/clang/include/clang/Sema/HeuristicResolver.h @@ -67,8 +67,7 @@ public: // Try to heuristically resolve a dependent nested name specifier // to the type it likely denotes. Note that *dependent* name specifiers always // denote types, not namespaces. - QualType - resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const; + QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS) const; // Perform an imprecise lookup of a dependent name in `RD`. // This function does not follow strict semantic rules and should be used diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index 3a8050f..4a3df78 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -48,8 +48,8 @@ namespace clang { /// /// \param Arg the template type argument or non-type template argument. /// \param Loc the location of the type. - ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc) - : Kind(Kind), Arg(Arg), Loc(Loc) { } + ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation NameLoc) + : Kind(Kind), Arg(Arg), NameLoc(NameLoc) {} /// Create a template template argument. /// @@ -60,11 +60,11 @@ namespace clang { /// argument refers. /// /// \param TemplateLoc the location of the template name. - ParsedTemplateArgument(const CXXScopeSpec &SS, - ParsedTemplateTy Template, - SourceLocation TemplateLoc) - : Kind(ParsedTemplateArgument::Template), - Arg(Template.getAsOpaquePtr()), SS(SS), Loc(TemplateLoc) {} + ParsedTemplateArgument(SourceLocation TemplateKwLoc, const CXXScopeSpec &SS, + ParsedTemplateTy Template, SourceLocation NameLoc) + : Kind(ParsedTemplateArgument::Template), + Arg(Template.getAsOpaquePtr()), SS(SS), TemplateKwLoc(TemplateKwLoc), + NameLoc(NameLoc) {} /// Determine whether the given template argument is invalid. bool isInvalid() const { return Arg == nullptr; } @@ -91,7 +91,10 @@ namespace clang { } /// Retrieve the location of the template argument. - SourceLocation getLocation() const { return Loc; } + SourceLocation getTemplateKwLoc() const { return TemplateKwLoc; } + + /// Retrieve the location of the template argument. + SourceLocation getNameLoc() const { return NameLoc; } /// Retrieve the nested-name-specifier that precedes the template /// name in a template template argument. @@ -128,8 +131,11 @@ namespace clang { /// argument. CXXScopeSpec SS; - /// the location of the template argument. - SourceLocation Loc; + /// the location of the template keyword. + SourceLocation TemplateKwLoc; + + /// the location of the template name. + SourceLocation NameLoc; /// The ellipsis location that can accompany a template template /// argument (turning it into a template template argument expansion). diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 94b247a..4f4d38c 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -933,7 +933,7 @@ public: /// to local variables that are usable as constant expressions and /// do not involve an odr-use (they may still need to be captured /// if the enclosing full-expression is instantiation dependent). - llvm::SmallSet<Expr *, 8> NonODRUsedCapturingExprs; + llvm::SmallPtrSet<Expr *, 8> NonODRUsedCapturingExprs; /// A map of explicit capture indices to their introducer source ranges. llvm::DenseMap<unsigned, SourceRange> ExplicitCaptureRanges; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5211373..c3fb57774 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -228,7 +228,9 @@ void threadSafetyCleanup(BeforeSet *Cache); // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. -typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>, +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *, + const TemplateSpecializationType *, + const SubstBuiltinTemplatePackType *>, SourceLocation> UnexpandedParameterPack; @@ -2659,9 +2661,9 @@ public: /// identifies the magic value. typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue; - /// Diagnoses the current set of gathered accesses. This typically - /// happens at full expression level. The set is cleared after emitting the - /// diagnostics. + /// Diagnoses the current set of gathered accesses. This happens at the end of + /// each expression evaluation context. Diagnostics are emitted only for + /// accesses gathered in the current evaluation context. void DiagnoseMisalignedMembers(); /// This function checks if the expression is in the sef of potentially @@ -3117,9 +3119,6 @@ private: bool operator==(const MisalignedMember &m) { return this->E == m.E; } }; - /// Small set of gathered accesses to potentially misaligned members - /// due to the packed attribute. - SmallVector<MisalignedMember, 4> MisalignedMembers; /// Adds an expression to the set of gathered misaligned members. void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, @@ -3225,7 +3224,7 @@ public: /// current instantiation (C++0x [temp.dep.type]p1). /// /// \param NNS a dependent nested name specifier. - CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier NNS); /// The parser has parsed a global nested-name-specifier '::'. /// @@ -3262,7 +3261,7 @@ public: /// (e.g., Base::), perform name lookup for that identifier as a /// nested-name-specifier within the given scope, and return the result of /// that name lookup. - NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier NNS); /// Keeps information about an identifier in a nested-name-spec. /// @@ -3581,8 +3580,8 @@ public: /// Returns the TypeDeclType for the given type declaration, /// as ASTContext::getTypeDeclType would, but /// performs the required semantic checks for name lookup of said entity. - QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, - TypeDecl *TD, SourceLocation NameLoc); + void checkTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, TypeDecl *TD, + SourceLocation NameLoc); /// If the identifier refers to a type name within this scope, /// return the declaration of that type. @@ -4179,8 +4178,15 @@ public: /// return statement in the scope of a variable has the same NRVO candidate, /// that candidate is an NRVO variable. void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); - Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); - Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); + + /// Performs semantic analysis at the end of a function body. + /// + /// \param RetainFunctionScopeInfo If \c true, the client is responsible for + /// releasing the associated \p FunctionScopeInfo. This is useful when + /// building e.g. LambdaExprs. + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, + bool IsInstantiation = false, + bool RetainFunctionScopeInfo = false); Decl *ActOnSkippedFunctionBody(Decl *Decl); void ActOnFinishInlineFunctionDef(FunctionDecl *D); @@ -5398,7 +5404,7 @@ public: /// 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. @@ -6765,6 +6771,10 @@ public: /// InLifetimeExtendingContext is true. SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps; + /// Small set of gathered accesses to potentially misaligned members + /// due to the packed attribute. + SmallVector<MisalignedMember, 4> MisalignedMembers; + /// \brief Describes whether we are in an expression constext which we have /// to handle differently. enum ExpressionKind { @@ -6873,23 +6883,23 @@ public: assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); return ExprEvalContexts.back(); - }; + } ExpressionEvaluationContextRecord ¤tEvaluationContext() { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); return ExprEvalContexts.back(); - }; + } ExpressionEvaluationContextRecord &parentEvaluationContext() { assert(ExprEvalContexts.size() >= 2 && "Must be in an expression evaluation context"); return ExprEvalContexts[ExprEvalContexts.size() - 2]; - }; + } const ExpressionEvaluationContextRecord &parentEvaluationContext() const { return const_cast<Sema *>(this)->parentEvaluationContext(); - }; + } bool isAttrContext() const { return ExprEvalContexts.back().ExprContext == @@ -7618,7 +7628,7 @@ public: /// "real" base class is checked as appropriate when checking the access of /// the member name. ExprResult PerformObjectMemberConversion(Expr *From, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); @@ -8055,8 +8065,8 @@ public: ExprResult &RHS); QualType CheckMultiplyDivideOperands( // C99 6.5.5 - ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, - bool IsDivide); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc); QualType CheckRemainderOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); @@ -8065,7 +8075,7 @@ public: BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr); QualType CheckSubtractionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, - QualType *CompLHSTy = nullptr); + BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr); QualType CheckShiftOperands( // C99 6.5.7 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign = false); @@ -9139,8 +9149,7 @@ public: /// Complete a lambda-expression having processed and attached the /// lambda body. - ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, - sema::LambdaScopeInfo *LSI); + ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc); /// Get the return type to use for a lambda's conversion function(s) to /// function pointer type, given the type of the call operator. @@ -9836,7 +9845,7 @@ public: SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, ModuleIdPath Partition, ModuleImportState &ImportState, - bool IntroducerIsFirstPPToken); + bool SeenNoTrivialPPDirective); /// The parser has processed a global-module-fragment declaration that begins /// the definition of the global module fragment of the current module unit. @@ -10210,7 +10219,7 @@ public: ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj, FunctionDecl *Fun); ExprResult PerformImplicitObjectArgumentInitialization( - Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, + Expr *From, NestedNameSpecifier Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -11618,13 +11627,16 @@ public: void NoteAllFoundTemplates(TemplateName Name); - QualType CheckTemplateIdType(TemplateName Template, + QualType CheckTemplateIdType(ElaboratedTypeKeyword Keyword, + TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs); TypeResult - ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - TemplateTy Template, const IdentifierInfo *TemplateII, + ActOnTemplateIdType(Scope *S, ElaboratedTypeKeyword ElaboratedKeyword, + SourceLocation ElaboratedKeywordLoc, CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, TemplateTy Template, + const IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false, bool IsClassName = false, @@ -11858,8 +11870,8 @@ public: /// argument, substitute into that default template argument and /// return the corresponding template argument. TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable( - TemplateDecl *Template, SourceLocation TemplateLoc, - SourceLocation RAngleLoc, Decl *Param, + TemplateDecl *Template, SourceLocation TemplateKWLoc, + SourceLocation TemplateNameLoc, SourceLocation RAngleLoc, Decl *Param, ArrayRef<TemplateArgument> SugaredConverted, ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg); @@ -13487,8 +13499,6 @@ public: ~ArgPackSubstIndexRAII() { Self.ArgPackSubstIndex = OldSubstIndex; } }; - friend class ArgumentPackSubstitutionRAII; - void pushCodeSynthesisContext(CodeSynthesisContext Ctx); void popCodeSynthesisContext(); @@ -13762,8 +13772,9 @@ public: SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName - SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, - SourceLocation Loc, + SubstTemplateName(SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc &QualifierLoc, TemplateName Name, + SourceLocation NameLoc, const MultiLevelTemplateArgumentList &TemplateArgs); bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC, @@ -14417,6 +14428,15 @@ public: static void collectUnexpandedParameterPacks( Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// Invoked when parsing a template argument. + /// + /// \param Arg the template argument, which may already be invalid. + /// + /// If it is followed by ellipsis, this function is called before + /// `ActOnPackExpansion`. + ParsedTemplateArgument + ActOnTemplateTemplateArgument(const ParsedTemplateArgument &Arg); + /// Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// @@ -14504,7 +14524,8 @@ public: bool CheckParameterPacksForExpansion( SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, - const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool FailOnPackProducingTemplates, bool &ShouldExpand, bool &RetainExpansion, UnsignedOrNone &NumExpansions); /// Determine the number of arguments in the given pack expansion @@ -15179,14 +15200,6 @@ public: return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser); } - /// Retrieve a version of the type 'T' that is elaborated by Keyword, - /// qualified by the nested-name-specifier contained in SS, and that is - /// (re)declared by OwnedTagDecl, which is nullptr if this is not a - /// (re)declaration. - QualType getElaboratedType(ElaboratedTypeKeyword Keyword, - const CXXScopeSpec &SS, QualType T, - TagDecl *OwnedTagDecl = nullptr); - // Returns the underlying type of a decltype with the given expression. QualType getDecltypeForExpr(Expr *E); @@ -15331,6 +15344,16 @@ public: NamedDecl *Hidden; return hasVisibleDefinition(const_cast<NamedDecl *>(D), &Hidden); } + /// Determine if \p D has a definition which allows we redefine it in current + /// TU. \p Suggested is the definition that should be made visible to expose + /// the definition. + bool isRedefinitionAllowedFor(NamedDecl *D, NamedDecl **Suggested, + bool &Visible); + bool isRedefinitionAllowedFor(const NamedDecl *D, bool &Visible) { + NamedDecl *Hidden; + return isRedefinitionAllowedFor(const_cast<NamedDecl *>(D), &Hidden, + Visible); + } /// Determine if \p D has a reachable definition. If not, suggest a /// declaration that should be made reachable to expose the definition. diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 085c9ed..5cbe1b6 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -153,6 +153,10 @@ public: ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent, ArrayRef<hlsl::RootSignatureElement> Elements); + void SetRootSignatureOverride(IdentifierInfo *DeclIdent) { + RootSigOverrideIdent = DeclIdent; + } + // Returns true if any RootSignatureElement is invalid and a diagnostic was // produced bool @@ -221,6 +225,8 @@ private: uint32_t ImplicitBindingNextOrderID = 0; + IdentifierInfo *RootSigOverrideIdent = nullptr; + private: void collectResourceBindingsOnVarDecl(VarDecl *D); void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD, @@ -229,10 +235,17 @@ private: void diagnoseAvailabilityViolations(TranslationUnitDecl *TU); - bool initGlobalResourceDecl(VarDecl *VD); uint32_t getNextImplicitBindingOrderID() { return ImplicitBindingNextOrderID++; } + + bool initGlobalResourceDecl(VarDecl *VD); + bool initGlobalResourceArrayDecl(VarDecl *VD); + void createResourceRecordCtorArgs(const Type *ResourceTy, StringRef VarName, + HLSLResourceBindingAttr *RBA, + HLSLVkBindingAttr *VkBinding, + uint32_t ArrayIndex, + llvm::SmallVectorImpl<Expr *> &Args); }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 42c9469..8f6041b 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -71,12 +71,17 @@ inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) { } /// Retrieve the depth and index of an unexpanded parameter pack. -inline std::pair<unsigned, unsigned> +/// Returns nullopt when the unexpanded packs do not correspond to template +/// parameters, e.g. __builtin_dedup_types. +inline std::optional<std::pair<unsigned, unsigned>> getDepthAndIndex(UnexpandedParameterPack UPP) { if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(UPP.first)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - return getDepthAndIndex(cast<NamedDecl *>(UPP.first)); + if (isa<NamedDecl *>(UPP.first)) + return getDepthAndIndex(cast<NamedDecl *>(UPP.first)); + assert((isa<const TemplateSpecializationType *, + const SubstBuiltinTemplatePackType *>(UPP.first))); + return std::nullopt; } class TypoCorrectionConsumer : public VisibleDeclConsumer { @@ -209,7 +214,7 @@ private: class NamespaceSpecifierSet { struct SpecifierInfo { DeclContext* DeclCtx; - NestedNameSpecifier* NameSpecifier; + NestedNameSpecifier NameSpecifier; unsigned EditDistance; }; @@ -229,9 +234,9 @@ private: static DeclContextList buildContextChain(DeclContext *Start); unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, - NestedNameSpecifier *&NNS); + NestedNameSpecifier &NNS); - public: + public: NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec); @@ -276,7 +281,7 @@ private: }; void addName(StringRef Name, NamedDecl *ND, - NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); + NestedNameSpecifier NNS = std::nullopt, bool isKeyword = false); /// Find any visible decls for the given typo correction candidate. /// If none are found, it to the set of candidates for which qualified lookups diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 964749c..42e8658 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -240,7 +240,18 @@ public: // Creates a VarDecl with a proper default init for the purposes of a // `private`/'firstprivate'/'reduction' clause, so it can be used to generate // a recipe later. - VarDecl *CreateInitRecipe(OpenACCClauseKind CK, const Expr *VarExpr); + // The first entry is the recipe itself, the second is any required + // 'temporary' created for the init (in the case of a copy), such as with + // firstprivate. + std::pair<VarDecl *, VarDecl *> CreateInitRecipe(OpenACCClauseKind CK, + const Expr *VarExpr) { + assert(CK != OpenACCClauseKind::Reduction); + return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr); + } + std::pair<VarDecl *, VarDecl *> + CreateInitRecipe(OpenACCClauseKind CK, + OpenACCReductionOperator ReductionOperator, + const Expr *VarExpr); public: ComputeConstructInfo &getActiveComputeConstructInfo() { @@ -943,12 +954,12 @@ public: ArrayRef<Expr *> IntExprs, SourceLocation EndLoc); // Does the checking for a 'reduction ' clause that needs to be done in // dependent and not dependent cases. - OpenACCClause * - CheckReductionClause(ArrayRef<const OpenACCClause *> ExistingClauses, - OpenACCDirectiveKind DirectiveKind, - SourceLocation BeginLoc, SourceLocation LParenLoc, - OpenACCReductionOperator ReductionOp, - ArrayRef<Expr *> Vars, SourceLocation EndLoc); + OpenACCClause *CheckReductionClause( + ArrayRef<const OpenACCClause *> ExistingClauses, + OpenACCDirectiveKind DirectiveKind, SourceLocation BeginLoc, + SourceLocation LParenLoc, OpenACCReductionOperator ReductionOp, + ArrayRef<Expr *> Vars, ArrayRef<OpenACCReductionRecipe> Recipes, + SourceLocation EndLoc); ExprResult BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc); ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc); diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index b47b2f15..7ae556d 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -64,6 +64,7 @@ public: void handleKernelAttr(Decl *D, const ParsedAttr &AL); void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL); + void CheckSYCLExternalFunctionDecl(FunctionDecl *FD); void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD); StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body); }; diff --git a/clang/include/clang/Sema/SemaWasm.h b/clang/include/clang/Sema/SemaWasm.h index 8c0639f..f825907 100644 --- a/clang/include/clang/Sema/SemaWasm.h +++ b/clang/include/clang/Sema/SemaWasm.h @@ -37,7 +37,8 @@ public: bool BuiltinWasmTableGrow(CallExpr *TheCall); bool BuiltinWasmTableFill(CallExpr *TheCall); bool BuiltinWasmTableCopy(CallExpr *TheCall); - bool BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall); + bool BuiltinWasmTestFunctionPointerSignature(const TargetInfo &TI, + CallExpr *TheCall); WebAssemblyImportNameAttr * mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL); diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h index 09de164..1d780c4 100644 --- a/clang/include/clang/Sema/TypoCorrection.h +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -57,15 +57,15 @@ public: static const unsigned CallbackDistanceWeight = 150U; TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, - NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0, - unsigned QualifierDistance = 0) + NestedNameSpecifier NNS = std::nullopt, + unsigned CharDistance = 0, unsigned QualifierDistance = 0) : CorrectionName(Name), CorrectionNameSpec(NNS), CharDistance(CharDistance), QualifierDistance(QualifierDistance) { if (NameDecl) CorrectionDecls.push_back(NameDecl); } - TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr, + TypoCorrection(NamedDecl *Name, NestedNameSpecifier NNS = std::nullopt, unsigned CharDistance = 0) : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), CharDistance(CharDistance) { @@ -73,7 +73,7 @@ public: CorrectionDecls.push_back(Name); } - TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr, + TypoCorrection(DeclarationName Name, NestedNameSpecifier NNS = std::nullopt, unsigned CharDistance = 0) : CorrectionName(Name), CorrectionNameSpec(NNS), CharDistance(CharDistance) {} @@ -88,13 +88,13 @@ public: } /// Gets the NestedNameSpecifier needed to use the typo correction - NestedNameSpecifier *getCorrectionSpecifier() const { + NestedNameSpecifier getCorrectionSpecifier() const { return CorrectionNameSpec; } - void setCorrectionSpecifier(NestedNameSpecifier *NNS) { + void setCorrectionSpecifier(NestedNameSpecifier NNS) { CorrectionNameSpec = NNS; - ForceSpecifierReplacement = (NNS != nullptr); + ForceSpecifierReplacement = !!NNS; } void WillReplaceSpecifier(bool ForceReplacement) { @@ -264,7 +264,7 @@ private: // Results. DeclarationName CorrectionName; - NestedNameSpecifier *CorrectionNameSpec = nullptr; + NestedNameSpecifier CorrectionNameSpec = std::nullopt; SmallVector<NamedDecl *, 1> CorrectionDecls; unsigned CharDistance = 0; unsigned QualifierDistance = 0; @@ -282,8 +282,9 @@ class CorrectionCandidateCallback { public: static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; - explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr, - NestedNameSpecifier *TypoNNS = nullptr) + explicit CorrectionCandidateCallback( + const IdentifierInfo *Typo = nullptr, + NestedNameSpecifier TypoNNS = std::nullopt) : Typo(Typo), TypoNNS(TypoNNS) {} virtual ~CorrectionCandidateCallback() = default; @@ -320,7 +321,7 @@ public: virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0; void setTypoName(const IdentifierInfo *II) { Typo = II; } - void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; } + void setTypoNNS(NestedNameSpecifier NNS) { TypoNNS = NNS; } // Flags for context-dependent keywords. WantFunctionLikeCasts is only // used/meaningful when WantCXXNamedCasts is false. @@ -346,13 +347,13 @@ protected: } const IdentifierInfo *Typo; - NestedNameSpecifier *TypoNNS; + NestedNameSpecifier TypoNNS; }; class DefaultFilterCCC final : public CorrectionCandidateCallback { public: explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr, - NestedNameSpecifier *TypoNNS = nullptr) + NestedNameSpecifier TypoNNS = std::nullopt) : CorrectionCandidateCallback(Typo, TypoNNS) {} std::unique_ptr<CorrectionCandidateCallback> clone() override { @@ -366,7 +367,7 @@ template <class C> class DeclFilterCCC final : public CorrectionCandidateCallback { public: explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr, - NestedNameSpecifier *TypoNNS = nullptr) + NestedNameSpecifier TypoNNS = std::nullopt) : CorrectionCandidateCallback(Typo, TypoNNS) {} bool ValidateCandidate(const TypoCorrection &candidate) override { diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 7ce626c..3ede092 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -526,6 +526,9 @@ private: /// A timer used to track the time spent deserializing. std::unique_ptr<llvm::Timer> ReadTimer; + // A TimeRegion used to start and stop ReadTimer via RAII. + std::optional<llvm::TimeRegion> ReadTimeRegion; + /// The location where the module file will be considered as /// imported from. For non-module AST types it should be invalid. SourceLocation CurrentImportLoc; diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 1472497..aed1b7d 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -223,7 +223,7 @@ public: void readQualifierInfo(QualifierInfo &Info); /// Return a nested name specifier, advancing Idx. - // NestedNameSpecifier *readNestedNameSpecifier(); (inherited) + // NestedNameSpecifier readNestedNameSpecifier(); (inherited) NestedNameSpecifierLoc readNestedNameSpecifierLoc(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index ee005ec..9849ea6 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -247,8 +247,7 @@ public: void AddTypeLoc(TypeLoc TL); /// Emits a template argument location info. - void AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, - const TemplateArgumentLocInfo &Arg); + void AddTemplateArgumentLocInfo(const TemplateArgumentLoc &Arg); /// Emits a template argument location. void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg); @@ -280,7 +279,7 @@ public: void AddQualifierInfo(const QualifierInfo &Info); /// Emit a nested name specifier. - void AddNestedNameSpecifier(NestedNameSpecifier *NNS) { + void AddNestedNameSpecifier(NestedNameSpecifier NNS) { writeNestedNameSpecifier(NNS); } diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def index 613eb6a..bea1525 100644 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -32,7 +32,6 @@ TYPE_BIT_CODE(Enum, ENUM, 20) TYPE_BIT_CODE(ObjCInterface, OBJC_INTERFACE, 21) TYPE_BIT_CODE(ObjCObjectPointer, OBJC_OBJECT_POINTER, 22) TYPE_BIT_CODE(Decltype, DECLTYPE, 23) -TYPE_BIT_CODE(Elaborated, ELABORATED, 24) TYPE_BIT_CODE(SubstTemplateTypeParm, SUBST_TEMPLATE_TYPE_PARM, 25) TYPE_BIT_CODE(UnresolvedUsing, UNRESOLVED_USING, 26) TYPE_BIT_CODE(InjectedClassName, INJECTED_CLASS_NAME, 27) @@ -70,5 +69,6 @@ TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58) TYPE_BIT_CODE(HLSLAttributedResource, HLSLRESOURCE_ATTRIBUTED, 59) TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60) TYPE_BIT_CODE(PredefinedSugar, PREDEFINED_SUGAR, 61) +TYPE_BIT_CODE(SubstBuiltinTemplatePack, SUBST_BUILTIN_TEMPLATE_PACK, 62) #undef TYPE_BIT_CODE diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 8696fce..f6a0233 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -320,7 +320,7 @@ protected: /// A set of location contexts that correspoind to call sites which should be /// considered "interesting". - llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; + llvm::SmallPtrSet<const LocationContext *, 2> InterestingLocationContexts; /// A set of custom visitors which generate "event" diagnostics at /// interesting points in the path. @@ -348,7 +348,7 @@ protected: llvm::SmallSet<InvalidationRecord, 4> Invalidations; /// Conditions we're already tracking. - llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions; + llvm::SmallPtrSet<const ExplodedNode *, 4> TrackedConditions; /// Reports with different uniqueing locations are considered to be different /// for the purposes of deduplication. @@ -623,10 +623,12 @@ public: ASTContext &getContext() { return D.getASTContext(); } const SourceManager &getSourceManager() { return D.getSourceManager(); } + const SourceManager &getSourceManager() const { return D.getSourceManager(); } const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); } Preprocessor &getPreprocessor() { return D.getPreprocessor(); } + const Preprocessor &getPreprocessor() const { return D.getPreprocessor(); } /// Get the top-level entry point for the issue to be reported. const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; } diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index 31cc095c..d9a7c00 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -209,8 +209,8 @@ public: class Bind { template <typename CHECKER> static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S, - CheckerContext &C) { - ((const CHECKER *)checker)->checkBind(location, val, S, C); + bool AtDeclInit, CheckerContext &C) { + ((const CHECKER *)checker)->checkBind(location, val, S, AtDeclInit, C); } public: diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index c8e6f12..bf33ce6 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -338,10 +338,9 @@ public: ExprEngine &Eng); /// Run checkers for binding of a value to a location. - void runCheckersForBind(ExplodedNodeSet &Dst, - const ExplodedNodeSet &Src, - SVal location, SVal val, - const Stmt *S, ExprEngine &Eng, + void runCheckersForBind(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + SVal location, SVal val, const Stmt *S, + bool AtDeclInit, ExprEngine &Eng, const ProgramPoint &PP); /// Run checkers after taking a control flow edge. @@ -499,8 +498,8 @@ public: using CheckLocationFunc = CheckerFn<void(SVal location, bool isLoad, const Stmt *S, CheckerContext &)>; - using CheckBindFunc = - CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>; + using CheckBindFunc = CheckerFn<void(SVal location, SVal val, const Stmt *S, + bool AtDeclInit, CheckerContext &)>; using CheckBlockEntranceFunc = CheckerFn<void(const BlockEntrance &, CheckerContext &)>; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index f20b003..cf035a9 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -58,25 +58,34 @@ public: AnalysisManager &getAnalysisManager() { return Eng.getAnalysisManager(); } + const AnalysisManager &getAnalysisManager() const { + return Eng.getAnalysisManager(); + } ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } + const ConstraintManager &getConstraintManager() const { + return Eng.getConstraintManager(); + } StoreManager &getStoreManager() { return Eng.getStoreManager(); } + const StoreManager &getStoreManager() const { return Eng.getStoreManager(); } /// Returns the previous node in the exploded graph, which includes /// the state of the program before the checker ran. Note, checkers should /// not retain the node in their state since the nodes might get invalidated. ExplodedNode *getPredecessor() { return Pred; } + const ExplodedNode *getPredecessor() const { return Pred; } const ProgramPoint getLocation() const { return Location; } const ProgramStateRef &getState() const { return Pred->getState(); } /// Check if the checker changed the state of the execution; ex: added /// a new transition or a bug report. bool isDifferent() { return Changed; } + bool isDifferent() const { return Changed; } /// Returns the number of times the current block has been visited /// along the analyzed path. @@ -108,24 +117,38 @@ public: BugReporter &getBugReporter() { return Eng.getBugReporter(); } + const BugReporter &getBugReporter() const { return Eng.getBugReporter(); } const SourceManager &getSourceManager() { return getBugReporter().getSourceManager(); } + const SourceManager &getSourceManager() const { + return getBugReporter().getSourceManager(); + } Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); } + const Preprocessor &getPreprocessor() const { + return getBugReporter().getPreprocessor(); + } SValBuilder &getSValBuilder() { return Eng.getSValBuilder(); } + const SValBuilder &getSValBuilder() const { return Eng.getSValBuilder(); } SymbolManager &getSymbolManager() { return getSValBuilder().getSymbolManager(); } + const SymbolManager &getSymbolManager() const { + return getSValBuilder().getSymbolManager(); + } ProgramStateManager &getStateManager() { return Eng.getStateManager(); } + const ProgramStateManager &getStateManager() const { + return Eng.getStateManager(); + } AnalysisDeclContext *getCurrentAnalysisDeclContext() const { return Pred->getLocationContext()->getAnalysisDeclContext(); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index fbb3434..d184986cd 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -196,6 +196,7 @@ public: ASTContext &getContext() const { return AMgr.getASTContext(); } AnalysisManager &getAnalysisManager() { return AMgr; } + const AnalysisManager &getAnalysisManager() const { return AMgr; } AnalysisDeclContextManager &getAnalysisDeclContextManager() { return AMgr.getAnalysisDeclContextManager(); @@ -206,8 +207,10 @@ public: } SValBuilder &getSValBuilder() { return svalBuilder; } + const SValBuilder &getSValBuilder() const { return svalBuilder; } BugReporter &getBugReporter() { return BR; } + const BugReporter &getBugReporter() const { return BR; } cross_tu::CrossTranslationUnitContext * getCrossTranslationUnitContext() { @@ -416,12 +419,19 @@ public: unsigned int Space, bool IsDot) const; ProgramStateManager &getStateManager() { return StateMgr; } + const ProgramStateManager &getStateManager() const { return StateMgr; } StoreManager &getStoreManager() { return StateMgr.getStoreManager(); } + const StoreManager &getStoreManager() const { + return StateMgr.getStoreManager(); + } ConstraintManager &getConstraintManager() { return StateMgr.getConstraintManager(); } + const ConstraintManager &getConstraintManager() const { + return StateMgr.getConstraintManager(); + } // FIXME: Remove when we migrate over to just using SValBuilder. BasicValueFactory &getBasicVals() { @@ -429,6 +439,7 @@ public: } SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } MemRegionManager &getRegionManager() { return MRMgr; } DataTag::Factory &getDataTags() { return Engine.getDataTags(); } @@ -660,7 +671,7 @@ private: /// evalBind - Handle the semantics of binding a value to a specific location. /// This method is used by evalStore, VisitDeclStmt, and others. void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, - SVal location, SVal Val, bool atDeclInit = false, + SVal location, SVal Val, bool AtDeclInit = false, const ProgramPoint *PP = nullptr); ProgramStateRef diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 5271453..12487a3 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -572,7 +572,11 @@ public: CallEventManager &getCallEventManager() { return *CallEventMgr; } StoreManager &getStoreManager() { return *StoreMgr; } + const StoreManager &getStoreManager() const { return *StoreMgr; } ConstraintManager &getConstraintManager() { return *ConstraintMgr; } + const ConstraintManager &getConstraintManager() const { + return *ConstraintMgr; + } ExprEngine &getOwningEngine() { return *Eng; } ProgramStateRef diff --git a/clang/include/clang/Tooling/Refactoring/Lookup.h b/clang/include/clang/Tooling/Refactoring/Lookup.h index dcb40b7e..fe0df86 100644 --- a/clang/include/clang/Tooling/Refactoring/Lookup.h +++ b/clang/include/clang/Tooling/Refactoring/Lookup.h @@ -38,8 +38,7 @@ namespace tooling { /// \param ReplacementString The replacement nested name. Must be fully /// qualified including a leading "::". /// \returns The new name to be inserted in place of the current nested name. -std::string replaceNestedName(const NestedNameSpecifier *Use, - SourceLocation UseLoc, +std::string replaceNestedName(NestedNameSpecifier Use, SourceLocation UseLoc, const DeclContext *UseContext, const NamedDecl *FromDecl, StringRef ReplacementString); diff --git a/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h index 271232e..319569f 100644 --- a/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h +++ b/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h @@ -108,19 +108,21 @@ public: bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(TL.getBeginLoc(), 0, SM, LangOpts); - return visit(TL.getTypedefNameDecl(), TL.getBeginLoc(), TypeEndLoc); + return visit(TL.getDecl(), TL.getBeginLoc(), TypeEndLoc); } - bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc) { // The base visitor will visit NNSL prefixes, so we should only look at // the current NNS. - if (NNS) { - const auto *ND = dyn_cast_if_present<NamespaceDecl>( - NNS.getNestedNameSpecifier()->getAsNamespace()); - if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc())) + if (NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) { + const auto *ND = dyn_cast<NamespaceDecl>( + Qualifier.getAsNamespaceAndPrefix().Namespace); + if (!visit(ND, QualifierLoc.getLocalBeginLoc(), + QualifierLoc.getLocalEndLoc())) return false; } - return BaseType::TraverseNestedNameSpecifierLoc(NNS); + return BaseType::TraverseNestedNameSpecifierLoc(QualifierLoc); } bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) { diff --git a/clang/include/module.modulemap b/clang/include/module.modulemap index 42ee34f..c553526 100644 --- a/clang/include/module.modulemap +++ b/clang/include/module.modulemap @@ -37,6 +37,7 @@ module Clang_Basic { umbrella "clang/Basic" textual header "clang/Basic/AArch64ACLETypes.def" + textual header "clang/Basic/ABIVersions.def" textual header "clang/Basic/AMDGPUTypes.def" textual header "clang/Basic/BuiltinHeaders.def" textual header "clang/Basic/BuiltinsAArch64.def" |