summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2018-08-13 22:07:09 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2018-08-13 22:07:09 +0000
commitf79178635abeec3bf958a08eb760d6db911ee3c1 (patch)
treec9cf488faba0e90cec9623aefe73c907dff70aad /clang/lib/Sema
parentcade635c77004ddfabe97a0bbefefcf90d322ed8 (diff)
downloadbcm5719-llvm-f79178635abeec3bf958a08eb760d6db911ee3c1.tar.gz
bcm5719-llvm-f79178635abeec3bf958a08eb760d6db911ee3c1.zip
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 llvm-svn: 339623
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp10
-rw-r--r--clang/lib/Sema/SemaExpr.cpp8
-rw-r--r--clang/lib/Sema/SemaInit.cpp2
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp4
-rw-r--r--clang/lib/Sema/SemaType.cpp521
-rw-r--r--clang/lib/Sema/TreeTransform.h21
6 files changed, 282 insertions, 284 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index abdeba60be7..e62728c124c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5999,14 +5999,14 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
// The [[lifetimebound]] attribute can be applied to the implicit object
// parameter of a non-static member function (other than a ctor or dtor)
// by applying it to the function type.
- if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) {
+ if (const auto *A = ATL.getAttrAs<LifetimeBoundAttr>()) {
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
if (!MD || MD->isStatic()) {
- S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_no_object_param)
- << !MD << ATL.getLocalSourceRange();
+ S.Diag(A->getLocation(), diag::err_lifetimebound_no_object_param)
+ << !MD << A->getRange();
} else if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) {
- S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor)
- << isa<CXXDestructorDecl>(MD) << ATL.getLocalSourceRange();
+ S.Diag(A->getLocation(), diag::err_lifetimebound_ctor_dtor)
+ << isa<CXXDestructorDecl>(MD) << A->getRange();
}
}
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1259d25629b..baa114b350a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14658,15 +14658,15 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
if (const auto *PT = CaptureType->getAs<PointerType>()) {
// This function finds out whether there is an AttributedType of kind
- // attr_objc_ownership in Ty. The existence of AttributedType of kind
- // attr_objc_ownership implies __autoreleasing was explicitly specified
+ // attr::ObjCOwnership in Ty. The existence of AttributedType of kind
+ // attr::ObjCOwnership implies __autoreleasing was explicitly specified
// rather than being added implicitly by the compiler.
auto IsObjCOwnershipAttributedType = [](QualType Ty) {
while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
- if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership)
+ if (AttrTy->getAttrKind() == attr::ObjCOwnership)
return true;
- // Peel off AttributedTypes that are not of kind objc_ownership.
+ // Peel off AttributedTypes that are not of kind ObjCOwnership.
Ty = AttrTy->getModifiedType();
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 766f23b05b0..0d3e3d4c47a 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6360,7 +6360,7 @@ static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
for (TypeLoc TL = TSI->getTypeLoc();
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
TL = ATL.getModifiedLoc()) {
- if (ATL.getAttrKind() == AttributedType::attr_lifetimebound)
+ if (ATL.getAttrAs<LifetimeBoundAttr>())
return true;
}
return false;
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 3aad25b73a7..ab7b83c4c33 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -2384,7 +2384,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
QualType modifiedTy = resultTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
if (*nullability == NullabilityKind::Unspecified)
- resultTy = Context.getAttributedType(AttributedType::attr_nonnull,
+ resultTy = Context.getAttributedType(attr::TypeNonNull,
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(AttributedType::attr_nullable,
+ paramTy = Context.getAttributedType(attr::TypeNullable,
modifiedTy, modifiedTy);
}
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 486d8ac4ed0..bad66162491 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -172,6 +172,16 @@ 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),
@@ -230,6 +240,43 @@ 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;
@@ -3832,6 +3879,32 @@ 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) {
@@ -4184,9 +4257,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
D.getDeclSpec().getEndLoc(),
D.getMutableDeclSpec().getAttributes())) {
- T = Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
- attr->setUsedAsTypeAttr();
+ T = state.getAttributedType(
+ createNullabilityAttr(Context, *attr, *inferNullability), T, T);
}
}
}
@@ -5025,7 +5097,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (D.isInvalidType())
return Context.getTrivialTypeSourceInfo(T);
- return S.GetTypeSourceInfoForDeclarator(D, T, TInfo);
+ return GetTypeSourceInfoForDeclarator(state, T, TInfo);
}
/// GetTypeForDeclarator - Convert the type for the specified
@@ -5161,131 +5233,25 @@ 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,
- const ParsedAttributesView &Attrs,
- const ParsedAttributesView &DeclAttrs) {
- // DeclAttrs and Attrs cannot be both empty.
- assert((!Attrs.empty() || !DeclAttrs.empty()) &&
- "no type attributes in the expected location!");
-
- ParsedAttr::Kind parsedKind = getAttrListKind(TL.getAttrKind());
- // Try to search for an attribute of matching kind in Attrs list.
- for (const ParsedAttr &AL : Attrs)
- if (AL.getKind() == parsedKind)
- return setAttributedTypeLoc(TL, AL);
-
- for (const ParsedAttr &AL : DeclAttrs)
- if (AL.isCXX11Attribute() || AL.getKind() == parsedKind)
- return setAttributedTypeLoc(TL, AL);
- llvm_unreachable("no matching type attribute in expected location!");
+ TypeProcessingState &State) {
+ TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr()));
}
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
ASTContext &Context;
+ TypeProcessingState &State;
const DeclSpec &DS;
public:
- TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS)
- : Context(Context), DS(DS) {}
+ TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
+ const DeclSpec &DS)
+ : Context(Context), State(State), DS(DS) {}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
- fillAttributedTypeLoc(TL, DS.getAttributes(), ParsedAttributesView{});
Visit(TL.getModifiedLoc());
+ fillAttributedTypeLoc(TL, State);
}
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
Visit(TL.getUnqualifiedLoc());
@@ -5442,11 +5408,13 @@ namespace {
class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> {
ASTContext &Context;
+ TypeProcessingState &State;
const DeclaratorChunk &Chunk;
public:
- DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk)
- : Context(Context), Chunk(Chunk) {}
+ DeclaratorLocFiller(ASTContext &Context, TypeProcessingState &State,
+ const DeclaratorChunk &Chunk)
+ : Context(Context), State(State), Chunk(Chunk) {}
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
llvm_unreachable("qualified type locs not expected here!");
@@ -5456,7 +5424,7 @@ namespace {
}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
- fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{});
+ fillAttributedTypeLoc(TL, State);
}
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
// nothing
@@ -5613,10 +5581,13 @@ 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.
-TypeSourceInfo *
-Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
- TypeSourceInfo *ReturnTypeInfo) {
- TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
+static TypeSourceInfo *
+GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
+ QualType T, TypeSourceInfo *ReturnTypeInfo) {
+ Sema &S = State.getSema();
+ Declarator &D = State.getDeclarator();
+
+ TypeSourceInfo *TInfo = S.Context.CreateTypeSourceInfo(T);
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
// Handle parameter packs whose type is a pack expansion.
@@ -5626,7 +5597,6 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
-
if (DependentAddressSpaceTypeLoc DASTL =
CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
@@ -5641,8 +5611,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
}
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
- fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(),
- D.getAttributes());
+ fillAttributedTypeLoc(TL, State);
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
}
@@ -5650,7 +5619,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
- DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
+ DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
@@ -5661,7 +5630,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
} else {
- TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL);
+ TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
}
return TInfo;
@@ -5890,7 +5859,7 @@ static bool hasDirectOwnershipQualifier(QualType type) {
while (true) {
// __strong id
if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
- if (attr->getAttrKind() == AttributedType::attr_objc_ownership)
+ if (attr->getAttrKind() == attr::ObjCOwnership)
return true;
type = attr->getModifiedType();
@@ -6034,9 +6003,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// the coexistence problems with __unsafe_unretained.
if (!S.getLangOpts().ObjCAutoRefCount &&
lifetime == Qualifiers::OCL_ExplicitNone) {
- type = S.Context.getAttributedType(
- AttributedType::attr_objc_inert_unsafe_unretained,
- type, type);
+ type = state.getAttributedType(
+ createSimpleAttr<ObjCInertUnsafeUnretainedAttr>(S.Context, attr),
+ type, type);
return true;
}
@@ -6046,9 +6015,12 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// If we have a valid source location for the attribute, use an
// AttributedType instead.
- if (AttrLoc.isValid())
- type = S.Context.getAttributedType(AttributedType::attr_objc_ownership,
- origType, type);
+ if (AttrLoc.isValid()) {
+ type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr(
+ attr.getRange(), S.Context, II,
+ attr.getAttributeSpellingListIndex()),
+ origType, type);
+ }
auto diagnoseOrDelay = [](Sema &S, SourceLocation loc,
unsigned diagnostic, QualType type) {
@@ -6148,8 +6120,10 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// Make an attributed type to preserve the source information.
if (attr.getLoc().isValid())
- type = S.Context.getAttributedType(AttributedType::attr_objc_gc,
- origType, type);
+ type = state.getAttributedType(
+ ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II,
+ attr.getAttributeSpellingListIndex()),
+ origType, type);
return true;
}
@@ -6292,37 +6266,50 @@ namespace {
} // end anonymous namespace
static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
- ParsedAttr &Attr, QualType &Type) {
+ ParsedAttr &PAttr, QualType &Type) {
Sema &S = State.getSema();
- ParsedAttr::Kind Kind = Attr.getKind();
+ Attr *A;
+ switch (PAttr.getKind()) {
+ default: llvm_unreachable("Unknown attribute kind");
+ case ParsedAttr::AT_Ptr32:
+ A = createSimpleAttr<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;
const AttributedType *AT = dyn_cast<AttributedType>(Type);
while (AT) {
- AttributedType::Kind CurAttrKind = AT->getAttrKind();
+ attr::Kind CurAttrKind = AT->getAttrKind();
// You cannot specify duplicate type attributes, so if the attribute has
// already been applied, flag it.
- if (getAttrListKind(CurAttrKind) == Kind) {
- S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute_exact)
- << Attr.getName();
+ if (NewAttrKind == CurAttrKind) {
+ S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact)
+ << PAttr.getName();
return true;
}
// You cannot have both __sptr and __uptr on the same type, nor can you
// have __ptr32 and __ptr64.
- if ((CurAttrKind == AttributedType::attr_ptr32 &&
- Kind == ParsedAttr::AT_Ptr64) ||
- (CurAttrKind == AttributedType::attr_ptr64 &&
- Kind == ParsedAttr::AT_Ptr32)) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) ||
+ (CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) {
+ S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
<< "'__ptr32'" << "'__ptr64'";
return true;
- } else if ((CurAttrKind == AttributedType::attr_sptr &&
- Kind == ParsedAttr::AT_UPtr) ||
- (CurAttrKind == AttributedType::attr_uptr &&
- Kind == ParsedAttr::AT_SPtr)) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ } else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) ||
+ (CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) {
+ S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
<< "'__sptr'" << "'__uptr'";
return true;
}
@@ -6333,41 +6320,64 @@ 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(Attr.getLoc(), diag::err_attribute_no_member_pointers) << Attr;
+ S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr;
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;
}
- AttributedType::Kind TAK;
- switch (Kind) {
- default: llvm_unreachable("Unknown attribute kind");
- case ParsedAttr::AT_Ptr32:
- TAK = AttributedType::attr_ptr32;
- break;
- case ParsedAttr::AT_Ptr64:
- TAK = AttributedType::attr_ptr64;
- break;
- case ParsedAttr::AT_SPtr:
- TAK = AttributedType::attr_sptr;
- break;
- case ParsedAttr::AT_UPtr:
- TAK = AttributedType::attr_uptr;
- break;
- }
-
- Type = S.Context.getAttributedType(TAK, Type, Type);
+ Type = State.getAttributedType(A, Type, Type);
return false;
}
-bool Sema::checkNullabilityTypeSpecifier(QualType &type,
- NullabilityKind nullability,
- SourceLocation nullabilityLoc,
- bool isContextSensitive,
- bool allowOnArrayType) {
- recordNullabilitySeen(*this, nullabilityLoc);
+/// Map a nullability attribute kind to a nullability kind.
+static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
+ switch (kind) {
+ case ParsedAttr::AT_TypeNonNull:
+ return NullabilityKind::NonNull;
+
+ case ParsedAttr::AT_TypeNullable:
+ return NullabilityKind::Nullable;
+
+ case ParsedAttr::AT_TypeNullUnspecified:
+ return NullabilityKind::Unspecified;
+
+ default:
+ llvm_unreachable("not a nullability attribute kind");
+ }
+}
+
+/// Applies a nullability type specifier to the given type, if possible.
+///
+/// \param state The type processing state.
+///
+/// \param type The type to which the nullability specifier will be
+/// added. On success, this type will be updated appropriately.
+///
+/// \param attr The attribute as written on the type.
+///
+/// \param allowArrayTypes Whether to accept nullability specifiers on an
+/// array type (e.g., because it will decay to a pointer).
+///
+/// \returns true if a problem has been diagnosed, false on success.
+static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
+ QualType &type,
+ ParsedAttr &attr,
+ bool allowOnArrayType) {
+ Sema &S = state.getSema();
+
+ NullabilityKind nullability = mapNullabilityAttrKind(attr.getKind());
+ SourceLocation nullabilityLoc = attr.getLoc();
+ bool isContextSensitive = attr.isContextSensitiveKeywordAttribute();
+
+ recordNullabilitySeen(S, nullabilityLoc);
// Check for existing nullability attributes on the type.
QualType desugared = type;
@@ -6376,7 +6386,7 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
if (auto existingNullability = attributed->getImmediateNullability()) {
// Duplicated nullability.
if (nullability == *existingNullability) {
- Diag(nullabilityLoc, diag::warn_nullability_duplicate)
+ S.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< FixItHint::CreateRemoval(nullabilityLoc);
@@ -6384,7 +6394,7 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
}
// Conflicting nullability.
- Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< DiagNullabilityKind(*existingNullability, false);
return true;
@@ -6397,9 +6407,9 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
// This (unlike the code above) looks through typedefs that might
// have nullability specifiers on them, which means we cannot
// provide a useful Fix-It.
- if (auto existingNullability = desugared->getNullability(Context)) {
+ if (auto existingNullability = desugared->getNullability(S.Context)) {
if (nullability != *existingNullability) {
- Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
<< DiagNullabilityKind(*existingNullability, false);
@@ -6410,7 +6420,7 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
if (auto typedefNullability
= AttributedType::stripOuterNullability(underlyingType)) {
if (*typedefNullability == *existingNullability) {
- Diag(typedefDecl->getLocation(), diag::note_nullability_here)
+ S.Diag(typedefDecl->getLocation(), diag::note_nullability_here)
<< DiagNullabilityKind(*existingNullability, false);
}
}
@@ -6423,7 +6433,7 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
// If this definitely isn't a pointer type, reject the specifier.
if (!desugared->canHaveNullability() &&
!(allowOnArrayType && desugared->isArrayType())) {
- Diag(nullabilityLoc, diag::err_nullability_nonpointer)
+ S.Diag(nullabilityLoc, diag::err_nullability_nonpointer)
<< DiagNullabilityKind(nullability, isContextSensitive) << type;
return true;
}
@@ -6441,10 +6451,10 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
if (pointeeType->isAnyPointerType() ||
pointeeType->isObjCObjectPointerType() ||
pointeeType->isMemberPointerType()) {
- Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
+ S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
<< DiagNullabilityKind(nullability, true)
<< type;
- Diag(nullabilityLoc, diag::note_nullability_type_specifier)
+ S.Diag(nullabilityLoc, diag::note_nullability_type_specifier)
<< DiagNullabilityKind(nullability, false)
<< type
<< FixItHint::CreateReplacement(nullabilityLoc,
@@ -6454,16 +6464,21 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
}
// Form the attributed type.
- type = Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(nullability), type, type);
+ type = state.getAttributedType(
+ createNullabilityAttr(S.Context, attr, nullability), type, type);
return false;
}
-bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
+/// Check the application of the Objective-C '__kindof' qualifier to
+/// the given type.
+static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type,
+ ParsedAttr &attr) {
+ Sema &S = state.getSema();
+
if (isa<ObjCTypeParamType>(type)) {
// Build the attributed type to record where __kindof occurred.
- type = Context.getAttributedType(AttributedType::attr_objc_kindof,
- type, type);
+ type = state.getAttributedType(
+ createSimpleAttr<ObjCKindOfAttr>(S.Context, attr), type, type);
return false;
}
@@ -6475,7 +6490,7 @@ bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
// If not, we can't apply __kindof.
if (!objType) {
// FIXME: Handle dependent types that aren't yet object types.
- Diag(loc, diag::err_objc_kindof_nonobject)
+ S.Diag(attr.getLoc(), diag::err_objc_kindof_nonobject)
<< type;
return true;
}
@@ -6483,45 +6498,31 @@ bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
// Rebuild the "equivalent" type, which pushes __kindof down into
// the object type.
// There is no need to apply kindof on an unqualified id type.
- QualType equivType = Context.getObjCObjectType(
+ QualType equivType = S.Context.getObjCObjectType(
objType->getBaseType(), objType->getTypeArgsAsWritten(),
objType->getProtocols(),
/*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true);
// If we started with an object pointer type, rebuild it.
if (ptrType) {
- equivType = Context.getObjCObjectPointerType(equivType);
- if (auto nullability = type->getNullability(Context)) {
- auto attrKind = AttributedType::getNullabilityAttrKind(*nullability);
- equivType = Context.getAttributedType(attrKind, equivType, equivType);
+ equivType = S.Context.getObjCObjectPointerType(equivType);
+ if (auto nullability = type->getNullability(S.Context)) {
+ // We create a nullability attribute from the __kindof attribute.
+ // Make sure that will make sense.
+ assert(attr.getAttributeSpellingListIndex() == 0 &&
+ "multiple spellings for __kindof?");
+ Attr *A = createNullabilityAttr(S.Context, attr, *nullability);
+ A->setImplicit(true);
+ equivType = state.getAttributedType(A, equivType, equivType);
}
}
// Build the attributed type to record where __kindof occurred.
- type = Context.getAttributedType(AttributedType::attr_objc_kindof,
- type,
- equivType);
-
+ type = state.getAttributedType(
+ createSimpleAttr<ObjCKindOfAttr>(S.Context, attr), type, equivType);
return false;
}
-/// Map a nullability attribute kind to a nullability kind.
-static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
- switch (kind) {
- case ParsedAttr::AT_TypeNonNull:
- return NullabilityKind::NonNull;
-
- case ParsedAttr::AT_TypeNullable:
- return NullabilityKind::Nullable;
-
- case ParsedAttr::AT_TypeNullUnspecified:
- return NullabilityKind::Unspecified;
-
- default:
- llvm_unreachable("not a nullability attribute kind");
- }
-}
-
/// Distribute a nullability type attribute that cannot be applied to
/// the type specifier to a pointer, block pointer, or member pointer
/// declarator, complaining if necessary.
@@ -6609,27 +6610,27 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
return false;
}
-static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) {
+static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
assert(!Attr.isInvalid());
switch (Attr.getKind()) {
default:
llvm_unreachable("not a calling convention attribute");
case ParsedAttr::AT_CDecl:
- return AttributedType::attr_cdecl;
+ return createSimpleAttr<CDeclAttr>(Ctx, Attr);
case ParsedAttr::AT_FastCall:
- return AttributedType::attr_fastcall;
+ return createSimpleAttr<FastCallAttr>(Ctx, Attr);
case ParsedAttr::AT_StdCall:
- return AttributedType::attr_stdcall;
+ return createSimpleAttr<StdCallAttr>(Ctx, Attr);
case ParsedAttr::AT_ThisCall:
- return AttributedType::attr_thiscall;
+ return createSimpleAttr<ThisCallAttr>(Ctx, Attr);
case ParsedAttr::AT_RegCall:
- return AttributedType::attr_regcall;
+ return createSimpleAttr<RegCallAttr>(Ctx, Attr);
case ParsedAttr::AT_Pascal:
- return AttributedType::attr_pascal;
+ return createSimpleAttr<PascalAttr>(Ctx, Attr);
case ParsedAttr::AT_SwiftCall:
- return AttributedType::attr_swiftcall;
+ return createSimpleAttr<SwiftCallAttr>(Ctx, Attr);
case ParsedAttr::AT_VectorCall:
- return AttributedType::attr_vectorcall;
+ return createSimpleAttr<VectorCallAttr>(Ctx, Attr);
case ParsedAttr::AT_Pcs: {
// The attribute may have had a fixit applied where we treated an
// identifier as a string literal. The contents of the string are valid,
@@ -6639,20 +6640,22 @@ static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) {
Str = cast<StringLiteral>(Attr.getArgAsExpr(0))->getString();
else
Str = Attr.getArgAsIdent(0)->Ident->getName();
- return llvm::StringSwitch<AttributedType::Kind>(Str)
- .Case("aapcs", AttributedType::attr_pcs)
- .Case("aapcs-vfp", AttributedType::attr_pcs_vfp);
+ PcsAttr::PCSType Type;
+ if (!PcsAttr::ConvertStrToPCSType(Str, Type))
+ llvm_unreachable("already validated the attribute");
+ return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type,
+ Attr.getAttributeSpellingListIndex());
}
case ParsedAttr::AT_IntelOclBicc:
- return AttributedType::attr_inteloclbicc;
+ return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr);
case ParsedAttr::AT_MSABI:
- return AttributedType::attr_ms_abi;
+ return createSimpleAttr<MSABIAttr>(Ctx, Attr);
case ParsedAttr::AT_SysVABI:
- return AttributedType::attr_sysv_abi;
+ return createSimpleAttr<SysVABIAttr>(Ctx, Attr);
case ParsedAttr::AT_PreserveMost:
- return AttributedType::attr_preserve_most;
+ return createSimpleAttr<PreserveMostAttr>(Ctx, Attr);
case ParsedAttr::AT_PreserveAll:
- return AttributedType::attr_preserve_all;
+ return createSimpleAttr<PreserveAllAttr>(Ctx, Attr);
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -6700,8 +6703,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
= unwrapped.get()->getExtInfo().withProducesResult(true);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
}
- type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
- origType, type);
+ type = state.getAttributedType(
+ createSimpleAttr<NSReturnsRetainedAttr>(S.Context, attr),
+ origType, type);
return true;
}
@@ -6776,13 +6780,12 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
const FunctionType *fn = unwrapped.get();
CallingConv CCOld = fn->getCallConv();
- AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr);
+ Attr *CCAttr = getCCTypeAttr(S.Context, attr);
if (CCOld != CC) {
// Error out on when there's already an attribute on the type
// and the CCs don't match.
- const AttributedType *AT = S.getCallingConvAttributedType(type);
- if (AT && AT->getAttrKind() != CCAttrKind) {
+ if (const AttributedType *AT = S.getCallingConvAttributedType(type)) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
<< FunctionType::getNameForCallConv(CCOld);
@@ -6836,7 +6839,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
Equivalent =
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
}
- type = S.Context.getAttributedType(CCAttrKind, type, Equivalent);
+ type = state.getAttributedType(CCAttr, type, Equivalent);
return true;
}
@@ -7192,14 +7195,15 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
}
-static void HandleLifetimeBoundAttr(QualType &CurType,
- const ParsedAttr &Attr,
- Sema &S, Declarator &D) {
- if (D.isDeclarationOfFunction()) {
- CurType = S.Context.getAttributedType(AttributedType::attr_lifetimebound,
- CurType, CurType);
+static void HandleLifetimeBoundAttr(TypeProcessingState &State,
+ QualType &CurType,
+ ParsedAttr &Attr) {
+ if (State.getDeclarator().isDeclarationOfFunction()) {
+ CurType = State.getAttributedType(
+ createSimpleAttr<LifetimeBoundAttr>(State.getSema().Context, Attr),
+ CurType, CurType);
} else {
- Attr.diagnoseAppertainsTo(S, nullptr);
+ Attr.diagnoseAppertainsTo(State.getSema(), nullptr);
}
}
@@ -7309,11 +7313,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
case ParsedAttr::AT_LifetimeBound:
- if (TAL == TAL_DeclChunk) {
- HandleLifetimeBoundAttr(type, attr, state.getSema(),
- state.getDeclarator());
- attr.setUsedAsTypeAttr();
- }
+ if (TAL == TAL_DeclChunk)
+ HandleLifetimeBoundAttr(state, type, attr);
break;
MS_TYPE_ATTRS_CASELIST:
@@ -7337,11 +7338,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
bool allowOnArrayType =
state.getDeclarator().isPrototypeContext() &&
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
- if (state.getSema().checkNullabilityTypeSpecifier(
+ if (checkNullabilityTypeSpecifier(
+ state,
type,
- mapNullabilityAttrKind(attr.getKind()),
- attr.getLoc(),
- attr.isContextSensitiveKeywordAttribute(),
+ attr,
allowOnArrayType)) {
attr.setInvalid();
}
@@ -7368,9 +7368,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
}
// Apply it regardless.
- if (state.getSema().checkObjCKindOfType(type, attr.getLoc()))
+ if (checkObjCKindOfType(state, type, attr))
attr.setInvalid();
- attr.setUsedAsTypeAttr();
break;
FUNCTION_TYPE_ATTRS_CASELIST:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index d680e6be6d3..98256d66a2a 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -6058,6 +6058,11 @@ 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?
@@ -6074,26 +6079,20 @@ 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.getAttrNameLoc(), diag::err_nullability_nonpointer)
- << DiagNullabilityKind(*nullability, false) << modifiedType;
+ SemaRef.Diag(TL.getAttr()->getLocation(),
+ diag::err_nullability_nonpointer)
+ << DiagNullabilityKind(*nullability, false) << modifiedType;
return QualType();
}
}
- result = SemaRef.Context.getAttributedType(oldType->getAttrKind(),
+ result = SemaRef.Context.getAttributedType(newAttr->getKind(),
modifiedType,
equivalentType);
}
AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result);
- newTL.setAttrNameLoc(TL.getAttrNameLoc());
- if (TL.hasAttrOperand())
- newTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
- if (TL.hasAttrExprOperand())
- newTL.setAttrExprOperand(TL.getAttrExprOperand());
- else if (TL.hasAttrEnumOperand())
- newTL.setAttrEnumOperandLoc(TL.getAttrEnumOperandLoc());
-
+ newTL.setAttr(newAttr);
return result;
}
OpenPOWER on IntegriCloud