Revert r339623 "Model type attributes as regular Attrs."

This breaks compiling atlwin.h in Chromium. I'm sure the code is invalid
in some way, but we put a lot of work into accepting it, and I'm sure
rejecting it was not an intended consequence of this refactoring. :)

llvm-svn: 339638
This commit is contained in:
Reid Kleckner 2018-08-14 01:55:37 +00:00
parent c7816800d8
commit 11f9f8acde
25 changed files with 835 additions and 680 deletions

View File

@ -31,7 +31,6 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
@ -1423,7 +1422,7 @@ public:
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
QualType getAttributedType(attr::Kind attrKind,
QualType getAttributedType(AttributedType::Kind attrKind,
QualType modifiedType,
QualType equivalentType);

View File

@ -113,19 +113,6 @@ public:
void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
};
class TypeAttr : public Attr {
protected:
TypeAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
bool IsLateParsed)
: Attr(AK, R, SpellingListIndex, IsLateParsed) {}
public:
static bool classof(const Attr *A) {
return A->getKind() >= attr::FirstTypeAttr &&
A->getKind() <= attr::LastTypeAttr;
}
};
class StmtAttr : public Attr {
protected:
StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,

View File

@ -21,7 +21,6 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/LLVM.h"
@ -1871,16 +1870,7 @@ public:
bool isObjCQualifiedClassType() const; // Class<foo>
bool isObjCObjectOrInterfaceType() const;
bool isObjCIdType() const; // id
/// Was this type written with the special inert-in-ARC __unsafe_unretained
/// qualifier?
///
/// This approximates the answer to the following question: if this
/// translation unit were compiled in ARC, would this type be qualified
/// with __unsafe_unretained?
bool isObjCInertUnsafeUnretainedType() const {
return hasAttr(attr::ObjCInertUnsafeUnretained);
}
bool isObjCInertUnsafeUnretainedType() const;
/// Whether the type is Objective-C 'id' or a __kindof type of an
/// object type, e.g., __kindof NSView * or __kindof id
@ -2094,10 +2084,6 @@ public:
/// qualifiers from the outermost type.
const ArrayType *castAsArrayTypeUnsafe() const;
/// Determine whether this type had the specified attribute applied to it
/// (looking through top-level type sugar).
bool hasAttr(attr::Kind AK) const;
/// Get the base element type of this type, potentially discarding type
/// qualifiers. This should never be used when type qualifiers
/// are meaningful.
@ -4207,7 +4193,56 @@ public:
/// - the canonical type is VectorType(16, int)
class AttributedType : public Type, public llvm::FoldingSetNode {
public:
using Kind = attr::Kind;
// It is really silly to have yet another attribute-kind enum, but
// clang::attr::Kind doesn't currently cover the pure type attrs.
enum Kind {
// Expression operand.
attr_address_space,
attr_regparm,
attr_vector_size,
attr_neon_vector_type,
attr_neon_polyvector_type,
FirstExprOperandKind = attr_address_space,
LastExprOperandKind = attr_neon_polyvector_type,
// Enumerated operand (string or keyword).
attr_objc_gc,
attr_objc_ownership,
attr_pcs,
attr_pcs_vfp,
FirstEnumOperandKind = attr_objc_gc,
LastEnumOperandKind = attr_pcs_vfp,
// No operand.
attr_noreturn,
attr_nocf_check,
attr_cdecl,
attr_fastcall,
attr_stdcall,
attr_thiscall,
attr_regcall,
attr_pascal,
attr_swiftcall,
attr_vectorcall,
attr_inteloclbicc,
attr_ms_abi,
attr_sysv_abi,
attr_preserve_most,
attr_preserve_all,
attr_ptr32,
attr_ptr64,
attr_sptr,
attr_uptr,
attr_nonnull,
attr_ns_returns_retained,
attr_nullable,
attr_null_unspecified,
attr_objc_kindof,
attr_objc_inert_unsafe_unretained,
attr_lifetimebound,
};
private:
friend class ASTContext; // ASTContext creates these
@ -4215,7 +4250,7 @@ private:
QualType ModifiedType;
QualType EquivalentType;
AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
AttributedType(QualType canon, Kind attrKind, QualType modified,
QualType equivalent)
: Type(Attributed, canon, equivalent->isDependentType(),
equivalent->isInstantiationDependentType(),
@ -4264,13 +4299,13 @@ public:
static Kind getNullabilityAttrKind(NullabilityKind kind) {
switch (kind) {
case NullabilityKind::NonNull:
return attr::TypeNonNull;
return attr_nonnull;
case NullabilityKind::Nullable:
return attr::TypeNullable;
return attr_nullable;
case NullabilityKind::Unspecified:
return attr::TypeNullUnspecified;
return attr_null_unspecified;
}
llvm_unreachable("Unknown nullability kind.");
}

View File

@ -15,7 +15,6 @@
#ifndef LLVM_CLANG_AST_TYPELOC_H
#define LLVM_CLANG_AST_TYPELOC_H
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateBase.h"
@ -850,7 +849,16 @@ class SubstTemplateTypeParmPackTypeLoc :
};
struct AttributedLocInfo {
const Attr *TypeAttr;
union {
Expr *ExprOperand;
/// A raw SourceLocation.
unsigned EnumOperandLoc;
};
SourceRange OperandParens;
SourceLocation AttrLoc;
};
/// Type source information for an attributed type.
@ -859,10 +867,24 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
AttributedType,
AttributedLocInfo> {
public:
attr::Kind getAttrKind() const {
AttributedType::Kind getAttrKind() const {
return getTypePtr()->getAttrKind();
}
bool hasAttrExprOperand() const {
return (getAttrKind() >= AttributedType::FirstExprOperandKind &&
getAttrKind() <= AttributedType::LastExprOperandKind);
}
bool hasAttrEnumOperand() const {
return (getAttrKind() >= AttributedType::FirstEnumOperandKind &&
getAttrKind() <= AttributedType::LastEnumOperandKind);
}
bool hasAttrOperand() const {
return hasAttrExprOperand() || hasAttrEnumOperand();
}
bool isQualifier() const {
return getTypePtr()->isQualifier();
}
@ -875,16 +897,51 @@ public:
return getInnerTypeLoc();
}
/// The type attribute.
const Attr *getAttr() const {
return getLocalData()->TypeAttr;
/// The location of the attribute name, i.e.
/// __attribute__((regparm(1000)))
/// ^~~~~~~
SourceLocation getAttrNameLoc() const {
return getLocalData()->AttrLoc;
}
void setAttr(const Attr *A) {
getLocalData()->TypeAttr = A;
void setAttrNameLoc(SourceLocation loc) {
getLocalData()->AttrLoc = loc;
}
template<typename T> const T *getAttrAs() {
return dyn_cast_or_null<T>(getAttr());
/// The attribute's expression operand, if it has one.
/// void *cur_thread __attribute__((address_space(21)))
/// ^~
Expr *getAttrExprOperand() const {
assert(hasAttrExprOperand());
return getLocalData()->ExprOperand;
}
void setAttrExprOperand(Expr *e) {
assert(hasAttrExprOperand());
getLocalData()->ExprOperand = e;
}
/// The location of the attribute's enumerated operand, if it has one.
/// void * __attribute__((objc_gc(weak)))
/// ^~~~
SourceLocation getAttrEnumOperandLoc() const {
assert(hasAttrEnumOperand());
return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc);
}
void setAttrEnumOperandLoc(SourceLocation loc) {
assert(hasAttrEnumOperand());
getLocalData()->EnumOperandLoc = loc.getRawEncoding();
}
/// The location of the parentheses around the operand, if there is
/// an operand.
/// void * __attribute__((objc_gc(weak)))
/// ^ ^
SourceRange getAttrOperandParensRange() const {
assert(hasAttrOperand());
return getLocalData()->OperandParens;
}
void setAttrOperandParensRange(SourceRange range) {
assert(hasAttrOperand());
getLocalData()->OperandParens = range;
}
SourceRange getLocalSourceRange() const {
@ -897,11 +954,21 @@ public:
// ^~ ~~
// That enclosure doesn't necessarily belong to a single attribute
// anyway.
return getAttr() ? getAttr()->getRange() : SourceRange();
SourceRange range(getAttrNameLoc());
if (hasAttrOperand())
range.setEnd(getAttrOperandParensRange().getEnd());
return range;
}
void initializeLocal(ASTContext &Context, SourceLocation loc) {
setAttr(nullptr);
setAttrNameLoc(loc);
if (hasAttrExprOperand()) {
setAttrOperandParensRange(SourceRange(loc));
setAttrExprOperand(nullptr);
} else if (hasAttrEnumOperand()) {
setAttrOperandParensRange(SourceRange(loc));
setAttrEnumOperandLoc(loc);
}
}
QualType getInnerType() const {

View File

@ -494,7 +494,10 @@ class Attr {
}
/// A type attribute is not processed on a declaration or a statement.
class TypeAttr : Attr;
class TypeAttr : Attr {
// By default, type attributes do not get an AST node.
let ASTNode = 0;
}
/// A stmt attribute is not processed on a declaration or a type.
class StmtAttr : Attr;
@ -564,8 +567,6 @@ def AddressSpace : TypeAttr {
let Spellings = [Clang<"address_space">];
let Args = [IntArgument<"AddressSpace">];
let Documentation = [Undocumented];
// Represented as a qualifier or DependentAddressSpaceType instead.
let ASTNode = 0;
}
def Alias : Attr {
@ -1223,7 +1224,7 @@ def LayoutVersion : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
let Documentation = [LayoutVersionDocs];
}
def LifetimeBound : DeclOrTypeAttr {
def LifetimeBound : InheritableAttr {
let Spellings = [Clang<"lifetimebound", 0>];
let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
let Documentation = [LifetimeBoundDocs];
@ -1326,16 +1327,12 @@ def NeonPolyVectorType : TypeAttr {
let Spellings = [Clang<"neon_polyvector_type">];
let Args = [IntArgument<"NumElements">];
let Documentation = [Undocumented];
// Represented as VectorType instead.
let ASTNode = 0;
}
def NeonVectorType : TypeAttr {
let Spellings = [Clang<"neon_vector_type">];
let Args = [IntArgument<"NumElements">];
let Documentation = [Undocumented];
// Represented as VectorType instead.
let ASTNode = 0;
}
def ReturnsTwice : InheritableAttr {
@ -1510,14 +1507,6 @@ def TypeNullUnspecified : TypeAttr {
let Documentation = [TypeNullUnspecifiedDocs];
}
// This is a marker used to indicate that an __unsafe_unretained qualifier was
// ignored because ARC is not enabled. The usual representation for this
// qualifier is as an ObjCOwnership attribute with Kind == "none".
def ObjCInertUnsafeUnretained : TypeAttr {
let Spellings = [Keyword<"__unsafe_unretained">];
let Documentation = [Undocumented];
}
def ObjCKindOf : TypeAttr {
let Spellings = [Keyword<"__kindof">];
let Documentation = [Undocumented];
@ -1605,7 +1594,7 @@ def ObjCBridgeRelated : InheritableAttr {
let Documentation = [Undocumented];
}
def NSReturnsRetained : DeclOrTypeAttr {
def NSReturnsRetained : InheritableAttr {
let Spellings = [Clang<"ns_returns_retained">];
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
let Documentation = [Undocumented];
@ -1790,8 +1779,6 @@ def Regparm : TypeAttr {
let Spellings = [GCC<"regparm">];
let Args = [UnsignedArgument<"NumParams">];
let Documentation = [RegparmDocs];
// Represented as part of the enclosing function type.
let ASTNode = 0;
}
def ReqdWorkGroupSize : InheritableAttr {
@ -2080,9 +2067,10 @@ def ObjCGC : TypeAttr {
let Documentation = [Undocumented];
}
def ObjCOwnership : DeclOrTypeAttr {
def ObjCOwnership : InheritableAttr {
let Spellings = [Clang<"objc_ownership">];
let Args = [IdentifierArgument<"Kind">];
let ASTNode = 0;
let Documentation = [Undocumented];
}
@ -2120,8 +2108,6 @@ def VectorSize : TypeAttr {
let Spellings = [GCC<"vector_size">];
let Args = [ExprArgument<"NumBytes">];
let Documentation = [Undocumented];
// Represented as VectorType instead.
let ASTNode = 0;
}
def VecTypeHint : InheritableAttr {
@ -2216,7 +2202,7 @@ def AnyX86NoCallerSavedRegisters : InheritableAttr,
let Documentation = [AnyX86NoCallerSavedRegistersDocs];
}
def AnyX86NoCfCheck : DeclOrTypeAttr, TargetSpecificAttr<TargetAnyX86>{
def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr<TargetAnyX86>{
let Spellings = [GCC<"nocf_check">];
let Subjects = SubjectList<[FunctionLike]>;
let Documentation = [AnyX86NoCfCheckDocs];

View File

@ -1435,6 +1435,8 @@ public:
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
TypeSourceInfo *ReturnTypeInfo);
/// Package the given type and TSI into a ParsedType.
ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo);
@ -3376,6 +3378,30 @@ public:
/// Valid types should not have multiple attributes with different CCs.
const AttributedType *getCallingConvAttributedType(QualType T) const;
/// Check whether a nullability type specifier can be added to the given
/// type.
///
/// \param type The type to which the nullability specifier will be
/// added. On success, this type will be updated appropriately.
///
/// \param nullability The nullability specifier to add.
///
/// \param nullabilityLoc The location of the nullability specifier.
///
/// \param isContextSensitive Whether this nullability specifier was
/// written as a context-sensitive keyword (in an Objective-C
/// method) or an Objective-C property attribute, rather than as an
/// underscored type specifier.
///
/// \param allowArrayTypes Whether to accept nullability specifiers on an
/// array type (e.g., because it will decay to a pointer).
///
/// \returns true if nullability cannot be applied, false otherwise.
bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability,
SourceLocation nullabilityLoc,
bool isContextSensitive,
bool allowArrayTypes);
/// Stmt attributes - this routine is the top level dispatcher.
StmtResult ProcessStmtAttributes(Stmt *Stmt,
const ParsedAttributesView &Attrs,
@ -8045,6 +8071,10 @@ public:
SourceLocation ProtocolRAngleLoc,
bool FailOnError = false);
/// Check the application of the Objective-C '__kindof' qualifier to
/// the given type.
bool checkObjCKindOfType(QualType &type, SourceLocation loc);
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \p PropertyTy.

View File

@ -2245,9 +2245,6 @@ public:
CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
/// Reads one attribute from the current stream position.
Attr *ReadAttr(ModuleFile &M, const RecordData &Record, unsigned &Idx);
/// Reads attributes from the current stream position.
void ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs);
@ -2633,11 +2630,6 @@ public:
return ASTReader::ReadVersionTuple(Record, Idx);
}
/// Reads one attribute from the current stream position, advancing Idx.
Attr *readAttr() {
return Reader->ReadAttr(*F, Record, Idx);
}
/// Reads attributes from the current stream position, advancing Idx.
void readAttributes(AttrVec &Attrs) {
return Reader->ReadAttributes(*this, Attrs);

View File

@ -955,9 +955,6 @@ public:
return Writer->AddVersionTuple(Version, *Record);
}
// Emit an attribute.
void AddAttr(const Attr *A);
/// Emit a list of attributes.
void AddAttributes(ArrayRef<const Attr*> Attrs);
};

View File

@ -81,11 +81,10 @@ public:
}
bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
if (!OwnershipAttr)
if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
return false;
SourceLocation Loc = OwnershipAttr->getLocation();
SourceLocation Loc = TL.getAttrNameLoc();
unsigned RawLoc = Loc.getRawEncoding();
if (MigrateCtx.AttrSet.count(RawLoc))
return true;
@ -94,7 +93,13 @@ public:
SourceManager &SM = Ctx.getSourceManager();
if (Loc.isMacroID())
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
StringRef Spell = OwnershipAttr->getKind()->getName();
SmallString<32> Buf;
bool Invalid = false;
StringRef Spell = Lexer::getSpelling(
SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
Buf, SM, Ctx.getLangOpts(), &Invalid);
if (Invalid)
return false;
MigrationContext::GCAttrOccurrence::AttrKind Kind;
if (Spell == "strong")
Kind = MigrationContext::GCAttrOccurrence::Strong;
@ -279,7 +284,7 @@ static void checkAllAtProps(MigrationContext &MigrateCtx,
}
for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
if (Loc.isMacroID())
Loc = MigrateCtx.Pass.Ctx.getSourceManager()
.getImmediateExpansionRange(Loc)

View File

@ -359,7 +359,7 @@ MigrationContext::~MigrationContext() {
bool MigrationContext::isGCOwnedNonObjC(QualType T) {
while (!T.isNull()) {
if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
if (AttrT->getAttrKind() == attr::ObjCOwnership)
if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
return !AttrT->getModifiedType()->isObjCRetainableType();
}

View File

@ -3876,7 +3876,7 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
return QualType(newType, 0);
}
QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
QualType modifiedType,
QualType equivalentType) {
llvm::FoldingSetNodeID id;

View File

@ -592,6 +592,28 @@ bool Type::isObjCClassOrClassKindOfType() const {
return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType();
}
/// Was this type written with the special inert-in-MRC __unsafe_unretained
/// qualifier?
///
/// This approximates the answer to the following question: if this
/// translation unit were compiled in ARC, would this type be qualified
/// with __unsafe_unretained?
bool Type::isObjCInertUnsafeUnretainedType() const {
const Type *cur = this;
while (true) {
if (const auto attributed = dyn_cast<AttributedType>(cur)) {
if (attributed->getAttrKind() ==
AttributedType::attr_objc_inert_unsafe_unretained)
return true;
}
// Single-step desugar until we run out of sugar.
QualType next = cur->getLocallyUnqualifiedSingleStepDesugaredType();
if (next.getTypePtr() == cur) return false;
cur = next.getTypePtr();
}
}
ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D,
QualType can,
ArrayRef<ObjCProtocolDecl *> protocols)
@ -1619,16 +1641,6 @@ TagDecl *Type::getAsTagDecl() const {
return nullptr;
}
bool Type::hasAttr(attr::Kind AK) const {
const Type *Cur = this;
while (const auto *AT = Cur->getAs<AttributedType>()) {
if (AT->getAttrKind() == AK)
return true;
Cur = AT->getEquivalentType().getTypePtr();
}
return false;
}
namespace {
class GetContainedDeducedTypeVisitor :
@ -3155,58 +3167,105 @@ bool RecordType::hasConstFields() const {
}
bool AttributedType::isQualifier() const {
// FIXME: Generate this with TableGen.
switch (getAttrKind()) {
// These are type qualifiers in the traditional C sense: they annotate
// something about a specific value/variable of a type. (They aren't
// always part of the canonical type, though.)
case attr::ObjCGC:
case attr::ObjCOwnership:
case attr::ObjCInertUnsafeUnretained:
case attr::TypeNonNull:
case attr::TypeNullable:
case attr::TypeNullUnspecified:
case attr::LifetimeBound:
case AttributedType::attr_address_space:
case AttributedType::attr_objc_gc:
case AttributedType::attr_objc_ownership:
case AttributedType::attr_objc_inert_unsafe_unretained:
case AttributedType::attr_nonnull:
case AttributedType::attr_nullable:
case AttributedType::attr_null_unspecified:
case AttributedType::attr_lifetimebound:
return true;
// All other type attributes aren't qualifiers; they rewrite the modified
// type to be a semantically different type.
default:
// These aren't qualifiers; they rewrite the modified type to be a
// semantically different type.
case AttributedType::attr_regparm:
case AttributedType::attr_vector_size:
case AttributedType::attr_neon_vector_type:
case AttributedType::attr_neon_polyvector_type:
case AttributedType::attr_pcs:
case AttributedType::attr_pcs_vfp:
case AttributedType::attr_noreturn:
case AttributedType::attr_cdecl:
case AttributedType::attr_fastcall:
case AttributedType::attr_stdcall:
case AttributedType::attr_thiscall:
case AttributedType::attr_regcall:
case AttributedType::attr_pascal:
case AttributedType::attr_swiftcall:
case AttributedType::attr_vectorcall:
case AttributedType::attr_inteloclbicc:
case AttributedType::attr_preserve_most:
case AttributedType::attr_preserve_all:
case AttributedType::attr_ms_abi:
case AttributedType::attr_sysv_abi:
case AttributedType::attr_ptr32:
case AttributedType::attr_ptr64:
case AttributedType::attr_sptr:
case AttributedType::attr_uptr:
case AttributedType::attr_objc_kindof:
case AttributedType::attr_ns_returns_retained:
case AttributedType::attr_nocf_check:
return false;
}
llvm_unreachable("bad attributed type kind");
}
bool AttributedType::isMSTypeSpec() const {
// FIXME: Generate this with TableGen?
switch (getAttrKind()) {
default: return false;
case attr::Ptr32:
case attr::Ptr64:
case attr::SPtr:
case attr::UPtr:
default: return false;
case attr_ptr32:
case attr_ptr64:
case attr_sptr:
case attr_uptr:
return true;
}
llvm_unreachable("invalid attr kind");
}
bool AttributedType::isCallingConv() const {
// FIXME: Generate this with TableGen.
switch (getAttrKind()) {
default: return false;
case attr::Pcs:
case attr::CDecl:
case attr::FastCall:
case attr::StdCall:
case attr::ThisCall:
case attr::RegCall:
case attr::SwiftCall:
case attr::VectorCall:
case attr::Pascal:
case attr::MSABI:
case attr::SysVABI:
case attr::IntelOclBicc:
case attr::PreserveMost:
case attr::PreserveAll:
case attr_ptr32:
case attr_ptr64:
case attr_sptr:
case attr_uptr:
case attr_address_space:
case attr_regparm:
case attr_vector_size:
case attr_neon_vector_type:
case attr_neon_polyvector_type:
case attr_objc_gc:
case attr_objc_ownership:
case attr_objc_inert_unsafe_unretained:
case attr_noreturn:
case attr_nonnull:
case attr_ns_returns_retained:
case attr_nullable:
case attr_null_unspecified:
case attr_objc_kindof:
case attr_nocf_check:
case attr_lifetimebound:
return false;
case attr_pcs:
case attr_pcs_vfp:
case attr_cdecl:
case attr_fastcall:
case attr_stdcall:
case attr_thiscall:
case attr_regcall:
case attr_swiftcall:
case attr_vectorcall:
case attr_pascal:
case attr_ms_abi:
case attr_sysv_abi:
case attr_inteloclbicc:
case attr_preserve_most:
case attr_preserve_all:
return true;
}
llvm_unreachable("invalid attr kind");
@ -3649,18 +3708,23 @@ LinkageInfo Type::getLinkageAndVisibility() const {
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
}
Optional<NullabilityKind>
Type::getNullability(const ASTContext &Context) const {
QualType Type(this, 0);
while (const auto *AT = Type->getAs<AttributedType>()) {
Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const {
QualType type(this, 0);
do {
// Check whether this is an attributed type with nullability
// information.
if (auto Nullability = AT->getImmediateNullability())
return Nullability;
if (auto attributed = dyn_cast<AttributedType>(type.getTypePtr())) {
if (auto nullability = attributed->getImmediateNullability())
return nullability;
}
Type = AT->getEquivalentType();
}
return None;
// Desugar the type. If desugaring does nothing, we're done.
QualType desugared = type.getSingleStepDesugaredType(context);
if (desugared.getTypePtr() == type.getTypePtr())
return None;
type = desugared;
} while (true);
}
bool Type::canHaveNullability(bool ResultIfUnknown) const {
@ -3773,13 +3837,12 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
llvm_unreachable("bad type kind!");
}
llvm::Optional<NullabilityKind>
AttributedType::getImmediateNullability() const {
if (getAttrKind() == attr::TypeNonNull)
llvm::Optional<NullabilityKind> AttributedType::getImmediateNullability() const {
if (getAttrKind() == AttributedType::attr_nonnull)
return NullabilityKind::NonNull;
if (getAttrKind() == attr::TypeNullable)
if (getAttrKind() == AttributedType::attr_nullable)
return NullabilityKind::Nullable;
if (getAttrKind() == attr::TypeNullUnspecified)
if (getAttrKind() == AttributedType::attr_null_unspecified)
return NullabilityKind::Unspecified;
return None;
}

View File

@ -404,11 +404,11 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
}
SourceLocation TypeLoc::findNullabilityLoc() const {
if (auto ATL = getAs<AttributedTypeLoc>()) {
const Attr *A = ATL.getAttr();
if (A && (isa<TypeNullableAttr>(A) || isa<TypeNonNullAttr>(A) ||
isa<TypeNullUnspecifiedAttr>(A)))
return A->getLocation();
if (auto attributedLoc = getAs<AttributedTypeLoc>()) {
if (attributedLoc.getAttrKind() == AttributedType::attr_nullable ||
attributedLoc.getAttrKind() == AttributedType::attr_nonnull ||
attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified)
return attributedLoc.getAttrNameLoc();
}
return {};

View File

@ -1354,14 +1354,12 @@ void TypePrinter::printPackExpansionAfter(const PackExpansionType *T,
void TypePrinter::printAttributedBefore(const AttributedType *T,
raw_ostream &OS) {
// FIXME: Generate this with TableGen.
// Prefer the macro forms of the GC and ownership qualifiers.
if (T->getAttrKind() == attr::ObjCGC ||
T->getAttrKind() == attr::ObjCOwnership)
if (T->getAttrKind() == AttributedType::attr_objc_gc ||
T->getAttrKind() == AttributedType::attr_objc_ownership)
return printBefore(T->getEquivalentType(), OS);
if (T->getAttrKind() == attr::ObjCKindOf)
if (T->getAttrKind() == AttributedType::attr_objc_kindof)
OS << "__kindof ";
printBefore(T->getModifiedType(), OS);
@ -1369,21 +1367,23 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
if (T->isMSTypeSpec()) {
switch (T->getAttrKind()) {
default: return;
case attr::Ptr32: OS << " __ptr32"; break;
case attr::Ptr64: OS << " __ptr64"; break;
case attr::SPtr: OS << " __sptr"; break;
case attr::UPtr: OS << " __uptr"; break;
case AttributedType::attr_ptr32: OS << " __ptr32"; break;
case AttributedType::attr_ptr64: OS << " __ptr64"; break;
case AttributedType::attr_sptr: OS << " __sptr"; break;
case AttributedType::attr_uptr: OS << " __uptr"; break;
}
spaceBeforePlaceHolder(OS);
}
// Print nullability type specifiers.
if (T->getImmediateNullability()) {
if (T->getAttrKind() == attr::TypeNonNull)
if (T->getAttrKind() == AttributedType::attr_nonnull ||
T->getAttrKind() == AttributedType::attr_nullable ||
T->getAttrKind() == AttributedType::attr_null_unspecified) {
if (T->getAttrKind() == AttributedType::attr_nonnull)
OS << " _Nonnull";
else if (T->getAttrKind() == attr::TypeNullable)
else if (T->getAttrKind() == AttributedType::attr_nullable)
OS << " _Nullable";
else if (T->getAttrKind() == attr::TypeNullUnspecified)
else if (T->getAttrKind() == AttributedType::attr_null_unspecified)
OS << " _Null_unspecified";
else
llvm_unreachable("unhandled nullability");
@ -1393,11 +1393,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
void TypePrinter::printAttributedAfter(const AttributedType *T,
raw_ostream &OS) {
// FIXME: Generate this with TableGen.
// Prefer the macro forms of the GC and ownership qualifiers.
if (T->getAttrKind() == attr::ObjCGC ||
T->getAttrKind() == attr::ObjCOwnership)
if (T->getAttrKind() == AttributedType::attr_objc_gc ||
T->getAttrKind() == AttributedType::attr_objc_ownership)
return printAfter(T->getEquivalentType(), OS);
// If this is a calling convention attribute, don't print the implicit CC from
@ -1408,74 +1406,107 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
// Some attributes are printed as qualifiers before the type, so we have
// nothing left to do.
if (T->getAttrKind() == attr::ObjCKindOf ||
T->isMSTypeSpec() || T->getImmediateNullability())
if (T->getAttrKind() == AttributedType::attr_objc_kindof ||
T->isMSTypeSpec() ||
T->getAttrKind() == AttributedType::attr_nonnull ||
T->getAttrKind() == AttributedType::attr_nullable ||
T->getAttrKind() == AttributedType::attr_null_unspecified)
return;
// Don't print the inert __unsafe_unretained attribute at all.
if (T->getAttrKind() == attr::ObjCInertUnsafeUnretained)
if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
return;
// Don't print ns_returns_retained unless it had an effect.
if (T->getAttrKind() == attr::NSReturnsRetained &&
if (T->getAttrKind() == AttributedType::attr_ns_returns_retained &&
!T->getEquivalentType()->castAs<FunctionType>()
->getExtInfo().getProducesResult())
return;
if (T->getAttrKind() == attr::LifetimeBound) {
if (T->getAttrKind() == AttributedType::attr_lifetimebound) {
OS << " [[clang::lifetimebound]]";
return;
}
OS << " __attribute__((";
switch (T->getAttrKind()) {
#define TYPE_ATTR(NAME)
#define DECL_OR_TYPE_ATTR(NAME)
#define ATTR(NAME) case attr::NAME:
#include "clang/Basic/AttrList.inc"
llvm_unreachable("non-type attribute attached to type");
case attr::OpenCLPrivateAddressSpace:
case attr::OpenCLGlobalAddressSpace:
case attr::OpenCLLocalAddressSpace:
case attr::OpenCLConstantAddressSpace:
case attr::OpenCLGenericAddressSpace:
// FIXME: Update printAttributedBefore to print these once we generate
// AttributedType nodes for them.
break;
case attr::LifetimeBound:
case attr::TypeNonNull:
case attr::TypeNullable:
case attr::TypeNullUnspecified:
case attr::ObjCGC:
case attr::ObjCInertUnsafeUnretained:
case attr::ObjCKindOf:
case attr::ObjCOwnership:
case attr::Ptr32:
case attr::Ptr64:
case attr::SPtr:
case attr::UPtr:
case AttributedType::attr_lifetimebound:
case AttributedType::attr_nonnull:
case AttributedType::attr_nullable:
case AttributedType::attr_null_unspecified:
case AttributedType::attr_objc_gc:
case AttributedType::attr_objc_inert_unsafe_unretained:
case AttributedType::attr_objc_kindof:
case AttributedType::attr_objc_ownership:
case AttributedType::attr_ptr32:
case AttributedType::attr_ptr64:
case AttributedType::attr_sptr:
case AttributedType::attr_uptr:
llvm_unreachable("This attribute should have been handled already");
case attr::NSReturnsRetained:
case AttributedType::attr_address_space:
OS << "address_space(";
// FIXME: printing the raw LangAS value is wrong. This should probably
// use the same code as Qualifiers::print()
OS << (unsigned)T->getEquivalentType().getAddressSpace();
OS << ')';
break;
case AttributedType::attr_vector_size:
OS << "__vector_size__(";
if (const auto *vector = T->getEquivalentType()->getAs<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";
break;
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
case attr::AnyX86NoCfCheck: OS << "nocf_check"; break;
case attr::CDecl: OS << "cdecl"; break;
case attr::FastCall: OS << "fastcall"; break;
case attr::StdCall: OS << "stdcall"; break;
case attr::ThisCall: OS << "thiscall"; break;
case attr::SwiftCall: OS << "swiftcall"; break;
case attr::VectorCall: OS << "vectorcall"; break;
case attr::Pascal: OS << "pascal"; break;
case attr::MSABI: OS << "ms_abi"; break;
case attr::SysVABI: OS << "sysv_abi"; break;
case attr::RegCall: OS << "regcall"; break;
case attr::Pcs: {
case AttributedType::attr_noreturn: OS << "noreturn"; break;
case AttributedType::attr_nocf_check: OS << "nocf_check"; break;
case AttributedType::attr_cdecl: OS << "cdecl"; break;
case AttributedType::attr_fastcall: OS << "fastcall"; break;
case AttributedType::attr_stdcall: OS << "stdcall"; break;
case AttributedType::attr_thiscall: OS << "thiscall"; break;
case AttributedType::attr_swiftcall: OS << "swiftcall"; break;
case AttributedType::attr_vectorcall: OS << "vectorcall"; break;
case AttributedType::attr_pascal: OS << "pascal"; break;
case AttributedType::attr_ms_abi: OS << "ms_abi"; break;
case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break;
case AttributedType::attr_regcall: OS << "regcall"; break;
case AttributedType::attr_pcs:
case AttributedType::attr_pcs_vfp: {
OS << "pcs(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@ -1486,12 +1517,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
break;
}
case attr::IntelOclBicc: OS << "inteloclbicc"; break;
case attr::PreserveMost:
case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
case AttributedType::attr_preserve_most:
OS << "preserve_most";
break;
case attr::PreserveAll:
case AttributedType::attr_preserve_all:
OS << "preserve_all";
break;
}

View File

@ -5999,14 +5999,14 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
// The [[lifetimebound]] attribute can be applied to the implicit object
// parameter of a non-static member function (other than a ctor or dtor)
// by applying it to the function type.
if (const auto *A = ATL.getAttrAs<LifetimeBoundAttr>()) {
if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) {
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
if (!MD || MD->isStatic()) {
S.Diag(A->getLocation(), diag::err_lifetimebound_no_object_param)
<< !MD << A->getRange();
S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_no_object_param)
<< !MD << ATL.getLocalSourceRange();
} else if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) {
S.Diag(A->getLocation(), diag::err_lifetimebound_ctor_dtor)
<< isa<CXXDestructorDecl>(MD) << A->getRange();
S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor)
<< isa<CXXDestructorDecl>(MD) << ATL.getLocalSourceRange();
}
}
}

View File

@ -14658,15 +14658,15 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
if (const auto *PT = CaptureType->getAs<PointerType>()) {
// This function finds out whether there is an AttributedType of kind
// attr::ObjCOwnership in Ty. The existence of AttributedType of kind
// attr::ObjCOwnership implies __autoreleasing was explicitly specified
// attr_objc_ownership in Ty. The existence of AttributedType of kind
// attr_objc_ownership implies __autoreleasing was explicitly specified
// rather than being added implicitly by the compiler.
auto IsObjCOwnershipAttributedType = [](QualType Ty) {
while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
if (AttrTy->getAttrKind() == attr::ObjCOwnership)
if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership)
return true;
// Peel off AttributedTypes that are not of kind ObjCOwnership.
// Peel off AttributedTypes that are not of kind objc_ownership.
Ty = AttrTy->getModifiedType();
}

View File

@ -6360,7 +6360,7 @@ static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
for (TypeLoc TL = TSI->getTypeLoc();
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
TL = ATL.getModifiedLoc()) {
if (ATL.getAttrAs<LifetimeBoundAttr>())
if (ATL.getAttrKind() == AttributedType::attr_lifetimebound)
return true;
}
return false;

View File

@ -2384,7 +2384,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
QualType modifiedTy = resultTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
if (*nullability == NullabilityKind::Unspecified)
resultTy = Context.getAttributedType(attr::TypeNonNull,
resultTy = Context.getAttributedType(AttributedType::attr_nonnull,
modifiedTy, modifiedTy);
}
}
@ -2458,7 +2458,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
QualType modifiedTy = paramTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
if (*nullability == NullabilityKind::Unspecified)
paramTy = Context.getAttributedType(attr::TypeNullable,
paramTy = Context.getAttributedType(AttributedType::attr_nullable,
modifiedTy, modifiedTy);
}
}

View File

@ -172,16 +172,6 @@ namespace {
/// processing is complete.
SmallVector<ParsedAttr *, 2> ignoredTypeAttrs;
/// Attributes corresponding to AttributedTypeLocs that we have not yet
/// populated.
// FIXME: The two-phase mechanism by which we construct Types and fill
// their TypeLocs makes it hard to correctly assign these. We keep the
// attributes in creation order as an attempt to make them line up
// properly.
using TypeAttrPair = std::pair<const AttributedType*, const Attr*>;
SmallVector<TypeAttrPair, 8> AttrsForTypes;
bool AttrsForTypesSorted = true;
public:
TypeProcessingState(Sema &sema, Declarator &declarator)
: sema(sema), declarator(declarator),
@ -240,43 +230,6 @@ namespace {
diagnoseBadTypeAttribute(getSema(), *Attr, type);
}
/// Get an attributed type for the given attribute, and remember the Attr
/// object so that we can attach it to the AttributedTypeLoc.
QualType getAttributedType(Attr *A, QualType ModifiedType,
QualType EquivType) {
QualType T =
sema.Context.getAttributedType(A->getKind(), ModifiedType, EquivType);
AttrsForTypes.push_back({cast<AttributedType>(T.getTypePtr()), A});
AttrsForTypesSorted = false;
return T;
}
/// Extract and remove the Attr* for a given attributed type.
const Attr *takeAttrForAttributedType(const AttributedType *AT) {
if (!AttrsForTypesSorted) {
std::stable_sort(AttrsForTypes.begin(), AttrsForTypes.end(),
[](const TypeAttrPair &A, const TypeAttrPair &B) {
return A.first < B.first;
});
AttrsForTypesSorted = true;
}
// FIXME: This is quadratic if we have lots of reuses of the same
// attributed type.
for (auto It = std::partition_point(
AttrsForTypes.begin(), AttrsForTypes.end(),
[=](const TypeAttrPair &A) { return A.first < AT; });
It != AttrsForTypes.end() && It->first == AT; ++It) {
if (It->second) {
const Attr *Result = It->second;
It->second = nullptr;
return Result;
}
}
llvm_unreachable("no Attr* for AttributedType*");
}
~TypeProcessingState() {
if (trivial) return;
@ -3879,32 +3832,6 @@ static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) {
return false;
}
template<typename AttrT>
static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &Attr) {
Attr.setUsedAsTypeAttr();
return ::new (Ctx)
AttrT(Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex());
}
static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr,
NullabilityKind NK) {
switch (NK) {
case NullabilityKind::NonNull:
return createSimpleAttr<TypeNonNullAttr>(Ctx, Attr);
case NullabilityKind::Nullable:
return createSimpleAttr<TypeNullableAttr>(Ctx, Attr);
case NullabilityKind::Unspecified:
return createSimpleAttr<TypeNullUnspecifiedAttr>(Ctx, Attr);
}
llvm_unreachable("unknown NullabilityKind");
}
static TypeSourceInfo *
GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
QualType T, TypeSourceInfo *ReturnTypeInfo);
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@ -4257,8 +4184,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
D.getDeclSpec().getEndLoc(),
D.getMutableDeclSpec().getAttributes())) {
T = state.getAttributedType(
createNullabilityAttr(Context, *attr, *inferNullability), T, T);
T = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
attr->setUsedAsTypeAttr();
}
}
}
@ -5097,7 +5025,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (D.isInvalidType())
return Context.getTrivialTypeSourceInfo(T);
return GetTypeSourceInfoForDeclarator(state, T, TInfo);
return S.GetTypeSourceInfoForDeclarator(D, T, TInfo);
}
/// GetTypeForDeclarator - Convert the type for the specified
@ -5233,25 +5161,131 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo);
}
/// Map an AttributedType::Kind to an ParsedAttr::Kind.
static ParsedAttr::Kind getAttrListKind(AttributedType::Kind kind) {
switch (kind) {
case AttributedType::attr_address_space:
return ParsedAttr::AT_AddressSpace;
case AttributedType::attr_regparm:
return ParsedAttr::AT_Regparm;
case AttributedType::attr_vector_size:
return ParsedAttr::AT_VectorSize;
case AttributedType::attr_neon_vector_type:
return ParsedAttr::AT_NeonVectorType;
case AttributedType::attr_neon_polyvector_type:
return ParsedAttr::AT_NeonPolyVectorType;
case AttributedType::attr_objc_gc:
return ParsedAttr::AT_ObjCGC;
case AttributedType::attr_objc_ownership:
case AttributedType::attr_objc_inert_unsafe_unretained:
return ParsedAttr::AT_ObjCOwnership;
case AttributedType::attr_noreturn:
return ParsedAttr::AT_NoReturn;
case AttributedType::attr_nocf_check:
return ParsedAttr::AT_AnyX86NoCfCheck;
case AttributedType::attr_cdecl:
return ParsedAttr::AT_CDecl;
case AttributedType::attr_fastcall:
return ParsedAttr::AT_FastCall;
case AttributedType::attr_stdcall:
return ParsedAttr::AT_StdCall;
case AttributedType::attr_thiscall:
return ParsedAttr::AT_ThisCall;
case AttributedType::attr_regcall:
return ParsedAttr::AT_RegCall;
case AttributedType::attr_pascal:
return ParsedAttr::AT_Pascal;
case AttributedType::attr_swiftcall:
return ParsedAttr::AT_SwiftCall;
case AttributedType::attr_vectorcall:
return ParsedAttr::AT_VectorCall;
case AttributedType::attr_pcs:
case AttributedType::attr_pcs_vfp:
return ParsedAttr::AT_Pcs;
case AttributedType::attr_inteloclbicc:
return ParsedAttr::AT_IntelOclBicc;
case AttributedType::attr_ms_abi:
return ParsedAttr::AT_MSABI;
case AttributedType::attr_sysv_abi:
return ParsedAttr::AT_SysVABI;
case AttributedType::attr_preserve_most:
return ParsedAttr::AT_PreserveMost;
case AttributedType::attr_preserve_all:
return ParsedAttr::AT_PreserveAll;
case AttributedType::attr_ptr32:
return ParsedAttr::AT_Ptr32;
case AttributedType::attr_ptr64:
return ParsedAttr::AT_Ptr64;
case AttributedType::attr_sptr:
return ParsedAttr::AT_SPtr;
case AttributedType::attr_uptr:
return ParsedAttr::AT_UPtr;
case AttributedType::attr_nonnull:
return ParsedAttr::AT_TypeNonNull;
case AttributedType::attr_nullable:
return ParsedAttr::AT_TypeNullable;
case AttributedType::attr_null_unspecified:
return ParsedAttr::AT_TypeNullUnspecified;
case AttributedType::attr_objc_kindof:
return ParsedAttr::AT_ObjCKindOf;
case AttributedType::attr_ns_returns_retained:
return ParsedAttr::AT_NSReturnsRetained;
case AttributedType::attr_lifetimebound:
return ParsedAttr::AT_LifetimeBound;
}
llvm_unreachable("unexpected attribute kind!");
}
static void setAttributedTypeLoc(AttributedTypeLoc TL, const ParsedAttr &attr) {
TL.setAttrNameLoc(attr.getLoc());
if (TL.hasAttrExprOperand()) {
assert(attr.isArgExpr(0) && "mismatched attribute operand kind");
TL.setAttrExprOperand(attr.getArgAsExpr(0));
} else if (TL.hasAttrEnumOperand()) {
assert((attr.isArgIdent(0) || attr.isArgExpr(0)) &&
"unexpected attribute operand kind");
if (attr.isArgIdent(0))
TL.setAttrEnumOperandLoc(attr.getArgAsIdent(0)->Loc);
else
TL.setAttrEnumOperandLoc(attr.getArgAsExpr(0)->getExprLoc());
}
// FIXME: preserve this information to here.
if (TL.hasAttrOperand())
TL.setAttrOperandParensRange(SourceRange());
}
static void fillAttributedTypeLoc(AttributedTypeLoc TL,
TypeProcessingState &State) {
TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr()));
const ParsedAttributesView &Attrs,
const ParsedAttributesView &DeclAttrs) {
// DeclAttrs and Attrs cannot be both empty.
assert((!Attrs.empty() || !DeclAttrs.empty()) &&
"no type attributes in the expected location!");
ParsedAttr::Kind parsedKind = getAttrListKind(TL.getAttrKind());
// Try to search for an attribute of matching kind in Attrs list.
for (const ParsedAttr &AL : Attrs)
if (AL.getKind() == parsedKind)
return setAttributedTypeLoc(TL, AL);
for (const ParsedAttr &AL : DeclAttrs)
if (AL.isCXX11Attribute() || AL.getKind() == parsedKind)
return setAttributedTypeLoc(TL, AL);
llvm_unreachable("no matching type attribute in expected location!");
}
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
ASTContext &Context;
TypeProcessingState &State;
const DeclSpec &DS;
public:
TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
const DeclSpec &DS)
: Context(Context), State(State), DS(DS) {}
TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS)
: Context(Context), DS(DS) {}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
fillAttributedTypeLoc(TL, DS.getAttributes(), ParsedAttributesView{});
Visit(TL.getModifiedLoc());
fillAttributedTypeLoc(TL, State);
}
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
Visit(TL.getUnqualifiedLoc());
@ -5408,13 +5442,11 @@ namespace {
class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> {
ASTContext &Context;
TypeProcessingState &State;
const DeclaratorChunk &Chunk;
public:
DeclaratorLocFiller(ASTContext &Context, TypeProcessingState &State,
const DeclaratorChunk &Chunk)
: Context(Context), State(State), Chunk(Chunk) {}
DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk)
: Context(Context), Chunk(Chunk) {}
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
llvm_unreachable("qualified type locs not expected here!");
@ -5424,7 +5456,7 @@ namespace {
}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
fillAttributedTypeLoc(TL, State);
fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{});
}
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
// nothing
@ -5581,13 +5613,10 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL,
/// up in the normal place in the declaration specifiers (such as a C++
/// conversion function), this pointer will refer to a type source information
/// for that return type.
static TypeSourceInfo *
GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
QualType T, TypeSourceInfo *ReturnTypeInfo) {
Sema &S = State.getSema();
Declarator &D = State.getDeclarator();
TypeSourceInfo *TInfo = S.Context.CreateTypeSourceInfo(T);
TypeSourceInfo *
Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
TypeSourceInfo *ReturnTypeInfo) {
TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
// Handle parameter packs whose type is a pack expansion.
@ -5597,6 +5626,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
if (DependentAddressSpaceTypeLoc DASTL =
CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
@ -5611,7 +5641,8 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
}
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
fillAttributedTypeLoc(TL, State);
fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(),
D.getAttributes());
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
}
@ -5619,7 +5650,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL);
DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
@ -5630,7 +5661,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
} else {
TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL);
}
return TInfo;
@ -5859,7 +5890,7 @@ static bool hasDirectOwnershipQualifier(QualType type) {
while (true) {
// __strong id
if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
if (attr->getAttrKind() == attr::ObjCOwnership)
if (attr->getAttrKind() == AttributedType::attr_objc_ownership)
return true;
type = attr->getModifiedType();
@ -6003,9 +6034,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// the coexistence problems with __unsafe_unretained.
if (!S.getLangOpts().ObjCAutoRefCount &&
lifetime == Qualifiers::OCL_ExplicitNone) {
type = state.getAttributedType(
createSimpleAttr<ObjCInertUnsafeUnretainedAttr>(S.Context, attr),
type, type);
type = S.Context.getAttributedType(
AttributedType::attr_objc_inert_unsafe_unretained,
type, type);
return true;
}
@ -6015,12 +6046,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// If we have a valid source location for the attribute, use an
// AttributedType instead.
if (AttrLoc.isValid()) {
type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr(
attr.getRange(), S.Context, II,
attr.getAttributeSpellingListIndex()),
origType, type);
}
if (AttrLoc.isValid())
type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
origType, type);
auto diagnoseOrDelay = [](Sema &S, SourceLocation loc,
unsigned diagnostic, QualType type) {
@ -6120,10 +6148,8 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// Make an attributed type to preserve the source information.
if (attr.getLoc().isValid())
type = state.getAttributedType(
::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II,
attr.getAttributeSpellingListIndex()),
origType, type);
type = S.Context.getAttributedType(AttributedType::attr_objc_gc,
origType, type);
return true;
}
@ -6266,50 +6292,37 @@ namespace {
} // end anonymous namespace
static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
ParsedAttr &PAttr, QualType &Type) {
ParsedAttr &Attr, QualType &Type) {
Sema &S = State.getSema();
Attr *A;
switch (PAttr.getKind()) {
default: llvm_unreachable("Unknown attribute kind");
case ParsedAttr::AT_Ptr32:
A = createSimpleAttr<Ptr32Attr>(S.Context, PAttr);
break;
case ParsedAttr::AT_Ptr64:
A = createSimpleAttr<Ptr64Attr>(S.Context, PAttr);
break;
case ParsedAttr::AT_SPtr:
A = createSimpleAttr<SPtrAttr>(S.Context, PAttr);
break;
case ParsedAttr::AT_UPtr:
A = createSimpleAttr<UPtrAttr>(S.Context, PAttr);
break;
}
attr::Kind NewAttrKind = A->getKind();
ParsedAttr::Kind Kind = Attr.getKind();
QualType Desugared = Type;
const AttributedType *AT = dyn_cast<AttributedType>(Type);
while (AT) {
attr::Kind CurAttrKind = AT->getAttrKind();
AttributedType::Kind CurAttrKind = AT->getAttrKind();
// You cannot specify duplicate type attributes, so if the attribute has
// already been applied, flag it.
if (NewAttrKind == CurAttrKind) {
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact)
<< PAttr.getName();
if (getAttrListKind(CurAttrKind) == Kind) {
S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact)
<< Attr.getName();
return true;
}
// You cannot have both __sptr and __uptr on the same type, nor can you
// have __ptr32 and __ptr64.
if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) ||
(CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) {
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
if ((CurAttrKind == AttributedType::attr_ptr32 &&
Kind == ParsedAttr::AT_Ptr64) ||
(CurAttrKind == AttributedType::attr_ptr64 &&
Kind == ParsedAttr::AT_Ptr32)) {
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
<< "'__ptr32'" << "'__ptr64'";
return true;
} else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) ||
(CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) {
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
} else if ((CurAttrKind == AttributedType::attr_sptr &&
Kind == ParsedAttr::AT_UPtr) ||
(CurAttrKind == AttributedType::attr_uptr &&
Kind == ParsedAttr::AT_SPtr)) {
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
<< "'__sptr'" << "'__uptr'";
return true;
}
@ -6320,20 +6333,175 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
// Pointer type qualifiers can only operate on pointer types, but not
// pointer-to-member types.
//
// FIXME: Should we really be disallowing this attribute if there is any
// type sugar between it and the pointer (other than attributes)? Eg, this
// disallows the attribute on a parenthesized pointer.
// And if so, should we really allow *any* type attribute?
if (!isa<PointerType>(Desugared)) {
if (Type->isMemberPointerType())
S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr;
S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers) << Attr;
else
S.Diag(PAttr.getLoc(), diag::err_attribute_pointers_only) << PAttr << 0;
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) << Attr << 0;
return true;
}
Type = State.getAttributedType(A, Type, Type);
AttributedType::Kind TAK;
switch (Kind) {
default: llvm_unreachable("Unknown attribute kind");
case ParsedAttr::AT_Ptr32:
TAK = AttributedType::attr_ptr32;
break;
case ParsedAttr::AT_Ptr64:
TAK = AttributedType::attr_ptr64;
break;
case ParsedAttr::AT_SPtr:
TAK = AttributedType::attr_sptr;
break;
case ParsedAttr::AT_UPtr:
TAK = AttributedType::attr_uptr;
break;
}
Type = S.Context.getAttributedType(TAK, Type, Type);
return false;
}
bool Sema::checkNullabilityTypeSpecifier(QualType &type,
NullabilityKind nullability,
SourceLocation nullabilityLoc,
bool isContextSensitive,
bool allowOnArrayType) {
recordNullabilitySeen(*this, nullabilityLoc);
// Check for existing nullability attributes on the type.
QualType desugared = type;
while (auto attributed = dyn_cast<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;
}
@ -6354,175 +6522,6 @@ static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
}
}
/// Applies a nullability type specifier to the given type, if possible.
///
/// \param state The type processing state.
///
/// \param type The type to which the nullability specifier will be
/// added. On success, this type will be updated appropriately.
///
/// \param attr The attribute as written on the type.
///
/// \param allowArrayTypes Whether to accept nullability specifiers on an
/// array type (e.g., because it will decay to a pointer).
///
/// \returns true if a problem has been diagnosed, false on success.
static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
QualType &type,
ParsedAttr &attr,
bool allowOnArrayType) {
Sema &S = state.getSema();
NullabilityKind nullability = mapNullabilityAttrKind(attr.getKind());
SourceLocation nullabilityLoc = attr.getLoc();
bool isContextSensitive = attr.isContextSensitiveKeywordAttribute();
recordNullabilitySeen(S, nullabilityLoc);
// Check for existing nullability attributes on the type.
QualType desugared = type;
while (auto attributed = dyn_cast<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
/// the type specifier to a pointer, block pointer, or member pointer
/// declarator, complaining if necessary.
@ -6610,27 +6609,27 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
return false;
}
static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) {
assert(!Attr.isInvalid());
switch (Attr.getKind()) {
default:
llvm_unreachable("not a calling convention attribute");
case ParsedAttr::AT_CDecl:
return createSimpleAttr<CDeclAttr>(Ctx, Attr);
return AttributedType::attr_cdecl;
case ParsedAttr::AT_FastCall:
return createSimpleAttr<FastCallAttr>(Ctx, Attr);
return AttributedType::attr_fastcall;
case ParsedAttr::AT_StdCall:
return createSimpleAttr<StdCallAttr>(Ctx, Attr);
return AttributedType::attr_stdcall;
case ParsedAttr::AT_ThisCall:
return createSimpleAttr<ThisCallAttr>(Ctx, Attr);
return AttributedType::attr_thiscall;
case ParsedAttr::AT_RegCall:
return createSimpleAttr<RegCallAttr>(Ctx, Attr);
return AttributedType::attr_regcall;
case ParsedAttr::AT_Pascal:
return createSimpleAttr<PascalAttr>(Ctx, Attr);
return AttributedType::attr_pascal;
case ParsedAttr::AT_SwiftCall:
return createSimpleAttr<SwiftCallAttr>(Ctx, Attr);
return AttributedType::attr_swiftcall;
case ParsedAttr::AT_VectorCall:
return createSimpleAttr<VectorCallAttr>(Ctx, Attr);
return AttributedType::attr_vectorcall;
case ParsedAttr::AT_Pcs: {
// The attribute may have had a fixit applied where we treated an
// identifier as a string literal. The contents of the string are valid,
@ -6640,22 +6639,20 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
Str = cast<StringLiteral>(Attr.getArgAsExpr(0))->getString();
else
Str = Attr.getArgAsIdent(0)->Ident->getName();
PcsAttr::PCSType Type;
if (!PcsAttr::ConvertStrToPCSType(Str, Type))
llvm_unreachable("already validated the attribute");
return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type,
Attr.getAttributeSpellingListIndex());
return llvm::StringSwitch<AttributedType::Kind>(Str)
.Case("aapcs", AttributedType::attr_pcs)
.Case("aapcs-vfp", AttributedType::attr_pcs_vfp);
}
case ParsedAttr::AT_IntelOclBicc:
return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr);
return AttributedType::attr_inteloclbicc;
case ParsedAttr::AT_MSABI:
return createSimpleAttr<MSABIAttr>(Ctx, Attr);
return AttributedType::attr_ms_abi;
case ParsedAttr::AT_SysVABI:
return createSimpleAttr<SysVABIAttr>(Ctx, Attr);
return AttributedType::attr_sysv_abi;
case ParsedAttr::AT_PreserveMost:
return createSimpleAttr<PreserveMostAttr>(Ctx, Attr);
return AttributedType::attr_preserve_most;
case ParsedAttr::AT_PreserveAll:
return createSimpleAttr<PreserveAllAttr>(Ctx, Attr);
return AttributedType::attr_preserve_all;
}
llvm_unreachable("unexpected attribute kind!");
}
@ -6703,9 +6700,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
= unwrapped.get()->getExtInfo().withProducesResult(true);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
}
type = state.getAttributedType(
createSimpleAttr<NSReturnsRetainedAttr>(S.Context, attr),
origType, type);
type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
origType, type);
return true;
}
@ -6780,12 +6776,13 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
const FunctionType *fn = unwrapped.get();
CallingConv CCOld = fn->getCallConv();
Attr *CCAttr = getCCTypeAttr(S.Context, attr);
AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr);
if (CCOld != CC) {
// Error out on when there's already an attribute on the type
// and the CCs don't match.
if (const AttributedType *AT = S.getCallingConvAttributedType(type)) {
const AttributedType *AT = S.getCallingConvAttributedType(type);
if (AT && AT->getAttrKind() != CCAttrKind) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
<< FunctionType::getNameForCallConv(CCOld);
@ -6839,7 +6836,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
Equivalent =
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
}
type = state.getAttributedType(CCAttr, type, Equivalent);
type = S.Context.getAttributedType(CCAttrKind, type, Equivalent);
return true;
}
@ -7195,15 +7192,14 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
}
static void HandleLifetimeBoundAttr(TypeProcessingState &State,
QualType &CurType,
ParsedAttr &Attr) {
if (State.getDeclarator().isDeclarationOfFunction()) {
CurType = State.getAttributedType(
createSimpleAttr<LifetimeBoundAttr>(State.getSema().Context, Attr),
CurType, CurType);
static void HandleLifetimeBoundAttr(QualType &CurType,
const ParsedAttr &Attr,
Sema &S, Declarator &D) {
if (D.isDeclarationOfFunction()) {
CurType = S.Context.getAttributedType(AttributedType::attr_lifetimebound,
CurType, CurType);
} else {
Attr.diagnoseAppertainsTo(State.getSema(), nullptr);
Attr.diagnoseAppertainsTo(S, nullptr);
}
}
@ -7313,8 +7309,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
case ParsedAttr::AT_LifetimeBound:
if (TAL == TAL_DeclChunk)
HandleLifetimeBoundAttr(state, type, attr);
if (TAL == TAL_DeclChunk) {
HandleLifetimeBoundAttr(type, attr, state.getSema(),
state.getDeclarator());
attr.setUsedAsTypeAttr();
}
break;
MS_TYPE_ATTRS_CASELIST:
@ -7338,10 +7337,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
bool allowOnArrayType =
state.getDeclarator().isPrototypeContext() &&
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
if (checkNullabilityTypeSpecifier(
state,
if (state.getSema().checkNullabilityTypeSpecifier(
type,
attr,
mapNullabilityAttrKind(attr.getKind()),
attr.getLoc(),
attr.isContextSensitiveKeywordAttribute(),
allowOnArrayType)) {
attr.setInvalid();
}
@ -7368,8 +7368,9 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
}
// Apply it regardless.
if (checkObjCKindOfType(state, type, attr))
if (state.getSema().checkObjCKindOfType(type, attr.getLoc()))
attr.setInvalid();
attr.setUsedAsTypeAttr();
break;
FUNCTION_TYPE_ATTRS_CASELIST:

View File

@ -6058,11 +6058,6 @@ QualType TreeTransform<Derived>::TransformAttributedType(
if (modifiedType.isNull())
return QualType();
const Attr *oldAttr = TL.getAttr();
const Attr *newAttr = getDerived().TransformAttr(oldAttr);
if (!newAttr)
return QualType();
QualType result = TL.getType();
// FIXME: dependent operand expressions?
@ -6079,20 +6074,26 @@ QualType TreeTransform<Derived>::TransformAttributedType(
// type sugar, and therefore cannot be diagnosed in any other way.
if (auto nullability = oldType->getImmediateNullability()) {
if (!modifiedType->canHaveNullability()) {
SemaRef.Diag(TL.getAttr()->getLocation(),
diag::err_nullability_nonpointer)
<< DiagNullabilityKind(*nullability, false) << modifiedType;
SemaRef.Diag(TL.getAttrNameLoc(), diag::err_nullability_nonpointer)
<< DiagNullabilityKind(*nullability, false) << modifiedType;
return QualType();
}
}
result = SemaRef.Context.getAttributedType(newAttr->getKind(),
result = SemaRef.Context.getAttributedType(oldType->getAttrKind(),
modifiedType,
equivalentType);
}
AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result);
newTL.setAttr(newAttr);
newTL.setAttrNameLoc(TL.getAttrNameLoc());
if (TL.hasAttrOperand())
newTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
if (TL.hasAttrExprOperand())
newTL.setAttrExprOperand(TL.getAttrExprOperand());
else if (TL.hasAttrEnumOperand())
newTL.setAttrEnumOperandLoc(TL.getAttrEnumOperandLoc());
return result;
}

View File

@ -6455,10 +6455,6 @@ class TypeLocReader : public TypeLocVisitor<TypeLocReader> {
return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx);
}
Attr *ReadAttr() {
return Reader->ReadAttr(*F, Record, Idx);
}
public:
TypeLocReader(ModuleFile &F, ASTReader &Reader,
const ASTReader::RecordData &Record, unsigned &Idx)
@ -6650,7 +6646,20 @@ void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
}
void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
TL.setAttr(ReadAttr());
TL.setAttrNameLoc(ReadSourceLocation());
if (TL.hasAttrOperand()) {
SourceRange range;
range.setBegin(ReadSourceLocation());
range.setEnd(ReadSourceLocation());
TL.setAttrOperandParensRange(range);
}
if (TL.hasAttrExprOperand()) {
if (Record[Idx++])
TL.setAttrExprOperand(Reader->ReadExpr(*F));
else
TL.setAttrExprOperand(nullptr);
} else if (TL.hasAttrEnumOperand())
TL.setAttrEnumOperandLoc(ReadSourceLocation());
}
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {

View File

@ -2648,72 +2648,19 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
// Attribute Reading
//===----------------------------------------------------------------------===//
namespace {
class AttrReader {
ModuleFile *F;
ASTReader *Reader;
const ASTReader::RecordData &Record;
unsigned &Idx;
public:
AttrReader(ModuleFile &F, ASTReader &Reader,
const ASTReader::RecordData &Record, unsigned &Idx)
: F(&F), Reader(&Reader), Record(Record), Idx(Idx) {}
const uint64_t &readInt() { return Record[Idx++]; }
SourceRange readSourceRange() {
return Reader->ReadSourceRange(*F, Record, Idx);
}
Expr *readExpr() { return Reader->ReadExpr(*F); }
std::string readString() {
return Reader->ReadString(Record, Idx);
}
TypeSourceInfo *getTypeSourceInfo() {
return Reader->GetTypeSourceInfo(*F, Record, Idx);
}
IdentifierInfo *getIdentifierInfo() {
return Reader->GetIdentifierInfo(*F, Record, Idx);
}
VersionTuple readVersionTuple() {
return ASTReader::ReadVersionTuple(Record, Idx);
}
template <typename T> T *GetLocalDeclAs(uint32_t LocalID) {
return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID));
}
};
}
Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec,
unsigned &Idx) {
AttrReader Record(M, *this, Rec, Idx);
auto V = Record.readInt();
if (!V)
return nullptr;
Attr *New = nullptr;
// Kind is stored as a 1-based integer because 0 is used to indicate a null
// Attr pointer.
auto Kind = static_cast<attr::Kind>(V - 1);
SourceRange Range = Record.readSourceRange();
ASTContext &Context = getContext();
/// Reads attributes from the current stream position.
void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) {
for (unsigned i = 0, e = Record.readInt(); i != e; ++i) {
Attr *New = nullptr;
auto Kind = (attr::Kind)Record.readInt();
SourceRange Range = Record.readSourceRange();
ASTContext &Context = getContext();
#include "clang/Serialization/AttrPCHRead.inc"
assert(New && "Unable to decode attribute?");
return New;
}
/// Reads attributes from the current stream position.
void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) {
for (unsigned I = 0, E = Record.readInt(); I != E; ++I)
Attrs.push_back(Record.readAttr());
assert(New && "Unable to decode attribute?");
Attrs.push_back(New);
}
}
//===----------------------------------------------------------------------===//

View File

@ -770,7 +770,19 @@ void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
}
void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
Record.AddAttr(TL.getAttr());
Record.AddSourceLocation(TL.getAttrNameLoc());
if (TL.hasAttrOperand()) {
SourceRange range = TL.getAttrOperandParensRange();
Record.AddSourceLocation(range.getBegin());
Record.AddSourceLocation(range.getEnd());
}
if (TL.hasAttrExprOperand()) {
Expr *operand = TL.getAttrExprOperand();
Record.push_back(operand ? 1 : 0);
if (operand) Record.AddStmt(operand);
} else if (TL.hasAttrEnumOperand()) {
Record.AddSourceLocation(TL.getAttrEnumOperandLoc());
}
}
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
@ -4469,21 +4481,16 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
// General Serialization Routines
//===----------------------------------------------------------------------===//
void ASTRecordWriter::AddAttr(const Attr *A) {
auto &Record = *this;
if (!A)
return Record.push_back(0);
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
Record.AddSourceRange(A->getRange());
#include "clang/Serialization/AttrPCHWrite.inc"
}
/// Emit the list of attributes to the specified record.
void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
push_back(Attrs.size());
for (const auto *A : Attrs)
AddAttr(A);
auto &Record = *this;
Record.push_back(Attrs.size());
for (const auto *A : Attrs) {
Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
Record.AddSourceRange(A->getRange());
#include "clang/Serialization/AttrPCHWrite.inc"
}
}
void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {

View File

@ -103,9 +103,9 @@ Nullability getNullabilityAnnotation(QualType Type) {
const auto *AttrType = Type->getAs<AttributedType>();
if (!AttrType)
return Nullability::Unspecified;
if (AttrType->getAttrKind() == attr::TypeNullable)
if (AttrType->getAttrKind() == AttributedType::attr_nullable)
return Nullability::Nullable;
else if (AttrType->getAttrKind() == attr::TypeNonNull)
else if (AttrType->getAttrKind() == AttributedType::attr_nonnull)
return Nullability::Nonnull;
return Nullability::Unspecified;
}

View File

@ -2470,10 +2470,8 @@ namespace {
static const AttrClassDescriptor AttrClassDescriptors[] = {
{ "ATTR", "Attr" },
{ "TYPE_ATTR", "TypeAttr" },
{ "STMT_ATTR", "StmtAttr" },
{ "INHERITABLE_ATTR", "InheritableAttr" },
{ "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" },
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" }
};