rsmith created this revision.
rsmith added a reviewer: aaron.ballman.
rsmith added a project: clang.

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 fields mirroring those 
that would be present in the corresponding `Attr` subclass.

This aims to simplify and unify the modeling of attributes, both to make 
tooling simpler and to avoid code duplication for attributes that can be both 
type and declaration attributes.


Repository:
  rC Clang

https://reviews.llvm.org/D50526

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/Attr.h
  include/clang/AST/Type.h
  include/clang/AST/TypeLoc.h
  include/clang/Basic/Attr.td
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTReader.h
  include/clang/Serialization/ASTWriter.h
  lib/ARCMigrate/TransGCAttrs.cpp
  lib/ARCMigrate/Transforms.cpp
  lib/AST/ASTContext.cpp
  lib/AST/Type.cpp
  lib/AST/TypeLoc.cpp
  lib/AST/TypePrinter.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaObjCProperty.cpp
  lib/Sema/SemaType.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  lib/StaticAnalyzer/Core/CheckerHelpers.cpp
  utils/TableGen/ClangAttrEmitter.cpp

Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -2470,8 +2470,10 @@
 
 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" }
 };
Index: lib/StaticAnalyzer/Core/CheckerHelpers.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CheckerHelpers.cpp
+++ lib/StaticAnalyzer/Core/CheckerHelpers.cpp
@@ -103,9 +103,9 @@
   const auto *AttrType = Type->getAs<AttributedType>();
   if (!AttrType)
     return Nullability::Unspecified;
-  if (AttrType->getAttrKind() == AttributedType::attr_nullable)
+  if (AttrType->getAttrKind() == attr::TypeNullable)
     return Nullability::Nullable;
-  else if (AttrType->getAttrKind() == AttributedType::attr_nonnull)
+  else if (AttrType->getAttrKind() == attr::TypeNonNull)
     return Nullability::Nonnull;
   return Nullability::Unspecified;
 }
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -770,19 +770,7 @@
 }
 
 void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
-  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());
-  }
+  Record.AddAttr(TL.getAttr());
 }
 
 void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
@@ -4481,16 +4469,21 @@
 // General Serialization Routines
 //===----------------------------------------------------------------------===//
 
-/// Emit the list of attributes to the specified record.
-void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
+void ASTRecordWriter::AddAttr(const Attr *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());
+  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);
 }
 
 void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -2642,19 +2642,70 @@
 // 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;
+  auto Kind = (attr::Kind)(V - 1);
+  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) {
-    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?");
-    Attrs.push_back(New);
-  }
+  for (unsigned i = 0, e = Record.readInt(); i != e; ++i)
+    Attrs.push_back(Record.readAttr());
 }
 
 //===----------------------------------------------------------------------===//
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6455,6 +6455,10 @@
     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)
@@ -6646,20 +6650,7 @@
 }
 
 void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
-  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());
+  TL.setAttr(ReadAttr());
 }
 
 void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -6058,6 +6058,11 @@
   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 @@
     // 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;
 }
 
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -172,6 +172,16 @@
     /// 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 use the
+    // keep the attributes in creation order as an attempt to make them
+    // line up properly.
+    using TypeAttr = std::pair<const AttributedType*, const Attr*>;
+    SmallVector<TypeAttr, 8> TypeAttrs;
+    bool TypeAttrsSorted = true;
+
   public:
     TypeProcessingState(Sema &sema, Declarator &declarator)
       : sema(sema), declarator(declarator),
@@ -230,6 +240,43 @@
         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);
+      TypeAttrs.push_back({cast<AttributedType>(T.getTypePtr()), A});
+      TypeAttrsSorted = false;
+      return T;
+    }
+
+    /// Extract and remove the Attr* for a given attributed type.
+    const Attr *takeAttrForAttributedType(const AttributedType *AT) {
+      if (!TypeAttrsSorted) {
+        std::stable_sort(TypeAttrs.begin(), TypeAttrs.end(),
+                         [](const TypeAttr &A, const TypeAttr &B) {
+                           return A.first < B.first;
+                         });
+        TypeAttrsSorted = true;
+      }
+
+      // FIXME: This is quadratic if we have lots of reuses of the same
+      // attributed type.
+      for (auto It = std::partition_point(
+               TypeAttrs.begin(), TypeAttrs.end(),
+               [=](const TypeAttr &A) { return A.first < AT; });
+           It != TypeAttrs.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;
 
@@ -3834,6 +3881,32 @@
   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) {
@@ -4186,9 +4259,8 @@
                 pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
                 D.getDeclSpec().getLocEnd(),
                 D.getMutableDeclSpec().getAttributes())) {
-          T = Context.getAttributedType(
-                AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
-          attr->setUsedAsTypeAttr();
+          T = state.getAttributedType(
+              createNullabilityAttr(Context, *attr, *inferNullability), T, T);
         }
       }
     }
@@ -5028,7 +5100,7 @@
   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
@@ -5164,131 +5236,25 @@
   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());
@@ -5445,11 +5411,13 @@
 
   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!");
@@ -5459,7 +5427,7 @@
     }
 
     void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
-      fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{});
+      fillAttributedTypeLoc(TL, State);
     }
     void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
       // nothing
@@ -5616,10 +5584,13 @@
 /// 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.
@@ -5629,7 +5600,6 @@
   }
 
   for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
-
     if (DependentAddressSpaceTypeLoc DASTL =
         CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
       fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
@@ -5644,16 +5614,15 @@
     }
 
     while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
-      fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(),
-                            D.getAttributes());
+      fillAttributedTypeLoc(TL, State);
       CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
     }
 
     // FIXME: Ordering here?
     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();
   }
 
@@ -5664,7 +5633,7 @@
     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;
@@ -5893,7 +5862,7 @@
   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();
@@ -6037,9 +6006,9 @@
   // 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;
   }
 
@@ -6049,9 +6018,12 @@
 
   // 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) {
@@ -6151,8 +6123,10 @@
 
   // 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;
 }
@@ -6295,37 +6269,50 @@
 } // 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;
     }
@@ -6336,60 +6323,83 @@
 
   // 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.getName();
+      S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers)
+          << PAttr.getName();
     else
-      S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
-          << Attr.getName() << 0;
+      S.Diag(PAttr.getLoc(), diag::err_attribute_pointers_only)
+          << PAttr.getName() << 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;
   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)
+        S.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
           << DiagNullabilityKind(nullability, isContextSensitive)
           << FixItHint::CreateRemoval(nullabilityLoc);
 
         break;
       }
 
       // Conflicting nullability.
-      Diag(nullabilityLoc, diag::err_nullability_conflicting)
+      S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
         << DiagNullabilityKind(nullability, isContextSensitive)
         << DiagNullabilityKind(*existingNullability, false);
       return true;
@@ -6402,9 +6412,9 @@
   // 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);
 
@@ -6415,7 +6425,7 @@
         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);
           }
         }
@@ -6428,7 +6438,7 @@
   // 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;
   }
@@ -6446,10 +6456,10 @@
     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,
@@ -6459,16 +6469,21 @@
   }
 
   // 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;
   }
 
@@ -6480,53 +6495,39 @@
   // 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;
   }
 
   // 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.
@@ -6614,27 +6615,27 @@
   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,
@@ -6644,20 +6645,22 @@
       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!");
 }
@@ -6705,8 +6708,9 @@
         = 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;
   }
 
@@ -6781,13 +6785,12 @@
 
   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);
@@ -6841,7 +6844,7 @@
     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;
 }
 
@@ -7196,14 +7199,15 @@
   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);
   }
 }
 
@@ -7313,11 +7317,8 @@
       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:
@@ -7341,11 +7342,10 @@
         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();
         }
@@ -7371,9 +7371,8 @@
       }
 
       // Apply it regardless.
-      if (state.getSema().checkObjCKindOfType(type, attr.getLoc()))
+      if (checkObjCKindOfType(state, type, attr))
         attr.setInvalid();
-      attr.setUsedAsTypeAttr();
       break;
 
     FUNCTION_TYPE_ATTRS_CASELIST:
Index: lib/Sema/SemaObjCProperty.cpp
===================================================================
--- lib/Sema/SemaObjCProperty.cpp
+++ lib/Sema/SemaObjCProperty.cpp
@@ -2384,7 +2384,7 @@
       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 @@
         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);
         }
       }
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -6378,7 +6378,7 @@
   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;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -14663,15 +14663,15 @@
   // 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();
       }
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -6021,14 +6021,14 @@
       // 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 (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();
         }
       }
     }
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -1354,36 +1354,36 @@
 
 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);
 
   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;
   }
Index: lib/AST/TypeLoc.cpp
===================================================================
--- lib/AST/TypeLoc.cpp
+++ lib/AST/TypeLoc.cpp
@@ -405,10 +405,10 @@
 
 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();
+    auto *A = attributedLoc.getAttr();
+    if (A && (isa<TypeNullableAttr>(A) || isa<TypeNonNullAttr>(A) ||
+              isa<TypeNullUnspecifiedAttr>(A)))
+      return A->getLocation();
   }
 
   return {};
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ 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 (auto *AT = Cur->getAs<AttributedType>()) {
+    if (AT->getAttrKind() == AK)
+      return true;
+    Cur = AT->getEquivalentType().getTypePtr();
+  }
+  return false;
+}
+
 namespace {
 
   class GetContainedDeducedTypeVisitor :
@@ -3167,105 +3155,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");
@@ -3708,23 +3649,18 @@
   return LinkageComputer{}.getTypeLinkageAndVisibility(this);
 }
 
-Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const {
+Optional<NullabilityKind>
+Type::getNullability(const ASTContext &context) const {
   QualType type(this, 0);
-  do {
+  while (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 {
@@ -3837,12 +3773,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;
 }
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -3873,7 +3873,7 @@
   return QualType(newType, 0);
 }
 
-QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
+QualType ASTContext::getAttributedType(attr::Kind attrKind,
                                        QualType modifiedType,
                                        QualType equivalentType) {
   llvm::FoldingSetNodeID id;
Index: lib/ARCMigrate/Transforms.cpp
===================================================================
--- lib/ARCMigrate/Transforms.cpp
+++ lib/ARCMigrate/Transforms.cpp
@@ -359,7 +359,7 @@
 bool MigrationContext::isGCOwnedNonObjC(QualType T) {
   while (!T.isNull()) {
     if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
-      if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
+      if (AttrT->getAttrKind() == attr::ObjCOwnership)
         return !AttrT->getModifiedType()->isObjCRetainableType();
     }
 
Index: lib/ARCMigrate/TransGCAttrs.cpp
===================================================================
--- lib/ARCMigrate/TransGCAttrs.cpp
+++ lib/ARCMigrate/TransGCAttrs.cpp
@@ -81,25 +81,20 @@
   }
 
   bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
-    if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
+    auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
+    if (!OwnershipAttr)
       return false;
 
-    SourceLocation Loc = TL.getAttrNameLoc();
+    SourceLocation Loc = OwnershipAttr->getLocation();
     unsigned RawLoc = Loc.getRawEncoding();
     if (MigrateCtx.AttrSet.count(RawLoc))
       return true;
 
     ASTContext &Ctx = MigrateCtx.Pass.Ctx;
     SourceManager &SM = Ctx.getSourceManager();
     if (Loc.isMacroID())
       Loc = SM.getImmediateExpansionRange(Loc).getBegin();
-    SmallString<32> Buf;
-    bool Invalid = false;
-    StringRef Spell = Lexer::getSpelling(
-                                  SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
-                                  Buf, SM, Ctx.getLangOpts(), &Invalid);
-    if (Invalid)
-      return false;
+    StringRef Spell = OwnershipAttr->getKind()->getName();
     MigrationContext::GCAttrOccurrence::AttrKind Kind;
     if (Spell == "strong")
       Kind = MigrationContext::GCAttrOccurrence::Strong;
@@ -284,7 +279,7 @@
   }
 
   for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
-    SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
+    SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
     if (Loc.isMacroID())
       Loc = MigrateCtx.Pass.Ctx.getSourceManager()
                 .getImmediateExpansionRange(Loc)
Index: include/clang/Serialization/ASTWriter.h
===================================================================
--- include/clang/Serialization/ASTWriter.h
+++ include/clang/Serialization/ASTWriter.h
@@ -955,6 +955,9 @@
     return Writer->AddVersionTuple(Version, *Record);
   }
 
+  // Emit an attribute.
+  void AddAttr(const Attr *A);
+
   /// Emit a list of attributes.
   void AddAttributes(ArrayRef<const Attr*> Attrs);
 };
Index: include/clang/Serialization/ASTReader.h
===================================================================
--- include/clang/Serialization/ASTReader.h
+++ include/clang/Serialization/ASTReader.h
@@ -2245,6 +2245,9 @@
   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);
 
@@ -2630,6 +2633,11 @@
     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);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1435,8 +1435,6 @@
 
   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);
@@ -3378,30 +3376,6 @@
   /// 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,
@@ -8071,10 +8045,6 @@
                                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.
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -489,10 +489,7 @@
 }
 
 /// A type attribute is not processed on a declaration or a statement.
-class TypeAttr : Attr {
-  // By default, type attributes do not get an AST node.
-  let ASTNode = 0;
-}
+class TypeAttr : Attr;
 
 /// A stmt attribute is not processed on a declaration or a type.
 class StmtAttr : Attr;
@@ -562,6 +559,8 @@
   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 {
@@ -1219,7 +1218,7 @@
   let Documentation = [LayoutVersionDocs];
 }
 
-def LifetimeBound : InheritableAttr {
+def LifetimeBound : DeclOrTypeAttr {
   let Spellings = [Clang<"lifetimebound", 0>];
   let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
   let Documentation = [LifetimeBoundDocs];
@@ -1322,12 +1321,16 @@
   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 {
@@ -1502,6 +1505,11 @@
   let Documentation = [TypeNullUnspecifiedDocs];
 }
 
+def ObjCInertUnsafeUnretained : TypeAttr {
+  let Spellings = [Keyword<"__unsafe_unretained">];
+  let Documentation = [Undocumented];
+}
+
 def ObjCKindOf : TypeAttr {
   let Spellings = [Keyword<"__kindof">];
   let Documentation = [Undocumented];
@@ -1589,7 +1597,7 @@
   let Documentation = [Undocumented];
 }
 
-def NSReturnsRetained : InheritableAttr {
+def NSReturnsRetained : DeclOrTypeAttr {
   let Spellings = [Clang<"ns_returns_retained">];
 //  let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
   let Documentation = [Undocumented];
@@ -1774,6 +1782,8 @@
   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 {
@@ -2062,10 +2072,9 @@
   let Documentation = [Undocumented];
 }
 
-def ObjCOwnership : InheritableAttr {
+def ObjCOwnership : DeclOrTypeAttr {
   let Spellings = [Clang<"objc_ownership">];
   let Args = [IdentifierArgument<"Kind">];
-  let ASTNode = 0;
   let Documentation = [Undocumented];
 }
 
@@ -2103,6 +2112,8 @@
   let Spellings = [GCC<"vector_size">];
   let Args = [ExprArgument<"NumBytes">];
   let Documentation = [Undocumented];
+  // Represented as VectorType instead.
+  let ASTNode = 0;
 }
 
 def VecTypeHint : InheritableAttr {
@@ -2197,7 +2208,7 @@
   let Documentation = [AnyX86NoCallerSavedRegistersDocs];
 }
 
-def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr<TargetAnyX86>{
+def AnyX86NoCfCheck : DeclOrTypeAttr, TargetSpecificAttr<TargetAnyX86>{
   let Spellings = [GCC<"nocf_check">];
   let Subjects = SubjectList<[FunctionLike]>;
   let Documentation = [AnyX86NoCfCheckDocs];
Index: include/clang/AST/TypeLoc.h
===================================================================
--- include/clang/AST/TypeLoc.h
+++ include/clang/AST/TypeLoc.h
@@ -15,6 +15,7 @@
 #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"
@@ -843,42 +844,19 @@
 };
 
 struct AttributedLocInfo {
-  union {
-    Expr *ExprOperand;
-
-    /// A raw SourceLocation.
-    unsigned EnumOperandLoc;
-  };
-
-  SourceRange OperandParens;
-
-  SourceLocation AttrLoc;
+  const Attr *TypeAttr;
 };
 
 /// Type source information for an attributed type.
 class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
                                                  AttributedTypeLoc,
                                                  AttributedType,
                                                  AttributedLocInfo> {
 public:
-  AttributedType::Kind getAttrKind() const {
+  attr::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();
   }
@@ -891,51 +869,16 @@
     return getInnerTypeLoc();
   }
 
-  /// The location of the attribute name, i.e.
-  ///    __attribute__((regparm(1000)))
-  ///                   ^~~~~~~
-  SourceLocation getAttrNameLoc() const {
-    return getLocalData()->AttrLoc;
+  /// The type attribute.
+  const Attr *getAttr() const {
+    return getLocalData()->TypeAttr;
   }
-  void setAttrNameLoc(SourceLocation loc) {
-    getLocalData()->AttrLoc = loc;
+  void setAttr(const Attr *A) {
+    getLocalData()->TypeAttr = A;
   }
 
-  /// 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;
+  template<typename T> const T *getAttrAs() {
+    return dyn_cast_or_null<T>(getAttr());
   }
 
   SourceRange getLocalSourceRange() const {
@@ -948,21 +891,11 @@
     //    ^~        ~~
     // That enclosure doesn't necessarily belong to a single attribute
     // anyway.
-    SourceRange range(getAttrNameLoc());
-    if (hasAttrOperand())
-      range.setEnd(getAttrOperandParensRange().getEnd());
-    return range;
+    return getAttr() ? getAttr()->getRange() : SourceRange();
   }
 
   void initializeLocal(ASTContext &Context, SourceLocation loc) {
-    setAttrNameLoc(loc);
-    if (hasAttrExprOperand()) {
-      setAttrOperandParensRange(SourceRange(loc));
-      setAttrExprOperand(nullptr);
-    } else if (hasAttrEnumOperand()) {
-      setAttrOperandParensRange(SourceRange(loc));
-      setAttrEnumOperandLoc(loc);
-    }
+    setAttr(nullptr);
   }
 
   QualType getInnerType() const {
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -21,6 +21,7 @@
 #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"
@@ -1851,7 +1852,16 @@
   bool isObjCQualifiedClassType() const;        // Class<foo>
   bool isObjCObjectOrInterfaceType() const;
   bool isObjCIdType() const;                    // id
-  bool isObjCInertUnsafeUnretainedType() const;
+
+  /// 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 isObjCInertUnsafeUnretainedType() const {
+    return hasAttr(attr::ObjCInertUnsafeUnretained);
+  }
 
   /// Whether the type is Objective-C 'id' or a __kindof type of an
   /// object type, e.g., __kindof NSView * or __kindof id
@@ -2065,6 +2075,10 @@
   /// 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.
@@ -4174,64 +4188,15 @@
 ///   - the canonical type is VectorType(16, int)
 class AttributedType : public Type, public llvm::FoldingSetNode {
 public:
-  // 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,
-  };
+  using Kind = attr::Kind;
 
 private:
   friend class ASTContext; // ASTContext creates these
 
   QualType ModifiedType;
   QualType EquivalentType;
 
-  AttributedType(QualType canon, Kind attrKind, QualType modified,
+  AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
                  QualType equivalent)
       : Type(Attributed, canon, equivalent->isDependentType(),
              equivalent->isInstantiationDependentType(),
@@ -4280,13 +4245,13 @@
   static Kind getNullabilityAttrKind(NullabilityKind kind) {
     switch (kind) {
     case NullabilityKind::NonNull:
-      return attr_nonnull;
+      return attr::TypeNonNull;
 
     case NullabilityKind::Nullable:
-      return attr_nullable;
+      return attr::TypeNullable;
 
     case NullabilityKind::Unspecified:
-      return attr_null_unspecified;
+      return attr::TypeNullUnspecified;
     }
     llvm_unreachable("Unknown nullability kind.");
   }
Index: include/clang/AST/Attr.h
===================================================================
--- include/clang/AST/Attr.h
+++ include/clang/AST/Attr.h
@@ -113,6 +113,19 @@
   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,
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -30,6 +30,7 @@
 #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"
@@ -1405,7 +1406,7 @@
 
   QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
 
-  QualType getAttributedType(AttributedType::Kind attrKind,
+  QualType getAttributedType(attr::Kind attrKind,
                              QualType modifiedType,
                              QualType equivalentType);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D50526: M... Richard Smith - zygoloid via Phabricator via cfe-commits

Reply via email to