mirror of https://github.com/microsoft/clang.git
Model type attributes as regular Attrs.
Specifically, AttributedType now tracks a regular attr::Kind rather than having its own parallel Kind enumeration, and AttributedTypeLoc now holds an Attr* instead of holding an ad-hoc collection of Attr fields. Differential Revision: https://reviews.llvm.org/D50526 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@339623 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
293b7c5989
commit
a3402fe23c
|
@ -31,6 +31,7 @@
|
||||||
#include "clang/AST/TemplateName.h"
|
#include "clang/AST/TemplateName.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/Basic/AddressSpaces.h"
|
#include "clang/Basic/AddressSpaces.h"
|
||||||
|
#include "clang/Basic/AttrKinds.h"
|
||||||
#include "clang/Basic/IdentifierTable.h"
|
#include "clang/Basic/IdentifierTable.h"
|
||||||
#include "clang/Basic/LLVM.h"
|
#include "clang/Basic/LLVM.h"
|
||||||
#include "clang/Basic/LangOptions.h"
|
#include "clang/Basic/LangOptions.h"
|
||||||
|
@ -1422,7 +1423,7 @@ public:
|
||||||
|
|
||||||
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
|
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
|
||||||
|
|
||||||
QualType getAttributedType(AttributedType::Kind attrKind,
|
QualType getAttributedType(attr::Kind attrKind,
|
||||||
QualType modifiedType,
|
QualType modifiedType,
|
||||||
QualType equivalentType);
|
QualType equivalentType);
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,19 @@ public:
|
||||||
void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
|
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 {
|
class StmtAttr : public Attr {
|
||||||
protected:
|
protected:
|
||||||
StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
|
StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "clang/AST/NestedNameSpecifier.h"
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
#include "clang/AST/TemplateName.h"
|
#include "clang/AST/TemplateName.h"
|
||||||
#include "clang/Basic/AddressSpaces.h"
|
#include "clang/Basic/AddressSpaces.h"
|
||||||
|
#include "clang/Basic/AttrKinds.h"
|
||||||
#include "clang/Basic/Diagnostic.h"
|
#include "clang/Basic/Diagnostic.h"
|
||||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||||
#include "clang/Basic/LLVM.h"
|
#include "clang/Basic/LLVM.h"
|
||||||
|
@ -1870,7 +1871,16 @@ public:
|
||||||
bool isObjCQualifiedClassType() const; // Class<foo>
|
bool isObjCQualifiedClassType() const; // Class<foo>
|
||||||
bool isObjCObjectOrInterfaceType() const;
|
bool isObjCObjectOrInterfaceType() const;
|
||||||
bool isObjCIdType() const; // id
|
bool isObjCIdType() const; // id
|
||||||
bool isObjCInertUnsafeUnretainedType() const;
|
|
||||||
|
/// Was this type written with the special inert-in-ARC __unsafe_unretained
|
||||||
|
/// qualifier?
|
||||||
|
///
|
||||||
|
/// This approximates the answer to the following question: if this
|
||||||
|
/// translation unit were compiled in ARC, would this type be qualified
|
||||||
|
/// with __unsafe_unretained?
|
||||||
|
bool isObjCInertUnsafeUnretainedType() const {
|
||||||
|
return hasAttr(attr::ObjCInertUnsafeUnretained);
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the type is Objective-C 'id' or a __kindof type of an
|
/// Whether the type is Objective-C 'id' or a __kindof type of an
|
||||||
/// object type, e.g., __kindof NSView * or __kindof id
|
/// object type, e.g., __kindof NSView * or __kindof id
|
||||||
|
@ -2084,6 +2094,10 @@ public:
|
||||||
/// qualifiers from the outermost type.
|
/// qualifiers from the outermost type.
|
||||||
const ArrayType *castAsArrayTypeUnsafe() const;
|
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
|
/// Get the base element type of this type, potentially discarding type
|
||||||
/// qualifiers. This should never be used when type qualifiers
|
/// qualifiers. This should never be used when type qualifiers
|
||||||
/// are meaningful.
|
/// are meaningful.
|
||||||
|
@ -4193,56 +4207,7 @@ public:
|
||||||
/// - the canonical type is VectorType(16, int)
|
/// - the canonical type is VectorType(16, int)
|
||||||
class AttributedType : public Type, public llvm::FoldingSetNode {
|
class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||||
public:
|
public:
|
||||||
// It is really silly to have yet another attribute-kind enum, but
|
using Kind = attr::Kind;
|
||||||
// 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:
|
private:
|
||||||
friend class ASTContext; // ASTContext creates these
|
friend class ASTContext; // ASTContext creates these
|
||||||
|
@ -4250,7 +4215,7 @@ private:
|
||||||
QualType ModifiedType;
|
QualType ModifiedType;
|
||||||
QualType EquivalentType;
|
QualType EquivalentType;
|
||||||
|
|
||||||
AttributedType(QualType canon, Kind attrKind, QualType modified,
|
AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
|
||||||
QualType equivalent)
|
QualType equivalent)
|
||||||
: Type(Attributed, canon, equivalent->isDependentType(),
|
: Type(Attributed, canon, equivalent->isDependentType(),
|
||||||
equivalent->isInstantiationDependentType(),
|
equivalent->isInstantiationDependentType(),
|
||||||
|
@ -4299,13 +4264,13 @@ public:
|
||||||
static Kind getNullabilityAttrKind(NullabilityKind kind) {
|
static Kind getNullabilityAttrKind(NullabilityKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case NullabilityKind::NonNull:
|
case NullabilityKind::NonNull:
|
||||||
return attr_nonnull;
|
return attr::TypeNonNull;
|
||||||
|
|
||||||
case NullabilityKind::Nullable:
|
case NullabilityKind::Nullable:
|
||||||
return attr_nullable;
|
return attr::TypeNullable;
|
||||||
|
|
||||||
case NullabilityKind::Unspecified:
|
case NullabilityKind::Unspecified:
|
||||||
return attr_null_unspecified;
|
return attr::TypeNullUnspecified;
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unknown nullability kind.");
|
llvm_unreachable("Unknown nullability kind.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#ifndef LLVM_CLANG_AST_TYPELOC_H
|
#ifndef LLVM_CLANG_AST_TYPELOC_H
|
||||||
#define LLVM_CLANG_AST_TYPELOC_H
|
#define LLVM_CLANG_AST_TYPELOC_H
|
||||||
|
|
||||||
|
#include "clang/AST/Attr.h"
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/NestedNameSpecifier.h"
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
#include "clang/AST/TemplateBase.h"
|
#include "clang/AST/TemplateBase.h"
|
||||||
|
@ -849,16 +850,7 @@ class SubstTemplateTypeParmPackTypeLoc :
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AttributedLocInfo {
|
struct AttributedLocInfo {
|
||||||
union {
|
const Attr *TypeAttr;
|
||||||
Expr *ExprOperand;
|
|
||||||
|
|
||||||
/// A raw SourceLocation.
|
|
||||||
unsigned EnumOperandLoc;
|
|
||||||
};
|
|
||||||
|
|
||||||
SourceRange OperandParens;
|
|
||||||
|
|
||||||
SourceLocation AttrLoc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Type source information for an attributed type.
|
/// Type source information for an attributed type.
|
||||||
|
@ -867,24 +859,10 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||||
AttributedType,
|
AttributedType,
|
||||||
AttributedLocInfo> {
|
AttributedLocInfo> {
|
||||||
public:
|
public:
|
||||||
AttributedType::Kind getAttrKind() const {
|
attr::Kind getAttrKind() const {
|
||||||
return getTypePtr()->getAttrKind();
|
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 {
|
bool isQualifier() const {
|
||||||
return getTypePtr()->isQualifier();
|
return getTypePtr()->isQualifier();
|
||||||
}
|
}
|
||||||
|
@ -897,51 +875,16 @@ public:
|
||||||
return getInnerTypeLoc();
|
return getInnerTypeLoc();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The location of the attribute name, i.e.
|
/// The type attribute.
|
||||||
/// __attribute__((regparm(1000)))
|
const Attr *getAttr() const {
|
||||||
/// ^~~~~~~
|
return getLocalData()->TypeAttr;
|
||||||
SourceLocation getAttrNameLoc() const {
|
|
||||||
return getLocalData()->AttrLoc;
|
|
||||||
}
|
}
|
||||||
void setAttrNameLoc(SourceLocation loc) {
|
void setAttr(const Attr *A) {
|
||||||
getLocalData()->AttrLoc = loc;
|
getLocalData()->TypeAttr = A;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The attribute's expression operand, if it has one.
|
template<typename T> const T *getAttrAs() {
|
||||||
/// void *cur_thread __attribute__((address_space(21)))
|
return dyn_cast_or_null<T>(getAttr());
|
||||||
/// ^~
|
|
||||||
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 {
|
SourceRange getLocalSourceRange() const {
|
||||||
|
@ -954,21 +897,11 @@ public:
|
||||||
// ^~ ~~
|
// ^~ ~~
|
||||||
// That enclosure doesn't necessarily belong to a single attribute
|
// That enclosure doesn't necessarily belong to a single attribute
|
||||||
// anyway.
|
// anyway.
|
||||||
SourceRange range(getAttrNameLoc());
|
return getAttr() ? getAttr()->getRange() : SourceRange();
|
||||||
if (hasAttrOperand())
|
|
||||||
range.setEnd(getAttrOperandParensRange().getEnd());
|
|
||||||
return range;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeLocal(ASTContext &Context, SourceLocation loc) {
|
void initializeLocal(ASTContext &Context, SourceLocation loc) {
|
||||||
setAttrNameLoc(loc);
|
setAttr(nullptr);
|
||||||
if (hasAttrExprOperand()) {
|
|
||||||
setAttrOperandParensRange(SourceRange(loc));
|
|
||||||
setAttrExprOperand(nullptr);
|
|
||||||
} else if (hasAttrEnumOperand()) {
|
|
||||||
setAttrOperandParensRange(SourceRange(loc));
|
|
||||||
setAttrEnumOperandLoc(loc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType getInnerType() const {
|
QualType getInnerType() const {
|
||||||
|
|
|
@ -494,10 +494,7 @@ class Attr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type attribute is not processed on a declaration or a statement.
|
/// 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.
|
/// A stmt attribute is not processed on a declaration or a type.
|
||||||
class StmtAttr : Attr;
|
class StmtAttr : Attr;
|
||||||
|
@ -567,6 +564,8 @@ def AddressSpace : TypeAttr {
|
||||||
let Spellings = [Clang<"address_space">];
|
let Spellings = [Clang<"address_space">];
|
||||||
let Args = [IntArgument<"AddressSpace">];
|
let Args = [IntArgument<"AddressSpace">];
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
|
// Represented as a qualifier or DependentAddressSpaceType instead.
|
||||||
|
let ASTNode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
def Alias : Attr {
|
def Alias : Attr {
|
||||||
|
@ -1224,7 +1223,7 @@ def LayoutVersion : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
|
||||||
let Documentation = [LayoutVersionDocs];
|
let Documentation = [LayoutVersionDocs];
|
||||||
}
|
}
|
||||||
|
|
||||||
def LifetimeBound : InheritableAttr {
|
def LifetimeBound : DeclOrTypeAttr {
|
||||||
let Spellings = [Clang<"lifetimebound", 0>];
|
let Spellings = [Clang<"lifetimebound", 0>];
|
||||||
let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
|
let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
|
||||||
let Documentation = [LifetimeBoundDocs];
|
let Documentation = [LifetimeBoundDocs];
|
||||||
|
@ -1327,12 +1326,16 @@ def NeonPolyVectorType : TypeAttr {
|
||||||
let Spellings = [Clang<"neon_polyvector_type">];
|
let Spellings = [Clang<"neon_polyvector_type">];
|
||||||
let Args = [IntArgument<"NumElements">];
|
let Args = [IntArgument<"NumElements">];
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
|
// Represented as VectorType instead.
|
||||||
|
let ASTNode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
def NeonVectorType : TypeAttr {
|
def NeonVectorType : TypeAttr {
|
||||||
let Spellings = [Clang<"neon_vector_type">];
|
let Spellings = [Clang<"neon_vector_type">];
|
||||||
let Args = [IntArgument<"NumElements">];
|
let Args = [IntArgument<"NumElements">];
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
|
// Represented as VectorType instead.
|
||||||
|
let ASTNode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
def ReturnsTwice : InheritableAttr {
|
def ReturnsTwice : InheritableAttr {
|
||||||
|
@ -1507,6 +1510,14 @@ def TypeNullUnspecified : TypeAttr {
|
||||||
let Documentation = [TypeNullUnspecifiedDocs];
|
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 {
|
def ObjCKindOf : TypeAttr {
|
||||||
let Spellings = [Keyword<"__kindof">];
|
let Spellings = [Keyword<"__kindof">];
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
|
@ -1594,7 +1605,7 @@ def ObjCBridgeRelated : InheritableAttr {
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
}
|
}
|
||||||
|
|
||||||
def NSReturnsRetained : InheritableAttr {
|
def NSReturnsRetained : DeclOrTypeAttr {
|
||||||
let Spellings = [Clang<"ns_returns_retained">];
|
let Spellings = [Clang<"ns_returns_retained">];
|
||||||
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
|
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
|
@ -1779,6 +1790,8 @@ def Regparm : TypeAttr {
|
||||||
let Spellings = [GCC<"regparm">];
|
let Spellings = [GCC<"regparm">];
|
||||||
let Args = [UnsignedArgument<"NumParams">];
|
let Args = [UnsignedArgument<"NumParams">];
|
||||||
let Documentation = [RegparmDocs];
|
let Documentation = [RegparmDocs];
|
||||||
|
// Represented as part of the enclosing function type.
|
||||||
|
let ASTNode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
def ReqdWorkGroupSize : InheritableAttr {
|
def ReqdWorkGroupSize : InheritableAttr {
|
||||||
|
@ -2067,10 +2080,9 @@ def ObjCGC : TypeAttr {
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
}
|
}
|
||||||
|
|
||||||
def ObjCOwnership : InheritableAttr {
|
def ObjCOwnership : DeclOrTypeAttr {
|
||||||
let Spellings = [Clang<"objc_ownership">];
|
let Spellings = [Clang<"objc_ownership">];
|
||||||
let Args = [IdentifierArgument<"Kind">];
|
let Args = [IdentifierArgument<"Kind">];
|
||||||
let ASTNode = 0;
|
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2108,6 +2120,8 @@ def VectorSize : TypeAttr {
|
||||||
let Spellings = [GCC<"vector_size">];
|
let Spellings = [GCC<"vector_size">];
|
||||||
let Args = [ExprArgument<"NumBytes">];
|
let Args = [ExprArgument<"NumBytes">];
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
|
// Represented as VectorType instead.
|
||||||
|
let ASTNode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
def VecTypeHint : InheritableAttr {
|
def VecTypeHint : InheritableAttr {
|
||||||
|
@ -2202,7 +2216,7 @@ def AnyX86NoCallerSavedRegisters : InheritableAttr,
|
||||||
let Documentation = [AnyX86NoCallerSavedRegistersDocs];
|
let Documentation = [AnyX86NoCallerSavedRegistersDocs];
|
||||||
}
|
}
|
||||||
|
|
||||||
def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr<TargetAnyX86>{
|
def AnyX86NoCfCheck : DeclOrTypeAttr, TargetSpecificAttr<TargetAnyX86>{
|
||||||
let Spellings = [GCC<"nocf_check">];
|
let Spellings = [GCC<"nocf_check">];
|
||||||
let Subjects = SubjectList<[FunctionLike]>;
|
let Subjects = SubjectList<[FunctionLike]>;
|
||||||
let Documentation = [AnyX86NoCfCheckDocs];
|
let Documentation = [AnyX86NoCfCheckDocs];
|
||||||
|
|
|
@ -1435,8 +1435,6 @@ public:
|
||||||
|
|
||||||
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
|
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
|
||||||
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
|
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
|
||||||
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
|
||||||
TypeSourceInfo *ReturnTypeInfo);
|
|
||||||
|
|
||||||
/// Package the given type and TSI into a ParsedType.
|
/// Package the given type and TSI into a ParsedType.
|
||||||
ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo);
|
ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo);
|
||||||
|
@ -3378,30 +3376,6 @@ public:
|
||||||
/// Valid types should not have multiple attributes with different CCs.
|
/// Valid types should not have multiple attributes with different CCs.
|
||||||
const AttributedType *getCallingConvAttributedType(QualType T) const;
|
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.
|
/// Stmt attributes - this routine is the top level dispatcher.
|
||||||
StmtResult ProcessStmtAttributes(Stmt *Stmt,
|
StmtResult ProcessStmtAttributes(Stmt *Stmt,
|
||||||
const ParsedAttributesView &Attrs,
|
const ParsedAttributesView &Attrs,
|
||||||
|
@ -8071,10 +8045,6 @@ public:
|
||||||
SourceLocation ProtocolRAngleLoc,
|
SourceLocation ProtocolRAngleLoc,
|
||||||
bool FailOnError = false);
|
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.
|
/// Ensure attributes are consistent with type.
|
||||||
/// \param [in, out] Attributes The attributes to check; they will
|
/// \param [in, out] Attributes The attributes to check; they will
|
||||||
/// be modified to be consistent with \p PropertyTy.
|
/// be modified to be consistent with \p PropertyTy.
|
||||||
|
|
|
@ -2245,6 +2245,9 @@ public:
|
||||||
CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record,
|
CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record,
|
||||||
unsigned &Idx);
|
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.
|
/// Reads attributes from the current stream position.
|
||||||
void ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs);
|
void ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs);
|
||||||
|
|
||||||
|
@ -2630,6 +2633,11 @@ public:
|
||||||
return ASTReader::ReadVersionTuple(Record, Idx);
|
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.
|
/// Reads attributes from the current stream position, advancing Idx.
|
||||||
void readAttributes(AttrVec &Attrs) {
|
void readAttributes(AttrVec &Attrs) {
|
||||||
return Reader->ReadAttributes(*this, Attrs);
|
return Reader->ReadAttributes(*this, Attrs);
|
||||||
|
|
|
@ -955,6 +955,9 @@ public:
|
||||||
return Writer->AddVersionTuple(Version, *Record);
|
return Writer->AddVersionTuple(Version, *Record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit an attribute.
|
||||||
|
void AddAttr(const Attr *A);
|
||||||
|
|
||||||
/// Emit a list of attributes.
|
/// Emit a list of attributes.
|
||||||
void AddAttributes(ArrayRef<const Attr*> Attrs);
|
void AddAttributes(ArrayRef<const Attr*> Attrs);
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,10 +81,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
|
bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
|
||||||
if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
|
auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
|
||||||
|
if (!OwnershipAttr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SourceLocation Loc = TL.getAttrNameLoc();
|
SourceLocation Loc = OwnershipAttr->getLocation();
|
||||||
unsigned RawLoc = Loc.getRawEncoding();
|
unsigned RawLoc = Loc.getRawEncoding();
|
||||||
if (MigrateCtx.AttrSet.count(RawLoc))
|
if (MigrateCtx.AttrSet.count(RawLoc))
|
||||||
return true;
|
return true;
|
||||||
|
@ -93,13 +94,7 @@ public:
|
||||||
SourceManager &SM = Ctx.getSourceManager();
|
SourceManager &SM = Ctx.getSourceManager();
|
||||||
if (Loc.isMacroID())
|
if (Loc.isMacroID())
|
||||||
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
|
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
|
||||||
SmallString<32> Buf;
|
StringRef Spell = OwnershipAttr->getKind()->getName();
|
||||||
bool Invalid = false;
|
|
||||||
StringRef Spell = Lexer::getSpelling(
|
|
||||||
SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
|
|
||||||
Buf, SM, Ctx.getLangOpts(), &Invalid);
|
|
||||||
if (Invalid)
|
|
||||||
return false;
|
|
||||||
MigrationContext::GCAttrOccurrence::AttrKind Kind;
|
MigrationContext::GCAttrOccurrence::AttrKind Kind;
|
||||||
if (Spell == "strong")
|
if (Spell == "strong")
|
||||||
Kind = MigrationContext::GCAttrOccurrence::Strong;
|
Kind = MigrationContext::GCAttrOccurrence::Strong;
|
||||||
|
@ -284,7 +279,7 @@ static void checkAllAtProps(MigrationContext &MigrateCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
|
||||||
SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
|
SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
|
||||||
if (Loc.isMacroID())
|
if (Loc.isMacroID())
|
||||||
Loc = MigrateCtx.Pass.Ctx.getSourceManager()
|
Loc = MigrateCtx.Pass.Ctx.getSourceManager()
|
||||||
.getImmediateExpansionRange(Loc)
|
.getImmediateExpansionRange(Loc)
|
||||||
|
|
|
@ -359,7 +359,7 @@ MigrationContext::~MigrationContext() {
|
||||||
bool MigrationContext::isGCOwnedNonObjC(QualType T) {
|
bool MigrationContext::isGCOwnedNonObjC(QualType T) {
|
||||||
while (!T.isNull()) {
|
while (!T.isNull()) {
|
||||||
if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
|
if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
|
||||||
if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
|
if (AttrT->getAttrKind() == attr::ObjCOwnership)
|
||||||
return !AttrT->getModifiedType()->isObjCRetainableType();
|
return !AttrT->getModifiedType()->isObjCRetainableType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3876,7 +3876,7 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
|
||||||
return QualType(newType, 0);
|
return QualType(newType, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
|
QualType ASTContext::getAttributedType(attr::Kind attrKind,
|
||||||
QualType modifiedType,
|
QualType modifiedType,
|
||||||
QualType equivalentType) {
|
QualType equivalentType) {
|
||||||
llvm::FoldingSetNodeID id;
|
llvm::FoldingSetNodeID id;
|
||||||
|
|
177
lib/AST/Type.cpp
177
lib/AST/Type.cpp
|
@ -592,28 +592,6 @@ bool Type::isObjCClassOrClassKindOfType() const {
|
||||||
return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType();
|
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,
|
ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D,
|
||||||
QualType can,
|
QualType can,
|
||||||
ArrayRef<ObjCProtocolDecl *> protocols)
|
ArrayRef<ObjCProtocolDecl *> protocols)
|
||||||
|
@ -1641,6 +1619,16 @@ TagDecl *Type::getAsTagDecl() const {
|
||||||
return nullptr;
|
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 {
|
namespace {
|
||||||
|
|
||||||
class GetContainedDeducedTypeVisitor :
|
class GetContainedDeducedTypeVisitor :
|
||||||
|
@ -3167,105 +3155,58 @@ bool RecordType::hasConstFields() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttributedType::isQualifier() const {
|
bool AttributedType::isQualifier() const {
|
||||||
|
// FIXME: Generate this with TableGen.
|
||||||
switch (getAttrKind()) {
|
switch (getAttrKind()) {
|
||||||
// These are type qualifiers in the traditional C sense: they annotate
|
// These are type qualifiers in the traditional C sense: they annotate
|
||||||
// something about a specific value/variable of a type. (They aren't
|
// something about a specific value/variable of a type. (They aren't
|
||||||
// always part of the canonical type, though.)
|
// always part of the canonical type, though.)
|
||||||
case AttributedType::attr_address_space:
|
case attr::ObjCGC:
|
||||||
case AttributedType::attr_objc_gc:
|
case attr::ObjCOwnership:
|
||||||
case AttributedType::attr_objc_ownership:
|
case attr::ObjCInertUnsafeUnretained:
|
||||||
case AttributedType::attr_objc_inert_unsafe_unretained:
|
case attr::TypeNonNull:
|
||||||
case AttributedType::attr_nonnull:
|
case attr::TypeNullable:
|
||||||
case AttributedType::attr_nullable:
|
case attr::TypeNullUnspecified:
|
||||||
case AttributedType::attr_null_unspecified:
|
case attr::LifetimeBound:
|
||||||
case AttributedType::attr_lifetimebound:
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// These aren't qualifiers; they rewrite the modified type to be a
|
// All other type attributes aren't qualifiers; they rewrite the modified
|
||||||
// semantically different type.
|
// type to be a semantically different type.
|
||||||
case AttributedType::attr_regparm:
|
default:
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
llvm_unreachable("bad attributed type kind");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttributedType::isMSTypeSpec() const {
|
bool AttributedType::isMSTypeSpec() const {
|
||||||
|
// FIXME: Generate this with TableGen?
|
||||||
switch (getAttrKind()) {
|
switch (getAttrKind()) {
|
||||||
default: return false;
|
default: return false;
|
||||||
case attr_ptr32:
|
case attr::Ptr32:
|
||||||
case attr_ptr64:
|
case attr::Ptr64:
|
||||||
case attr_sptr:
|
case attr::SPtr:
|
||||||
case attr_uptr:
|
case attr::UPtr:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
llvm_unreachable("invalid attr kind");
|
llvm_unreachable("invalid attr kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttributedType::isCallingConv() const {
|
bool AttributedType::isCallingConv() const {
|
||||||
|
// FIXME: Generate this with TableGen.
|
||||||
switch (getAttrKind()) {
|
switch (getAttrKind()) {
|
||||||
case attr_ptr32:
|
default: return false;
|
||||||
case attr_ptr64:
|
case attr::Pcs:
|
||||||
case attr_sptr:
|
case attr::CDecl:
|
||||||
case attr_uptr:
|
case attr::FastCall:
|
||||||
case attr_address_space:
|
case attr::StdCall:
|
||||||
case attr_regparm:
|
case attr::ThisCall:
|
||||||
case attr_vector_size:
|
case attr::RegCall:
|
||||||
case attr_neon_vector_type:
|
case attr::SwiftCall:
|
||||||
case attr_neon_polyvector_type:
|
case attr::VectorCall:
|
||||||
case attr_objc_gc:
|
case attr::Pascal:
|
||||||
case attr_objc_ownership:
|
case attr::MSABI:
|
||||||
case attr_objc_inert_unsafe_unretained:
|
case attr::SysVABI:
|
||||||
case attr_noreturn:
|
case attr::IntelOclBicc:
|
||||||
case attr_nonnull:
|
case attr::PreserveMost:
|
||||||
case attr_ns_returns_retained:
|
case attr::PreserveAll:
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
llvm_unreachable("invalid attr kind");
|
llvm_unreachable("invalid attr kind");
|
||||||
|
@ -3708,23 +3649,18 @@ LinkageInfo Type::getLinkageAndVisibility() const {
|
||||||
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
|
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const {
|
Optional<NullabilityKind>
|
||||||
QualType type(this, 0);
|
Type::getNullability(const ASTContext &Context) const {
|
||||||
do {
|
QualType Type(this, 0);
|
||||||
|
while (const auto *AT = Type->getAs<AttributedType>()) {
|
||||||
// Check whether this is an attributed type with nullability
|
// Check whether this is an attributed type with nullability
|
||||||
// information.
|
// information.
|
||||||
if (auto attributed = dyn_cast<AttributedType>(type.getTypePtr())) {
|
if (auto Nullability = AT->getImmediateNullability())
|
||||||
if (auto nullability = attributed->getImmediateNullability())
|
return Nullability;
|
||||||
return nullability;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Desugar the type. If desugaring does nothing, we're done.
|
Type = AT->getEquivalentType();
|
||||||
QualType desugared = type.getSingleStepDesugaredType(context);
|
}
|
||||||
if (desugared.getTypePtr() == type.getTypePtr())
|
return None;
|
||||||
return None;
|
|
||||||
|
|
||||||
type = desugared;
|
|
||||||
} while (true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Type::canHaveNullability(bool ResultIfUnknown) const {
|
bool Type::canHaveNullability(bool ResultIfUnknown) const {
|
||||||
|
@ -3837,12 +3773,13 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
|
||||||
llvm_unreachable("bad type kind!");
|
llvm_unreachable("bad type kind!");
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<NullabilityKind> AttributedType::getImmediateNullability() const {
|
llvm::Optional<NullabilityKind>
|
||||||
if (getAttrKind() == AttributedType::attr_nonnull)
|
AttributedType::getImmediateNullability() const {
|
||||||
|
if (getAttrKind() == attr::TypeNonNull)
|
||||||
return NullabilityKind::NonNull;
|
return NullabilityKind::NonNull;
|
||||||
if (getAttrKind() == AttributedType::attr_nullable)
|
if (getAttrKind() == attr::TypeNullable)
|
||||||
return NullabilityKind::Nullable;
|
return NullabilityKind::Nullable;
|
||||||
if (getAttrKind() == AttributedType::attr_null_unspecified)
|
if (getAttrKind() == attr::TypeNullUnspecified)
|
||||||
return NullabilityKind::Unspecified;
|
return NullabilityKind::Unspecified;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,11 +404,11 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation TypeLoc::findNullabilityLoc() const {
|
SourceLocation TypeLoc::findNullabilityLoc() const {
|
||||||
if (auto attributedLoc = getAs<AttributedTypeLoc>()) {
|
if (auto ATL = getAs<AttributedTypeLoc>()) {
|
||||||
if (attributedLoc.getAttrKind() == AttributedType::attr_nullable ||
|
const Attr *A = ATL.getAttr();
|
||||||
attributedLoc.getAttrKind() == AttributedType::attr_nonnull ||
|
if (A && (isa<TypeNullableAttr>(A) || isa<TypeNonNullAttr>(A) ||
|
||||||
attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified)
|
isa<TypeNullUnspecifiedAttr>(A)))
|
||||||
return attributedLoc.getAttrNameLoc();
|
return A->getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -1354,12 +1354,14 @@ void TypePrinter::printPackExpansionAfter(const PackExpansionType *T,
|
||||||
|
|
||||||
void TypePrinter::printAttributedBefore(const AttributedType *T,
|
void TypePrinter::printAttributedBefore(const AttributedType *T,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
|
// FIXME: Generate this with TableGen.
|
||||||
|
|
||||||
// Prefer the macro forms of the GC and ownership qualifiers.
|
// Prefer the macro forms of the GC and ownership qualifiers.
|
||||||
if (T->getAttrKind() == AttributedType::attr_objc_gc ||
|
if (T->getAttrKind() == attr::ObjCGC ||
|
||||||
T->getAttrKind() == AttributedType::attr_objc_ownership)
|
T->getAttrKind() == attr::ObjCOwnership)
|
||||||
return printBefore(T->getEquivalentType(), OS);
|
return printBefore(T->getEquivalentType(), OS);
|
||||||
|
|
||||||
if (T->getAttrKind() == AttributedType::attr_objc_kindof)
|
if (T->getAttrKind() == attr::ObjCKindOf)
|
||||||
OS << "__kindof ";
|
OS << "__kindof ";
|
||||||
|
|
||||||
printBefore(T->getModifiedType(), OS);
|
printBefore(T->getModifiedType(), OS);
|
||||||
|
@ -1367,23 +1369,21 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
|
||||||
if (T->isMSTypeSpec()) {
|
if (T->isMSTypeSpec()) {
|
||||||
switch (T->getAttrKind()) {
|
switch (T->getAttrKind()) {
|
||||||
default: return;
|
default: return;
|
||||||
case AttributedType::attr_ptr32: OS << " __ptr32"; break;
|
case attr::Ptr32: OS << " __ptr32"; break;
|
||||||
case AttributedType::attr_ptr64: OS << " __ptr64"; break;
|
case attr::Ptr64: OS << " __ptr64"; break;
|
||||||
case AttributedType::attr_sptr: OS << " __sptr"; break;
|
case attr::SPtr: OS << " __sptr"; break;
|
||||||
case AttributedType::attr_uptr: OS << " __uptr"; break;
|
case attr::UPtr: OS << " __uptr"; break;
|
||||||
}
|
}
|
||||||
spaceBeforePlaceHolder(OS);
|
spaceBeforePlaceHolder(OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print nullability type specifiers.
|
// Print nullability type specifiers.
|
||||||
if (T->getAttrKind() == AttributedType::attr_nonnull ||
|
if (T->getImmediateNullability()) {
|
||||||
T->getAttrKind() == AttributedType::attr_nullable ||
|
if (T->getAttrKind() == attr::TypeNonNull)
|
||||||
T->getAttrKind() == AttributedType::attr_null_unspecified) {
|
|
||||||
if (T->getAttrKind() == AttributedType::attr_nonnull)
|
|
||||||
OS << " _Nonnull";
|
OS << " _Nonnull";
|
||||||
else if (T->getAttrKind() == AttributedType::attr_nullable)
|
else if (T->getAttrKind() == attr::TypeNullable)
|
||||||
OS << " _Nullable";
|
OS << " _Nullable";
|
||||||
else if (T->getAttrKind() == AttributedType::attr_null_unspecified)
|
else if (T->getAttrKind() == attr::TypeNullUnspecified)
|
||||||
OS << " _Null_unspecified";
|
OS << " _Null_unspecified";
|
||||||
else
|
else
|
||||||
llvm_unreachable("unhandled nullability");
|
llvm_unreachable("unhandled nullability");
|
||||||
|
@ -1393,9 +1393,11 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
|
||||||
|
|
||||||
void TypePrinter::printAttributedAfter(const AttributedType *T,
|
void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
|
// FIXME: Generate this with TableGen.
|
||||||
|
|
||||||
// Prefer the macro forms of the GC and ownership qualifiers.
|
// Prefer the macro forms of the GC and ownership qualifiers.
|
||||||
if (T->getAttrKind() == AttributedType::attr_objc_gc ||
|
if (T->getAttrKind() == attr::ObjCGC ||
|
||||||
T->getAttrKind() == AttributedType::attr_objc_ownership)
|
T->getAttrKind() == attr::ObjCOwnership)
|
||||||
return printAfter(T->getEquivalentType(), OS);
|
return printAfter(T->getEquivalentType(), OS);
|
||||||
|
|
||||||
// If this is a calling convention attribute, don't print the implicit CC from
|
// If this is a calling convention attribute, don't print the implicit CC from
|
||||||
|
@ -1406,107 +1408,74 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||||
|
|
||||||
// Some attributes are printed as qualifiers before the type, so we have
|
// Some attributes are printed as qualifiers before the type, so we have
|
||||||
// nothing left to do.
|
// nothing left to do.
|
||||||
if (T->getAttrKind() == AttributedType::attr_objc_kindof ||
|
if (T->getAttrKind() == attr::ObjCKindOf ||
|
||||||
T->isMSTypeSpec() ||
|
T->isMSTypeSpec() || T->getImmediateNullability())
|
||||||
T->getAttrKind() == AttributedType::attr_nonnull ||
|
|
||||||
T->getAttrKind() == AttributedType::attr_nullable ||
|
|
||||||
T->getAttrKind() == AttributedType::attr_null_unspecified)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't print the inert __unsafe_unretained attribute at all.
|
// Don't print the inert __unsafe_unretained attribute at all.
|
||||||
if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
|
if (T->getAttrKind() == attr::ObjCInertUnsafeUnretained)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't print ns_returns_retained unless it had an effect.
|
// Don't print ns_returns_retained unless it had an effect.
|
||||||
if (T->getAttrKind() == AttributedType::attr_ns_returns_retained &&
|
if (T->getAttrKind() == attr::NSReturnsRetained &&
|
||||||
!T->getEquivalentType()->castAs<FunctionType>()
|
!T->getEquivalentType()->castAs<FunctionType>()
|
||||||
->getExtInfo().getProducesResult())
|
->getExtInfo().getProducesResult())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (T->getAttrKind() == AttributedType::attr_lifetimebound) {
|
if (T->getAttrKind() == attr::LifetimeBound) {
|
||||||
OS << " [[clang::lifetimebound]]";
|
OS << " [[clang::lifetimebound]]";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << " __attribute__((";
|
OS << " __attribute__((";
|
||||||
switch (T->getAttrKind()) {
|
switch (T->getAttrKind()) {
|
||||||
case AttributedType::attr_lifetimebound:
|
#define TYPE_ATTR(NAME)
|
||||||
case AttributedType::attr_nonnull:
|
#define DECL_OR_TYPE_ATTR(NAME)
|
||||||
case AttributedType::attr_nullable:
|
#define ATTR(NAME) case attr::NAME:
|
||||||
case AttributedType::attr_null_unspecified:
|
#include "clang/Basic/AttrList.inc"
|
||||||
case AttributedType::attr_objc_gc:
|
llvm_unreachable("non-type attribute attached to type");
|
||||||
case AttributedType::attr_objc_inert_unsafe_unretained:
|
|
||||||
case AttributedType::attr_objc_kindof:
|
case attr::OpenCLPrivateAddressSpace:
|
||||||
case AttributedType::attr_objc_ownership:
|
case attr::OpenCLGlobalAddressSpace:
|
||||||
case AttributedType::attr_ptr32:
|
case attr::OpenCLLocalAddressSpace:
|
||||||
case AttributedType::attr_ptr64:
|
case attr::OpenCLConstantAddressSpace:
|
||||||
case AttributedType::attr_sptr:
|
case attr::OpenCLGenericAddressSpace:
|
||||||
case AttributedType::attr_uptr:
|
// FIXME: Update printAttributedBefore to print these once we generate
|
||||||
|
// AttributedType nodes for them.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case attr::LifetimeBound:
|
||||||
|
case attr::TypeNonNull:
|
||||||
|
case attr::TypeNullable:
|
||||||
|
case attr::TypeNullUnspecified:
|
||||||
|
case attr::ObjCGC:
|
||||||
|
case attr::ObjCInertUnsafeUnretained:
|
||||||
|
case attr::ObjCKindOf:
|
||||||
|
case attr::ObjCOwnership:
|
||||||
|
case attr::Ptr32:
|
||||||
|
case attr::Ptr64:
|
||||||
|
case attr::SPtr:
|
||||||
|
case attr::UPtr:
|
||||||
llvm_unreachable("This attribute should have been handled already");
|
llvm_unreachable("This attribute should have been handled already");
|
||||||
|
|
||||||
case AttributedType::attr_address_space:
|
case attr::NSReturnsRetained:
|
||||||
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<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 AttributedType::attr_ns_returns_retained:
|
|
||||||
OS << "ns_returns_retained";
|
OS << "ns_returns_retained";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// FIXME: When Sema learns to form this AttributedType, avoid printing the
|
// FIXME: When Sema learns to form this AttributedType, avoid printing the
|
||||||
// attribute again in printFunctionProtoAfter.
|
// attribute again in printFunctionProtoAfter.
|
||||||
case AttributedType::attr_noreturn: OS << "noreturn"; break;
|
case attr::AnyX86NoCfCheck: OS << "nocf_check"; break;
|
||||||
case AttributedType::attr_nocf_check: OS << "nocf_check"; break;
|
case attr::CDecl: OS << "cdecl"; break;
|
||||||
case AttributedType::attr_cdecl: OS << "cdecl"; break;
|
case attr::FastCall: OS << "fastcall"; break;
|
||||||
case AttributedType::attr_fastcall: OS << "fastcall"; break;
|
case attr::StdCall: OS << "stdcall"; break;
|
||||||
case AttributedType::attr_stdcall: OS << "stdcall"; break;
|
case attr::ThisCall: OS << "thiscall"; break;
|
||||||
case AttributedType::attr_thiscall: OS << "thiscall"; break;
|
case attr::SwiftCall: OS << "swiftcall"; break;
|
||||||
case AttributedType::attr_swiftcall: OS << "swiftcall"; break;
|
case attr::VectorCall: OS << "vectorcall"; break;
|
||||||
case AttributedType::attr_vectorcall: OS << "vectorcall"; break;
|
case attr::Pascal: OS << "pascal"; break;
|
||||||
case AttributedType::attr_pascal: OS << "pascal"; break;
|
case attr::MSABI: OS << "ms_abi"; break;
|
||||||
case AttributedType::attr_ms_abi: OS << "ms_abi"; break;
|
case attr::SysVABI: OS << "sysv_abi"; break;
|
||||||
case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break;
|
case attr::RegCall: OS << "regcall"; break;
|
||||||
case AttributedType::attr_regcall: OS << "regcall"; break;
|
case attr::Pcs: {
|
||||||
case AttributedType::attr_pcs:
|
|
||||||
case AttributedType::attr_pcs_vfp: {
|
|
||||||
OS << "pcs(";
|
OS << "pcs(";
|
||||||
QualType t = T->getEquivalentType();
|
QualType t = T->getEquivalentType();
|
||||||
while (!t->isFunctionType())
|
while (!t->isFunctionType())
|
||||||
|
@ -1517,12 +1486,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
|
case attr::IntelOclBicc: OS << "inteloclbicc"; break;
|
||||||
case AttributedType::attr_preserve_most:
|
case attr::PreserveMost:
|
||||||
OS << "preserve_most";
|
OS << "preserve_most";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AttributedType::attr_preserve_all:
|
case attr::PreserveAll:
|
||||||
OS << "preserve_all";
|
OS << "preserve_all";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5999,14 +5999,14 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
|
||||||
// The [[lifetimebound]] attribute can be applied to the implicit object
|
// The [[lifetimebound]] attribute can be applied to the implicit object
|
||||||
// parameter of a non-static member function (other than a ctor or dtor)
|
// parameter of a non-static member function (other than a ctor or dtor)
|
||||||
// by applying it to the function type.
|
// by applying it to the function type.
|
||||||
if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) {
|
if (const auto *A = ATL.getAttrAs<LifetimeBoundAttr>()) {
|
||||||
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
|
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
|
||||||
if (!MD || MD->isStatic()) {
|
if (!MD || MD->isStatic()) {
|
||||||
S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_no_object_param)
|
S.Diag(A->getLocation(), diag::err_lifetimebound_no_object_param)
|
||||||
<< !MD << ATL.getLocalSourceRange();
|
<< !MD << A->getRange();
|
||||||
} else if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) {
|
} else if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) {
|
||||||
S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor)
|
S.Diag(A->getLocation(), diag::err_lifetimebound_ctor_dtor)
|
||||||
<< isa<CXXDestructorDecl>(MD) << ATL.getLocalSourceRange();
|
<< isa<CXXDestructorDecl>(MD) << A->getRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14658,15 +14658,15 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
|
||||||
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
|
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
|
||||||
if (const auto *PT = CaptureType->getAs<PointerType>()) {
|
if (const auto *PT = CaptureType->getAs<PointerType>()) {
|
||||||
// This function finds out whether there is an AttributedType of kind
|
// This function finds out whether there is an AttributedType of kind
|
||||||
// attr_objc_ownership in Ty. The existence of AttributedType of kind
|
// attr::ObjCOwnership in Ty. The existence of AttributedType of kind
|
||||||
// attr_objc_ownership implies __autoreleasing was explicitly specified
|
// attr::ObjCOwnership implies __autoreleasing was explicitly specified
|
||||||
// rather than being added implicitly by the compiler.
|
// rather than being added implicitly by the compiler.
|
||||||
auto IsObjCOwnershipAttributedType = [](QualType Ty) {
|
auto IsObjCOwnershipAttributedType = [](QualType Ty) {
|
||||||
while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
|
while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
|
||||||
if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership)
|
if (AttrTy->getAttrKind() == attr::ObjCOwnership)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Peel off AttributedTypes that are not of kind objc_ownership.
|
// Peel off AttributedTypes that are not of kind ObjCOwnership.
|
||||||
Ty = AttrTy->getModifiedType();
|
Ty = AttrTy->getModifiedType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6360,7 +6360,7 @@ static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
|
||||||
for (TypeLoc TL = TSI->getTypeLoc();
|
for (TypeLoc TL = TSI->getTypeLoc();
|
||||||
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
|
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
|
||||||
TL = ATL.getModifiedLoc()) {
|
TL = ATL.getModifiedLoc()) {
|
||||||
if (ATL.getAttrKind() == AttributedType::attr_lifetimebound)
|
if (ATL.getAttrAs<LifetimeBoundAttr>())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2384,7 +2384,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
|
||||||
QualType modifiedTy = resultTy;
|
QualType modifiedTy = resultTy;
|
||||||
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
|
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
|
||||||
if (*nullability == NullabilityKind::Unspecified)
|
if (*nullability == NullabilityKind::Unspecified)
|
||||||
resultTy = Context.getAttributedType(AttributedType::attr_nonnull,
|
resultTy = Context.getAttributedType(attr::TypeNonNull,
|
||||||
modifiedTy, modifiedTy);
|
modifiedTy, modifiedTy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2458,7 +2458,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
|
||||||
QualType modifiedTy = paramTy;
|
QualType modifiedTy = paramTy;
|
||||||
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
|
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
|
||||||
if (*nullability == NullabilityKind::Unspecified)
|
if (*nullability == NullabilityKind::Unspecified)
|
||||||
paramTy = Context.getAttributedType(AttributedType::attr_nullable,
|
paramTy = Context.getAttributedType(attr::TypeNullable,
|
||||||
modifiedTy, modifiedTy);
|
modifiedTy, modifiedTy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,16 @@ namespace {
|
||||||
/// processing is complete.
|
/// processing is complete.
|
||||||
SmallVector<ParsedAttr *, 2> ignoredTypeAttrs;
|
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:
|
public:
|
||||||
TypeProcessingState(Sema &sema, Declarator &declarator)
|
TypeProcessingState(Sema &sema, Declarator &declarator)
|
||||||
: sema(sema), declarator(declarator),
|
: sema(sema), declarator(declarator),
|
||||||
|
@ -230,6 +240,43 @@ namespace {
|
||||||
diagnoseBadTypeAttribute(getSema(), *Attr, type);
|
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() {
|
~TypeProcessingState() {
|
||||||
if (trivial) return;
|
if (trivial) return;
|
||||||
|
|
||||||
|
@ -3832,6 +3879,32 @@ static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) {
|
||||||
return false;
|
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,
|
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
QualType declSpecType,
|
QualType declSpecType,
|
||||||
TypeSourceInfo *TInfo) {
|
TypeSourceInfo *TInfo) {
|
||||||
|
@ -4184,9 +4257,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
|
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||||
D.getDeclSpec().getEndLoc(),
|
D.getDeclSpec().getEndLoc(),
|
||||||
D.getMutableDeclSpec().getAttributes())) {
|
D.getMutableDeclSpec().getAttributes())) {
|
||||||
T = Context.getAttributedType(
|
T = state.getAttributedType(
|
||||||
AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
|
createNullabilityAttr(Context, *attr, *inferNullability), T, T);
|
||||||
attr->setUsedAsTypeAttr();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5025,7 +5097,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
if (D.isInvalidType())
|
if (D.isInvalidType())
|
||||||
return Context.getTrivialTypeSourceInfo(T);
|
return Context.getTrivialTypeSourceInfo(T);
|
||||||
|
|
||||||
return S.GetTypeSourceInfoForDeclarator(D, T, TInfo);
|
return GetTypeSourceInfoForDeclarator(state, T, TInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GetTypeForDeclarator - Convert the type for the specified
|
/// GetTypeForDeclarator - Convert the type for the specified
|
||||||
|
@ -5161,131 +5233,25 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
|
||||||
return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo);
|
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,
|
static void fillAttributedTypeLoc(AttributedTypeLoc TL,
|
||||||
const ParsedAttributesView &Attrs,
|
TypeProcessingState &State) {
|
||||||
const ParsedAttributesView &DeclAttrs) {
|
TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr()));
|
||||||
// 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 {
|
namespace {
|
||||||
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
|
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
|
||||||
ASTContext &Context;
|
ASTContext &Context;
|
||||||
|
TypeProcessingState &State;
|
||||||
const DeclSpec &DS;
|
const DeclSpec &DS;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS)
|
TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
|
||||||
: Context(Context), DS(DS) {}
|
const DeclSpec &DS)
|
||||||
|
: Context(Context), State(State), DS(DS) {}
|
||||||
|
|
||||||
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
||||||
fillAttributedTypeLoc(TL, DS.getAttributes(), ParsedAttributesView{});
|
|
||||||
Visit(TL.getModifiedLoc());
|
Visit(TL.getModifiedLoc());
|
||||||
|
fillAttributedTypeLoc(TL, State);
|
||||||
}
|
}
|
||||||
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
||||||
Visit(TL.getUnqualifiedLoc());
|
Visit(TL.getUnqualifiedLoc());
|
||||||
|
@ -5442,11 +5408,13 @@ namespace {
|
||||||
|
|
||||||
class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> {
|
class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> {
|
||||||
ASTContext &Context;
|
ASTContext &Context;
|
||||||
|
TypeProcessingState &State;
|
||||||
const DeclaratorChunk &Chunk;
|
const DeclaratorChunk &Chunk;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk)
|
DeclaratorLocFiller(ASTContext &Context, TypeProcessingState &State,
|
||||||
: Context(Context), Chunk(Chunk) {}
|
const DeclaratorChunk &Chunk)
|
||||||
|
: Context(Context), State(State), Chunk(Chunk) {}
|
||||||
|
|
||||||
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
||||||
llvm_unreachable("qualified type locs not expected here!");
|
llvm_unreachable("qualified type locs not expected here!");
|
||||||
|
@ -5456,7 +5424,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
||||||
fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{});
|
fillAttributedTypeLoc(TL, State);
|
||||||
}
|
}
|
||||||
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -5613,10 +5581,13 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL,
|
||||||
/// up in the normal place in the declaration specifiers (such as a C++
|
/// up in the normal place in the declaration specifiers (such as a C++
|
||||||
/// conversion function), this pointer will refer to a type source information
|
/// conversion function), this pointer will refer to a type source information
|
||||||
/// for that return type.
|
/// for that return type.
|
||||||
TypeSourceInfo *
|
static TypeSourceInfo *
|
||||||
Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
|
||||||
TypeSourceInfo *ReturnTypeInfo) {
|
QualType T, TypeSourceInfo *ReturnTypeInfo) {
|
||||||
TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
|
Sema &S = State.getSema();
|
||||||
|
Declarator &D = State.getDeclarator();
|
||||||
|
|
||||||
|
TypeSourceInfo *TInfo = S.Context.CreateTypeSourceInfo(T);
|
||||||
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
|
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
|
||||||
|
|
||||||
// Handle parameter packs whose type is a pack expansion.
|
// Handle parameter packs whose type is a pack expansion.
|
||||||
|
@ -5626,7 +5597,6 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
|
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
|
||||||
|
|
||||||
if (DependentAddressSpaceTypeLoc DASTL =
|
if (DependentAddressSpaceTypeLoc DASTL =
|
||||||
CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
|
CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
|
||||||
fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
|
fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
|
||||||
|
@ -5641,8 +5611,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||||
}
|
}
|
||||||
|
|
||||||
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
|
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
|
||||||
fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(),
|
fillAttributedTypeLoc(TL, State);
|
||||||
D.getAttributes());
|
|
||||||
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5650,7 +5619,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||||
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
|
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
|
||||||
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
||||||
|
|
||||||
DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
|
DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL);
|
||||||
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
|
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5661,7 +5630,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||||
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
|
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
|
||||||
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
|
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
|
||||||
} else {
|
} else {
|
||||||
TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL);
|
TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TInfo;
|
return TInfo;
|
||||||
|
@ -5890,7 +5859,7 @@ static bool hasDirectOwnershipQualifier(QualType type) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// __strong id
|
// __strong id
|
||||||
if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
|
if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
|
||||||
if (attr->getAttrKind() == AttributedType::attr_objc_ownership)
|
if (attr->getAttrKind() == attr::ObjCOwnership)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
type = attr->getModifiedType();
|
type = attr->getModifiedType();
|
||||||
|
@ -6034,9 +6003,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
|
||||||
// the coexistence problems with __unsafe_unretained.
|
// the coexistence problems with __unsafe_unretained.
|
||||||
if (!S.getLangOpts().ObjCAutoRefCount &&
|
if (!S.getLangOpts().ObjCAutoRefCount &&
|
||||||
lifetime == Qualifiers::OCL_ExplicitNone) {
|
lifetime == Qualifiers::OCL_ExplicitNone) {
|
||||||
type = S.Context.getAttributedType(
|
type = state.getAttributedType(
|
||||||
AttributedType::attr_objc_inert_unsafe_unretained,
|
createSimpleAttr<ObjCInertUnsafeUnretainedAttr>(S.Context, attr),
|
||||||
type, type);
|
type, type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6046,9 +6015,12 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
|
||||||
|
|
||||||
// If we have a valid source location for the attribute, use an
|
// If we have a valid source location for the attribute, use an
|
||||||
// AttributedType instead.
|
// AttributedType instead.
|
||||||
if (AttrLoc.isValid())
|
if (AttrLoc.isValid()) {
|
||||||
type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
|
type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr(
|
||||||
origType, type);
|
attr.getRange(), S.Context, II,
|
||||||
|
attr.getAttributeSpellingListIndex()),
|
||||||
|
origType, type);
|
||||||
|
}
|
||||||
|
|
||||||
auto diagnoseOrDelay = [](Sema &S, SourceLocation loc,
|
auto diagnoseOrDelay = [](Sema &S, SourceLocation loc,
|
||||||
unsigned diagnostic, QualType type) {
|
unsigned diagnostic, QualType type) {
|
||||||
|
@ -6148,8 +6120,10 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
|
||||||
|
|
||||||
// Make an attributed type to preserve the source information.
|
// Make an attributed type to preserve the source information.
|
||||||
if (attr.getLoc().isValid())
|
if (attr.getLoc().isValid())
|
||||||
type = S.Context.getAttributedType(AttributedType::attr_objc_gc,
|
type = state.getAttributedType(
|
||||||
origType, type);
|
::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II,
|
||||||
|
attr.getAttributeSpellingListIndex()),
|
||||||
|
origType, type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6292,37 +6266,50 @@ namespace {
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
|
static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
|
||||||
ParsedAttr &Attr, QualType &Type) {
|
ParsedAttr &PAttr, QualType &Type) {
|
||||||
Sema &S = State.getSema();
|
Sema &S = State.getSema();
|
||||||
|
|
||||||
ParsedAttr::Kind Kind = Attr.getKind();
|
Attr *A;
|
||||||
|
switch (PAttr.getKind()) {
|
||||||
|
default: llvm_unreachable("Unknown attribute kind");
|
||||||
|
case ParsedAttr::AT_Ptr32:
|
||||||
|
A = createSimpleAttr<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();
|
||||||
QualType Desugared = Type;
|
QualType Desugared = Type;
|
||||||
const AttributedType *AT = dyn_cast<AttributedType>(Type);
|
const AttributedType *AT = dyn_cast<AttributedType>(Type);
|
||||||
while (AT) {
|
while (AT) {
|
||||||
AttributedType::Kind CurAttrKind = AT->getAttrKind();
|
attr::Kind CurAttrKind = AT->getAttrKind();
|
||||||
|
|
||||||
// You cannot specify duplicate type attributes, so if the attribute has
|
// You cannot specify duplicate type attributes, so if the attribute has
|
||||||
// already been applied, flag it.
|
// already been applied, flag it.
|
||||||
if (getAttrListKind(CurAttrKind) == Kind) {
|
if (NewAttrKind == CurAttrKind) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact)
|
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact)
|
||||||
<< Attr.getName();
|
<< PAttr.getName();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// You cannot have both __sptr and __uptr on the same type, nor can you
|
// You cannot have both __sptr and __uptr on the same type, nor can you
|
||||||
// have __ptr32 and __ptr64.
|
// have __ptr32 and __ptr64.
|
||||||
if ((CurAttrKind == AttributedType::attr_ptr32 &&
|
if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) ||
|
||||||
Kind == ParsedAttr::AT_Ptr64) ||
|
(CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) {
|
||||||
(CurAttrKind == AttributedType::attr_ptr64 &&
|
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||||
Kind == ParsedAttr::AT_Ptr32)) {
|
|
||||||
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
|
|
||||||
<< "'__ptr32'" << "'__ptr64'";
|
<< "'__ptr32'" << "'__ptr64'";
|
||||||
return true;
|
return true;
|
||||||
} else if ((CurAttrKind == AttributedType::attr_sptr &&
|
} else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) ||
|
||||||
Kind == ParsedAttr::AT_UPtr) ||
|
(CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) {
|
||||||
(CurAttrKind == AttributedType::attr_uptr &&
|
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||||
Kind == ParsedAttr::AT_SPtr)) {
|
|
||||||
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
|
|
||||||
<< "'__sptr'" << "'__uptr'";
|
<< "'__sptr'" << "'__uptr'";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6333,175 +6320,20 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
|
||||||
|
|
||||||
// Pointer type qualifiers can only operate on pointer types, but not
|
// Pointer type qualifiers can only operate on pointer types, but not
|
||||||
// pointer-to-member types.
|
// 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 (!isa<PointerType>(Desugared)) {
|
||||||
if (Type->isMemberPointerType())
|
if (Type->isMemberPointerType())
|
||||||
S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers) << Attr;
|
S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr;
|
||||||
else
|
else
|
||||||
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) << Attr << 0;
|
S.Diag(PAttr.getLoc(), diag::err_attribute_pointers_only) << PAttr << 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributedType::Kind TAK;
|
Type = State.getAttributedType(A, Type, Type);
|
||||||
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<AttributedType>(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<TypedefType>()) {
|
|
||||||
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<ObjCTypeParamType>(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<ObjCObjectPointerType>();
|
|
||||||
const ObjCObjectType *objType = ptrType ? ptrType->getObjectType()
|
|
||||||
: type->getAs<ObjCObjectType>();
|
|
||||||
|
|
||||||
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6522,6 +6354,175 @@ 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<AttributedType>(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<TypedefType>()) {
|
||||||
|
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<ObjCTypeParamType>(type)) {
|
||||||
|
// Build the attributed type to record where __kindof occurred.
|
||||||
|
type = state.getAttributedType(
|
||||||
|
createSimpleAttr<ObjCKindOfAttr>(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<ObjCObjectPointerType>();
|
||||||
|
const ObjCObjectType *objType = ptrType ? ptrType->getObjectType()
|
||||||
|
: type->getAs<ObjCObjectType>();
|
||||||
|
|
||||||
|
// 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<ObjCKindOfAttr>(S.Context, attr), type, equivType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Distribute a nullability type attribute that cannot be applied to
|
/// Distribute a nullability type attribute that cannot be applied to
|
||||||
/// the type specifier to a pointer, block pointer, or member pointer
|
/// the type specifier to a pointer, block pointer, or member pointer
|
||||||
/// declarator, complaining if necessary.
|
/// declarator, complaining if necessary.
|
||||||
|
@ -6609,27 +6610,27 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) {
|
static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
|
||||||
assert(!Attr.isInvalid());
|
assert(!Attr.isInvalid());
|
||||||
switch (Attr.getKind()) {
|
switch (Attr.getKind()) {
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("not a calling convention attribute");
|
llvm_unreachable("not a calling convention attribute");
|
||||||
case ParsedAttr::AT_CDecl:
|
case ParsedAttr::AT_CDecl:
|
||||||
return AttributedType::attr_cdecl;
|
return createSimpleAttr<CDeclAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_FastCall:
|
case ParsedAttr::AT_FastCall:
|
||||||
return AttributedType::attr_fastcall;
|
return createSimpleAttr<FastCallAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_StdCall:
|
case ParsedAttr::AT_StdCall:
|
||||||
return AttributedType::attr_stdcall;
|
return createSimpleAttr<StdCallAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_ThisCall:
|
case ParsedAttr::AT_ThisCall:
|
||||||
return AttributedType::attr_thiscall;
|
return createSimpleAttr<ThisCallAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_RegCall:
|
case ParsedAttr::AT_RegCall:
|
||||||
return AttributedType::attr_regcall;
|
return createSimpleAttr<RegCallAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_Pascal:
|
case ParsedAttr::AT_Pascal:
|
||||||
return AttributedType::attr_pascal;
|
return createSimpleAttr<PascalAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_SwiftCall:
|
case ParsedAttr::AT_SwiftCall:
|
||||||
return AttributedType::attr_swiftcall;
|
return createSimpleAttr<SwiftCallAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_VectorCall:
|
case ParsedAttr::AT_VectorCall:
|
||||||
return AttributedType::attr_vectorcall;
|
return createSimpleAttr<VectorCallAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_Pcs: {
|
case ParsedAttr::AT_Pcs: {
|
||||||
// The attribute may have had a fixit applied where we treated an
|
// The attribute may have had a fixit applied where we treated an
|
||||||
// identifier as a string literal. The contents of the string are valid,
|
// identifier as a string literal. The contents of the string are valid,
|
||||||
|
@ -6639,20 +6640,22 @@ static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) {
|
||||||
Str = cast<StringLiteral>(Attr.getArgAsExpr(0))->getString();
|
Str = cast<StringLiteral>(Attr.getArgAsExpr(0))->getString();
|
||||||
else
|
else
|
||||||
Str = Attr.getArgAsIdent(0)->Ident->getName();
|
Str = Attr.getArgAsIdent(0)->Ident->getName();
|
||||||
return llvm::StringSwitch<AttributedType::Kind>(Str)
|
PcsAttr::PCSType Type;
|
||||||
.Case("aapcs", AttributedType::attr_pcs)
|
if (!PcsAttr::ConvertStrToPCSType(Str, Type))
|
||||||
.Case("aapcs-vfp", AttributedType::attr_pcs_vfp);
|
llvm_unreachable("already validated the attribute");
|
||||||
|
return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type,
|
||||||
|
Attr.getAttributeSpellingListIndex());
|
||||||
}
|
}
|
||||||
case ParsedAttr::AT_IntelOclBicc:
|
case ParsedAttr::AT_IntelOclBicc:
|
||||||
return AttributedType::attr_inteloclbicc;
|
return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_MSABI:
|
case ParsedAttr::AT_MSABI:
|
||||||
return AttributedType::attr_ms_abi;
|
return createSimpleAttr<MSABIAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_SysVABI:
|
case ParsedAttr::AT_SysVABI:
|
||||||
return AttributedType::attr_sysv_abi;
|
return createSimpleAttr<SysVABIAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_PreserveMost:
|
case ParsedAttr::AT_PreserveMost:
|
||||||
return AttributedType::attr_preserve_most;
|
return createSimpleAttr<PreserveMostAttr>(Ctx, Attr);
|
||||||
case ParsedAttr::AT_PreserveAll:
|
case ParsedAttr::AT_PreserveAll:
|
||||||
return AttributedType::attr_preserve_all;
|
return createSimpleAttr<PreserveAllAttr>(Ctx, Attr);
|
||||||
}
|
}
|
||||||
llvm_unreachable("unexpected attribute kind!");
|
llvm_unreachable("unexpected attribute kind!");
|
||||||
}
|
}
|
||||||
|
@ -6700,8 +6703,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
|
||||||
= unwrapped.get()->getExtInfo().withProducesResult(true);
|
= unwrapped.get()->getExtInfo().withProducesResult(true);
|
||||||
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
||||||
}
|
}
|
||||||
type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
|
type = state.getAttributedType(
|
||||||
origType, type);
|
createSimpleAttr<NSReturnsRetainedAttr>(S.Context, attr),
|
||||||
|
origType, type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6776,13 +6780,12 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
|
||||||
|
|
||||||
const FunctionType *fn = unwrapped.get();
|
const FunctionType *fn = unwrapped.get();
|
||||||
CallingConv CCOld = fn->getCallConv();
|
CallingConv CCOld = fn->getCallConv();
|
||||||
AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr);
|
Attr *CCAttr = getCCTypeAttr(S.Context, attr);
|
||||||
|
|
||||||
if (CCOld != CC) {
|
if (CCOld != CC) {
|
||||||
// Error out on when there's already an attribute on the type
|
// Error out on when there's already an attribute on the type
|
||||||
// and the CCs don't match.
|
// and the CCs don't match.
|
||||||
const AttributedType *AT = S.getCallingConvAttributedType(type);
|
if (const AttributedType *AT = S.getCallingConvAttributedType(type)) {
|
||||||
if (AT && AT->getAttrKind() != CCAttrKind) {
|
|
||||||
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
|
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||||
<< FunctionType::getNameForCallConv(CC)
|
<< FunctionType::getNameForCallConv(CC)
|
||||||
<< FunctionType::getNameForCallConv(CCOld);
|
<< FunctionType::getNameForCallConv(CCOld);
|
||||||
|
@ -6836,7 +6839,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
|
||||||
Equivalent =
|
Equivalent =
|
||||||
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
|
||||||
}
|
}
|
||||||
type = S.Context.getAttributedType(CCAttrKind, type, Equivalent);
|
type = state.getAttributedType(CCAttr, type, Equivalent);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7192,14 +7195,15 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
|
||||||
T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
|
T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleLifetimeBoundAttr(QualType &CurType,
|
static void HandleLifetimeBoundAttr(TypeProcessingState &State,
|
||||||
const ParsedAttr &Attr,
|
QualType &CurType,
|
||||||
Sema &S, Declarator &D) {
|
ParsedAttr &Attr) {
|
||||||
if (D.isDeclarationOfFunction()) {
|
if (State.getDeclarator().isDeclarationOfFunction()) {
|
||||||
CurType = S.Context.getAttributedType(AttributedType::attr_lifetimebound,
|
CurType = State.getAttributedType(
|
||||||
CurType, CurType);
|
createSimpleAttr<LifetimeBoundAttr>(State.getSema().Context, Attr),
|
||||||
|
CurType, CurType);
|
||||||
} else {
|
} else {
|
||||||
Attr.diagnoseAppertainsTo(S, nullptr);
|
Attr.diagnoseAppertainsTo(State.getSema(), nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7309,11 +7313,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
||||||
attr.setUsedAsTypeAttr();
|
attr.setUsedAsTypeAttr();
|
||||||
break;
|
break;
|
||||||
case ParsedAttr::AT_LifetimeBound:
|
case ParsedAttr::AT_LifetimeBound:
|
||||||
if (TAL == TAL_DeclChunk) {
|
if (TAL == TAL_DeclChunk)
|
||||||
HandleLifetimeBoundAttr(type, attr, state.getSema(),
|
HandleLifetimeBoundAttr(state, type, attr);
|
||||||
state.getDeclarator());
|
|
||||||
attr.setUsedAsTypeAttr();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
MS_TYPE_ATTRS_CASELIST:
|
MS_TYPE_ATTRS_CASELIST:
|
||||||
|
@ -7337,11 +7338,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
||||||
bool allowOnArrayType =
|
bool allowOnArrayType =
|
||||||
state.getDeclarator().isPrototypeContext() &&
|
state.getDeclarator().isPrototypeContext() &&
|
||||||
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
|
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
|
||||||
if (state.getSema().checkNullabilityTypeSpecifier(
|
if (checkNullabilityTypeSpecifier(
|
||||||
|
state,
|
||||||
type,
|
type,
|
||||||
mapNullabilityAttrKind(attr.getKind()),
|
attr,
|
||||||
attr.getLoc(),
|
|
||||||
attr.isContextSensitiveKeywordAttribute(),
|
|
||||||
allowOnArrayType)) {
|
allowOnArrayType)) {
|
||||||
attr.setInvalid();
|
attr.setInvalid();
|
||||||
}
|
}
|
||||||
|
@ -7368,9 +7368,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply it regardless.
|
// Apply it regardless.
|
||||||
if (state.getSema().checkObjCKindOfType(type, attr.getLoc()))
|
if (checkObjCKindOfType(state, type, attr))
|
||||||
attr.setInvalid();
|
attr.setInvalid();
|
||||||
attr.setUsedAsTypeAttr();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
FUNCTION_TYPE_ATTRS_CASELIST:
|
FUNCTION_TYPE_ATTRS_CASELIST:
|
||||||
|
|
|
@ -6058,6 +6058,11 @@ QualType TreeTransform<Derived>::TransformAttributedType(
|
||||||
if (modifiedType.isNull())
|
if (modifiedType.isNull())
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
||||||
|
const Attr *oldAttr = TL.getAttr();
|
||||||
|
const Attr *newAttr = getDerived().TransformAttr(oldAttr);
|
||||||
|
if (!newAttr)
|
||||||
|
return QualType();
|
||||||
|
|
||||||
QualType result = TL.getType();
|
QualType result = TL.getType();
|
||||||
|
|
||||||
// FIXME: dependent operand expressions?
|
// FIXME: dependent operand expressions?
|
||||||
|
@ -6074,26 +6079,20 @@ QualType TreeTransform<Derived>::TransformAttributedType(
|
||||||
// type sugar, and therefore cannot be diagnosed in any other way.
|
// type sugar, and therefore cannot be diagnosed in any other way.
|
||||||
if (auto nullability = oldType->getImmediateNullability()) {
|
if (auto nullability = oldType->getImmediateNullability()) {
|
||||||
if (!modifiedType->canHaveNullability()) {
|
if (!modifiedType->canHaveNullability()) {
|
||||||
SemaRef.Diag(TL.getAttrNameLoc(), diag::err_nullability_nonpointer)
|
SemaRef.Diag(TL.getAttr()->getLocation(),
|
||||||
<< DiagNullabilityKind(*nullability, false) << modifiedType;
|
diag::err_nullability_nonpointer)
|
||||||
|
<< DiagNullabilityKind(*nullability, false) << modifiedType;
|
||||||
return QualType();
|
return QualType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = SemaRef.Context.getAttributedType(oldType->getAttrKind(),
|
result = SemaRef.Context.getAttributedType(newAttr->getKind(),
|
||||||
modifiedType,
|
modifiedType,
|
||||||
equivalentType);
|
equivalentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result);
|
AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result);
|
||||||
newTL.setAttrNameLoc(TL.getAttrNameLoc());
|
newTL.setAttr(newAttr);
|
||||||
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 result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6455,6 +6455,10 @@ class TypeLocReader : public TypeLocVisitor<TypeLocReader> {
|
||||||
return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx);
|
return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attr *ReadAttr() {
|
||||||
|
return Reader->ReadAttr(*F, Record, Idx);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TypeLocReader(ModuleFile &F, ASTReader &Reader,
|
TypeLocReader(ModuleFile &F, ASTReader &Reader,
|
||||||
const ASTReader::RecordData &Record, unsigned &Idx)
|
const ASTReader::RecordData &Record, unsigned &Idx)
|
||||||
|
@ -6646,20 +6650,7 @@ void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
||||||
TL.setAttrNameLoc(ReadSourceLocation());
|
TL.setAttr(ReadAttr());
|
||||||
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) {
|
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
||||||
|
|
|
@ -2648,19 +2648,72 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
|
||||||
// Attribute Reading
|
// Attribute Reading
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Reads attributes from the current stream position.
|
namespace {
|
||||||
void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) {
|
class AttrReader {
|
||||||
for (unsigned i = 0, e = Record.readInt(); i != e; ++i) {
|
ModuleFile *F;
|
||||||
Attr *New = nullptr;
|
ASTReader *Reader;
|
||||||
auto Kind = (attr::Kind)Record.readInt();
|
const ASTReader::RecordData &Record;
|
||||||
SourceRange Range = Record.readSourceRange();
|
unsigned &Idx;
|
||||||
ASTContext &Context = getContext();
|
|
||||||
|
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();
|
||||||
|
|
||||||
#include "clang/Serialization/AttrPCHRead.inc"
|
#include "clang/Serialization/AttrPCHRead.inc"
|
||||||
|
|
||||||
assert(New && "Unable to decode attribute?");
|
assert(New && "Unable to decode attribute?");
|
||||||
Attrs.push_back(New);
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -770,19 +770,7 @@ void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
||||||
Record.AddSourceLocation(TL.getAttrNameLoc());
|
Record.AddAttr(TL.getAttr());
|
||||||
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) {
|
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
||||||
|
@ -4481,16 +4469,21 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
|
||||||
// General Serialization Routines
|
// General Serialization Routines
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Emit the list of attributes to the specified record.
|
void ASTRecordWriter::AddAttr(const Attr *A) {
|
||||||
void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
|
|
||||||
auto &Record = *this;
|
auto &Record = *this;
|
||||||
Record.push_back(Attrs.size());
|
if (!A)
|
||||||
for (const auto *A : Attrs) {
|
return Record.push_back(0);
|
||||||
Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
|
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
|
||||||
Record.AddSourceRange(A->getRange());
|
Record.AddSourceRange(A->getRange());
|
||||||
|
|
||||||
#include "clang/Serialization/AttrPCHWrite.inc"
|
#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) {
|
void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
|
||||||
|
|
|
@ -103,9 +103,9 @@ Nullability getNullabilityAnnotation(QualType Type) {
|
||||||
const auto *AttrType = Type->getAs<AttributedType>();
|
const auto *AttrType = Type->getAs<AttributedType>();
|
||||||
if (!AttrType)
|
if (!AttrType)
|
||||||
return Nullability::Unspecified;
|
return Nullability::Unspecified;
|
||||||
if (AttrType->getAttrKind() == AttributedType::attr_nullable)
|
if (AttrType->getAttrKind() == attr::TypeNullable)
|
||||||
return Nullability::Nullable;
|
return Nullability::Nullable;
|
||||||
else if (AttrType->getAttrKind() == AttributedType::attr_nonnull)
|
else if (AttrType->getAttrKind() == attr::TypeNonNull)
|
||||||
return Nullability::Nonnull;
|
return Nullability::Nonnull;
|
||||||
return Nullability::Unspecified;
|
return Nullability::Unspecified;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2470,8 +2470,10 @@ namespace {
|
||||||
|
|
||||||
static const AttrClassDescriptor AttrClassDescriptors[] = {
|
static const AttrClassDescriptor AttrClassDescriptors[] = {
|
||||||
{ "ATTR", "Attr" },
|
{ "ATTR", "Attr" },
|
||||||
|
{ "TYPE_ATTR", "TypeAttr" },
|
||||||
{ "STMT_ATTR", "StmtAttr" },
|
{ "STMT_ATTR", "StmtAttr" },
|
||||||
{ "INHERITABLE_ATTR", "InheritableAttr" },
|
{ "INHERITABLE_ATTR", "InheritableAttr" },
|
||||||
|
{ "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" },
|
||||||
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
|
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
|
||||||
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" }
|
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue