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
This reinstates r339623, reverted in r339638, with a fix to not fail
template instantiation if we instantiate a QualType with no associated
type source information and we encounter an AttributedType.
llvm-svn: 340215
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0a40ee5..098abf2 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3876,7 +3876,7 @@
return QualType(newType, 0);
}
-QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
+QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType modifiedType,
QualType equivalentType) {
llvm::FoldingSetNodeID id;
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 7dc01b2..2e1aed2 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -592,28 +592,6 @@
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)
@@ -1641,6 +1619,16 @@
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 :
@@ -3168,105 +3156,58 @@
}
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 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:
+ case attr::ObjCGC:
+ case attr::ObjCOwnership:
+ case attr::ObjCInertUnsafeUnretained:
+ case attr::TypeNonNull:
+ case attr::TypeNullable:
+ case attr::TypeNullUnspecified:
+ case attr::LifetimeBound:
return true;
- // 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:
+ // All other type attributes aren't qualifiers; they rewrite the modified
+ // type to be a semantically different type.
+ default:
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()) {
- 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:
+ 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:
return true;
}
llvm_unreachable("invalid attr kind");
@@ -3712,23 +3653,18 @@
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
}
-Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const {
- QualType type(this, 0);
- do {
+Optional<NullabilityKind>
+Type::getNullability(const ASTContext &Context) const {
+ QualType Type(this, 0);
+ while (const auto *AT = Type->getAs<AttributedType>()) {
// Check whether this is an attributed type with nullability
// information.
- if (auto attributed = dyn_cast<AttributedType>(type.getTypePtr())) {
- if (auto nullability = attributed->getImmediateNullability())
- return nullability;
- }
+ if (auto Nullability = AT->getImmediateNullability())
+ return Nullability;
- // 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);
+ Type = AT->getEquivalentType();
+ }
+ return None;
}
bool Type::canHaveNullability(bool ResultIfUnknown) const {
@@ -3841,12 +3777,13 @@
llvm_unreachable("bad type kind!");
}
-llvm::Optional<NullabilityKind> AttributedType::getImmediateNullability() const {
- if (getAttrKind() == AttributedType::attr_nonnull)
+llvm::Optional<NullabilityKind>
+AttributedType::getImmediateNullability() const {
+ if (getAttrKind() == attr::TypeNonNull)
return NullabilityKind::NonNull;
- if (getAttrKind() == AttributedType::attr_nullable)
+ if (getAttrKind() == attr::TypeNullable)
return NullabilityKind::Nullable;
- if (getAttrKind() == AttributedType::attr_null_unspecified)
+ if (getAttrKind() == attr::TypeNullUnspecified)
return NullabilityKind::Unspecified;
return None;
}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index e4fd6f1..b6dc679 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -404,11 +404,11 @@
}
SourceLocation TypeLoc::findNullabilityLoc() const {
- 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();
+ if (auto ATL = getAs<AttributedTypeLoc>()) {
+ const Attr *A = ATL.getAttr();
+ if (A && (isa<TypeNullableAttr>(A) || isa<TypeNonNullAttr>(A) ||
+ isa<TypeNullUnspecifiedAttr>(A)))
+ return A->getLocation();
}
return {};
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 1cb5ff4..d86849f 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1354,12 +1354,14 @@
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() == AttributedType::attr_objc_gc ||
- T->getAttrKind() == AttributedType::attr_objc_ownership)
+ if (T->getAttrKind() == attr::ObjCGC ||
+ T->getAttrKind() == attr::ObjCOwnership)
return printBefore(T->getEquivalentType(), OS);
- if (T->getAttrKind() == AttributedType::attr_objc_kindof)
+ if (T->getAttrKind() == attr::ObjCKindOf)
OS << "__kindof ";
printBefore(T->getModifiedType(), OS);
@@ -1367,23 +1369,21 @@
if (T->isMSTypeSpec()) {
switch (T->getAttrKind()) {
default: return;
- 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;
+ case attr::Ptr32: OS << " __ptr32"; break;
+ case attr::Ptr64: OS << " __ptr64"; break;
+ case attr::SPtr: OS << " __sptr"; break;
+ case attr::UPtr: OS << " __uptr"; break;
}
spaceBeforePlaceHolder(OS);
}
// Print nullability type specifiers.
- if (T->getAttrKind() == AttributedType::attr_nonnull ||
- T->getAttrKind() == AttributedType::attr_nullable ||
- T->getAttrKind() == AttributedType::attr_null_unspecified) {
- if (T->getAttrKind() == AttributedType::attr_nonnull)
+ if (T->getImmediateNullability()) {
+ if (T->getAttrKind() == attr::TypeNonNull)
OS << " _Nonnull";
- else if (T->getAttrKind() == AttributedType::attr_nullable)
+ else if (T->getAttrKind() == attr::TypeNullable)
OS << " _Nullable";
- else if (T->getAttrKind() == AttributedType::attr_null_unspecified)
+ else if (T->getAttrKind() == attr::TypeNullUnspecified)
OS << " _Null_unspecified";
else
llvm_unreachable("unhandled nullability");
@@ -1393,9 +1393,11 @@
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() == AttributedType::attr_objc_gc ||
- T->getAttrKind() == AttributedType::attr_objc_ownership)
+ if (T->getAttrKind() == attr::ObjCGC ||
+ T->getAttrKind() == attr::ObjCOwnership)
return printAfter(T->getEquivalentType(), OS);
// If this is a calling convention attribute, don't print the implicit CC from
@@ -1406,107 +1408,74 @@
// Some attributes are printed as qualifiers before the type, so we have
// nothing left to do.
- 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)
+ if (T->getAttrKind() == attr::ObjCKindOf ||
+ T->isMSTypeSpec() || T->getImmediateNullability())
return;
// Don't print the inert __unsafe_unretained attribute at all.
- if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
+ if (T->getAttrKind() == attr::ObjCInertUnsafeUnretained)
return;
// Don't print ns_returns_retained unless it had an effect.
- if (T->getAttrKind() == AttributedType::attr_ns_returns_retained &&
+ if (T->getAttrKind() == attr::NSReturnsRetained &&
!T->getEquivalentType()->castAs<FunctionType>()
->getExtInfo().getProducesResult())
return;
- if (T->getAttrKind() == AttributedType::attr_lifetimebound) {
+ if (T->getAttrKind() == attr::LifetimeBound) {
OS << " [[clang::lifetimebound]]";
return;
}
OS << " __attribute__((";
switch (T->getAttrKind()) {
- 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:
+#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:
llvm_unreachable("This attribute should have been handled already");
- case AttributedType::attr_address_space:
- OS << "address_space(";
- // FIXME: printing the raw LangAS value is wrong. This should probably
- // use the same code as Qualifiers::print()
- OS << (unsigned)T->getEquivalentType().getAddressSpace();
- OS << ')';
- break;
-
- case 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:
+ case attr::NSReturnsRetained:
OS << "ns_returns_retained";
break;
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
- 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: {
+ 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: {
OS << "pcs(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@@ -1517,12 +1486,12 @@
break;
}
- case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
- case AttributedType::attr_preserve_most:
+ case attr::IntelOclBicc: OS << "inteloclbicc"; break;
+ case attr::PreserveMost:
OS << "preserve_most";
break;
- case AttributedType::attr_preserve_all:
+ case attr::PreserveAll:
OS << "preserve_all";
break;
}