#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"
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
- QualType getAttributedType(attr::Kind attrKind,
+ QualType getAttributedType(AttributedType::Kind attrKind,
QualType modifiedType,
QualType equivalentType);
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,
#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"
bool isObjCQualifiedClassType() const; // Class<foo>
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
/// 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.
/// - 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
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(),
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.");
}
#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"
};
struct AttributedLocInfo {
- const Attr *TypeAttr;
+ union {
+ Expr *ExprOperand;
+
+ /// A raw SourceLocation.
+ unsigned EnumOperandLoc;
+ };
+
+ SourceRange OperandParens;
+
+ SourceLocation AttrLoc;
};
/// Type source information for an attributed type.
AttributedType,
AttributedLocInfo> {
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();
}
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<typename T> const T *getAttrAs() {
- return dyn_cast_or_null<T>(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 {
// ^~ ~~
// 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 {
}
/// 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;
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 {
let Documentation = [LayoutVersionDocs];
}
-def LifetimeBound : DeclOrTypeAttr {
+def LifetimeBound : InheritableAttr {
let Spellings = [Clang<"lifetimebound", 0>];
let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
let Documentation = [LifetimeBoundDocs];
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 {
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];
let Documentation = [Undocumented];
}
-def NSReturnsRetained : DeclOrTypeAttr {
+def NSReturnsRetained : InheritableAttr {
let Spellings = [Clang<"ns_returns_retained">];
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
let Documentation = [Undocumented];
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 {
let Documentation = [Undocumented];
}
-def ObjCOwnership : DeclOrTypeAttr {
+def ObjCOwnership : InheritableAttr {
let Spellings = [Clang<"objc_ownership">];
let Args = [IdentifierArgument<"Kind">];
+ let ASTNode = 0;
let Documentation = [Undocumented];
}
let Spellings = [GCC<"vector_size">];
let Args = [ExprArgument<"NumBytes">];
let Documentation = [Undocumented];
- // Represented as VectorType instead.
- let ASTNode = 0;
}
def VecTypeHint : InheritableAttr {
let Documentation = [AnyX86NoCallerSavedRegistersDocs];
}
-def AnyX86NoCfCheck : DeclOrTypeAttr, TargetSpecificAttr<TargetAnyX86>{
+def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr<TargetAnyX86>{
let Spellings = [GCC<"nocf_check">];
let Subjects = SubjectList<[FunctionLike]>;
let Documentation = [AnyX86NoCfCheckDocs];
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);
/// 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,
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.
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);
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);
return Writer->AddVersionTuple(Version, *Record);
}
- // Emit an attribute.
- void AddAttr(const Attr *A);
-
/// Emit a list of attributes.
void AddAttributes(ArrayRef<const Attr*> Attrs);
};
}
bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
- auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
- 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;
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;
}
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)
bool MigrationContext::isGCOwnedNonObjC(QualType T) {
while (!T.isNull()) {
if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
- if (AttrT->getAttrKind() == attr::ObjCOwnership)
+ if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
return !AttrT->getModifiedType()->isObjCRetainableType();
}
return QualType(newType, 0);
}
-QualType ASTContext::getAttributedType(attr::Kind attrKind,
+QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
QualType modifiedType,
QualType equivalentType) {
llvm::FoldingSetNodeID id;
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<AttributedType>(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<ObjCProtocolDecl *> protocols)
return nullptr;
}
-bool Type::hasAttr(attr::Kind AK) const {
- const Type *Cur = this;
- while (const auto *AT = Cur->getAs<AttributedType>()) {
- if (AT->getAttrKind() == AK)
- return true;
- Cur = AT->getEquivalentType().getTypePtr();
- }
- return false;
-}
-
namespace {
class GetContainedDeducedTypeVisitor :
}
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");
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
}
-Optional<NullabilityKind>
-Type::getNullability(const ASTContext &Context) const {
- QualType Type(this, 0);
- while (const auto *AT = Type->getAs<AttributedType>()) {
+Optional<NullabilityKind> 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<AttributedType>(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 {
llvm_unreachable("bad type kind!");
}
-llvm::Optional<NullabilityKind>
-AttributedType::getImmediateNullability() const {
- if (getAttrKind() == attr::TypeNonNull)
+llvm::Optional<NullabilityKind> 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;
}
}
SourceLocation TypeLoc::findNullabilityLoc() const {
- if (auto ATL = getAs<AttributedTypeLoc>()) {
- const Attr *A = ATL.getAttr();
- if (A && (isa<TypeNullableAttr>(A) || isa<TypeNonNullAttr>(A) ||
- isa<TypeNullUnspecifiedAttr>(A)))
- return A->getLocation();
+ if (auto attributedLoc = getAs<AttributedTypeLoc>()) {
+ if (attributedLoc.getAttrKind() == AttributedType::attr_nullable ||
+ attributedLoc.getAttrKind() == AttributedType::attr_nonnull ||
+ attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified)
+ return attributedLoc.getAttrNameLoc();
}
return {};
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);
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");
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
// 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<FunctionType>()
->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.
+ 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 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 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_vector_size:
+ OS << "__vector_size__(";
+ if (const auto *vector = T->getEquivalentType()->getAs<VectorType>()) {
+ 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<VectorType>();
+ 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<FunctionType>()->getRegParmType();
+ OS << ')';
+ break;
+ }
- case attr::NSReturnsRetained:
+ 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())
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;
}
// 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<LifetimeBoundAttr>()) {
+ if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) {
const auto *MD = dyn_cast<CXXMethodDecl>(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<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) {
- S.Diag(A->getLocation(), diag::err_lifetimebound_ctor_dtor)
- << isa<CXXDestructorDecl>(MD) << A->getRange();
+ S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor)
+ << isa<CXXDestructorDecl>(MD) << ATL.getLocalSourceRange();
}
}
}
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
if (const auto *PT = CaptureType->getAs<PointerType>()) {
// 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<AttributedType>()) {
- 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();
}
for (TypeLoc TL = TSI->getTypeLoc();
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
TL = ATL.getModifiedLoc()) {
- if (ATL.getAttrAs<LifetimeBoundAttr>())
+ if (ATL.getAttrKind() == AttributedType::attr_lifetimebound)
return true;
}
return false;
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);
}
}
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);
}
}
/// processing is complete.
SmallVector<ParsedAttr *, 2> 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<const AttributedType*, const Attr*>;
- SmallVector<TypeAttrPair, 8> AttrsForTypes;
- bool AttrsForTypesSorted = true;
-
public:
TypeProcessingState(Sema &sema, Declarator &declarator)
: sema(sema), declarator(declarator),
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<AttributedType>(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;
return false;
}
-template<typename AttrT>
-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<TypeNonNullAttr>(Ctx, Attr);
-
- case NullabilityKind::Nullable:
- return createSimpleAttr<TypeNullableAttr>(Ctx, Attr);
-
- case NullabilityKind::Unspecified:
- return createSimpleAttr<TypeNullUnspecifiedAttr>(Ctx, Attr);
- }
- llvm_unreachable("unknown NullabilityKind");
-}
-
-static TypeSourceInfo *
-GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
- QualType T, TypeSourceInfo *ReturnTypeInfo);
-
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
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();
}
}
}
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
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<TypeSpecLocFiller> {
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());
class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> {
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!");
}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
- fillAttributedTypeLoc(TL, State);
+ fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{});
}
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
// nothing
/// 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.
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+
if (DependentAddressSpaceTypeLoc DASTL =
CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
}
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
- fillAttributedTypeLoc(TL, State);
+ fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(),
+ D.getAttributes());
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
}
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
- DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL);
+ DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
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;
while (true) {
// __strong id
if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
- if (attr->getAttrKind() == attr::ObjCOwnership)
+ if (attr->getAttrKind() == AttributedType::attr_objc_ownership)
return true;
type = attr->getModifiedType();
// the coexistence problems with __unsafe_unretained.
if (!S.getLangOpts().ObjCAutoRefCount &&
lifetime == Qualifiers::OCL_ExplicitNone) {
- type = state.getAttributedType(
- createSimpleAttr<ObjCInertUnsafeUnretainedAttr>(S.Context, attr),
- type, type);
+ type = S.Context.getAttributedType(
+ AttributedType::attr_objc_inert_unsafe_unretained,
+ type, type);
return true;
}
// 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) {
// 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;
}
} // 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<Ptr32Attr>(S.Context, PAttr);
- break;
- case ParsedAttr::AT_Ptr64:
- A = createSimpleAttr<Ptr64Attr>(S.Context, PAttr);
- break;
- case ParsedAttr::AT_SPtr:
- A = createSimpleAttr<SPtrAttr>(S.Context, PAttr);
- break;
- case ParsedAttr::AT_UPtr:
- A = createSimpleAttr<UPtrAttr>(S.Context, PAttr);
- break;
- }
-
- attr::Kind NewAttrKind = A->getKind();
+ ParsedAttr::Kind Kind = Attr.getKind();
QualType Desugared = Type;
const AttributedType *AT = dyn_cast<AttributedType>(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;
}
// 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<PointerType>(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);
- 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");
+ 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;
}
-}
-/// 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();
+ Type = S.Context.getAttributedType(TAK, Type, Type);
+ return false;
+}
- recordNullabilitySeen(S, nullabilityLoc);
+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;
if (auto existingNullability = attributed->getImmediateNullability()) {
// Duplicated nullability.
if (nullability == *existingNullability) {
- S.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
+ Diag(nullabilityLoc, diag::warn_nullability_duplicate)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< FixItHint::CreateRemoval(nullabilityLoc);
}
// Conflicting nullability.
- S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< DiagNullabilityKind(*existingNullability, false);
return true;
// 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 (auto existingNullability = desugared->getNullability(Context)) {
if (nullability != *existingNullability) {
- S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< DiagNullabilityKind(*existingNullability, false);
if (auto typedefNullability
= AttributedType::stripOuterNullability(underlyingType)) {
if (*typedefNullability == *existingNullability) {
- S.Diag(typedefDecl->getLocation(), diag::note_nullability_here)
+ Diag(typedefDecl->getLocation(), diag::note_nullability_here)
<< DiagNullabilityKind(*existingNullability, false);
}
}
// If this definitely isn't a pointer type, reject the specifier.
if (!desugared->canHaveNullability() &&
!(allowOnArrayType && desugared->isArrayType())) {
- S.Diag(nullabilityLoc, diag::err_nullability_nonpointer)
+ Diag(nullabilityLoc, diag::err_nullability_nonpointer)
<< DiagNullabilityKind(nullability, isContextSensitive) << type;
return true;
}
if (pointeeType->isAnyPointerType() ||
pointeeType->isObjCObjectPointerType() ||
pointeeType->isMemberPointerType()) {
- S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
+ Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
<< DiagNullabilityKind(nullability, true)
<< type;
- S.Diag(nullabilityLoc, diag::note_nullability_type_specifier)
+ Diag(nullabilityLoc, diag::note_nullability_type_specifier)
<< DiagNullabilityKind(nullability, false)
<< type
<< FixItHint::CreateReplacement(nullabilityLoc,
}
// Form the attributed type.
- type = state.getAttributedType(
- createNullabilityAttr(S.Context, attr, nullability), type, type);
+ type = Context.getAttributedType(
+ AttributedType::getNullabilityAttrKind(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();
-
+bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
if (isa<ObjCTypeParamType>(type)) {
// Build the attributed type to record where __kindof occurred.
- type = state.getAttributedType(
- createSimpleAttr<ObjCKindOfAttr>(S.Context, attr), type, type);
+ type = Context.getAttributedType(AttributedType::attr_objc_kindof,
+ type, type);
return false;
}
// 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)
+ 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 = S.Context.getObjCObjectType(
+ 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 = 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);
+ 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 = state.getAttributedType(
- createSimpleAttr<ObjCKindOfAttr>(S.Context, attr), type, equivType);
+ type = Context.getAttributedType(AttributedType::attr_objc_kindof,
+ 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.
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<CDeclAttr>(Ctx, Attr);
+ return AttributedType::attr_cdecl;
case ParsedAttr::AT_FastCall:
- return createSimpleAttr<FastCallAttr>(Ctx, Attr);
+ return AttributedType::attr_fastcall;
case ParsedAttr::AT_StdCall:
- return createSimpleAttr<StdCallAttr>(Ctx, Attr);
+ return AttributedType::attr_stdcall;
case ParsedAttr::AT_ThisCall:
- return createSimpleAttr<ThisCallAttr>(Ctx, Attr);
+ return AttributedType::attr_thiscall;
case ParsedAttr::AT_RegCall:
- return createSimpleAttr<RegCallAttr>(Ctx, Attr);
+ return AttributedType::attr_regcall;
case ParsedAttr::AT_Pascal:
- return createSimpleAttr<PascalAttr>(Ctx, Attr);
+ return AttributedType::attr_pascal;
case ParsedAttr::AT_SwiftCall:
- return createSimpleAttr<SwiftCallAttr>(Ctx, Attr);
+ return AttributedType::attr_swiftcall;
case ParsedAttr::AT_VectorCall:
- return createSimpleAttr<VectorCallAttr>(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,
Str = cast<StringLiteral>(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<AttributedType::Kind>(Str)
+ .Case("aapcs", AttributedType::attr_pcs)
+ .Case("aapcs-vfp", AttributedType::attr_pcs_vfp);
}
case ParsedAttr::AT_IntelOclBicc:
- return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr);
+ return AttributedType::attr_inteloclbicc;
case ParsedAttr::AT_MSABI:
- return createSimpleAttr<MSABIAttr>(Ctx, Attr);
+ return AttributedType::attr_ms_abi;
case ParsedAttr::AT_SysVABI:
- return createSimpleAttr<SysVABIAttr>(Ctx, Attr);
+ return AttributedType::attr_sysv_abi;
case ParsedAttr::AT_PreserveMost:
- return createSimpleAttr<PreserveMostAttr>(Ctx, Attr);
+ return AttributedType::attr_preserve_most;
case ParsedAttr::AT_PreserveAll:
- return createSimpleAttr<PreserveAllAttr>(Ctx, Attr);
+ return AttributedType::attr_preserve_all;
}
llvm_unreachable("unexpected attribute kind!");
}
= unwrapped.get()->getExtInfo().withProducesResult(true);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
}
- type = state.getAttributedType(
- createSimpleAttr<NSReturnsRetainedAttr>(S.Context, attr),
- origType, type);
+ type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
+ origType, type);
return true;
}
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);
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;
}
T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
}
-static void HandleLifetimeBoundAttr(TypeProcessingState &State,
- QualType &CurType,
- ParsedAttr &Attr) {
- if (State.getDeclarator().isDeclarationOfFunction()) {
- CurType = State.getAttributedType(
- createSimpleAttr<LifetimeBoundAttr>(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);
}
}
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:
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();
}
}
// Apply it regardless.
- if (checkObjCKindOfType(state, type, attr))
+ if (state.getSema().checkObjCKindOfType(type, attr.getLoc()))
attr.setInvalid();
+ attr.setUsedAsTypeAttr();
break;
FUNCTION_TYPE_ATTRS_CASELIST:
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?
// 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<AttributedTypeLoc>(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;
}
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)
}
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) {
// 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 <typename T> T *GetLocalDeclAs(uint32_t LocalID) {
- return cast_or_null<T>(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<attr::Kind>(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);
+ }
}
//===----------------------------------------------------------------------===//
}
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) {
// General Serialization Routines
//===----------------------------------------------------------------------===//
-void ASTRecordWriter::AddAttr(const Attr *A) {
+/// Emit the list of attributes to the specified record.
+void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
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());
+ 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"
-}
-
-/// Emit the list of attributes to the specified record.
-void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
- push_back(Attrs.size());
- for (const auto *A : Attrs)
- AddAttr(A);
+ }
}
void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
const auto *AttrType = Type->getAs<AttributedType>();
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;
}
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" }
};