From 3ae8feb8a46079a603edbec37886faa2adf4afcd Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 14 Aug 2018 01:55:37 +0000 Subject: [PATCH] Revert r339623 "Model type attributes as regular Attrs." This breaks compiling atlwin.h in Chromium. I'm sure the code is invalid in some way, but we put a lot of work into accepting it, and I'm sure rejecting it was not an intended consequence of this refactoring. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@339638 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 3 +- include/clang/AST/Attr.h | 13 - include/clang/AST/Type.h | 75 ++- include/clang/AST/TypeLoc.h | 91 ++- include/clang/Basic/Attr.td | 32 +- include/clang/Sema/Sema.h | 30 + include/clang/Serialization/ASTReader.h | 8 - include/clang/Serialization/ASTWriter.h | 3 - lib/ARCMigrate/TransGCAttrs.cpp | 15 +- lib/ARCMigrate/Transforms.cpp | 2 +- lib/AST/ASTContext.cpp | 2 +- lib/AST/Type.cpp | 177 +++-- lib/AST/TypeLoc.cpp | 10 +- lib/AST/TypePrinter.cpp | 161 +++-- lib/Sema/SemaDecl.cpp | 10 +- lib/Sema/SemaExpr.cpp | 8 +- lib/Sema/SemaInit.cpp | 2 +- lib/Sema/SemaObjCProperty.cpp | 4 +- lib/Sema/SemaType.cpp | 715 +++++++++++---------- lib/Sema/TreeTransform.h | 21 +- lib/Serialization/ASTReader.cpp | 19 +- lib/Serialization/ASTReaderDecl.cpp | 73 +-- lib/Serialization/ASTWriter.cpp | 35 +- lib/StaticAnalyzer/Core/CheckerHelpers.cpp | 4 +- utils/TableGen/ClangAttrEmitter.cpp | 2 - 25 files changed, 835 insertions(+), 680 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 87f0e8f150..ea07d5f80e 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -31,7 +31,6 @@ #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" @@ -1423,7 +1422,7 @@ public: QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; - QualType getAttributedType(attr::Kind attrKind, + QualType getAttributedType(AttributedType::Kind attrKind, QualType modifiedType, QualType equivalentType); diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 4ee083934c..20922742f6 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -113,19 +113,6 @@ public: 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, diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9bc1a53732..93dafc47dd 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -21,7 +21,6 @@ #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" @@ -1871,16 +1870,7 @@ public: bool isObjCQualifiedClassType() const; // Class bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id - - /// 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); - } + bool isObjCInertUnsafeUnretainedType() const; /// Whether the type is Objective-C 'id' or a __kindof type of an /// object type, e.g., __kindof NSView * or __kindof id @@ -2094,10 +2084,6 @@ public: /// 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. @@ -4207,7 +4193,56 @@ public: /// - the canonical type is VectorType(16, int) class AttributedType : public Type, public llvm::FoldingSetNode { public: - using Kind = attr::Kind; + // 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, + }; private: friend class ASTContext; // ASTContext creates these @@ -4215,7 +4250,7 @@ private: QualType ModifiedType; QualType EquivalentType; - AttributedType(QualType canon, attr::Kind attrKind, QualType modified, + AttributedType(QualType canon, Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), @@ -4264,13 +4299,13 @@ public: static Kind getNullabilityAttrKind(NullabilityKind kind) { switch (kind) { case NullabilityKind::NonNull: - return attr::TypeNonNull; + return attr_nonnull; case NullabilityKind::Nullable: - return attr::TypeNullable; + return attr_nullable; case NullabilityKind::Unspecified: - return attr::TypeNullUnspecified; + return attr_null_unspecified; } llvm_unreachable("Unknown nullability kind."); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 7ac8dedd3c..82e83eacc6 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -15,7 +15,6 @@ #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" @@ -850,7 +849,16 @@ class SubstTemplateTypeParmPackTypeLoc : }; struct AttributedLocInfo { - const Attr *TypeAttr; + union { + Expr *ExprOperand; + + /// A raw SourceLocation. + unsigned EnumOperandLoc; + }; + + SourceRange OperandParens; + + SourceLocation AttrLoc; }; /// Type source information for an attributed type. @@ -859,10 +867,24 @@ class AttributedTypeLoc : public ConcreteTypeLoc { public: - attr::Kind getAttrKind() const { + AttributedType::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(); } @@ -875,16 +897,51 @@ public: return getInnerTypeLoc(); } - /// The type attribute. - const Attr *getAttr() const { - return getLocalData()->TypeAttr; + /// The location of the attribute name, i.e. + /// __attribute__((regparm(1000))) + /// ^~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; } - void setAttr(const Attr *A) { - getLocalData()->TypeAttr = A; + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; } - template const T *getAttrAs() { - return dyn_cast_or_null(getAttr()); + /// 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; } SourceRange getLocalSourceRange() const { @@ -897,11 +954,21 @@ public: // ^~ ~~ // That enclosure doesn't necessarily belong to a single attribute // anyway. - return getAttr() ? getAttr()->getRange() : SourceRange(); + SourceRange range(getAttrNameLoc()); + if (hasAttrOperand()) + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; } void initializeLocal(ASTContext &Context, SourceLocation loc) { - setAttr(nullptr); + setAttrNameLoc(loc); + if (hasAttrExprOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(nullptr); + } else if (hasAttrEnumOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrEnumOperandLoc(loc); + } } QualType getInnerType() const { diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 736126b2aa..7591635176 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -494,7 +494,10 @@ class Attr { } /// A type attribute is not processed on a declaration or a statement. -class TypeAttr : Attr; +class TypeAttr : Attr { + // By default, type attributes do not get an AST node. + let ASTNode = 0; +} /// A stmt attribute is not processed on a declaration or a type. class StmtAttr : Attr; @@ -564,8 +567,6 @@ def AddressSpace : TypeAttr { 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 { @@ -1223,7 +1224,7 @@ def LayoutVersion : InheritableAttr, TargetSpecificAttr { let Documentation = [LayoutVersionDocs]; } -def LifetimeBound : DeclOrTypeAttr { +def LifetimeBound : InheritableAttr { let Spellings = [Clang<"lifetimebound", 0>]; let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>; let Documentation = [LifetimeBoundDocs]; @@ -1326,16 +1327,12 @@ def NeonPolyVectorType : TypeAttr { 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 { @@ -1510,14 +1507,6 @@ def TypeNullUnspecified : TypeAttr { 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]; @@ -1605,7 +1594,7 @@ def ObjCBridgeRelated : InheritableAttr { let Documentation = [Undocumented]; } -def NSReturnsRetained : DeclOrTypeAttr { +def NSReturnsRetained : InheritableAttr { let Spellings = [Clang<"ns_returns_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; @@ -1790,8 +1779,6 @@ def Regparm : TypeAttr { 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 { @@ -2080,9 +2067,10 @@ def ObjCGC : TypeAttr { let Documentation = [Undocumented]; } -def ObjCOwnership : DeclOrTypeAttr { +def ObjCOwnership : InheritableAttr { let Spellings = [Clang<"objc_ownership">]; let Args = [IdentifierArgument<"Kind">]; + let ASTNode = 0; let Documentation = [Undocumented]; } @@ -2120,8 +2108,6 @@ def VectorSize : TypeAttr { let Spellings = [GCC<"vector_size">]; let Args = [ExprArgument<"NumBytes">]; let Documentation = [Undocumented]; - // Represented as VectorType instead. - let ASTNode = 0; } def VecTypeHint : InheritableAttr { @@ -2216,7 +2202,7 @@ def AnyX86NoCallerSavedRegisters : InheritableAttr, let Documentation = [AnyX86NoCallerSavedRegistersDocs]; } -def AnyX86NoCfCheck : DeclOrTypeAttr, TargetSpecificAttr{ +def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr{ let Spellings = [GCC<"nocf_check">]; let Subjects = SubjectList<[FunctionLike]>; let Documentation = [AnyX86NoCfCheckDocs]; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c70e6dcdee..b3d1c96bdf 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1435,6 +1435,8 @@ public: 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); @@ -3376,6 +3378,30 @@ public: /// 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, @@ -8045,6 +8071,10 @@ public: 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. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 1efadc7435..b959f596f9 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -2245,9 +2245,6 @@ public: 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); @@ -2633,11 +2630,6 @@ public: 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); diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 1a89a9e14a..7ff5d65bd7 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -955,9 +955,6 @@ public: return Writer->AddVersionTuple(Version, *Record); } - // Emit an attribute. - void AddAttr(const Attr *A); - /// Emit a list of attributes. void AddAttributes(ArrayRef Attrs); }; diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp index 06f8a23e7e..fb45cd92c1 100644 --- a/lib/ARCMigrate/TransGCAttrs.cpp +++ b/lib/ARCMigrate/TransGCAttrs.cpp @@ -81,11 +81,10 @@ public: } bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) { - auto *OwnershipAttr = TL.getAttrAs(); - if (!OwnershipAttr) + if (TL.getAttrKind() != AttributedType::attr_objc_ownership) return false; - SourceLocation Loc = OwnershipAttr->getLocation(); + SourceLocation Loc = TL.getAttrNameLoc(); unsigned RawLoc = Loc.getRawEncoding(); if (MigrateCtx.AttrSet.count(RawLoc)) return true; @@ -94,7 +93,13 @@ public: SourceManager &SM = Ctx.getSourceManager(); if (Loc.isMacroID()) Loc = SM.getImmediateExpansionRange(Loc).getBegin(); - StringRef Spell = OwnershipAttr->getKind()->getName(); + SmallString<32> Buf; + bool Invalid = false; + StringRef Spell = Lexer::getSpelling( + SM.getSpellingLoc(TL.getAttrEnumOperandLoc()), + Buf, SM, Ctx.getLangOpts(), &Invalid); + if (Invalid) + return false; MigrationContext::GCAttrOccurrence::AttrKind Kind; if (Spell == "strong") Kind = MigrationContext::GCAttrOccurrence::Strong; @@ -279,7 +284,7 @@ static void checkAllAtProps(MigrationContext &MigrateCtx, } for (unsigned i = 0, e = ATLs.size(); i != e; ++i) { - SourceLocation Loc = ATLs[i].first.getAttr()->getLocation(); + SourceLocation Loc = ATLs[i].first.getAttrNameLoc(); if (Loc.isMacroID()) Loc = MigrateCtx.Pass.Ctx.getSourceManager() .getImmediateExpansionRange(Loc) diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index a403744de7..4a7af28588 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -359,7 +359,7 @@ MigrationContext::~MigrationContext() { bool MigrationContext::isGCOwnedNonObjC(QualType T) { while (!T.isNull()) { if (const AttributedType *AttrT = T->getAs()) { - if (AttrT->getAttrKind() == attr::ObjCOwnership) + if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership) return !AttrT->getModifiedType()->isObjCRetainableType(); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 45703cc24c..b96e24ae0f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3876,7 +3876,7 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const { return QualType(newType, 0); } -QualType ASTContext::getAttributedType(attr::Kind attrKind, +QualType ASTContext::getAttributedType(AttributedType::Kind attrKind, QualType modifiedType, QualType equivalentType) { llvm::FoldingSetNodeID id; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 333b07e887..315844fa42 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -592,6 +592,28 @@ bool Type::isObjCClassOrClassKindOfType() const { 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) @@ -1619,16 +1641,6 @@ TagDecl *Type::getAsTagDecl() const { 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 : @@ -3155,58 +3167,105 @@ bool RecordType::hasConstFields() const { } 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 attr::ObjCGC: - case attr::ObjCOwnership: - case attr::ObjCInertUnsafeUnretained: - case attr::TypeNonNull: - case attr::TypeNullable: - case attr::TypeNullUnspecified: - case attr::LifetimeBound: + 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: return true; - // All other type attributes aren't qualifiers; they rewrite the modified - // type to be a semantically different type. - default: + // 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: 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()) { - 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: + 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: return true; } llvm_unreachable("invalid attr kind"); @@ -3649,18 +3708,23 @@ LinkageInfo Type::getLinkageAndVisibility() const { return LinkageComputer{}.getTypeLinkageAndVisibility(this); } -Optional -Type::getNullability(const ASTContext &Context) const { - QualType Type(this, 0); - while (const auto *AT = Type->getAs()) { +Optional Type::getNullability(const ASTContext &context) const { + QualType type(this, 0); + do { // Check whether this is an attributed type with nullability // information. - if (auto Nullability = AT->getImmediateNullability()) - return Nullability; + if (auto attributed = dyn_cast(type.getTypePtr())) { + if (auto nullability = attributed->getImmediateNullability()) + return nullability; + } - Type = AT->getEquivalentType(); - } - return None; + // 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); } bool Type::canHaveNullability(bool ResultIfUnknown) const { @@ -3773,13 +3837,12 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { llvm_unreachable("bad type kind!"); } -llvm::Optional -AttributedType::getImmediateNullability() const { - if (getAttrKind() == attr::TypeNonNull) +llvm::Optional AttributedType::getImmediateNullability() const { + if (getAttrKind() == AttributedType::attr_nonnull) return NullabilityKind::NonNull; - if (getAttrKind() == attr::TypeNullable) + if (getAttrKind() == AttributedType::attr_nullable) return NullabilityKind::Nullable; - if (getAttrKind() == attr::TypeNullUnspecified) + if (getAttrKind() == AttributedType::attr_null_unspecified) return NullabilityKind::Unspecified; return None; } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index b6dc679bbf..e4fd6f106e 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -404,11 +404,11 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { } SourceLocation TypeLoc::findNullabilityLoc() const { - if (auto ATL = getAs()) { - const Attr *A = ATL.getAttr(); - if (A && (isa(A) || isa(A) || - isa(A))) - return A->getLocation(); + if (auto attributedLoc = getAs()) { + if (attributedLoc.getAttrKind() == AttributedType::attr_nullable || + attributedLoc.getAttrKind() == AttributedType::attr_nonnull || + attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified) + return attributedLoc.getAttrNameLoc(); } return {}; diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index d86849f64f..1cb5ff46b5 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -1354,14 +1354,12 @@ void TypePrinter::printPackExpansionAfter(const PackExpansionType *T, 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() == attr::ObjCGC || - T->getAttrKind() == attr::ObjCOwnership) + if (T->getAttrKind() == AttributedType::attr_objc_gc || + T->getAttrKind() == AttributedType::attr_objc_ownership) return printBefore(T->getEquivalentType(), OS); - if (T->getAttrKind() == attr::ObjCKindOf) + if (T->getAttrKind() == AttributedType::attr_objc_kindof) OS << "__kindof "; printBefore(T->getModifiedType(), OS); @@ -1369,21 +1367,23 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, if (T->isMSTypeSpec()) { switch (T->getAttrKind()) { default: return; - case attr::Ptr32: OS << " __ptr32"; break; - case attr::Ptr64: OS << " __ptr64"; break; - case attr::SPtr: OS << " __sptr"; break; - case attr::UPtr: OS << " __uptr"; break; + 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; } spaceBeforePlaceHolder(OS); } // Print nullability type specifiers. - if (T->getImmediateNullability()) { - if (T->getAttrKind() == attr::TypeNonNull) + if (T->getAttrKind() == AttributedType::attr_nonnull || + T->getAttrKind() == AttributedType::attr_nullable || + T->getAttrKind() == AttributedType::attr_null_unspecified) { + if (T->getAttrKind() == AttributedType::attr_nonnull) OS << " _Nonnull"; - else if (T->getAttrKind() == attr::TypeNullable) + else if (T->getAttrKind() == AttributedType::attr_nullable) OS << " _Nullable"; - else if (T->getAttrKind() == attr::TypeNullUnspecified) + else if (T->getAttrKind() == AttributedType::attr_null_unspecified) OS << " _Null_unspecified"; else llvm_unreachable("unhandled nullability"); @@ -1393,11 +1393,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, 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() == attr::ObjCGC || - T->getAttrKind() == attr::ObjCOwnership) + if (T->getAttrKind() == AttributedType::attr_objc_gc || + T->getAttrKind() == AttributedType::attr_objc_ownership) return printAfter(T->getEquivalentType(), OS); // If this is a calling convention attribute, don't print the implicit CC from @@ -1408,74 +1406,107 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, // Some attributes are printed as qualifiers before the type, so we have // nothing left to do. - if (T->getAttrKind() == attr::ObjCKindOf || - T->isMSTypeSpec() || T->getImmediateNullability()) + 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) return; // Don't print the inert __unsafe_unretained attribute at all. - if (T->getAttrKind() == attr::ObjCInertUnsafeUnretained) + if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained) return; // Don't print ns_returns_retained unless it had an effect. - if (T->getAttrKind() == attr::NSReturnsRetained && + if (T->getAttrKind() == AttributedType::attr_ns_returns_retained && !T->getEquivalentType()->castAs() ->getExtInfo().getProducesResult()) return; - if (T->getAttrKind() == attr::LifetimeBound) { + if (T->getAttrKind() == AttributedType::attr_lifetimebound) { OS << " [[clang::lifetimebound]]"; return; } OS << " __attribute__(("; switch (T->getAttrKind()) { -#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: + 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: llvm_unreachable("This attribute should have been handled already"); - case attr::NSReturnsRetained: + 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: OS << "ns_returns_retained"; break; // FIXME: When Sema learns to form this AttributedType, avoid printing the // attribute again in printFunctionProtoAfter. - 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: { + 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: { OS << "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) @@ -1486,12 +1517,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, break; } - case attr::IntelOclBicc: OS << "inteloclbicc"; break; - case attr::PreserveMost: + case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break; + case AttributedType::attr_preserve_most: OS << "preserve_most"; break; - case attr::PreserveAll: + case AttributedType::attr_preserve_all: OS << "preserve_all"; break; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e62728c124..abdeba60be 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5999,14 +5999,14 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // 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 (const auto *A = ATL.getAttrAs()) { + if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) { const auto *MD = dyn_cast(FD); if (!MD || MD->isStatic()) { - S.Diag(A->getLocation(), diag::err_lifetimebound_no_object_param) - << !MD << A->getRange(); + S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_no_object_param) + << !MD << ATL.getLocalSourceRange(); } else if (isa(MD) || isa(MD)) { - S.Diag(A->getLocation(), diag::err_lifetimebound_ctor_dtor) - << isa(MD) << A->getRange(); + S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor) + << isa(MD) << ATL.getLocalSourceRange(); } } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index baa114b350..1259d25629 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14658,15 +14658,15 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, // 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::ObjCOwnership in Ty. The existence of AttributedType of kind - // attr::ObjCOwnership implies __autoreleasing was explicitly specified + // attr_objc_ownership in Ty. The existence of AttributedType of kind + // attr_objc_ownership 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() == attr::ObjCOwnership) + if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership) return true; - // Peel off AttributedTypes that are not of kind ObjCOwnership. + // Peel off AttributedTypes that are not of kind objc_ownership. Ty = AttrTy->getModifiedType(); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0d3e3d4c47..766f23b05b 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -6360,7 +6360,7 @@ static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) { for (TypeLoc TL = TSI->getTypeLoc(); (ATL = TL.getAsAdjusted()); TL = ATL.getModifiedLoc()) { - if (ATL.getAttrAs()) + if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) return true; } return false; diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index ab7b83c4c3..3aad25b73a 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -2384,7 +2384,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { QualType modifiedTy = resultTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) { if (*nullability == NullabilityKind::Unspecified) - resultTy = Context.getAttributedType(attr::TypeNonNull, + resultTy = Context.getAttributedType(AttributedType::attr_nonnull, modifiedTy, modifiedTy); } } @@ -2458,7 +2458,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { QualType modifiedTy = paramTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){ if (*nullability == NullabilityKind::Unspecified) - paramTy = Context.getAttributedType(attr::TypeNullable, + paramTy = Context.getAttributedType(AttributedType::attr_nullable, modifiedTy, modifiedTy); } } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index bad6616249..486d8ac4ed 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -172,16 +172,6 @@ namespace { /// 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), @@ -240,43 +230,6 @@ namespace { 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; @@ -3879,32 +3832,6 @@ static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) { 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) { @@ -4257,8 +4184,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), D.getDeclSpec().getEndLoc(), D.getMutableDeclSpec().getAttributes())) { - T = state.getAttributedType( - createNullabilityAttr(Context, *attr, *inferNullability), T, T); + T = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*inferNullability),T,T); + attr->setUsedAsTypeAttr(); } } } @@ -5097,7 +5025,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); - return GetTypeSourceInfoForDeclarator(state, T, TInfo); + return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); } /// GetTypeForDeclarator - Convert the type for the specified @@ -5233,25 +5161,131 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { 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, - TypeProcessingState &State) { - TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr())); + 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!"); } namespace { class TypeSpecLocFiller : public TypeLocVisitor { ASTContext &Context; - TypeProcessingState &State; const DeclSpec &DS; public: - TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State, - const DeclSpec &DS) - : Context(Context), State(State), DS(DS) {} + TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS) + : Context(Context), DS(DS) {} void VisitAttributedTypeLoc(AttributedTypeLoc TL) { + fillAttributedTypeLoc(TL, DS.getAttributes(), ParsedAttributesView{}); Visit(TL.getModifiedLoc()); - fillAttributedTypeLoc(TL, State); } void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); @@ -5408,13 +5442,11 @@ namespace { class DeclaratorLocFiller : public TypeLocVisitor { ASTContext &Context; - TypeProcessingState &State; const DeclaratorChunk &Chunk; public: - DeclaratorLocFiller(ASTContext &Context, TypeProcessingState &State, - const DeclaratorChunk &Chunk) - : Context(Context), State(State), Chunk(Chunk) {} + DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk) + : Context(Context), Chunk(Chunk) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { llvm_unreachable("qualified type locs not expected here!"); @@ -5424,7 +5456,7 @@ namespace { } void VisitAttributedTypeLoc(AttributedTypeLoc TL) { - fillAttributedTypeLoc(TL, State); + fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{}); } void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing @@ -5581,13 +5613,10 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, /// 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. -static TypeSourceInfo * -GetTypeSourceInfoForDeclarator(TypeProcessingState &State, - QualType T, TypeSourceInfo *ReturnTypeInfo) { - Sema &S = State.getSema(); - Declarator &D = State.getDeclarator(); - - TypeSourceInfo *TInfo = S.Context.CreateTypeSourceInfo(T); +TypeSourceInfo * +Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo) { + TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); // Handle parameter packs whose type is a pack expansion. @@ -5597,6 +5626,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + if (DependentAddressSpaceTypeLoc DASTL = CurrTL.getAs()) { fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs()); @@ -5611,7 +5641,8 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, } while (AttributedTypeLoc TL = CurrTL.getAs()) { - fillAttributedTypeLoc(TL, State); + fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(), + D.getAttributes()); CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -5619,7 +5650,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, while (AdjustedTypeLoc TL = CurrTL.getAs()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); - DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL); + DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -5630,7 +5661,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { - TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL); + TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL); } return TInfo; @@ -5859,7 +5890,7 @@ static bool hasDirectOwnershipQualifier(QualType type) { while (true) { // __strong id if (const AttributedType *attr = dyn_cast(type)) { - if (attr->getAttrKind() == attr::ObjCOwnership) + if (attr->getAttrKind() == AttributedType::attr_objc_ownership) return true; type = attr->getModifiedType(); @@ -6003,9 +6034,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // the coexistence problems with __unsafe_unretained. if (!S.getLangOpts().ObjCAutoRefCount && lifetime == Qualifiers::OCL_ExplicitNone) { - type = state.getAttributedType( - createSimpleAttr(S.Context, attr), - type, type); + type = S.Context.getAttributedType( + AttributedType::attr_objc_inert_unsafe_unretained, + type, type); return true; } @@ -6015,12 +6046,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // If we have a valid source location for the attribute, use an // AttributedType instead. - if (AttrLoc.isValid()) { - type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr( - attr.getRange(), S.Context, II, - attr.getAttributeSpellingListIndex()), - origType, type); - } + if (AttrLoc.isValid()) + type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, + origType, type); auto diagnoseOrDelay = [](Sema &S, SourceLocation loc, unsigned diagnostic, QualType type) { @@ -6120,10 +6148,8 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // Make an attributed type to preserve the source information. if (attr.getLoc().isValid()) - type = state.getAttributedType( - ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II, - attr.getAttributeSpellingListIndex()), - origType, type); + type = S.Context.getAttributedType(AttributedType::attr_objc_gc, + origType, type); return true; } @@ -6266,50 +6292,37 @@ namespace { } // end anonymous namespace static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, - ParsedAttr &PAttr, QualType &Type) { + ParsedAttr &Attr, QualType &Type) { Sema &S = State.getSema(); - 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(); + ParsedAttr::Kind Kind = Attr.getKind(); QualType Desugared = Type; const AttributedType *AT = dyn_cast(Type); while (AT) { - attr::Kind CurAttrKind = AT->getAttrKind(); + AttributedType::Kind CurAttrKind = AT->getAttrKind(); // You cannot specify duplicate type attributes, so if the attribute has // already been applied, flag it. - if (NewAttrKind == CurAttrKind) { - S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) - << PAttr.getName(); + if (getAttrListKind(CurAttrKind) == Kind) { + S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact) + << Attr.getName(); return true; } // You cannot have both __sptr and __uptr on the same type, nor can you // have __ptr32 and __ptr64. - if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) || - (CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) { - S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) + 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) << "'__ptr32'" << "'__ptr64'"; return true; - } else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) || - (CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) { - S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) + } 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) << "'__sptr'" << "'__uptr'"; return true; } @@ -6320,20 +6333,175 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, // 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(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr; + S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers) << Attr; else - S.Diag(PAttr.getLoc(), diag::err_attribute_pointers_only) << PAttr << 0; + S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) << Attr << 0; return true; } - Type = State.getAttributedType(A, Type, Type); + 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); + return false; +} + +bool Sema::checkNullabilityTypeSpecifier(QualType &type, + NullabilityKind nullability, + SourceLocation nullabilityLoc, + bool isContextSensitive, + bool allowOnArrayType) { + recordNullabilitySeen(*this, nullabilityLoc); + + // Check for existing nullability attributes on the type. + QualType desugared = type; + while (auto attributed = dyn_cast(desugared.getTypePtr())) { + // Check whether there is already a null + if (auto existingNullability = attributed->getImmediateNullability()) { + // Duplicated nullability. + if (nullability == *existingNullability) { + Diag(nullabilityLoc, diag::warn_nullability_duplicate) + << DiagNullabilityKind(nullability, isContextSensitive) + << FixItHint::CreateRemoval(nullabilityLoc); + + break; + } + + // Conflicting nullability. + Diag(nullabilityLoc, diag::err_nullability_conflicting) + << DiagNullabilityKind(nullability, isContextSensitive) + << DiagNullabilityKind(*existingNullability, false); + return true; + } + + desugared = attributed->getModifiedType(); + } + + // If there is already a different nullability specifier, complain. + // 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 (nullability != *existingNullability) { + Diag(nullabilityLoc, diag::err_nullability_conflicting) + << DiagNullabilityKind(nullability, isContextSensitive) + << DiagNullabilityKind(*existingNullability, false); + + // Try to find the typedef with the existing nullability specifier. + if (auto typedefType = desugared->getAs()) { + TypedefNameDecl *typedefDecl = typedefType->getDecl(); + QualType underlyingType = typedefDecl->getUnderlyingType(); + if (auto typedefNullability + = AttributedType::stripOuterNullability(underlyingType)) { + if (*typedefNullability == *existingNullability) { + Diag(typedefDecl->getLocation(), diag::note_nullability_here) + << DiagNullabilityKind(*existingNullability, false); + } + } + } + + return true; + } + } + + // If this definitely isn't a pointer type, reject the specifier. + if (!desugared->canHaveNullability() && + !(allowOnArrayType && desugared->isArrayType())) { + Diag(nullabilityLoc, diag::err_nullability_nonpointer) + << DiagNullabilityKind(nullability, isContextSensitive) << type; + return true; + } + + // For the context-sensitive keywords/Objective-C property + // attributes, require that the type be a single-level pointer. + if (isContextSensitive) { + // Make sure that the pointee isn't itself a pointer type. + const Type *pointeeType; + if (desugared->isArrayType()) + pointeeType = desugared->getArrayElementTypeNoTypeQual(); + else + pointeeType = desugared->getPointeeType().getTypePtr(); + + if (pointeeType->isAnyPointerType() || + pointeeType->isObjCObjectPointerType() || + pointeeType->isMemberPointerType()) { + Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) + << DiagNullabilityKind(nullability, true) + << type; + Diag(nullabilityLoc, diag::note_nullability_type_specifier) + << DiagNullabilityKind(nullability, false) + << type + << FixItHint::CreateReplacement(nullabilityLoc, + getNullabilitySpelling(nullability)); + return true; + } + } + + // Form the attributed type. + type = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(nullability), type, type); + return false; +} + +bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { + if (isa(type)) { + // Build the attributed type to record where __kindof occurred. + type = Context.getAttributedType(AttributedType::attr_objc_kindof, + type, type); + return false; + } + + // Find out if it's an Objective-C object or object pointer type; + const ObjCObjectPointerType *ptrType = type->getAs(); + const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() + : type->getAs(); + + // 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) + << type; + return true; + } + + // 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( + 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); + } + } + + // Build the attributed type to record where __kindof occurred. + type = Context.getAttributedType(AttributedType::attr_objc_kindof, + type, + equivType); + return false; } @@ -6354,175 +6522,6 @@ static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind 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; - while (auto attributed = dyn_cast(desugared.getTypePtr())) { - // Check whether there is already a null - if (auto existingNullability = attributed->getImmediateNullability()) { - // Duplicated nullability. - if (nullability == *existingNullability) { - S.Diag(nullabilityLoc, diag::warn_nullability_duplicate) - << DiagNullabilityKind(nullability, isContextSensitive) - << FixItHint::CreateRemoval(nullabilityLoc); - - break; - } - - // Conflicting nullability. - S.Diag(nullabilityLoc, diag::err_nullability_conflicting) - << DiagNullabilityKind(nullability, isContextSensitive) - << DiagNullabilityKind(*existingNullability, false); - return true; - } - - desugared = attributed->getModifiedType(); - } - - // If there is already a different nullability specifier, complain. - // 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(S.Context)) { - if (nullability != *existingNullability) { - S.Diag(nullabilityLoc, diag::err_nullability_conflicting) - << DiagNullabilityKind(nullability, isContextSensitive) - << DiagNullabilityKind(*existingNullability, false); - - // Try to find the typedef with the existing nullability specifier. - if (auto typedefType = desugared->getAs()) { - TypedefNameDecl *typedefDecl = typedefType->getDecl(); - QualType underlyingType = typedefDecl->getUnderlyingType(); - if (auto typedefNullability - = AttributedType::stripOuterNullability(underlyingType)) { - if (*typedefNullability == *existingNullability) { - S.Diag(typedefDecl->getLocation(), diag::note_nullability_here) - << DiagNullabilityKind(*existingNullability, false); - } - } - } - - return true; - } - } - - // If this definitely isn't a pointer type, reject the specifier. - if (!desugared->canHaveNullability() && - !(allowOnArrayType && desugared->isArrayType())) { - S.Diag(nullabilityLoc, diag::err_nullability_nonpointer) - << DiagNullabilityKind(nullability, isContextSensitive) << type; - return true; - } - - // For the context-sensitive keywords/Objective-C property - // attributes, require that the type be a single-level pointer. - if (isContextSensitive) { - // Make sure that the pointee isn't itself a pointer type. - const Type *pointeeType; - if (desugared->isArrayType()) - pointeeType = desugared->getArrayElementTypeNoTypeQual(); - else - pointeeType = desugared->getPointeeType().getTypePtr(); - - if (pointeeType->isAnyPointerType() || - pointeeType->isObjCObjectPointerType() || - pointeeType->isMemberPointerType()) { - S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) - << DiagNullabilityKind(nullability, true) - << type; - S.Diag(nullabilityLoc, diag::note_nullability_type_specifier) - << DiagNullabilityKind(nullability, false) - << type - << FixItHint::CreateReplacement(nullabilityLoc, - getNullabilitySpelling(nullability)); - return true; - } - } - - // Form the attributed type. - type = state.getAttributedType( - createNullabilityAttr(S.Context, attr, nullability), type, type); - return false; -} - -/// 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 = state.getAttributedType( - createSimpleAttr(S.Context, attr), type, type); - return false; - } - - // Find out if it's an Objective-C object or object pointer type; - const ObjCObjectPointerType *ptrType = type->getAs(); - const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() - : type->getAs(); - - // If not, we can't apply __kindof. - if (!objType) { - // FIXME: Handle dependent types that aren't yet object types. - S.Diag(attr.getLoc(), diag::err_objc_kindof_nonobject) - << type; - return true; - } - - // 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 = 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 = 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 = state.getAttributedType( - createSimpleAttr(S.Context, attr), type, equivType); - return false; -} - /// 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. @@ -6610,27 +6609,27 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state, return false; } -static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { +static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) { assert(!Attr.isInvalid()); switch (Attr.getKind()) { default: llvm_unreachable("not a calling convention attribute"); case ParsedAttr::AT_CDecl: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_cdecl; case ParsedAttr::AT_FastCall: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_fastcall; case ParsedAttr::AT_StdCall: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_stdcall; case ParsedAttr::AT_ThisCall: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_thiscall; case ParsedAttr::AT_RegCall: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_regcall; case ParsedAttr::AT_Pascal: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_pascal; case ParsedAttr::AT_SwiftCall: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_swiftcall; case ParsedAttr::AT_VectorCall: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_vectorcall; 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, @@ -6640,22 +6639,20 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { Str = cast(Attr.getArgAsExpr(0))->getString(); else Str = Attr.getArgAsIdent(0)->Ident->getName(); - PcsAttr::PCSType Type; - if (!PcsAttr::ConvertStrToPCSType(Str, Type)) - llvm_unreachable("already validated the attribute"); - return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type, - Attr.getAttributeSpellingListIndex()); + return llvm::StringSwitch(Str) + .Case("aapcs", AttributedType::attr_pcs) + .Case("aapcs-vfp", AttributedType::attr_pcs_vfp); } case ParsedAttr::AT_IntelOclBicc: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_inteloclbicc; case ParsedAttr::AT_MSABI: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_ms_abi; case ParsedAttr::AT_SysVABI: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_sysv_abi; case ParsedAttr::AT_PreserveMost: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_preserve_most; case ParsedAttr::AT_PreserveAll: - return createSimpleAttr(Ctx, Attr); + return AttributedType::attr_preserve_all; } llvm_unreachable("unexpected attribute kind!"); } @@ -6703,9 +6700,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, = unwrapped.get()->getExtInfo().withProducesResult(true); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); } - type = state.getAttributedType( - createSimpleAttr(S.Context, attr), - origType, type); + type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained, + origType, type); return true; } @@ -6780,12 +6776,13 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, const FunctionType *fn = unwrapped.get(); CallingConv CCOld = fn->getCallConv(); - Attr *CCAttr = getCCTypeAttr(S.Context, attr); + AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr); if (CCOld != CC) { // Error out on when there's already an attribute on the type // and the CCs don't match. - if (const AttributedType *AT = S.getCallingConvAttributedType(type)) { + const AttributedType *AT = S.getCallingConvAttributedType(type); + if (AT && AT->getAttrKind() != CCAttrKind) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << FunctionType::getNameForCallConv(CCOld); @@ -6839,7 +6836,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, Equivalent = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); } - type = state.getAttributedType(CCAttr, type, Equivalent); + type = S.Context.getAttributedType(CCAttrKind, type, Equivalent); return true; } @@ -7195,15 +7192,14 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr); } -static void HandleLifetimeBoundAttr(TypeProcessingState &State, - QualType &CurType, - ParsedAttr &Attr) { - if (State.getDeclarator().isDeclarationOfFunction()) { - CurType = State.getAttributedType( - createSimpleAttr(State.getSema().Context, Attr), - CurType, CurType); +static void HandleLifetimeBoundAttr(QualType &CurType, + const ParsedAttr &Attr, + Sema &S, Declarator &D) { + if (D.isDeclarationOfFunction()) { + CurType = S.Context.getAttributedType(AttributedType::attr_lifetimebound, + CurType, CurType); } else { - Attr.diagnoseAppertainsTo(State.getSema(), nullptr); + Attr.diagnoseAppertainsTo(S, nullptr); } } @@ -7313,8 +7309,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_LifetimeBound: - if (TAL == TAL_DeclChunk) - HandleLifetimeBoundAttr(state, type, attr); + if (TAL == TAL_DeclChunk) { + HandleLifetimeBoundAttr(type, attr, state.getSema(), + state.getDeclarator()); + attr.setUsedAsTypeAttr(); + } break; MS_TYPE_ATTRS_CASELIST: @@ -7338,10 +7337,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, bool allowOnArrayType = state.getDeclarator().isPrototypeContext() && !hasOuterPointerLikeChunk(state.getDeclarator(), endIndex); - if (checkNullabilityTypeSpecifier( - state, + if (state.getSema().checkNullabilityTypeSpecifier( type, - attr, + mapNullabilityAttrKind(attr.getKind()), + attr.getLoc(), + attr.isContextSensitiveKeywordAttribute(), allowOnArrayType)) { attr.setInvalid(); } @@ -7368,8 +7368,9 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } // Apply it regardless. - if (checkObjCKindOfType(state, type, attr)) + if (state.getSema().checkObjCKindOfType(type, attr.getLoc())) attr.setInvalid(); + attr.setUsedAsTypeAttr(); break; FUNCTION_TYPE_ATTRS_CASELIST: diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 98256d66a2..d680e6be6d 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6058,11 +6058,6 @@ QualType TreeTransform::TransformAttributedType( 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? @@ -6079,20 +6074,26 @@ QualType TreeTransform::TransformAttributedType( // type sugar, and therefore cannot be diagnosed in any other way. if (auto nullability = oldType->getImmediateNullability()) { if (!modifiedType->canHaveNullability()) { - SemaRef.Diag(TL.getAttr()->getLocation(), - diag::err_nullability_nonpointer) - << DiagNullabilityKind(*nullability, false) << modifiedType; + SemaRef.Diag(TL.getAttrNameLoc(), diag::err_nullability_nonpointer) + << DiagNullabilityKind(*nullability, false) << modifiedType; return QualType(); } } - result = SemaRef.Context.getAttributedType(newAttr->getKind(), + result = SemaRef.Context.getAttributedType(oldType->getAttrKind(), modifiedType, equivalentType); } AttributedTypeLoc newTL = TLB.push(result); - newTL.setAttr(newAttr); + 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()); + return result; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index a9acf4e2f4..a6f624e326 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -6455,10 +6455,6 @@ class TypeLocReader : public TypeLocVisitor { 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) @@ -6650,7 +6646,20 @@ void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { } void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { - TL.setAttr(ReadAttr()); + 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()); } void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 8e7dc7c436..2b8cfac88d 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -2648,72 +2648,19 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { // 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(); +/// 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?"); - 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) - Attrs.push_back(Record.readAttr()); + assert(New && "Unable to decode attribute?"); + Attrs.push_back(New); + } } //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index f2fde2c76f..ea3a75da48 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -770,7 +770,19 @@ void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { } void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) { - Record.AddAttr(TL.getAttr()); + 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()); + } } void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { @@ -4469,21 +4481,16 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, // General Serialization Routines //===----------------------------------------------------------------------===// -void ASTRecordWriter::AddAttr(const Attr *A) { - auto &Record = *this; - 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); + 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()); + +#include "clang/Serialization/AttrPCHWrite.inc" + } } void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { diff --git a/lib/StaticAnalyzer/Core/CheckerHelpers.cpp b/lib/StaticAnalyzer/Core/CheckerHelpers.cpp index e73a22ae39..9d1ee75d3d 100644 --- a/lib/StaticAnalyzer/Core/CheckerHelpers.cpp +++ b/lib/StaticAnalyzer/Core/CheckerHelpers.cpp @@ -103,9 +103,9 @@ Nullability getNullabilityAnnotation(QualType Type) { const auto *AttrType = Type->getAs(); if (!AttrType) return Nullability::Unspecified; - if (AttrType->getAttrKind() == attr::TypeNullable) + if (AttrType->getAttrKind() == AttributedType::attr_nullable) return Nullability::Nullable; - else if (AttrType->getAttrKind() == attr::TypeNonNull) + else if (AttrType->getAttrKind() == AttributedType::attr_nonnull) return Nullability::Nonnull; return Nullability::Unspecified; } diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 5c6c7c3d01..71e003f0c8 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -2470,10 +2470,8 @@ namespace { 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" } };