Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -30,6 +30,7 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/AttrKinds.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -1405,7 +1406,7 @@ QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; - QualType getAttributedType(AttributedType::Kind attrKind, + QualType getAttributedType(attr::Kind attrKind, QualType modifiedType, QualType equivalentType); Index: include/clang/AST/Attr.h =================================================================== --- include/clang/AST/Attr.h +++ include/clang/AST/Attr.h @@ -113,6 +113,19 @@ void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; }; +class TypeAttr : public Attr { +protected: + TypeAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed) + : Attr(AK, R, SpellingListIndex, IsLateParsed) {} + +public: + static bool classof(const Attr *A) { + return A->getKind() >= attr::FirstTypeAttr && + A->getKind() <= attr::LastTypeAttr; + } +}; + class StmtAttr : public Attr { protected: StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -21,6 +21,7 @@ #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" @@ -1851,7 +1852,16 @@ bool isObjCQualifiedClassType() const; // Class bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id - bool isObjCInertUnsafeUnretainedType() 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 @@ -2065,6 +2075,10 @@ /// 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. @@ -4174,56 +4188,7 @@ /// - the canonical type is VectorType(16, int) class AttributedType : public Type, public llvm::FoldingSetNode { public: - // It is really silly to have yet another attribute-kind enum, but - // clang::attr::Kind doesn't currently cover the pure type attrs. - enum Kind { - // Expression operand. - attr_address_space, - attr_regparm, - attr_vector_size, - attr_neon_vector_type, - attr_neon_polyvector_type, - - FirstExprOperandKind = attr_address_space, - LastExprOperandKind = attr_neon_polyvector_type, - - // Enumerated operand (string or keyword). - attr_objc_gc, - attr_objc_ownership, - attr_pcs, - attr_pcs_vfp, - - FirstEnumOperandKind = attr_objc_gc, - LastEnumOperandKind = attr_pcs_vfp, - - // No operand. - attr_noreturn, - attr_nocf_check, - attr_cdecl, - attr_fastcall, - attr_stdcall, - attr_thiscall, - attr_regcall, - attr_pascal, - attr_swiftcall, - attr_vectorcall, - attr_inteloclbicc, - attr_ms_abi, - attr_sysv_abi, - attr_preserve_most, - attr_preserve_all, - attr_ptr32, - attr_ptr64, - attr_sptr, - attr_uptr, - attr_nonnull, - attr_ns_returns_retained, - attr_nullable, - attr_null_unspecified, - attr_objc_kindof, - attr_objc_inert_unsafe_unretained, - attr_lifetimebound, - }; + using Kind = attr::Kind; private: friend class ASTContext; // ASTContext creates these @@ -4231,7 +4196,7 @@ QualType ModifiedType; QualType EquivalentType; - AttributedType(QualType canon, Kind attrKind, QualType modified, + AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), @@ -4280,13 +4245,13 @@ static Kind getNullabilityAttrKind(NullabilityKind kind) { switch (kind) { case NullabilityKind::NonNull: - return attr_nonnull; + return attr::TypeNonNull; case NullabilityKind::Nullable: - return attr_nullable; + return attr::TypeNullable; case NullabilityKind::Unspecified: - return attr_null_unspecified; + return attr::TypeNullUnspecified; } llvm_unreachable("Unknown nullability kind."); } Index: include/clang/AST/TypeLoc.h =================================================================== --- include/clang/AST/TypeLoc.h +++ include/clang/AST/TypeLoc.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_AST_TYPELOC_H #define LLVM_CLANG_AST_TYPELOC_H +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" @@ -843,16 +844,7 @@ }; struct AttributedLocInfo { - union { - Expr *ExprOperand; - - /// A raw SourceLocation. - unsigned EnumOperandLoc; - }; - - SourceRange OperandParens; - - SourceLocation AttrLoc; + const Attr *TypeAttr; }; /// Type source information for an attributed type. @@ -861,24 +853,10 @@ AttributedType, AttributedLocInfo> { public: - AttributedType::Kind getAttrKind() const { + attr::Kind getAttrKind() const { return getTypePtr()->getAttrKind(); } - bool hasAttrExprOperand() const { - return (getAttrKind() >= AttributedType::FirstExprOperandKind && - getAttrKind() <= AttributedType::LastExprOperandKind); - } - - bool hasAttrEnumOperand() const { - return (getAttrKind() >= AttributedType::FirstEnumOperandKind && - getAttrKind() <= AttributedType::LastEnumOperandKind); - } - - bool hasAttrOperand() const { - return hasAttrExprOperand() || hasAttrEnumOperand(); - } - bool isQualifier() const { return getTypePtr()->isQualifier(); } @@ -891,51 +869,16 @@ return getInnerTypeLoc(); } - /// The location of the attribute name, i.e. - /// __attribute__((regparm(1000))) - /// ^~~~~~~ - SourceLocation getAttrNameLoc() const { - return getLocalData()->AttrLoc; + /// The type attribute. + const Attr *getAttr() const { + return getLocalData()->TypeAttr; } - void setAttrNameLoc(SourceLocation loc) { - getLocalData()->AttrLoc = loc; + void setAttr(const Attr *A) { + getLocalData()->TypeAttr = A; } - /// The attribute's expression operand, if it has one. - /// void *cur_thread __attribute__((address_space(21))) - /// ^~ - Expr *getAttrExprOperand() const { - assert(hasAttrExprOperand()); - return getLocalData()->ExprOperand; - } - void setAttrExprOperand(Expr *e) { - assert(hasAttrExprOperand()); - getLocalData()->ExprOperand = e; - } - - /// The location of the attribute's enumerated operand, if it has one. - /// void * __attribute__((objc_gc(weak))) - /// ^~~~ - SourceLocation getAttrEnumOperandLoc() const { - assert(hasAttrEnumOperand()); - return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc); - } - void setAttrEnumOperandLoc(SourceLocation loc) { - assert(hasAttrEnumOperand()); - getLocalData()->EnumOperandLoc = loc.getRawEncoding(); - } - - /// The location of the parentheses around the operand, if there is - /// an operand. - /// void * __attribute__((objc_gc(weak))) - /// ^ ^ - SourceRange getAttrOperandParensRange() const { - assert(hasAttrOperand()); - return getLocalData()->OperandParens; - } - void setAttrOperandParensRange(SourceRange range) { - assert(hasAttrOperand()); - getLocalData()->OperandParens = range; + template const T *getAttrAs() { + return dyn_cast_or_null(getAttr()); } SourceRange getLocalSourceRange() const { @@ -948,21 +891,11 @@ // ^~ ~~ // That enclosure doesn't necessarily belong to a single attribute // anyway. - SourceRange range(getAttrNameLoc()); - if (hasAttrOperand()) - range.setEnd(getAttrOperandParensRange().getEnd()); - return range; + return getAttr() ? getAttr()->getRange() : SourceRange(); } void initializeLocal(ASTContext &Context, SourceLocation loc) { - setAttrNameLoc(loc); - if (hasAttrExprOperand()) { - setAttrOperandParensRange(SourceRange(loc)); - setAttrExprOperand(nullptr); - } else if (hasAttrEnumOperand()) { - setAttrOperandParensRange(SourceRange(loc)); - setAttrEnumOperandLoc(loc); - } + setAttr(nullptr); } QualType getInnerType() const { Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -489,10 +489,7 @@ } /// A type attribute is not processed on a declaration or a statement. -class TypeAttr : Attr { - // By default, type attributes do not get an AST node. - let ASTNode = 0; -} +class TypeAttr : Attr; /// A stmt attribute is not processed on a declaration or a type. class StmtAttr : Attr; @@ -562,6 +559,8 @@ let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; + // Represented as a qualifier or DependentAddressSpaceType instead. + let ASTNode = 0; } def Alias : Attr { @@ -1219,7 +1218,7 @@ let Documentation = [LayoutVersionDocs]; } -def LifetimeBound : InheritableAttr { +def LifetimeBound : DeclOrTypeAttr { let Spellings = [Clang<"lifetimebound", 0>]; let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>; let Documentation = [LifetimeBoundDocs]; @@ -1322,12 +1321,16 @@ let Spellings = [Clang<"neon_polyvector_type">]; let Args = [IntArgument<"NumElements">]; let Documentation = [Undocumented]; + // Represented as VectorType instead. + let ASTNode = 0; } def NeonVectorType : TypeAttr { let Spellings = [Clang<"neon_vector_type">]; let Args = [IntArgument<"NumElements">]; let Documentation = [Undocumented]; + // Represented as VectorType instead. + let ASTNode = 0; } def ReturnsTwice : InheritableAttr { @@ -1502,6 +1505,14 @@ let Documentation = [TypeNullUnspecifiedDocs]; } +// This is a marker used to indicate that an __unsafe_unretained qualifier was +// ignored because ARC is not enabled. The usual representation for this +// qualifier is as an ObjCOwnership attribute with Kind == "none". +def ObjCInertUnsafeUnretained : TypeAttr { + let Spellings = [Keyword<"__unsafe_unretained">]; + let Documentation = [Undocumented]; +} + def ObjCKindOf : TypeAttr { let Spellings = [Keyword<"__kindof">]; let Documentation = [Undocumented]; @@ -1589,7 +1600,7 @@ let Documentation = [Undocumented]; } -def NSReturnsRetained : InheritableAttr { +def NSReturnsRetained : DeclOrTypeAttr { let Spellings = [Clang<"ns_returns_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; @@ -1774,6 +1785,8 @@ let Spellings = [GCC<"regparm">]; let Args = [UnsignedArgument<"NumParams">]; let Documentation = [RegparmDocs]; + // Represented as part of the enclosing function type. + let ASTNode = 0; } def ReqdWorkGroupSize : InheritableAttr { @@ -2062,10 +2075,9 @@ let Documentation = [Undocumented]; } -def ObjCOwnership : InheritableAttr { +def ObjCOwnership : DeclOrTypeAttr { let Spellings = [Clang<"objc_ownership">]; let Args = [IdentifierArgument<"Kind">]; - let ASTNode = 0; let Documentation = [Undocumented]; } @@ -2103,6 +2115,8 @@ let Spellings = [GCC<"vector_size">]; let Args = [ExprArgument<"NumBytes">]; let Documentation = [Undocumented]; + // Represented as VectorType instead. + let ASTNode = 0; } def VecTypeHint : InheritableAttr { @@ -2197,7 +2211,7 @@ let Documentation = [AnyX86NoCallerSavedRegistersDocs]; } -def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr{ +def AnyX86NoCfCheck : DeclOrTypeAttr, TargetSpecificAttr{ let Spellings = [GCC<"nocf_check">]; let Subjects = SubjectList<[FunctionLike]>; let Documentation = [AnyX86NoCfCheckDocs]; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1435,8 +1435,6 @@ TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); - TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, - TypeSourceInfo *ReturnTypeInfo); /// Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); @@ -3378,30 +3376,6 @@ /// Valid types should not have multiple attributes with different CCs. const AttributedType *getCallingConvAttributedType(QualType T) const; - /// Check whether a nullability type specifier can be added to the given - /// type. - /// - /// \param type The type to which the nullability specifier will be - /// added. On success, this type will be updated appropriately. - /// - /// \param nullability The nullability specifier to add. - /// - /// \param nullabilityLoc The location of the nullability specifier. - /// - /// \param isContextSensitive Whether this nullability specifier was - /// written as a context-sensitive keyword (in an Objective-C - /// method) or an Objective-C property attribute, rather than as an - /// underscored type specifier. - /// - /// \param allowArrayTypes Whether to accept nullability specifiers on an - /// array type (e.g., because it will decay to a pointer). - /// - /// \returns true if nullability cannot be applied, false otherwise. - bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability, - SourceLocation nullabilityLoc, - bool isContextSensitive, - bool allowArrayTypes); - /// Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, const ParsedAttributesView &Attrs, @@ -8071,10 +8045,6 @@ SourceLocation ProtocolRAngleLoc, bool FailOnError = false); - /// Check the application of the Objective-C '__kindof' qualifier to - /// the given type. - bool checkObjCKindOfType(QualType &type, SourceLocation loc); - /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -2245,6 +2245,9 @@ CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record, unsigned &Idx); + /// Reads one attribute from the current stream position. + Attr *ReadAttr(ModuleFile &M, const RecordData &Record, unsigned &Idx); + /// Reads attributes from the current stream position. void ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs); @@ -2630,6 +2633,11 @@ return ASTReader::ReadVersionTuple(Record, Idx); } + /// Reads one attribute from the current stream position, advancing Idx. + Attr *readAttr() { + return Reader->ReadAttr(*F, Record, Idx); + } + /// Reads attributes from the current stream position, advancing Idx. void readAttributes(AttrVec &Attrs) { return Reader->ReadAttributes(*this, Attrs); Index: include/clang/Serialization/ASTWriter.h =================================================================== --- include/clang/Serialization/ASTWriter.h +++ include/clang/Serialization/ASTWriter.h @@ -955,6 +955,9 @@ return Writer->AddVersionTuple(Version, *Record); } + // Emit an attribute. + void AddAttr(const Attr *A); + /// Emit a list of attributes. void AddAttributes(ArrayRef Attrs); }; Index: lib/ARCMigrate/TransGCAttrs.cpp =================================================================== --- lib/ARCMigrate/TransGCAttrs.cpp +++ lib/ARCMigrate/TransGCAttrs.cpp @@ -81,10 +81,11 @@ } bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) { - if (TL.getAttrKind() != AttributedType::attr_objc_ownership) + auto *OwnershipAttr = TL.getAttrAs(); + if (!OwnershipAttr) return false; - SourceLocation Loc = TL.getAttrNameLoc(); + SourceLocation Loc = OwnershipAttr->getLocation(); unsigned RawLoc = Loc.getRawEncoding(); if (MigrateCtx.AttrSet.count(RawLoc)) return true; @@ -93,13 +94,7 @@ SourceManager &SM = Ctx.getSourceManager(); if (Loc.isMacroID()) Loc = SM.getImmediateExpansionRange(Loc).getBegin(); - SmallString<32> Buf; - bool Invalid = false; - StringRef Spell = Lexer::getSpelling( - SM.getSpellingLoc(TL.getAttrEnumOperandLoc()), - Buf, SM, Ctx.getLangOpts(), &Invalid); - if (Invalid) - return false; + StringRef Spell = OwnershipAttr->getKind()->getName(); MigrationContext::GCAttrOccurrence::AttrKind Kind; if (Spell == "strong") Kind = MigrationContext::GCAttrOccurrence::Strong; @@ -284,7 +279,7 @@ } for (unsigned i = 0, e = ATLs.size(); i != e; ++i) { - SourceLocation Loc = ATLs[i].first.getAttrNameLoc(); + SourceLocation Loc = ATLs[i].first.getAttr()->getLocation(); if (Loc.isMacroID()) Loc = MigrateCtx.Pass.Ctx.getSourceManager() .getImmediateExpansionRange(Loc) Index: lib/ARCMigrate/Transforms.cpp =================================================================== --- lib/ARCMigrate/Transforms.cpp +++ lib/ARCMigrate/Transforms.cpp @@ -359,7 +359,7 @@ bool MigrationContext::isGCOwnedNonObjC(QualType T) { while (!T.isNull()) { if (const AttributedType *AttrT = T->getAs()) { - if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership) + if (AttrT->getAttrKind() == attr::ObjCOwnership) return !AttrT->getModifiedType()->isObjCRetainableType(); } Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -3873,7 +3873,7 @@ return QualType(newType, 0); } -QualType ASTContext::getAttributedType(AttributedType::Kind attrKind, +QualType ASTContext::getAttributedType(attr::Kind attrKind, QualType modifiedType, QualType equivalentType) { llvm::FoldingSetNodeID id; Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -592,28 +592,6 @@ return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType(); } -/// Was this type written with the special inert-in-MRC __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 Type::isObjCInertUnsafeUnretainedType() const { - const Type *cur = this; - while (true) { - if (const auto attributed = dyn_cast(cur)) { - if (attributed->getAttrKind() == - AttributedType::attr_objc_inert_unsafe_unretained) - return true; - } - - // Single-step desugar until we run out of sugar. - QualType next = cur->getLocallyUnqualifiedSingleStepDesugaredType(); - if (next.getTypePtr() == cur) return false; - cur = next.getTypePtr(); - } -} - ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols) @@ -1641,6 +1619,16 @@ return nullptr; } +bool Type::hasAttr(attr::Kind AK) const { + const Type *Cur = this; + while (const auto *AT = Cur->getAs()) { + if (AT->getAttrKind() == AK) + return true; + Cur = AT->getEquivalentType().getTypePtr(); + } + return false; +} + namespace { class GetContainedDeducedTypeVisitor : @@ -3167,105 +3155,58 @@ } bool AttributedType::isQualifier() const { + // FIXME: Generate this with TableGen. switch (getAttrKind()) { // These are type qualifiers in the traditional C sense: they annotate // something about a specific value/variable of a type. (They aren't // always part of the canonical type, though.) - case AttributedType::attr_address_space: - case AttributedType::attr_objc_gc: - case AttributedType::attr_objc_ownership: - case AttributedType::attr_objc_inert_unsafe_unretained: - case AttributedType::attr_nonnull: - case AttributedType::attr_nullable: - case AttributedType::attr_null_unspecified: - case AttributedType::attr_lifetimebound: + case attr::ObjCGC: + case attr::ObjCOwnership: + case attr::ObjCInertUnsafeUnretained: + case attr::TypeNonNull: + case attr::TypeNullable: + case attr::TypeNullUnspecified: + case attr::LifetimeBound: return true; - // These aren't qualifiers; they rewrite the modified type to be a - // semantically different type. - case AttributedType::attr_regparm: - case AttributedType::attr_vector_size: - case AttributedType::attr_neon_vector_type: - case AttributedType::attr_neon_polyvector_type: - case AttributedType::attr_pcs: - case AttributedType::attr_pcs_vfp: - case AttributedType::attr_noreturn: - case AttributedType::attr_cdecl: - case AttributedType::attr_fastcall: - case AttributedType::attr_stdcall: - case AttributedType::attr_thiscall: - case AttributedType::attr_regcall: - case AttributedType::attr_pascal: - case AttributedType::attr_swiftcall: - case AttributedType::attr_vectorcall: - case AttributedType::attr_inteloclbicc: - case AttributedType::attr_preserve_most: - case AttributedType::attr_preserve_all: - case AttributedType::attr_ms_abi: - case AttributedType::attr_sysv_abi: - case AttributedType::attr_ptr32: - case AttributedType::attr_ptr64: - case AttributedType::attr_sptr: - case AttributedType::attr_uptr: - case AttributedType::attr_objc_kindof: - case AttributedType::attr_ns_returns_retained: - case AttributedType::attr_nocf_check: + // All other type attributes aren't qualifiers; they rewrite the modified + // type to be a semantically different type. + default: return false; } - llvm_unreachable("bad attributed type kind"); } bool AttributedType::isMSTypeSpec() const { + // FIXME: Generate this with TableGen? switch (getAttrKind()) { - default: return false; - case attr_ptr32: - case attr_ptr64: - case attr_sptr: - case attr_uptr: + default: return false; + case attr::Ptr32: + case attr::Ptr64: + case attr::SPtr: + case attr::UPtr: return true; } llvm_unreachable("invalid attr kind"); } bool AttributedType::isCallingConv() const { + // FIXME: Generate this with TableGen. switch (getAttrKind()) { - case attr_ptr32: - case attr_ptr64: - case attr_sptr: - case attr_uptr: - case attr_address_space: - case attr_regparm: - case attr_vector_size: - case attr_neon_vector_type: - case attr_neon_polyvector_type: - case attr_objc_gc: - case attr_objc_ownership: - case attr_objc_inert_unsafe_unretained: - case attr_noreturn: - case attr_nonnull: - case attr_ns_returns_retained: - case attr_nullable: - case attr_null_unspecified: - case attr_objc_kindof: - case attr_nocf_check: - case attr_lifetimebound: - return false; - - case attr_pcs: - case attr_pcs_vfp: - case attr_cdecl: - case attr_fastcall: - case attr_stdcall: - case attr_thiscall: - case attr_regcall: - case attr_swiftcall: - case attr_vectorcall: - case attr_pascal: - case attr_ms_abi: - case attr_sysv_abi: - case attr_inteloclbicc: - case attr_preserve_most: - case attr_preserve_all: + default: return false; + case attr::Pcs: + case attr::CDecl: + case attr::FastCall: + case attr::StdCall: + case attr::ThisCall: + case attr::RegCall: + case attr::SwiftCall: + case attr::VectorCall: + case attr::Pascal: + case attr::MSABI: + case attr::SysVABI: + case attr::IntelOclBicc: + case attr::PreserveMost: + case attr::PreserveAll: return true; } llvm_unreachable("invalid attr kind"); @@ -3708,23 +3649,18 @@ return LinkageComputer{}.getTypeLinkageAndVisibility(this); } -Optional Type::getNullability(const ASTContext &context) const { - QualType type(this, 0); - do { +Optional +Type::getNullability(const ASTContext &Context) const { + QualType Type(this, 0); + while (const auto *AT = Type->getAs()) { // Check whether this is an attributed type with nullability // information. - if (auto attributed = dyn_cast(type.getTypePtr())) { - if (auto nullability = attributed->getImmediateNullability()) - return nullability; - } + if (auto Nullability = AT->getImmediateNullability()) + return Nullability; - // Desugar the type. If desugaring does nothing, we're done. - QualType desugared = type.getSingleStepDesugaredType(context); - if (desugared.getTypePtr() == type.getTypePtr()) - return None; - - type = desugared; - } while (true); + Type = AT->getEquivalentType(); + } + return None; } bool Type::canHaveNullability(bool ResultIfUnknown) const { @@ -3837,12 +3773,13 @@ llvm_unreachable("bad type kind!"); } -llvm::Optional AttributedType::getImmediateNullability() const { - if (getAttrKind() == AttributedType::attr_nonnull) +llvm::Optional +AttributedType::getImmediateNullability() const { + if (getAttrKind() == attr::TypeNonNull) return NullabilityKind::NonNull; - if (getAttrKind() == AttributedType::attr_nullable) + if (getAttrKind() == attr::TypeNullable) return NullabilityKind::Nullable; - if (getAttrKind() == AttributedType::attr_null_unspecified) + if (getAttrKind() == attr::TypeNullUnspecified) return NullabilityKind::Unspecified; return None; } Index: lib/AST/TypeLoc.cpp =================================================================== --- lib/AST/TypeLoc.cpp +++ lib/AST/TypeLoc.cpp @@ -404,11 +404,11 @@ } SourceLocation TypeLoc::findNullabilityLoc() const { - if (auto attributedLoc = getAs()) { - if (attributedLoc.getAttrKind() == AttributedType::attr_nullable || - attributedLoc.getAttrKind() == AttributedType::attr_nonnull || - attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified) - return attributedLoc.getAttrNameLoc(); + if (auto ATL = getAs()) { + const Attr *A = ATL.getAttr(); + if (A && (isa(A) || isa(A) || + isa(A))) + return A->getLocation(); } return {}; Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1354,12 +1354,14 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, raw_ostream &OS) { + // FIXME: Generate this with TableGen. + // Prefer the macro forms of the GC and ownership qualifiers. - if (T->getAttrKind() == AttributedType::attr_objc_gc || - T->getAttrKind() == AttributedType::attr_objc_ownership) + if (T->getAttrKind() == attr::ObjCGC || + T->getAttrKind() == attr::ObjCOwnership) return printBefore(T->getEquivalentType(), OS); - if (T->getAttrKind() == AttributedType::attr_objc_kindof) + if (T->getAttrKind() == attr::ObjCKindOf) OS << "__kindof "; printBefore(T->getModifiedType(), OS); @@ -1367,23 +1369,21 @@ if (T->isMSTypeSpec()) { switch (T->getAttrKind()) { default: return; - case AttributedType::attr_ptr32: OS << " __ptr32"; break; - case AttributedType::attr_ptr64: OS << " __ptr64"; break; - case AttributedType::attr_sptr: OS << " __sptr"; break; - case AttributedType::attr_uptr: OS << " __uptr"; break; + case attr::Ptr32: OS << " __ptr32"; break; + case attr::Ptr64: OS << " __ptr64"; break; + case attr::SPtr: OS << " __sptr"; break; + case attr::UPtr: OS << " __uptr"; break; } spaceBeforePlaceHolder(OS); } // Print nullability type specifiers. - if (T->getAttrKind() == AttributedType::attr_nonnull || - T->getAttrKind() == AttributedType::attr_nullable || - T->getAttrKind() == AttributedType::attr_null_unspecified) { - if (T->getAttrKind() == AttributedType::attr_nonnull) + if (T->getImmediateNullability()) { + if (T->getAttrKind() == attr::TypeNonNull) OS << " _Nonnull"; - else if (T->getAttrKind() == AttributedType::attr_nullable) + else if (T->getAttrKind() == attr::TypeNullable) OS << " _Nullable"; - else if (T->getAttrKind() == AttributedType::attr_null_unspecified) + else if (T->getAttrKind() == attr::TypeNullUnspecified) OS << " _Null_unspecified"; else llvm_unreachable("unhandled nullability"); @@ -1393,9 +1393,11 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, raw_ostream &OS) { + // FIXME: Generate this with TableGen. + // Prefer the macro forms of the GC and ownership qualifiers. - if (T->getAttrKind() == AttributedType::attr_objc_gc || - T->getAttrKind() == AttributedType::attr_objc_ownership) + if (T->getAttrKind() == attr::ObjCGC || + T->getAttrKind() == attr::ObjCOwnership) return printAfter(T->getEquivalentType(), OS); // If this is a calling convention attribute, don't print the implicit CC from @@ -1406,107 +1408,74 @@ // Some attributes are printed as qualifiers before the type, so we have // nothing left to do. - if (T->getAttrKind() == AttributedType::attr_objc_kindof || - T->isMSTypeSpec() || - T->getAttrKind() == AttributedType::attr_nonnull || - T->getAttrKind() == AttributedType::attr_nullable || - T->getAttrKind() == AttributedType::attr_null_unspecified) + if (T->getAttrKind() == attr::ObjCKindOf || + T->isMSTypeSpec() || T->getImmediateNullability()) return; // Don't print the inert __unsafe_unretained attribute at all. - if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained) + if (T->getAttrKind() == attr::ObjCInertUnsafeUnretained) return; // Don't print ns_returns_retained unless it had an effect. - if (T->getAttrKind() == AttributedType::attr_ns_returns_retained && + if (T->getAttrKind() == attr::NSReturnsRetained && !T->getEquivalentType()->castAs() ->getExtInfo().getProducesResult()) return; - if (T->getAttrKind() == AttributedType::attr_lifetimebound) { + if (T->getAttrKind() == attr::LifetimeBound) { OS << " [[clang::lifetimebound]]"; return; } OS << " __attribute__(("; switch (T->getAttrKind()) { - case AttributedType::attr_lifetimebound: - case AttributedType::attr_nonnull: - case AttributedType::attr_nullable: - case AttributedType::attr_null_unspecified: - case AttributedType::attr_objc_gc: - case AttributedType::attr_objc_inert_unsafe_unretained: - case AttributedType::attr_objc_kindof: - case AttributedType::attr_objc_ownership: - case AttributedType::attr_ptr32: - case AttributedType::attr_ptr64: - case AttributedType::attr_sptr: - case AttributedType::attr_uptr: +#define TYPE_ATTR(NAME) +#define DECL_OR_TYPE_ATTR(NAME) +#define ATTR(NAME) case attr::NAME: +#include "clang/Basic/AttrList.inc" + llvm_unreachable("non-type attribute attached to type"); + + case attr::OpenCLPrivateAddressSpace: + case attr::OpenCLGlobalAddressSpace: + case attr::OpenCLLocalAddressSpace: + case attr::OpenCLConstantAddressSpace: + case attr::OpenCLGenericAddressSpace: + // FIXME: Update printAttributedBefore to print these once we generate + // AttributedType nodes for them. + break; + + case attr::LifetimeBound: + case attr::TypeNonNull: + case attr::TypeNullable: + case attr::TypeNullUnspecified: + case attr::ObjCGC: + case attr::ObjCInertUnsafeUnretained: + case attr::ObjCKindOf: + case attr::ObjCOwnership: + case attr::Ptr32: + case attr::Ptr64: + case attr::SPtr: + case attr::UPtr: llvm_unreachable("This attribute should have been handled already"); - case AttributedType::attr_address_space: - OS << "address_space("; - // FIXME: printing the raw LangAS value is wrong. This should probably - // use the same code as Qualifiers::print() - OS << (unsigned)T->getEquivalentType().getAddressSpace(); - OS << ')'; - break; - - case AttributedType::attr_vector_size: - OS << "__vector_size__("; - if (const auto *vector = T->getEquivalentType()->getAs()) { - OS << vector->getNumElements(); - OS << " * sizeof("; - print(vector->getElementType(), OS, StringRef()); - OS << ')'; - } - OS << ')'; - break; - - case AttributedType::attr_neon_vector_type: - case AttributedType::attr_neon_polyvector_type: { - if (T->getAttrKind() == AttributedType::attr_neon_vector_type) - OS << "neon_vector_type("; - else - OS << "neon_polyvector_type("; - const auto *vector = T->getEquivalentType()->getAs(); - OS << vector->getNumElements(); - OS << ')'; - break; - } - - case AttributedType::attr_regparm: { - // FIXME: When Sema learns to form this AttributedType, avoid printing the - // attribute again in printFunctionProtoAfter. - OS << "regparm("; - QualType t = T->getEquivalentType(); - while (!t->isFunctionType()) - t = t->getPointeeType(); - OS << t->getAs()->getRegParmType(); - OS << ')'; - break; - } - - case AttributedType::attr_ns_returns_retained: + case attr::NSReturnsRetained: OS << "ns_returns_retained"; break; // FIXME: When Sema learns to form this AttributedType, avoid printing the // attribute again in printFunctionProtoAfter. - case AttributedType::attr_noreturn: OS << "noreturn"; break; - case AttributedType::attr_nocf_check: OS << "nocf_check"; break; - case AttributedType::attr_cdecl: OS << "cdecl"; break; - case AttributedType::attr_fastcall: OS << "fastcall"; break; - case AttributedType::attr_stdcall: OS << "stdcall"; break; - case AttributedType::attr_thiscall: OS << "thiscall"; break; - case AttributedType::attr_swiftcall: OS << "swiftcall"; break; - case AttributedType::attr_vectorcall: OS << "vectorcall"; break; - case AttributedType::attr_pascal: OS << "pascal"; break; - case AttributedType::attr_ms_abi: OS << "ms_abi"; break; - case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break; - case AttributedType::attr_regcall: OS << "regcall"; break; - case AttributedType::attr_pcs: - case AttributedType::attr_pcs_vfp: { + case attr::AnyX86NoCfCheck: OS << "nocf_check"; break; + case attr::CDecl: OS << "cdecl"; break; + case attr::FastCall: OS << "fastcall"; break; + case attr::StdCall: OS << "stdcall"; break; + case attr::ThisCall: OS << "thiscall"; break; + case attr::SwiftCall: OS << "swiftcall"; break; + case attr::VectorCall: OS << "vectorcall"; break; + case attr::Pascal: OS << "pascal"; break; + case attr::MSABI: OS << "ms_abi"; break; + case attr::SysVABI: OS << "sysv_abi"; break; + case attr::RegCall: OS << "regcall"; break; + case attr::Pcs: { OS << "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) @@ -1517,12 +1486,12 @@ break; } - case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break; - case AttributedType::attr_preserve_most: + case attr::IntelOclBicc: OS << "inteloclbicc"; break; + case attr::PreserveMost: OS << "preserve_most"; break; - case AttributedType::attr_preserve_all: + case attr::PreserveAll: OS << "preserve_all"; break; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -6021,14 +6021,14 @@ // The [[lifetimebound]] attribute can be applied to the implicit object // parameter of a non-static member function (other than a ctor or dtor) // by applying it to the function type. - if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) { + if (const auto *A = ATL.getAttrAs()) { const auto *MD = dyn_cast(FD); if (!MD || MD->isStatic()) { - S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_no_object_param) - << !MD << ATL.getLocalSourceRange(); + S.Diag(A->getLocation(), diag::err_lifetimebound_no_object_param) + << !MD << A->getRange(); } else if (isa(MD) || isa(MD)) { - S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor) - << isa(MD) << ATL.getLocalSourceRange(); + S.Diag(A->getLocation(), diag::err_lifetimebound_ctor_dtor) + << isa(MD) << A->getRange(); } } } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -14663,15 +14663,15 @@ // Warn about implicitly autoreleasing indirect parameters captured by blocks. if (const auto *PT = CaptureType->getAs()) { // This function finds out whether there is an AttributedType of kind - // attr_objc_ownership in Ty. The existence of AttributedType of kind - // attr_objc_ownership implies __autoreleasing was explicitly specified + // attr::ObjCOwnership in Ty. The existence of AttributedType of kind + // attr::ObjCOwnership implies __autoreleasing was explicitly specified // rather than being added implicitly by the compiler. auto IsObjCOwnershipAttributedType = [](QualType Ty) { while (const auto *AttrTy = Ty->getAs()) { - if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership) + if (AttrTy->getAttrKind() == attr::ObjCOwnership) return true; - // Peel off AttributedTypes that are not of kind objc_ownership. + // Peel off AttributedTypes that are not of kind ObjCOwnership. Ty = AttrTy->getModifiedType(); } Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -6378,7 +6378,7 @@ for (TypeLoc TL = TSI->getTypeLoc(); (ATL = TL.getAsAdjusted()); TL = ATL.getModifiedLoc()) { - if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) + if (ATL.getAttrAs()) return true; } return false; Index: lib/Sema/SemaObjCProperty.cpp =================================================================== --- lib/Sema/SemaObjCProperty.cpp +++ lib/Sema/SemaObjCProperty.cpp @@ -2384,7 +2384,7 @@ QualType modifiedTy = resultTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) { if (*nullability == NullabilityKind::Unspecified) - resultTy = Context.getAttributedType(AttributedType::attr_nonnull, + resultTy = Context.getAttributedType(attr::TypeNonNull, modifiedTy, modifiedTy); } } @@ -2458,7 +2458,7 @@ QualType modifiedTy = paramTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){ if (*nullability == NullabilityKind::Unspecified) - paramTy = Context.getAttributedType(AttributedType::attr_nullable, + paramTy = Context.getAttributedType(attr::TypeNullable, modifiedTy, modifiedTy); } } Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -172,6 +172,16 @@ /// processing is complete. SmallVector ignoredTypeAttrs; + /// Attributes corresponding to AttributedTypeLocs that we have not yet + /// populated. + // FIXME: The two-phase mechanism by which we construct Types and fill + // their TypeLocs makes it hard to correctly assign these. We keep the + // attributes in creation order as an attempt to make them line up + // properly. + using TypeAttrPair = std::pair; + SmallVector AttrsForTypes; + bool AttrsForTypesSorted = true; + public: TypeProcessingState(Sema &sema, Declarator &declarator) : sema(sema), declarator(declarator), @@ -230,6 +240,43 @@ diagnoseBadTypeAttribute(getSema(), *Attr, type); } + /// Get an attributed type for the given attribute, and remember the Attr + /// object so that we can attach it to the AttributedTypeLoc. + QualType getAttributedType(Attr *A, QualType ModifiedType, + QualType EquivType) { + QualType T = + sema.Context.getAttributedType(A->getKind(), ModifiedType, EquivType); + AttrsForTypes.push_back({cast(T.getTypePtr()), A}); + AttrsForTypesSorted = false; + return T; + } + + /// Extract and remove the Attr* for a given attributed type. + const Attr *takeAttrForAttributedType(const AttributedType *AT) { + if (!AttrsForTypesSorted) { + std::stable_sort(AttrsForTypes.begin(), AttrsForTypes.end(), + [](const TypeAttrPair &A, const TypeAttrPair &B) { + return A.first < B.first; + }); + AttrsForTypesSorted = true; + } + + // FIXME: This is quadratic if we have lots of reuses of the same + // attributed type. + for (auto It = std::partition_point( + AttrsForTypes.begin(), AttrsForTypes.end(), + [=](const TypeAttrPair &A) { return A.first < AT; }); + It != AttrsForTypes.end() && It->first == AT; ++It) { + if (It->second) { + const Attr *Result = It->second; + It->second = nullptr; + return Result; + } + } + + llvm_unreachable("no Attr* for AttributedType*"); + } + ~TypeProcessingState() { if (trivial) return; @@ -3834,6 +3881,32 @@ return false; } +template +static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &Attr) { + Attr.setUsedAsTypeAttr(); + return ::new (Ctx) + AttrT(Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex()); +} + +static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr, + NullabilityKind NK) { + switch (NK) { + case NullabilityKind::NonNull: + return createSimpleAttr(Ctx, Attr); + + case NullabilityKind::Nullable: + return createSimpleAttr(Ctx, Attr); + + case NullabilityKind::Unspecified: + return createSimpleAttr(Ctx, Attr); + } + llvm_unreachable("unknown NullabilityKind"); +} + +static TypeSourceInfo * +GetTypeSourceInfoForDeclarator(TypeProcessingState &State, + QualType T, TypeSourceInfo *ReturnTypeInfo); + static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -4186,9 +4259,8 @@ pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), D.getDeclSpec().getLocEnd(), D.getMutableDeclSpec().getAttributes())) { - T = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*inferNullability),T,T); - attr->setUsedAsTypeAttr(); + T = state.getAttributedType( + createNullabilityAttr(Context, *attr, *inferNullability), T, T); } } } @@ -5028,7 +5100,7 @@ if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); - return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); + return GetTypeSourceInfoForDeclarator(state, T, TInfo); } /// GetTypeForDeclarator - Convert the type for the specified @@ -5164,131 +5236,25 @@ return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); } -/// Map an AttributedType::Kind to an ParsedAttr::Kind. -static ParsedAttr::Kind getAttrListKind(AttributedType::Kind kind) { - switch (kind) { - case AttributedType::attr_address_space: - return ParsedAttr::AT_AddressSpace; - case AttributedType::attr_regparm: - return ParsedAttr::AT_Regparm; - case AttributedType::attr_vector_size: - return ParsedAttr::AT_VectorSize; - case AttributedType::attr_neon_vector_type: - return ParsedAttr::AT_NeonVectorType; - case AttributedType::attr_neon_polyvector_type: - return ParsedAttr::AT_NeonPolyVectorType; - case AttributedType::attr_objc_gc: - return ParsedAttr::AT_ObjCGC; - case AttributedType::attr_objc_ownership: - case AttributedType::attr_objc_inert_unsafe_unretained: - return ParsedAttr::AT_ObjCOwnership; - case AttributedType::attr_noreturn: - return ParsedAttr::AT_NoReturn; - case AttributedType::attr_nocf_check: - return ParsedAttr::AT_AnyX86NoCfCheck; - case AttributedType::attr_cdecl: - return ParsedAttr::AT_CDecl; - case AttributedType::attr_fastcall: - return ParsedAttr::AT_FastCall; - case AttributedType::attr_stdcall: - return ParsedAttr::AT_StdCall; - case AttributedType::attr_thiscall: - return ParsedAttr::AT_ThisCall; - case AttributedType::attr_regcall: - return ParsedAttr::AT_RegCall; - case AttributedType::attr_pascal: - return ParsedAttr::AT_Pascal; - case AttributedType::attr_swiftcall: - return ParsedAttr::AT_SwiftCall; - case AttributedType::attr_vectorcall: - return ParsedAttr::AT_VectorCall; - case AttributedType::attr_pcs: - case AttributedType::attr_pcs_vfp: - return ParsedAttr::AT_Pcs; - case AttributedType::attr_inteloclbicc: - return ParsedAttr::AT_IntelOclBicc; - case AttributedType::attr_ms_abi: - return ParsedAttr::AT_MSABI; - case AttributedType::attr_sysv_abi: - return ParsedAttr::AT_SysVABI; - case AttributedType::attr_preserve_most: - return ParsedAttr::AT_PreserveMost; - case AttributedType::attr_preserve_all: - return ParsedAttr::AT_PreserveAll; - case AttributedType::attr_ptr32: - return ParsedAttr::AT_Ptr32; - case AttributedType::attr_ptr64: - return ParsedAttr::AT_Ptr64; - case AttributedType::attr_sptr: - return ParsedAttr::AT_SPtr; - case AttributedType::attr_uptr: - return ParsedAttr::AT_UPtr; - case AttributedType::attr_nonnull: - return ParsedAttr::AT_TypeNonNull; - case AttributedType::attr_nullable: - return ParsedAttr::AT_TypeNullable; - case AttributedType::attr_null_unspecified: - return ParsedAttr::AT_TypeNullUnspecified; - case AttributedType::attr_objc_kindof: - return ParsedAttr::AT_ObjCKindOf; - case AttributedType::attr_ns_returns_retained: - return ParsedAttr::AT_NSReturnsRetained; - case AttributedType::attr_lifetimebound: - return ParsedAttr::AT_LifetimeBound; - } - llvm_unreachable("unexpected attribute kind!"); -} - -static void setAttributedTypeLoc(AttributedTypeLoc TL, const ParsedAttr &attr) { - TL.setAttrNameLoc(attr.getLoc()); - if (TL.hasAttrExprOperand()) { - assert(attr.isArgExpr(0) && "mismatched attribute operand kind"); - TL.setAttrExprOperand(attr.getArgAsExpr(0)); - } else if (TL.hasAttrEnumOperand()) { - assert((attr.isArgIdent(0) || attr.isArgExpr(0)) && - "unexpected attribute operand kind"); - if (attr.isArgIdent(0)) - TL.setAttrEnumOperandLoc(attr.getArgAsIdent(0)->Loc); - else - TL.setAttrEnumOperandLoc(attr.getArgAsExpr(0)->getExprLoc()); - } - - // FIXME: preserve this information to here. - if (TL.hasAttrOperand()) - TL.setAttrOperandParensRange(SourceRange()); -} - static void fillAttributedTypeLoc(AttributedTypeLoc TL, - const ParsedAttributesView &Attrs, - const ParsedAttributesView &DeclAttrs) { - // DeclAttrs and Attrs cannot be both empty. - assert((!Attrs.empty() || !DeclAttrs.empty()) && - "no type attributes in the expected location!"); - - ParsedAttr::Kind parsedKind = getAttrListKind(TL.getAttrKind()); - // Try to search for an attribute of matching kind in Attrs list. - for (const ParsedAttr &AL : Attrs) - if (AL.getKind() == parsedKind) - return setAttributedTypeLoc(TL, AL); - - for (const ParsedAttr &AL : DeclAttrs) - if (AL.isCXX11Attribute() || AL.getKind() == parsedKind) - return setAttributedTypeLoc(TL, AL); - llvm_unreachable("no matching type attribute in expected location!"); + TypeProcessingState &State) { + TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr())); } namespace { class TypeSpecLocFiller : public TypeLocVisitor { ASTContext &Context; + TypeProcessingState &State; const DeclSpec &DS; public: - TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS) - : Context(Context), DS(DS) {} + TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State, + const DeclSpec &DS) + : Context(Context), State(State), DS(DS) {} void VisitAttributedTypeLoc(AttributedTypeLoc TL) { - fillAttributedTypeLoc(TL, DS.getAttributes(), ParsedAttributesView{}); Visit(TL.getModifiedLoc()); + fillAttributedTypeLoc(TL, State); } void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); @@ -5445,11 +5411,13 @@ class DeclaratorLocFiller : public TypeLocVisitor { ASTContext &Context; + TypeProcessingState &State; const DeclaratorChunk &Chunk; public: - DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk) - : Context(Context), Chunk(Chunk) {} + DeclaratorLocFiller(ASTContext &Context, TypeProcessingState &State, + const DeclaratorChunk &Chunk) + : Context(Context), State(State), Chunk(Chunk) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { llvm_unreachable("qualified type locs not expected here!"); @@ -5459,7 +5427,7 @@ } void VisitAttributedTypeLoc(AttributedTypeLoc TL) { - fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{}); + fillAttributedTypeLoc(TL, State); } void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing @@ -5616,10 +5584,13 @@ /// up in the normal place in the declaration specifiers (such as a C++ /// conversion function), this pointer will refer to a type source information /// for that return type. -TypeSourceInfo * -Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, - TypeSourceInfo *ReturnTypeInfo) { - TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); +static TypeSourceInfo * +GetTypeSourceInfoForDeclarator(TypeProcessingState &State, + QualType T, TypeSourceInfo *ReturnTypeInfo) { + Sema &S = State.getSema(); + Declarator &D = State.getDeclarator(); + + TypeSourceInfo *TInfo = S.Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); // Handle parameter packs whose type is a pack expansion. @@ -5629,7 +5600,6 @@ } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { - if (DependentAddressSpaceTypeLoc DASTL = CurrTL.getAs()) { fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs()); @@ -5644,8 +5614,7 @@ } while (AttributedTypeLoc TL = CurrTL.getAs()) { - fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(), - D.getAttributes()); + fillAttributedTypeLoc(TL, State); CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -5653,7 +5622,7 @@ while (AdjustedTypeLoc TL = CurrTL.getAs()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); - DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL); + DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -5664,7 +5633,7 @@ assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { - TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL); + TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL); } return TInfo; @@ -5893,7 +5862,7 @@ while (true) { // __strong id if (const AttributedType *attr = dyn_cast(type)) { - if (attr->getAttrKind() == AttributedType::attr_objc_ownership) + if (attr->getAttrKind() == attr::ObjCOwnership) return true; type = attr->getModifiedType(); @@ -6037,9 +6006,9 @@ // the coexistence problems with __unsafe_unretained. if (!S.getLangOpts().ObjCAutoRefCount && lifetime == Qualifiers::OCL_ExplicitNone) { - type = S.Context.getAttributedType( - AttributedType::attr_objc_inert_unsafe_unretained, - type, type); + type = state.getAttributedType( + createSimpleAttr(S.Context, attr), + type, type); return true; } @@ -6049,9 +6018,12 @@ // If we have a valid source location for the attribute, use an // AttributedType instead. - if (AttrLoc.isValid()) - type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, - origType, type); + if (AttrLoc.isValid()) { + type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr( + attr.getRange(), S.Context, II, + attr.getAttributeSpellingListIndex()), + origType, type); + } auto diagnoseOrDelay = [](Sema &S, SourceLocation loc, unsigned diagnostic, QualType type) { @@ -6151,8 +6123,10 @@ // Make an attributed type to preserve the source information. if (attr.getLoc().isValid()) - type = S.Context.getAttributedType(AttributedType::attr_objc_gc, - origType, type); + type = state.getAttributedType( + ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II, + attr.getAttributeSpellingListIndex()), + origType, type); return true; } @@ -6295,37 +6269,50 @@ } // end anonymous namespace static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, - ParsedAttr &Attr, QualType &Type) { + ParsedAttr &PAttr, QualType &Type) { Sema &S = State.getSema(); - ParsedAttr::Kind Kind = Attr.getKind(); + Attr *A; + switch (PAttr.getKind()) { + default: llvm_unreachable("Unknown attribute kind"); + case ParsedAttr::AT_Ptr32: + A = createSimpleAttr(S.Context, PAttr); + break; + case ParsedAttr::AT_Ptr64: + A = createSimpleAttr(S.Context, PAttr); + break; + case ParsedAttr::AT_SPtr: + A = createSimpleAttr(S.Context, PAttr); + break; + case ParsedAttr::AT_UPtr: + A = createSimpleAttr(S.Context, PAttr); + break; + } + + attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; const AttributedType *AT = dyn_cast(Type); while (AT) { - AttributedType::Kind CurAttrKind = AT->getAttrKind(); + attr::Kind CurAttrKind = AT->getAttrKind(); // You cannot specify duplicate type attributes, so if the attribute has // already been applied, flag it. - if (getAttrListKind(CurAttrKind) == Kind) { - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact) - << Attr.getName(); + if (NewAttrKind == CurAttrKind) { + S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) + << PAttr.getName(); return true; } // You cannot have both __sptr and __uptr on the same type, nor can you // have __ptr32 and __ptr64. - if ((CurAttrKind == AttributedType::attr_ptr32 && - Kind == ParsedAttr::AT_Ptr64) || - (CurAttrKind == AttributedType::attr_ptr64 && - Kind == ParsedAttr::AT_Ptr32)) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) || + (CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) { + S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__ptr32'" << "'__ptr64'"; return true; - } else if ((CurAttrKind == AttributedType::attr_sptr && - Kind == ParsedAttr::AT_UPtr) || - (CurAttrKind == AttributedType::attr_uptr && - Kind == ParsedAttr::AT_SPtr)) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + } else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) || + (CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) { + S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__sptr'" << "'__uptr'"; return true; } @@ -6336,43 +6323,66 @@ // Pointer type qualifiers can only operate on pointer types, but not // pointer-to-member types. + // + // FIXME: Should we really be disallowing this attribute if there is any + // type sugar between it and the pointer (other than attributes)? Eg, this + // disallows the attribute on a parenthesized pointer. + // And if so, should we really allow *any* type attribute? if (!isa(Desugared)) { if (Type->isMemberPointerType()) - S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers) - << Attr.getName(); + S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) + << PAttr.getName(); else - S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << Attr.getName() << 0; + S.Diag(PAttr.getLoc(), diag::err_attribute_pointers_only) + << PAttr.getName() << 0; return true; } - AttributedType::Kind TAK; - switch (Kind) { - default: llvm_unreachable("Unknown attribute kind"); - case ParsedAttr::AT_Ptr32: - TAK = AttributedType::attr_ptr32; - break; - case ParsedAttr::AT_Ptr64: - TAK = AttributedType::attr_ptr64; - break; - case ParsedAttr::AT_SPtr: - TAK = AttributedType::attr_sptr; - break; - case ParsedAttr::AT_UPtr: - TAK = AttributedType::attr_uptr; - break; - } - - Type = S.Context.getAttributedType(TAK, Type, Type); + Type = State.getAttributedType(A, Type, Type); return false; } -bool Sema::checkNullabilityTypeSpecifier(QualType &type, - NullabilityKind nullability, - SourceLocation nullabilityLoc, - bool isContextSensitive, - bool allowOnArrayType) { - recordNullabilitySeen(*this, nullabilityLoc); +/// Map a nullability attribute kind to a nullability kind. +static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) { + switch (kind) { + case ParsedAttr::AT_TypeNonNull: + return NullabilityKind::NonNull; + + case ParsedAttr::AT_TypeNullable: + return NullabilityKind::Nullable; + + case ParsedAttr::AT_TypeNullUnspecified: + return NullabilityKind::Unspecified; + + default: + llvm_unreachable("not a nullability attribute kind"); + } +} + +/// Applies a nullability type specifier to the given type, if possible. +/// +/// \param state The type processing state. +/// +/// \param type The type to which the nullability specifier will be +/// added. On success, this type will be updated appropriately. +/// +/// \param attr The attribute as written on the type. +/// +/// \param allowArrayTypes Whether to accept nullability specifiers on an +/// array type (e.g., because it will decay to a pointer). +/// +/// \returns true if a problem has been diagnosed, false on success. +static bool checkNullabilityTypeSpecifier(TypeProcessingState &state, + QualType &type, + ParsedAttr &attr, + bool allowOnArrayType) { + Sema &S = state.getSema(); + + NullabilityKind nullability = mapNullabilityAttrKind(attr.getKind()); + SourceLocation nullabilityLoc = attr.getLoc(); + bool isContextSensitive = attr.isContextSensitiveKeywordAttribute(); + + recordNullabilitySeen(S, nullabilityLoc); // Check for existing nullability attributes on the type. QualType desugared = type; @@ -6381,7 +6391,7 @@ if (auto existingNullability = attributed->getImmediateNullability()) { // Duplicated nullability. if (nullability == *existingNullability) { - Diag(nullabilityLoc, diag::warn_nullability_duplicate) + S.Diag(nullabilityLoc, diag::warn_nullability_duplicate) << DiagNullabilityKind(nullability, isContextSensitive) << FixItHint::CreateRemoval(nullabilityLoc); @@ -6389,7 +6399,7 @@ } // Conflicting nullability. - Diag(nullabilityLoc, diag::err_nullability_conflicting) + S.Diag(nullabilityLoc, diag::err_nullability_conflicting) << DiagNullabilityKind(nullability, isContextSensitive) << DiagNullabilityKind(*existingNullability, false); return true; @@ -6402,9 +6412,9 @@ // This (unlike the code above) looks through typedefs that might // have nullability specifiers on them, which means we cannot // provide a useful Fix-It. - if (auto existingNullability = desugared->getNullability(Context)) { + if (auto existingNullability = desugared->getNullability(S.Context)) { if (nullability != *existingNullability) { - Diag(nullabilityLoc, diag::err_nullability_conflicting) + S.Diag(nullabilityLoc, diag::err_nullability_conflicting) << DiagNullabilityKind(nullability, isContextSensitive) << DiagNullabilityKind(*existingNullability, false); @@ -6415,7 +6425,7 @@ if (auto typedefNullability = AttributedType::stripOuterNullability(underlyingType)) { if (*typedefNullability == *existingNullability) { - Diag(typedefDecl->getLocation(), diag::note_nullability_here) + S.Diag(typedefDecl->getLocation(), diag::note_nullability_here) << DiagNullabilityKind(*existingNullability, false); } } @@ -6428,7 +6438,7 @@ // If this definitely isn't a pointer type, reject the specifier. if (!desugared->canHaveNullability() && !(allowOnArrayType && desugared->isArrayType())) { - Diag(nullabilityLoc, diag::err_nullability_nonpointer) + S.Diag(nullabilityLoc, diag::err_nullability_nonpointer) << DiagNullabilityKind(nullability, isContextSensitive) << type; return true; } @@ -6446,10 +6456,10 @@ if (pointeeType->isAnyPointerType() || pointeeType->isObjCObjectPointerType() || pointeeType->isMemberPointerType()) { - Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) + S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) << DiagNullabilityKind(nullability, true) << type; - Diag(nullabilityLoc, diag::note_nullability_type_specifier) + S.Diag(nullabilityLoc, diag::note_nullability_type_specifier) << DiagNullabilityKind(nullability, false) << type << FixItHint::CreateReplacement(nullabilityLoc, @@ -6459,16 +6469,21 @@ } // Form the attributed type. - type = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(nullability), type, type); + type = state.getAttributedType( + createNullabilityAttr(S.Context, attr, nullability), type, type); return false; } -bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { +/// Check the application of the Objective-C '__kindof' qualifier to +/// the given type. +static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type, + ParsedAttr &attr) { + Sema &S = state.getSema(); + if (isa(type)) { // Build the attributed type to record where __kindof occurred. - type = Context.getAttributedType(AttributedType::attr_objc_kindof, - type, type); + type = state.getAttributedType( + createSimpleAttr(S.Context, attr), type, type); return false; } @@ -6480,7 +6495,7 @@ // If not, we can't apply __kindof. if (!objType) { // FIXME: Handle dependent types that aren't yet object types. - Diag(loc, diag::err_objc_kindof_nonobject) + S.Diag(attr.getLoc(), diag::err_objc_kindof_nonobject) << type; return true; } @@ -6488,45 +6503,31 @@ // Rebuild the "equivalent" type, which pushes __kindof down into // the object type. // There is no need to apply kindof on an unqualified id type. - QualType equivType = Context.getObjCObjectType( + QualType equivType = S.Context.getObjCObjectType( objType->getBaseType(), objType->getTypeArgsAsWritten(), objType->getProtocols(), /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true); // If we started with an object pointer type, rebuild it. if (ptrType) { - equivType = Context.getObjCObjectPointerType(equivType); - if (auto nullability = type->getNullability(Context)) { - auto attrKind = AttributedType::getNullabilityAttrKind(*nullability); - equivType = Context.getAttributedType(attrKind, equivType, equivType); + equivType = S.Context.getObjCObjectPointerType(equivType); + if (auto nullability = type->getNullability(S.Context)) { + // We create a nullability attribute from the __kindof attribute. + // Make sure that will make sense. + assert(attr.getAttributeSpellingListIndex() == 0 && + "multiple spellings for __kindof?"); + Attr *A = createNullabilityAttr(S.Context, attr, *nullability); + A->setImplicit(true); + equivType = state.getAttributedType(A, equivType, equivType); } } // Build the attributed type to record where __kindof occurred. - type = Context.getAttributedType(AttributedType::attr_objc_kindof, - type, - equivType); - + type = state.getAttributedType( + createSimpleAttr(S.Context, attr), type, equivType); return false; } -/// Map a nullability attribute kind to a nullability kind. -static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) { - switch (kind) { - case ParsedAttr::AT_TypeNonNull: - return NullabilityKind::NonNull; - - case ParsedAttr::AT_TypeNullable: - return NullabilityKind::Nullable; - - case ParsedAttr::AT_TypeNullUnspecified: - return NullabilityKind::Unspecified; - - default: - llvm_unreachable("not a nullability attribute kind"); - } -} - /// Distribute a nullability type attribute that cannot be applied to /// the type specifier to a pointer, block pointer, or member pointer /// declarator, complaining if necessary. @@ -6614,27 +6615,27 @@ return false; } -static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) { +static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { assert(!Attr.isInvalid()); switch (Attr.getKind()) { default: llvm_unreachable("not a calling convention attribute"); case ParsedAttr::AT_CDecl: - return AttributedType::attr_cdecl; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_FastCall: - return AttributedType::attr_fastcall; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_StdCall: - return AttributedType::attr_stdcall; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_ThisCall: - return AttributedType::attr_thiscall; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_RegCall: - return AttributedType::attr_regcall; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_Pascal: - return AttributedType::attr_pascal; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_SwiftCall: - return AttributedType::attr_swiftcall; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_VectorCall: - return AttributedType::attr_vectorcall; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_Pcs: { // The attribute may have had a fixit applied where we treated an // identifier as a string literal. The contents of the string are valid, @@ -6644,20 +6645,22 @@ Str = cast(Attr.getArgAsExpr(0))->getString(); else Str = Attr.getArgAsIdent(0)->Ident->getName(); - return llvm::StringSwitch(Str) - .Case("aapcs", AttributedType::attr_pcs) - .Case("aapcs-vfp", AttributedType::attr_pcs_vfp); + PcsAttr::PCSType Type; + if (!PcsAttr::ConvertStrToPCSType(Str, Type)) + llvm_unreachable("already validated the attribute"); + return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type, + Attr.getAttributeSpellingListIndex()); } case ParsedAttr::AT_IntelOclBicc: - return AttributedType::attr_inteloclbicc; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_MSABI: - return AttributedType::attr_ms_abi; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_SysVABI: - return AttributedType::attr_sysv_abi; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_PreserveMost: - return AttributedType::attr_preserve_most; + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_PreserveAll: - return AttributedType::attr_preserve_all; + return createSimpleAttr(Ctx, Attr); } llvm_unreachable("unexpected attribute kind!"); } @@ -6705,8 +6708,9 @@ = unwrapped.get()->getExtInfo().withProducesResult(true); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); } - type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained, - origType, type); + type = state.getAttributedType( + createSimpleAttr(S.Context, attr), + origType, type); return true; } @@ -6781,13 +6785,12 @@ const FunctionType *fn = unwrapped.get(); CallingConv CCOld = fn->getCallConv(); - AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr); + Attr *CCAttr = getCCTypeAttr(S.Context, attr); if (CCOld != CC) { // Error out on when there's already an attribute on the type // and the CCs don't match. - const AttributedType *AT = S.getCallingConvAttributedType(type); - if (AT && AT->getAttrKind() != CCAttrKind) { + if (const AttributedType *AT = S.getCallingConvAttributedType(type)) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << FunctionType::getNameForCallConv(CCOld); @@ -6841,7 +6844,7 @@ Equivalent = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); } - type = S.Context.getAttributedType(CCAttrKind, type, Equivalent); + type = state.getAttributedType(CCAttr, type, Equivalent); return true; } @@ -7196,14 +7199,15 @@ T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr); } -static void HandleLifetimeBoundAttr(QualType &CurType, - const ParsedAttr &Attr, - Sema &S, Declarator &D) { - if (D.isDeclarationOfFunction()) { - CurType = S.Context.getAttributedType(AttributedType::attr_lifetimebound, - CurType, CurType); +static void HandleLifetimeBoundAttr(TypeProcessingState &State, + QualType &CurType, + ParsedAttr &Attr) { + if (State.getDeclarator().isDeclarationOfFunction()) { + CurType = State.getAttributedType( + createSimpleAttr(State.getSema().Context, Attr), + CurType, CurType); } else { - Attr.diagnoseAppertainsTo(S, nullptr); + Attr.diagnoseAppertainsTo(State.getSema(), nullptr); } } @@ -7313,11 +7317,8 @@ attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_LifetimeBound: - if (TAL == TAL_DeclChunk) { - HandleLifetimeBoundAttr(type, attr, state.getSema(), - state.getDeclarator()); - attr.setUsedAsTypeAttr(); - } + if (TAL == TAL_DeclChunk) + HandleLifetimeBoundAttr(state, type, attr); break; MS_TYPE_ATTRS_CASELIST: @@ -7341,11 +7342,10 @@ bool allowOnArrayType = state.getDeclarator().isPrototypeContext() && !hasOuterPointerLikeChunk(state.getDeclarator(), endIndex); - if (state.getSema().checkNullabilityTypeSpecifier( + if (checkNullabilityTypeSpecifier( + state, type, - mapNullabilityAttrKind(attr.getKind()), - attr.getLoc(), - attr.isContextSensitiveKeywordAttribute(), + attr, allowOnArrayType)) { attr.setInvalid(); } @@ -7371,9 +7371,8 @@ } // Apply it regardless. - if (state.getSema().checkObjCKindOfType(type, attr.getLoc())) + if (checkObjCKindOfType(state, type, attr)) attr.setInvalid(); - attr.setUsedAsTypeAttr(); break; FUNCTION_TYPE_ATTRS_CASELIST: Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -6058,6 +6058,11 @@ if (modifiedType.isNull()) return QualType(); + const Attr *oldAttr = TL.getAttr(); + const Attr *newAttr = getDerived().TransformAttr(oldAttr); + if (!newAttr) + return QualType(); + QualType result = TL.getType(); // FIXME: dependent operand expressions? @@ -6074,26 +6079,20 @@ // type sugar, and therefore cannot be diagnosed in any other way. if (auto nullability = oldType->getImmediateNullability()) { if (!modifiedType->canHaveNullability()) { - SemaRef.Diag(TL.getAttrNameLoc(), diag::err_nullability_nonpointer) - << DiagNullabilityKind(*nullability, false) << modifiedType; + SemaRef.Diag(TL.getAttr()->getLocation(), + diag::err_nullability_nonpointer) + << DiagNullabilityKind(*nullability, false) << modifiedType; return QualType(); } } - result = SemaRef.Context.getAttributedType(oldType->getAttrKind(), + result = SemaRef.Context.getAttributedType(newAttr->getKind(), modifiedType, equivalentType); } AttributedTypeLoc newTL = TLB.push(result); - newTL.setAttrNameLoc(TL.getAttrNameLoc()); - if (TL.hasAttrOperand()) - newTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); - if (TL.hasAttrExprOperand()) - newTL.setAttrExprOperand(TL.getAttrExprOperand()); - else if (TL.hasAttrEnumOperand()) - newTL.setAttrEnumOperandLoc(TL.getAttrEnumOperandLoc()); - + newTL.setAttr(newAttr); return result; } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -6455,6 +6455,10 @@ return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx); } + Attr *ReadAttr() { + return Reader->ReadAttr(*F, Record, Idx); + } + public: TypeLocReader(ModuleFile &F, ASTReader &Reader, const ASTReader::RecordData &Record, unsigned &Idx) @@ -6646,20 +6650,7 @@ } void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { - TL.setAttrNameLoc(ReadSourceLocation()); - if (TL.hasAttrOperand()) { - SourceRange range; - range.setBegin(ReadSourceLocation()); - range.setEnd(ReadSourceLocation()); - TL.setAttrOperandParensRange(range); - } - if (TL.hasAttrExprOperand()) { - if (Record[Idx++]) - TL.setAttrExprOperand(Reader->ReadExpr(*F)); - else - TL.setAttrExprOperand(nullptr); - } else if (TL.hasAttrEnumOperand()) - TL.setAttrEnumOperandLoc(ReadSourceLocation()); + TL.setAttr(ReadAttr()); } void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -2642,19 +2642,72 @@ // Attribute Reading //===----------------------------------------------------------------------===// +namespace { +class AttrReader { + ModuleFile *F; + ASTReader *Reader; + const ASTReader::RecordData &Record; + unsigned &Idx; + +public: + AttrReader(ModuleFile &F, ASTReader &Reader, + const ASTReader::RecordData &Record, unsigned &Idx) + : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {} + + const uint64_t &readInt() { return Record[Idx++]; } + + SourceRange readSourceRange() { + return Reader->ReadSourceRange(*F, Record, Idx); + } + + Expr *readExpr() { return Reader->ReadExpr(*F); } + + std::string readString() { + return Reader->ReadString(Record, Idx); + } + + TypeSourceInfo *getTypeSourceInfo() { + return Reader->GetTypeSourceInfo(*F, Record, Idx); + } + + IdentifierInfo *getIdentifierInfo() { + return Reader->GetIdentifierInfo(*F, Record, Idx); + } + + VersionTuple readVersionTuple() { + return ASTReader::ReadVersionTuple(Record, Idx); + } + + template T *GetLocalDeclAs(uint32_t LocalID) { + return cast_or_null(Reader->GetLocalDecl(*F, LocalID)); + } +}; +} + +Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec, + unsigned &Idx) { + AttrReader Record(M, *this, Rec, Idx); + auto V = Record.readInt(); + if (!V) + return nullptr; + + Attr *New = nullptr; + // Kind is stored as a 1-based integer because 0 is used to indicate a null + // Attr pointer. + auto Kind = static_cast(V - 1); + SourceRange Range = Record.readSourceRange(); + ASTContext &Context = getContext(); + +#include "clang/Serialization/AttrPCHRead.inc" + + assert(New && "Unable to decode attribute?"); + return New; +} + /// Reads attributes from the current stream position. void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) { - for (unsigned i = 0, e = Record.readInt(); i != e; ++i) { - Attr *New = nullptr; - auto Kind = (attr::Kind)Record.readInt(); - SourceRange Range = Record.readSourceRange(); - ASTContext &Context = getContext(); - -#include "clang/Serialization/AttrPCHRead.inc" - - assert(New && "Unable to decode attribute?"); - Attrs.push_back(New); - } + for (unsigned I = 0, E = Record.readInt(); I != E; ++I) + Attrs.push_back(Record.readAttr()); } //===----------------------------------------------------------------------===// Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -770,19 +770,7 @@ } void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) { - Record.AddSourceLocation(TL.getAttrNameLoc()); - if (TL.hasAttrOperand()) { - SourceRange range = TL.getAttrOperandParensRange(); - Record.AddSourceLocation(range.getBegin()); - Record.AddSourceLocation(range.getEnd()); - } - if (TL.hasAttrExprOperand()) { - Expr *operand = TL.getAttrExprOperand(); - Record.push_back(operand ? 1 : 0); - if (operand) Record.AddStmt(operand); - } else if (TL.hasAttrEnumOperand()) { - Record.AddSourceLocation(TL.getAttrEnumOperandLoc()); - } + Record.AddAttr(TL.getAttr()); } void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { @@ -4481,16 +4469,21 @@ // General Serialization Routines //===----------------------------------------------------------------------===// -/// Emit the list of attributes to the specified record. -void ASTRecordWriter::AddAttributes(ArrayRef Attrs) { +void ASTRecordWriter::AddAttr(const Attr *A) { auto &Record = *this; - Record.push_back(Attrs.size()); - for (const auto *A : Attrs) { - Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs - Record.AddSourceRange(A->getRange()); + if (!A) + return Record.push_back(0); + Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs + Record.AddSourceRange(A->getRange()); #include "clang/Serialization/AttrPCHWrite.inc" - } +} + +/// Emit the list of attributes to the specified record. +void ASTRecordWriter::AddAttributes(ArrayRef Attrs) { + push_back(Attrs.size()); + for (const auto *A : Attrs) + AddAttr(A); } void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { Index: lib/StaticAnalyzer/Core/CheckerHelpers.cpp =================================================================== --- lib/StaticAnalyzer/Core/CheckerHelpers.cpp +++ lib/StaticAnalyzer/Core/CheckerHelpers.cpp @@ -103,9 +103,9 @@ const auto *AttrType = Type->getAs(); if (!AttrType) return Nullability::Unspecified; - if (AttrType->getAttrKind() == AttributedType::attr_nullable) + if (AttrType->getAttrKind() == attr::TypeNullable) return Nullability::Nullable; - else if (AttrType->getAttrKind() == AttributedType::attr_nonnull) + else if (AttrType->getAttrKind() == attr::TypeNonNull) return Nullability::Nonnull; return Nullability::Unspecified; } Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2470,8 +2470,10 @@ static const AttrClassDescriptor AttrClassDescriptors[] = { { "ATTR", "Attr" }, + { "TYPE_ATTR", "TypeAttr" }, { "STMT_ATTR", "StmtAttr" }, { "INHERITABLE_ATTR", "InheritableAttr" }, + { "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" }, { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" }, { "PARAMETER_ABI_ATTR", "ParameterABIAttr" } };