Substantially alter the design of the Objective C type AST by introducing
ObjCObjectType, which is basically just a pair of
  one of {primitive-id, primitive-Class, user-defined @class}
with
  a list of protocols.
An ObjCObjectPointerType is therefore just a pointer which always points to
one of these types (possibly sugared).  ObjCInterfaceType is now just a kind
of ObjCObjectType which happens to not carry any protocols.

Alter a rather large number of use sites to use ObjCObjectType instead of
ObjCInterfaceType.  Store an ObjCInterfaceType as a pointer on the decl rather
than hashing them in a FoldingSet.  Remove some number of methods that are no
longer used, at least after this patch.

By simplifying ObjCObjectPointerType, we are now able to easily remove and apply
pointers to Objective-C types, which is crucial for a certain kind of ObjC++
metaprogramming common in WebKit.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103870 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 81b56ad..d0e4c02 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -595,6 +595,8 @@
     Align = EltInfo.second;
     break;
   }
+  case Type::ObjCObject:
+    return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
   case Type::ObjCInterface: {
     const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
     const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
@@ -1692,10 +1694,6 @@
   if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
     return getTypedefType(Typedef);
 
-  if (const ObjCInterfaceDecl *ObjCInterface
-               = dyn_cast<ObjCInterfaceDecl>(Decl))
-    return getObjCInterfaceType(ObjCInterface);
-
   assert(!isa<TemplateTypeParmDecl>(Decl) &&
          "Template type parameter types are always available.");
 
@@ -1991,7 +1989,7 @@
   return LHS->getDeclName() < RHS->getDeclName();
 }
 
-static bool areSortedAndUniqued(ObjCProtocolDecl **Protocols,
+static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols,
                                 unsigned NumProtocols) {
   if (NumProtocols == 0) return true;
 
@@ -2013,94 +2011,96 @@
   NumProtocols = ProtocolsEnd-Protocols;
 }
 
-/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
-/// the given interface decl and the conforming protocol list.
-QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
-                                              ObjCProtocolDecl **Protocols,
-                                              unsigned NumProtocols,
-                                              unsigned Quals) {
+QualType ASTContext::getObjCObjectType(QualType BaseType,
+                                       ObjCProtocolDecl * const *Protocols,
+                                       unsigned NumProtocols) {
+  // If the base type is an interface and there aren't any protocols
+  // to add, then the interface type will do just fine.
+  if (!NumProtocols && isa<ObjCInterfaceType>(BaseType))
+    return BaseType;
+
+  // Look in the folding set for an existing type.
   llvm::FoldingSetNodeID ID;
-  ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
-  Qualifiers Qs = Qualifiers::fromCVRMask(Quals);
-
+  ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols);
   void *InsertPos = 0;
-  if (ObjCObjectPointerType *QT =
-              ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
-    return getQualifiedType(QualType(QT, 0), Qs);
+  if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
+    return QualType(QT, 0);
 
-  // Sort the protocol list alphabetically to canonicalize it.
+  // Build the canonical type, which has the canonical base type and
+  // a sorted-and-uniqued list of protocols.
   QualType Canonical;
-  if (!InterfaceT.isCanonical() || 
-      !areSortedAndUniqued(Protocols, NumProtocols)) {
-    if (!areSortedAndUniqued(Protocols, NumProtocols)) {
+  bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols);
+  if (!ProtocolsSorted || !BaseType.isCanonical()) {
+    if (!ProtocolsSorted) {
       llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
                                                      Protocols + NumProtocols);
       unsigned UniqueCount = NumProtocols;
 
       SortAndUniqueProtocols(&Sorted[0], UniqueCount);
-
-      Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT),
-                                           &Sorted[0], UniqueCount);
+      Canonical = getObjCObjectType(getCanonicalType(BaseType),
+                                    &Sorted[0], UniqueCount);
     } else {
-      Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT),
-                                           Protocols, NumProtocols);
+      Canonical = getObjCObjectType(getCanonicalType(BaseType),
+                                    Protocols, NumProtocols);
     }
 
     // Regenerate InsertPos.
+    ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
+  }
+
+  unsigned Size = sizeof(ObjCObjectTypeImpl);
+  Size += NumProtocols * sizeof(ObjCProtocolDecl *);
+  void *Mem = Allocate(Size, TypeAlignment);
+  ObjCObjectTypeImpl *T =
+    new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols);
+
+  Types.push_back(T);
+  ObjCObjectTypes.InsertNode(T, InsertPos);
+  return QualType(T, 0);
+}
+
+/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
+/// the given object type.
+QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) {
+  llvm::FoldingSetNodeID ID;
+  ObjCObjectPointerType::Profile(ID, ObjectT);
+
+  void *InsertPos = 0;
+  if (ObjCObjectPointerType *QT =
+              ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
+    return QualType(QT, 0);
+
+  // Find the canonical object type.
+  QualType Canonical;
+  if (!ObjectT.isCanonical()) {
+    Canonical = getObjCObjectPointerType(getCanonicalType(ObjectT));
+
+    // Regenerate InsertPos.
     ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
   }
 
   // No match.
-  unsigned Size = sizeof(ObjCObjectPointerType) 
-                + NumProtocols * sizeof(ObjCProtocolDecl *);
-  void *Mem = Allocate(Size, TypeAlignment);
-  ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical, 
-                                                                 InterfaceT, 
-                                                                 Protocols,
-                                                                 NumProtocols);
+  void *Mem = Allocate(sizeof(ObjCObjectPointerType), TypeAlignment);
+  ObjCObjectPointerType *QType =
+    new (Mem) ObjCObjectPointerType(Canonical, ObjectT);
 
   Types.push_back(QType);
   ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
-  return getQualifiedType(QualType(QType, 0), Qs);
+  return QualType(QType, 0);
 }
 
 /// getObjCInterfaceType - Return the unique reference to the type for the
 /// specified ObjC interface decl. The list of protocols is optional.
-QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
-                       ObjCProtocolDecl **Protocols, unsigned NumProtocols) {
-  llvm::FoldingSetNodeID ID;
-  ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
+  if (Decl->TypeForDecl)
+    return QualType(Decl->TypeForDecl, 0);
 
-  void *InsertPos = 0;
-  if (ObjCInterfaceType *QT =
-      ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
-    return QualType(QT, 0);
-
-  // Sort the protocol list alphabetically to canonicalize it.
-  QualType Canonical;
-  if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) {
-    llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
-                                                   Protocols + NumProtocols);
-
-    unsigned UniqueCount = NumProtocols;
-    SortAndUniqueProtocols(&Sorted[0], UniqueCount);
-
-    Canonical = getObjCInterfaceType(Decl, &Sorted[0], UniqueCount);
-
-    ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos);
-  }
-
-  unsigned Size = sizeof(ObjCInterfaceType) 
-    + NumProtocols * sizeof(ObjCProtocolDecl *);
-  void *Mem = Allocate(Size, TypeAlignment);
-  ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical, 
-                                        const_cast<ObjCInterfaceDecl*>(Decl),
-                                                         Protocols, 
-                                                         NumProtocols);
-
-  Types.push_back(QType);
-  ObjCInterfaceTypes.InsertNode(QType, InsertPos);
-  return QualType(QType, 0);
+  // FIXME: redeclarations?
+  void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment);
+  ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl);
+  Decl->TypeForDecl = T;
+  Types.push_back(T);
+  return QualType(T, 0);
 }
 
 /// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique
@@ -3620,6 +3620,10 @@
     return;
   }
 
+  // Ignore protocol qualifiers when mangling at this level.
+  if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>())
+    T = OT->getBaseType();
+
   if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
     // @encode(class_name)
     ObjCInterfaceDecl *OI = OIT->getDecl();
@@ -4090,18 +4094,21 @@
 ///
 bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
                                          const ObjCObjectPointerType *RHSOPT) {
+  const ObjCObjectType* LHS = LHSOPT->getObjectType();
+  const ObjCObjectType* RHS = RHSOPT->getObjectType();
+
   // If either type represents the built-in 'id' or 'Class' types, return true.
-  if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType())
+  if (LHS->isObjCUnqualifiedIdOrClass() ||
+      RHS->isObjCUnqualifiedIdOrClass())
     return true;
 
-  if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+  if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId())
     return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
                                              QualType(RHSOPT,0),
                                              false);
 
-  const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
-  const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
-  if (LHS && RHS) // We have 2 user-defined types.
+  // If we have 2 user-defined types, fall into that path.
+  if (LHS->getInterface() && RHS->getInterface())
     return canAssignObjCInterfaces(LHS, RHS);
 
   return false;
@@ -4152,8 +4159,10 @@
                                 const ObjCObjectPointerType *RHSOPT,
       llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
   
-  const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
-  const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+  const ObjCObjectType* LHS = LHSOPT->getObjectType();
+  const ObjCObjectType* RHS = RHSOPT->getObjectType();
+  assert(LHS->getInterface() && "LHS must have an interface base");
+  assert(RHS->getInterface() && "RHS must have an interface base");
   
   llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet;
   unsigned LHSNumProtocols = LHS->getNumProtocols();
@@ -4161,7 +4170,8 @@
     InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
   else {
     llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
-    Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
+    Context.CollectInheritedProtocols(LHS->getInterface(),
+                                      LHSInheritedProtocols);
     InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), 
                                 LHSInheritedProtocols.end());
   }
@@ -4176,7 +4186,8 @@
   }
   else {
     llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
-    Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols);
+    Context.CollectInheritedProtocols(RHS->getInterface(),
+                                      RHSInheritedProtocols);
     for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = 
          RHSInheritedProtocols.begin(),
          E = RHSInheritedProtocols.end(); I != E; ++I) 
@@ -4190,37 +4201,40 @@
 /// last type comparison in a ?-exp of ObjC pointer types before a 
 /// warning is issued. So, its invokation is extremely rare.
 QualType ASTContext::areCommonBaseCompatible(
-                                          const ObjCObjectPointerType *LHSOPT,
-                                          const ObjCObjectPointerType *RHSOPT) {
-  const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
-  const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
-  if (!LHS || !RHS)
+                                          const ObjCObjectPointerType *Lptr,
+                                          const ObjCObjectPointerType *Rptr) {
+  const ObjCObjectType *LHS = Lptr->getObjectType();
+  const ObjCObjectType *RHS = Rptr->getObjectType();
+  const ObjCInterfaceDecl* LDecl = LHS->getInterface();
+  const ObjCInterfaceDecl* RDecl = RHS->getInterface();
+  if (!LDecl || !RDecl)
     return QualType();
   
-  while (const ObjCInterfaceDecl *LHSIDecl = LHS->getDecl()->getSuperClass()) {
-    QualType LHSTy = getObjCInterfaceType(LHSIDecl);
-    LHS = LHSTy->getAs<ObjCInterfaceType>();
+  while ((LDecl = LDecl->getSuperClass())) {
+    LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
     if (canAssignObjCInterfaces(LHS, RHS)) {
-      llvm::SmallVector<ObjCProtocolDecl *, 8> IntersectionOfProtocols;
-      getIntersectionOfProtocols(*this, 
-                                 LHSOPT, RHSOPT, IntersectionOfProtocols);
-      if (IntersectionOfProtocols.empty())
-        LHSTy = getObjCObjectPointerType(LHSTy);
-      else
-        LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0],
-                                                IntersectionOfProtocols.size());
-      return LHSTy;
+      llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols;
+      getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols);
+
+      QualType Result = QualType(LHS, 0);
+      if (!Protocols.empty())
+        Result = getObjCObjectType(Result, Protocols.data(), Protocols.size());
+      Result = getObjCObjectPointerType(Result);
+      return Result;
     }
   }
     
   return QualType();
 }
 
-bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
-                                         const ObjCInterfaceType *RHS) {
+bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
+                                         const ObjCObjectType *RHS) {
+  assert(LHS->getInterface() && "LHS is not an interface type");
+  assert(RHS->getInterface() && "RHS is not an interface type");
+
   // Verify that the base decls are compatible: the RHS must be a subclass of
   // the LHS.
-  if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
+  if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface()))
     return false;
 
   // RHS must have a superset of the protocols in the LHS.  If the LHS is not
@@ -4233,15 +4247,15 @@
   if (RHS->getNumProtocols() == 0)
     return true;  // FIXME: should return false!
 
-  for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(),
-                                        LHSPE = LHS->qual_end();
+  for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
+                                     LHSPE = LHS->qual_end();
        LHSPI != LHSPE; LHSPI++) {
     bool RHSImplementsProtocol = false;
 
     // If the RHS doesn't implement the protocol on the left, the types
     // are incompatible.
-    for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(),
-                                          RHSPE = RHS->qual_end();
+    for (ObjCObjectType::qual_iterator RHSPI = RHS->qual_begin(),
+                                       RHSPE = RHS->qual_end();
          RHSPI != RHSPE; RHSPI++) {
       if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) {
         RHSImplementsProtocol = true;
@@ -4467,6 +4481,10 @@
   if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray)
     RHSClass = Type::ConstantArray;
 
+  // ObjCInterfaces are just specialized ObjCObjects.
+  if (LHSClass == Type::ObjCInterface) LHSClass = Type::ObjCObject;
+  if (RHSClass == Type::ObjCInterface) RHSClass = Type::ObjCObject;
+
   // Canonicalize ExtVector -> Vector.
   if (LHSClass == Type::ExtVector) LHSClass = Type::Vector;
   if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
@@ -4506,6 +4524,7 @@
     assert(false && "C++ should never be in mergeTypes");
     return QualType();
 
+  case Type::ObjCInterface:
   case Type::IncompleteArray:
   case Type::VariableArray:
   case Type::FunctionProto:
@@ -4598,14 +4617,13 @@
                              RHSCan->getAs<VectorType>()))
       return LHS;
     return QualType();
-  case Type::ObjCInterface: {
-    // Check if the interfaces are assignment compatible.
+  case Type::ObjCObject: {
+    // Check if the types are assignment compatible.
     // FIXME: This should be type compatibility, e.g. whether
     // "LHS x; RHS x;" at global scope is legal.
-    const ObjCInterfaceType* LHSIface = LHS->getAs<ObjCInterfaceType>();
-    const ObjCInterfaceType* RHSIface = RHS->getAs<ObjCInterfaceType>();
-    if (LHSIface && RHSIface &&
-        canAssignObjCInterfaces(LHSIface, RHSIface))
+    const ObjCObjectType* LHSIface = LHS->getAs<ObjCObjectType>();
+    const ObjCObjectType* RHSIface = RHS->getAs<ObjCObjectType>();
+    if (canAssignObjCInterfaces(LHSIface, RHSIface))
       return LHS;
 
     return QualType();
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index aae02a4..9d75695 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -74,6 +74,7 @@
     QualType VisitElaboratedType(ElaboratedType *T);
     // FIXME: DependentNameType
     QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
+    QualType VisitObjCObjectType(ObjCObjectType *T);
     QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
                             
     // Importing declarations
@@ -632,12 +633,22 @@
     if (!IsStructurallyEquivalent(Context, 
                                   Iface1->getDecl(), Iface2->getDecl()))
       return false;
-    if (Iface1->getNumProtocols() != Iface2->getNumProtocols())
+    break;
+  }
+
+  case Type::ObjCObject: {
+    const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
+    const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
+    if (!IsStructurallyEquivalent(Context,
+                                  Obj1->getBaseType(),
+                                  Obj2->getBaseType()))
       return false;
-    for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) {
+    if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
+      return false;
+    for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
       if (!IsStructurallyEquivalent(Context,
-                                    Iface1->getProtocol(I),
-                                    Iface2->getProtocol(I)))
+                                    Obj1->getProtocol(I),
+                                    Obj2->getProtocol(I)))
         return false;
     }
     break;
@@ -650,14 +661,6 @@
                                   Ptr1->getPointeeType(),
                                   Ptr2->getPointeeType()))
       return false;
-    if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols())
-      return false;
-    for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) {
-      if (!IsStructurallyEquivalent(Context,
-                                    Ptr1->getProtocol(I),
-                                    Ptr2->getProtocol(I)))
-        return false;
-    }
     break;
   }
       
@@ -1305,8 +1308,16 @@
   if (!Class)
     return QualType();
 
+  return Importer.getToContext().getObjCInterfaceType(Class);
+}
+
+QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) {
+  QualType ToBaseType = Importer.Import(T->getBaseType());
+  if (ToBaseType.isNull())
+    return QualType();
+
   llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
-  for (ObjCInterfaceType::qual_iterator P = T->qual_begin(), 
+  for (ObjCObjectType::qual_iterator P = T->qual_begin(), 
                                      PEnd = T->qual_end();
        P != PEnd; ++P) {
     ObjCProtocolDecl *Protocol
@@ -1316,9 +1327,9 @@
     Protocols.push_back(Protocol);
   }
 
-  return Importer.getToContext().getObjCInterfaceType(Class,
-                                                      Protocols.data(),
-                                                      Protocols.size());
+  return Importer.getToContext().getObjCObjectType(ToBaseType,
+                                                   Protocols.data(),
+                                                   Protocols.size());
 }
 
 QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
@@ -1326,20 +1337,7 @@
   if (ToPointeeType.isNull())
     return QualType();
 
-  llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
-  for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(), 
-                                         PEnd = T->qual_end();
-       P != PEnd; ++P) {
-    ObjCProtocolDecl *Protocol
-      = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
-    if (!Protocol)
-      return QualType();
-    Protocols.push_back(Protocol);
-  }
-
-  return Importer.getToContext().getObjCObjectPointerType(ToPointeeType,
-                                                          Protocols.data(),
-                                                          Protocols.size());
+  return Importer.getToContext().getObjCObjectPointerType(ToPointeeType);
 }
 
 //----------------------------------------------------------------------------
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 39643ee..c38cec3 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2080,9 +2080,9 @@
     break;
 
   case Class:
-    if (const ObjCInterfaceType *Iface
-                       = getClassReceiver()->getAs<ObjCInterfaceType>())
-      return Iface->getDecl();
+    if (const ObjCObjectType *Ty
+          = getClassReceiver()->getAs<ObjCObjectType>())
+      return Ty->getInterface();
     break;
 
   case SuperInstance:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index a5c3a20..5b48405 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -345,29 +345,36 @@
   return 0;
 }
 
-ObjCInterfaceType::ObjCInterfaceType(QualType Canonical,
-                                     ObjCInterfaceDecl *D,
-                                     ObjCProtocolDecl **Protos, unsigned NumP) :
-  Type(ObjCInterface, Canonical, /*Dependent=*/false),
-  Decl(D), NumProtocols(NumP)
-{
-  if (NumProtocols)
-    memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos, 
-           NumProtocols * sizeof(*Protos));
-}
-
 void ObjCInterfaceType::Destroy(ASTContext& C) {
   this->~ObjCInterfaceType();
   C.Deallocate(this);
 }
 
-const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const {
-  // There is no sugar for ObjCInterfaceType's, just return the canonical
+ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
+                               ObjCProtocolDecl * const *Protocols,
+                               unsigned NumProtocols)
+  : Type(ObjCObject, Canonical, false),
+    NumProtocols(NumProtocols),
+    BaseType(Base) {
+  assert(this->NumProtocols == NumProtocols &&
+         "bitfield overflow in protocol count");
+  if (NumProtocols)
+    memcpy(getProtocolStorage(), Protocols,
+           NumProtocols * sizeof(ObjCProtocolDecl*));
+}
+
+void ObjCObjectTypeImpl::Destroy(ASTContext& C) {
+  this->~ObjCObjectTypeImpl();
+  C.Deallocate(this);
+}
+
+const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const {
+  // There is no sugar for ObjCObjectType's, just return the canonical
   // type pointer if it is the right class.  There is no typedef information to
   // return and these cannot be Address-space qualified.
-  if (const ObjCInterfaceType *OIT = getAs<ObjCInterfaceType>())
-    if (OIT->getNumProtocols())
-      return OIT;
+  if (const ObjCObjectType *T = getAs<ObjCObjectType>())
+    if (T->getNumProtocols() && T->getInterface())
+      return T;
   return 0;
 }
 
@@ -375,17 +382,6 @@
   return getAsObjCQualifiedInterfaceType() != 0;
 }
 
-ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T,
-                                             ObjCProtocolDecl **Protos,
-                                             unsigned NumP) :
-  Type(ObjCObjectPointer, Canonical, /*Dependent=*/false),
-  PointeeType(T), NumProtocols(NumP)
-{
-  if (NumProtocols)
-    memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos, 
-           NumProtocols * sizeof(*Protos));
-}
-
 void ObjCObjectPointerType::Destroy(ASTContext& C) {
   this->~ObjCObjectPointerType();
   C.Deallocate(this);
@@ -638,6 +634,8 @@
   case IncompleteArray:
     // An array of unknown size is an incomplete type (C99 6.2.5p22).
     return true;
+  case ObjCObject:
+    return cast<ObjCObjectType>(this)->getBaseType()->isIncompleteType();
   case ObjCInterface:
     // ObjC interfaces are incomplete if they are @class, not @interface.
     return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl();
@@ -768,7 +766,8 @@
   case Elaborated:
   case DependentName:
   case ObjCInterface:
-  case ObjCObjectPointer:
+  case ObjCObject:
+  case ObjCObjectPointer: // FIXME: object pointers aren't really specifiers
     return true;
   default:
     return false;
@@ -953,17 +952,8 @@
           getExtInfo());
 }
 
-void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
-                                    QualType OIT, 
-                                    ObjCProtocolDecl * const *protocols,
-                                    unsigned NumProtocols) {
-  ID.AddPointer(OIT.getAsOpaquePtr());
-  for (unsigned i = 0; i != NumProtocols; i++)
-    ID.AddPointer(protocols[i]);
-}
-
 void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getPointeeType(), qual_begin(), getNumProtocols());
+  Profile(ID, getPointeeType());
 }
 
 /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
@@ -1163,17 +1153,17 @@
   return Context->getQualifiedType(T, *this);
 }
 
-void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
-                                         const ObjCInterfaceDecl *Decl,
-                                         ObjCProtocolDecl * const *protocols,
-                                         unsigned NumProtocols) {
-  ID.AddPointer(Decl);
+void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
+                                 QualType BaseType,
+                                 ObjCProtocolDecl * const *Protocols,
+                                 unsigned NumProtocols) {
+  ID.AddPointer(BaseType.getAsOpaquePtr());
   for (unsigned i = 0; i != NumProtocols; i++)
-    ID.AddPointer(protocols[i]);
+    ID.AddPointer(Protocols[i]);
 }
 
-void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getDecl(), qual_begin(), getNumProtocols());
+void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
+  Profile(ID, getBaseType(), qual_begin(), getNumProtocols());
 }
 
 Linkage Type::getLinkage() const { 
@@ -1244,7 +1234,7 @@
   return L;
 }
 
-Linkage ObjCInterfaceType::getLinkage() const {
+Linkage ObjCObjectType::getLinkage() const {
   return ExternalLinkage;
 }
 
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0478d4e..ad5b91a 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -596,25 +596,37 @@
                                      std::string &S) { 
   if (!S.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     S = ' ' + S;
-  
+
   std::string ObjCQIString = T->getDecl()->getNameAsString();
-  if (T->getNumProtocols()) {
-    ObjCQIString += '<';
-    bool isFirst = true;
-    for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), 
-                                          E = T->qual_end(); 
-         I != E; ++I) {
-      if (isFirst)
-        isFirst = false;
-      else
-        ObjCQIString += ',';
-      ObjCQIString += (*I)->getNameAsString();
-    }
-    ObjCQIString += '>';
-  }
   S = ObjCQIString + S;
 }
 
+void TypePrinter::PrintObjCObject(const ObjCObjectType *T,
+                                  std::string &S) {
+  if (T->qual_empty())
+    return Print(T->getBaseType(), S);
+
+  std::string tmp;
+  Print(T->getBaseType(), tmp);
+  tmp += '<';
+  bool isFirst = true;
+  for (ObjCObjectType::qual_iterator
+         I = T->qual_begin(), E = T->qual_end(); I != E; ++I) {
+    if (isFirst)
+      isFirst = false;
+    else
+      tmp += ',';
+    tmp += (*I)->getNameAsString();
+  }
+  tmp += '>';
+
+  if (!S.empty()) {
+    tmp += ' ';
+    tmp += S;
+  }
+  std::swap(tmp, S);
+}
+
 void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, 
                                          std::string &S) { 
   std::string ObjCQIString;