This patch includes a conceptually simple, but very intrusive/pervasive change. 

The idea is to segregate Objective-C "object" pointers from general C pointers (utilizing the recently added ObjCObjectPointerType). The fun starts in Sema::GetTypeForDeclarator(), where "SomeInterface *" is now represented by a single AST node (rather than a PointerType whose Pointee is an ObjCInterfaceType). Since a significant amount of code assumed ObjC object pointers where based on C pointers/structs, this patch is very tedious. It should also explain why it is hard to accomplish this in smaller, self-contained patches.

This patch does most of the "heavy lifting" related to moving from PointerType->ObjCObjectPointerType. It doesn't include all potential "cleanups". The good news is additional cleanups can be done later (some are noted in the code). This patch is so large that I didn't want to include any changes that are purely aesthetic.

By making the ObjC types truly built-in, they are much easier to work with (and require fewer "hacks"). For example, there is no need for ASTContext::isObjCIdStructType() or ASTContext::isObjCClassStructType()! We believe this change (and the follow-up cleanups) will pay dividends over time. 

Given the amount of code change, I do expect some fallout from this change (though it does pass all of the clang tests). If you notice any problems, please let us know asap! Thanks.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75314 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 2bd1482..dbac120 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -42,8 +42,8 @@
   Idents(idents), Selectors(sels),
   BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {  
   if (size_reserve > 0) Types.reserve(size_reserve);    
-  InitBuiltinTypes();
   TUDecl = TranslationUnitDecl::Create(*this);
+  InitBuiltinTypes();
 }
 
 ASTContext::~ASTContext() {
@@ -190,11 +190,10 @@
   LongDoubleComplexTy = getComplexType(LongDoubleTy);
 
   BuiltinVaListType = QualType();
-  ObjCIdType = QualType();
-  IdStructType = 0;
-  ObjCClassType = QualType();
-  ClassStructType = 0;
   
+  ObjCIdType = QualType();
+  ObjCClassType = QualType();
+
   ObjCConstantStringType = QualType();
   
   // void * type
@@ -1071,7 +1070,7 @@
   
   if (T->isPointerType()) {
     QualType Pointee = T->getAsPointerType()->getPointeeType();
-    if (Pointee->isPointerType()) {
+    if (Pointee->isPointerType() || Pointee->isObjCObjectPointerType()) {
       QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
       return getPointerType(ResultType);
     }
@@ -1847,15 +1846,18 @@
 
 /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
 /// the given interface decl and the conforming protocol list.
-QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
+QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
                                               ObjCProtocolDecl **Protocols, 
                                               unsigned NumProtocols) {
+  if (InterfaceT.isNull()) 
+    InterfaceT = QualType(ObjCObjectPointerType::getIdInterface(), 0);
+    
   // Sort the protocol list alphabetically to canonicalize it.
   if (NumProtocols)
     SortAndUniqueProtocols(Protocols, NumProtocols);
 
   llvm::FoldingSetNodeID ID;
-  ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols);
+  ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
 
   void *InsertPos = 0;
   if (ObjCObjectPointerType *QT =
@@ -1864,7 +1866,7 @@
 
   // No Match;
   ObjCObjectPointerType *QType =
-    new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols);
+    new (*this,8) ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols);
   
   Types.push_back(QType);
   ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
@@ -2745,25 +2747,7 @@
     S += 'j';
     getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, 
                                false);
-  } else if (T->isObjCQualifiedIdType()) {
-    getObjCEncodingForTypeImpl(getObjCIdType(), S, 
-                               ExpandPointedToStructures,
-                               ExpandStructures, FD);
-    if (FD || EncodingProperty) {
-      // Note that we do extended encoding of protocol qualifer list
-      // Only when doing ivar or property encoding.
-      const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
-      S += '"';
-      for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(),
-           E = QIDT->qual_end(); I != E; ++I) {
-        S += '<';
-        S += (*I)->getNameAsString();
-        S += '>';
-      }
-      S += '"';
-    }
-    return;
-  }
+  } 
   else if (const PointerType *PT = T->getAsPointerType()) {
     QualType PointeeTy = PT->getPointeeType();
     bool isReadOnly = false;
@@ -2797,42 +2781,7 @@
         S.replace(S.end()-2, S.end(), replace);
       }
     }
-    if (isObjCIdStructType(PointeeTy)) {
-      S += '@';
-      return;
-    }
-    else if (PointeeTy->isObjCInterfaceType()) {
-      if (!EncodingProperty &&
-          isa<TypedefType>(PointeeTy.getTypePtr())) {
-        // Another historical/compatibility reason.
-        // We encode the underlying type which comes out as 
-        // {...};
-        S += '^';
-        getObjCEncodingForTypeImpl(PointeeTy, S, 
-                                   false, ExpandPointedToStructures, 
-                                   NULL);
-        return;
-      }
-      S += '@';
-      if (FD || EncodingProperty) {
-        const ObjCInterfaceType *OIT = 
-                PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType();
-        ObjCInterfaceDecl *OI = OIT->getDecl();
-        S += '"';
-        S += OI->getNameAsCString();
-        for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
-             E = OIT->qual_end(); I != E; ++I) {
-          S += '<';
-          S += (*I)->getNameAsString();
-          S += '>';
-        } 
-        S += '"';
-      }
-      return;
-    } else if (isObjCClassStructType(PointeeTy)) {
-      S += '#';
-      return;
-    } else if (isObjCSelType(PointeeTy)) {
+    if (isObjCSelType(PointeeTy)) {
       S += ':';
       return;
     }
@@ -2937,7 +2886,61 @@
     }
     S += '}';
   }
-  else
+  else if (const ObjCObjectPointerType *OPT = T->getAsObjCObjectPointerType()) {
+    if (OPT->isObjCIdType()) {
+      S += '@';
+      return;
+    } else if (OPT->isObjCClassType()) {
+      S += '#';
+      return;
+    } else if (OPT->isObjCQualifiedIdType()) {
+      getObjCEncodingForTypeImpl(getObjCIdType(), S, 
+                                 ExpandPointedToStructures,
+                                 ExpandStructures, FD);
+      if (FD || EncodingProperty) {
+        // Note that we do extended encoding of protocol qualifer list
+        // Only when doing ivar or property encoding.
+        const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
+        S += '"';
+        for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(),
+             E = QIDT->qual_end(); I != E; ++I) {
+          S += '<';
+          S += (*I)->getNameAsString();
+          S += '>';
+        }
+        S += '"';
+      }
+      return;
+    } else {
+      QualType PointeeTy = OPT->getPointeeType();
+      if (!EncodingProperty &&
+          isa<TypedefType>(PointeeTy.getTypePtr())) {
+        // Another historical/compatibility reason.
+        // We encode the underlying type which comes out as 
+        // {...};
+        S += '^';
+        getObjCEncodingForTypeImpl(PointeeTy, S, 
+                                   false, ExpandPointedToStructures, 
+                                   NULL);
+        return;
+      }
+      S += '@';
+      if (FD || EncodingProperty) {
+        const ObjCInterfaceType *OIT = OPT->getInterfaceType();
+        ObjCInterfaceDecl *OI = OIT->getDecl();
+        S += '"';
+        S += OI->getNameAsCString();
+        for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
+             E = OIT->qual_end(); I != E; ++I) {
+          S += '<';
+          S += (*I)->getNameAsString();
+          S += '>';
+        } 
+        S += '"';
+      }
+      return;
+    }
+  } else
     assert(0 && "@encode for type not implemented!");
 }
 
@@ -2967,23 +2970,12 @@
 void ASTContext::setObjCIdType(QualType T)
 {
   ObjCIdType = T;
-
   const TypedefType *TT = T->getAsTypedefType();
-  if (!TT)
-    return;
-
-  TypedefDecl *TD = TT->getDecl();
-
-  // typedef struct objc_object *id;
-  const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
-  // User error - caller will issue diagnostics.
-  if (!ptr)
-    return;
-  const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
-  // User error - caller will issue diagnostics.
-  if (!rec)
-    return;
-  IdStructType = rec;
+  assert(TT && "missing 'id' typedef");
+  const ObjCObjectPointerType *OPT = 
+    TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType();
+  assert(OPT && "missing 'id' type");
+  ObjCObjectPointerType::setIdInterface(OPT->getPointeeType());
 }
 
 void ASTContext::setObjCSelType(QualType T)
@@ -3013,18 +3005,12 @@
 void ASTContext::setObjCClassType(QualType T)
 {
   ObjCClassType = T;
-
   const TypedefType *TT = T->getAsTypedefType();
-  if (!TT)
-    return;
-  TypedefDecl *TD = TT->getDecl();
-
-  // typedef struct objc_class *Class;
-  const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
-  assert(ptr && "'Class' incorrectly typed");
-  const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
-  assert(rec && "'Class' incorrectly typed");
-  ClassStructType = rec;
+  assert(TT && "missing 'Class' typedef");
+  const ObjCObjectPointerType *OPT = 
+    TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType();
+  assert(OPT && "missing 'Class' type");
+  ObjCObjectPointerType::setClassInterface(OPT->getPointeeType());
 }
 
 void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
@@ -3123,6 +3109,8 @@
 /// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
 /// ID type).
 bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
+  if (Ty->isObjCObjectPointerType())
+    return true;
   if (Ty->isObjCQualifiedIdType())
     return true;
   
@@ -3198,8 +3186,30 @@
 /// compatible for assignment from RHS to LHS.  This handles validation of any
 /// protocol qualifiers on the LHS or RHS.
 ///
+/// FIXME: Move the following to ObjCObjectPointerType/ObjCInterfaceType.
+bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
+                                         const ObjCObjectPointerType *RHSOPT) {
+  // If either interface represents the built-in 'id' or 'Class' types, 
+  // then return true (no need to call canAssignObjCInterfaces()).
+  if (LHSOPT->isObjCIdType() || RHSOPT->isObjCIdType() ||
+      LHSOPT->isObjCClassType() || RHSOPT->isObjCClassType())
+    return true;
+
+  const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
+  const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+  if (!LHS || !RHS)
+    return false;
+  return canAssignObjCInterfaces(LHS, RHS);
+}
+
 bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
                                          const ObjCInterfaceType *RHS) {
+  // If either interface represents the built-in 'id' or 'Class' types, 
+  // then return true.
+  if (LHS->isObjCIdInterface() || RHS->isObjCIdInterface() ||
+      LHS->isObjCClassInterface() || RHS->isObjCClassInterface())
+    return true;
+
   // Verify that the base decls are compatible: the RHS must be a subclass of
   // the LHS.
   if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
@@ -3245,25 +3255,14 @@
 
 bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
   // get the "pointed to" types
-  const PointerType *LHSPT = LHS->getAsPointerType();
-  const PointerType *RHSPT = RHS->getAsPointerType();
+  const ObjCObjectPointerType *LHSOPT = LHS->getAsObjCObjectPointerType();
+  const ObjCObjectPointerType *RHSOPT = RHS->getAsObjCObjectPointerType();
   
-  if (!LHSPT || !RHSPT)
+  if (!LHSOPT || !RHSOPT)
     return false;
-    
-  QualType lhptee = LHSPT->getPointeeType();
-  QualType rhptee = RHSPT->getPointeeType();
-  const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
-  const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
-  // ID acts sort of like void* for ObjC interfaces
-  if (LHSIface && isObjCIdStructType(rhptee))
-    return true;
-  if (RHSIface && isObjCIdStructType(lhptee))
-    return true;
-  if (!LHSIface || !RHSIface)
-    return false;
-  return canAssignObjCInterfaces(LHSIface, RHSIface) ||
-         canAssignObjCInterfaces(RHSIface, LHSIface);
+
+  return canAssignObjCInterfaces(LHSOPT, RHSOPT) ||
+         canAssignObjCInterfaces(RHSOPT, LHSOPT);
 }
 
 /// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, 
@@ -3406,8 +3405,7 @@
       // issue error.
       if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) ||
           (GCAttr == QualType::Strong && GCLHSAttr != GCAttr &&
-           LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) &&
-           !isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType())))
+           !LHSCan->isObjCObjectPointerType()))
         return QualType();
           
       RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
@@ -3432,8 +3430,7 @@
       // issue error.
       if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) ||
           (GCAttr == QualType::Strong && GCRHSAttr != GCAttr &&
-           RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) &&
-           !isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType())))
+           !RHSCan->isObjCObjectPointerType()))
         return QualType();
       
       LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
@@ -3460,47 +3457,12 @@
   if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
   
   // Consider qualified interfaces and interfaces the same.
+  // FIXME: Remove (ObjCObjectPointerType should obsolete this funny business).
   if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface;
   if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface;
 
   // If the canonical type classes don't match.
   if (LHSClass != RHSClass) {
-    const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType();
-    const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType();
-    
-    // 'id' and 'Class' act sort of like void* for ObjC interfaces
-    if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS)))
-      return LHS;
-    if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS)))
-      return RHS;
-    
-    // ID is compatible with all qualified id types.
-    if (LHS->isObjCQualifiedIdType()) {
-      if (const PointerType *PT = RHS->getAsPointerType()) {
-        QualType pType = PT->getPointeeType();
-        if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
-          return LHS;
-        // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
-        // Unfortunately, this API is part of Sema (which we don't have access
-        // to. Need to refactor. The following check is insufficient, since we 
-        // need to make sure the class implements the protocol.
-        if (pType->isObjCInterfaceType())
-          return LHS;
-      }
-    }
-    if (RHS->isObjCQualifiedIdType()) {
-      if (const PointerType *PT = LHS->getAsPointerType()) {
-        QualType pType = PT->getPointeeType();
-        if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
-          return RHS;
-        // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
-        // Unfortunately, this API is part of Sema (which we don't have access
-        // to. Need to refactor. The following check is insufficient, since we 
-        // need to make sure the class implements the protocol.
-        if (pType->isObjCInterfaceType())
-          return RHS;
-      }
-    }
     // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
     // a signed integer type, or an unsigned integer type. 
     if (const EnumType* ETy = LHS->getAsEnumType()) {
@@ -3611,9 +3573,6 @@
     return mergeFunctionTypes(LHS, RHS);
   case Type::Record:
   case Type::Enum:
-    // FIXME: Why are these compatible?
-    if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS;
-    if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS;
     return QualType();
   case Type::Builtin:
     // Only exactly equal builtin types are compatible, which is tested above.
@@ -3638,10 +3597,17 @@
 
     return QualType();
   }
-  case Type::ObjCObjectPointer:
-    // FIXME: finish
-    // Distinct qualified id's are not compatible.
+  case Type::ObjCObjectPointer: {
+    // FIXME: Incorporate tests from Sema::ObjCQualifiedIdTypesAreCompatible().
+    if (LHS->isObjCQualifiedIdType() && RHS->isObjCQualifiedIdType())
+      return QualType();
+
+    if (canAssignObjCInterfaces(LHS->getAsObjCObjectPointerType(), 
+                                RHS->getAsObjCObjectPointerType()))
+      return LHS;
+
     return QualType();
+  }
   case Type::FixedWidthInt:
     // Distinct fixed-width integers are not compatible.
     return QualType();
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 54f13e1..613dc58 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -280,7 +280,7 @@
     // of the interface (which has been reported). Recover gracefully.
     if (OID) {
       selfTy = Context.getObjCInterfaceType(OID);
-      selfTy = Context.getPointerType(selfTy);
+      selfTy = Context.getObjCObjectPointerType(selfTy);
     } else {
       selfTy = Context.getObjCIdType();
     }
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 970e8bc..2c65179 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1095,6 +1095,7 @@
   switch (getStmtClass()) {
   default: break;
   case StringLiteralClass:
+  case ObjCStringLiteralClass:
   case ObjCEncodeExprClass:
     return true;
   case CompoundLiteralExprClass: {
@@ -1136,7 +1137,6 @@
       return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
     break;
   }
-
   return isEvaluatable(Ctx);
 }
 
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index eb6b5b7..c3d0402 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -382,7 +382,8 @@
   const Expr* SubExpr = E->getSubExpr();
 
    // Check for pointer->pointer cast
-  if (SubExpr->getType()->isPointerType()) {
+  if (SubExpr->getType()->isPointerType() ||
+      SubExpr->getType()->isObjCObjectPointerType()) {
     APValue Result;
     if (EvaluatePointer(SubExpr, Result, Info))
       return Result;
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 78c3b78..fd368c4 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -22,6 +22,9 @@
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
+ObjCInterfaceType *ObjCObjectPointerType::IdInterfaceT;
+ObjCInterfaceType *ObjCObjectPointerType::ClassInterfaceT;
+
 bool QualType::isConstant(ASTContext &Ctx) const {
   if (isConstQualified())
     return true;
@@ -295,6 +298,15 @@
   return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType());
 }
 
+QualType Type::getPointeeType() const {
+  if (const PointerType *PT = getAsPointerType())
+    return PT->getPointeeType();
+  if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType())
+    return OPT->getPointeeType();
+  if (const BlockPointerType *BPT = getAsBlockPointerType())
+    return BPT->getPointeeType();
+  return QualType();
+}
 
 const PointerType *Type::getAsPointerType() const {
   // If this is directly a pointer type, return it.
@@ -609,6 +621,14 @@
   return 0;
 }
 
+const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
+  if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) {
+    if (OPT->getInterfaceType())
+      return OPT;
+  }
+  return 0;
+}
+
 const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const {
   // There is no sugar for template type parameters, so just return
   // the canonical type pointer if it is the right class.
@@ -1016,16 +1036,18 @@
 }
 
 void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
-                                    const ObjCInterfaceDecl *Decl,
-                                    ObjCProtocolDecl **protocols,
+                                    QualType OIT, ObjCProtocolDecl **protocols,
                                     unsigned NumProtocols) {
-  ID.AddPointer(Decl);
+  ID.AddPointer(OIT.getAsOpaquePtr());
   for (unsigned i = 0; i != NumProtocols; i++)
     ID.AddPointer(protocols[i]);
 }
 
 void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
+  if (getNumProtocols())
+    Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols());
+  else
+    Profile(ID, getPointeeType(), 0, 0);
 }
 
 void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
@@ -1663,6 +1685,14 @@
     InnerString = MyString + ' ' + InnerString;
 }
 
+bool ObjCInterfaceType::isObjCIdInterface() const {
+  return this == ObjCObjectPointerType::getIdInterface();
+}
+
+bool ObjCInterfaceType::isObjCClassInterface() const {
+  return this == ObjCObjectPointerType::getClassInterface();
+}  
+
 void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
   if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     InnerString = ' ' + InnerString;
@@ -1671,15 +1701,7 @@
 
 void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, 
                                                 const PrintingPolicy &Policy) const {
-  if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
-    InnerString = ' ' + InnerString;
-
-  std::string ObjCQIString;
-  
-  if (getDecl())
-    ObjCQIString = getDecl()->getNameAsString();
-  else
-    ObjCQIString = "id";
+  std::string ObjCQIString = getInterfaceType()->getDecl()->getNameAsString();
 
   if (!qual_empty()) {
     ObjCQIString += '<';
@@ -1690,6 +1712,11 @@
     }
     ObjCQIString += '>';
   }
+  if (!isObjCIdType() && !isObjCQualifiedIdType())
+    ObjCQIString += " *"; // Don't forget the implicit pointer.
+  else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+    InnerString = ' ' + InnerString;
+
   InnerString = ObjCQIString + InnerString;
 }
 
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index aa85769..b454a36 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -31,26 +31,21 @@
 
 using namespace clang;
 
-static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
-  Expr* Receiver = ME->getReceiver();
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
+  const Expr* Receiver = ME->getReceiver();
   
   if (!Receiver)
     return NULL;
   
-  QualType X = Receiver->getType();
-  
-  if (X->isPointerType()) {
-    Type* TP = X.getTypePtr();
-    const PointerType* T = TP->getAsPointerType();    
-    return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
-  }
+  if (const ObjCObjectPointerType *PT =
+      Receiver->getType()->getAsObjCObjectPointerType())
+    return PT->getInterfaceType();
 
-  // FIXME: Support ObjCQualifiedIdType?
   return NULL;
 }
 
-static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
-  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
   return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
                       : NULL;
 }
@@ -67,7 +62,7 @@
   BugReporter& BR;
   ASTContext &Ctx;
       
-  bool isNSString(ObjCInterfaceType* T, const char* suffix);
+  bool isNSString(const ObjCInterfaceType *T, const char* suffix);
   bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
       
   void Warn(NodeTy* N, Expr* E, const std::string& s);  
@@ -114,7 +109,7 @@
   ObjCMessageExpr* ME =
     cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
 
-  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
   
   if (!ReceiverType)
     return false;
@@ -129,8 +124,7 @@
       
   name += 2;
   
-  // FIXME: Make all of this faster.
-  
+  // FIXME: Make all of this faster.  
   if (isNSString(ReceiverType, name))
     return AuditNSString(N, ME);
 
@@ -163,9 +157,8 @@
 // NSString checking.
 //===----------------------------------------------------------------------===//
 
-bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
-                                           const char* suffix) {
-  
+bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
+                                           const char* suffix) {  
   return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
 }
 
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index c74668c..1cfd783 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -547,14 +547,12 @@
     return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
   }
   
-  ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
-    
-    const PointerType* PT = E->getType()->getAsPointerType();
-    if (!PT) return 0;
-    
-    ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType());
-    
-    return OI ? OI->getDecl() : 0;
+  const ObjCInterfaceDecl* getReceiverDecl(Expr* E) {    
+    if (const ObjCObjectPointerType* PT =
+        E->getType()->getAsObjCObjectPointerType())
+      return PT->getInterfaceDecl();
+
+    return NULL;
   }
   
   iterator end() { return M.end(); }
@@ -564,7 +562,7 @@
     Selector S = ME->getSelector();
     
     if (Expr* Receiver = ME->getReceiver()) {
-      ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
+      const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
       return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
     }
     
@@ -886,20 +884,20 @@
   if (!Ctx.isObjCObjectPointerType(Ty))
     return false;
 
-  // We assume that id<..>, id, and "Class" all represent tracked objects.
-  const PointerType *PT = Ty->getAsPointerType();
-  if (PT == 0)
+  const ObjCObjectPointerType *PT = Ty->getAsObjCObjectPointerType();
+  
+  // Can be true for objects with the 'NSObject' attribute.
+  if (!PT)
     return true;
-    
-  const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType();
+  
+  // We assume that id<..>, id, and "Class" all represent tracked objects.
+  if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
+      PT->isObjCClassType())
+    return true;
 
-  // We assume that id<..>, id, and "Class" all represent tracked objects.
-  if (!OT)
-    return true;
-    
   // Does the interface subclass NSObject?    
   // FIXME: We can memoize here if this gets too expensive.    
-  ObjCInterfaceDecl* ID = OT->getDecl();  
+  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();  
 
   // Assume that anything declared with a forward declaration and no
   // @interface subclasses NSObject.
@@ -908,7 +906,6 @@
   
   IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
 
-
   for ( ; ID ; ID = ID->getSuperClass())
     if (ID->getIdentifier() == NSObjectII)
       return true;
@@ -977,7 +974,7 @@
       case 17:
         // Handle: id NSMakeCollectable(CFTypeRef)
         if (!memcmp(FName, "NSMakeCollectable", 17)) {
-          S = (RetTy == Ctx.getObjCIdType())
+          S = (RetTy->isObjCIdType())
               ? getUnarySummary(FT, cfmakecollectable)
               : getPersistentStopSummary();
         }
@@ -2726,34 +2723,26 @@
 ///  While the the return type can be queried directly from RetEx, when
 ///  invoking class methods we augment to the return type to be that of
 ///  a pointer to the class (as opposed it just being id).
-static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) {
-
+static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
   QualType RetTy = RetE->getType();
-
-  // FIXME: We aren't handling id<...>.
-  const PointerType* PT = RetTy->getAsPointerType();
-  if (!PT)
-    return RetTy;
-    
-  // If RetEx is not a message expression just return its type.
-  // If RetEx is a message expression, return its types if it is something
+  // If RetE is not a message expression just return its type.
+  // If RetE is a message expression, return its types if it is something
   /// more specific than id.
+  if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
+    if (const ObjCObjectPointerType *PT = RetTy->getAsObjCObjectPointerType())
+      if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || 
+          PT->isObjCClassType()) {
+        // At this point we know the return type of the message expression is
+        // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
+        // is a call to a class method whose type we can resolve.  In such
+        // cases, promote the return type to XXX* (where XXX is the class).
+        const ObjCInterfaceDecl *D = ME->getClassInfo().first;  
+        return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+      }
   
-  ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE);
-  
-  if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType()))
-    return RetTy;
-  
-  ObjCInterfaceDecl* D = ME->getClassInfo().first;  
-
-  // At this point we know the return type of the message expression is id.
-  // If we have an ObjCInterceDecl, we know this is a call to a class method
-  // whose type we can resolve.  In such cases, promote the return type to
-  // Class*.  
-  return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+  return RetTy;
 }
 
-
 void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
                              GRExprEngine& Eng,
                              GRStmtNodeBuilder<GRState>& Builder,
@@ -3009,26 +2998,21 @@
     SVal V = St->getSValAsScalarOrLoc(Receiver);
 
     SymbolRef Sym = V.getAsLocSymbol();
+    
     if (Sym) {
       if (const RefVal* T  = St->get<RefBindings>(Sym)) {
-        QualType Ty = T->getType();
-        
-        if (const PointerType* PT = Ty->getAsPointerType()) {
-          QualType PointeeTy = PT->getPointeeType();
-          
-          if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy))
-            ID = IT->getDecl();
-        }
+        if (const ObjCObjectPointerType* PT =
+            T->getType()->getAsObjCObjectPointerType())
+          ID = PT->getInterfaceDecl();
       }
     }
 
     // FIXME: this is a hack.  This may or may not be the actual method
     //  that is called.
     if (!ID) {
-      if (const PointerType *PT = Receiver->getType()->getAsPointerType())
-        if (const ObjCInterfaceType *p =
-            PT->getPointeeType()->getAsObjCInterfaceType())
-          ID = p->getDecl();
+      if (const ObjCObjectPointerType *PT =
+          Receiver->getType()->getAsObjCObjectPointerType())
+        ID = PT->getInterfaceDecl();
     }
 
     // FIXME: The receiver could be a reference to a class, meaning that
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp
index c91442b..c1382d0 100644
--- a/lib/Analysis/CheckNSError.cpp
+++ b/lib/Analysis/CheckNSError.cpp
@@ -162,16 +162,22 @@
 bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
   
   const PointerType* PPT = ArgTy->getAsPointerType();
-  if (!PPT) return false;
+  if (!PPT)
+    return false;
   
-  const PointerType* PT = PPT->getPointeeType()->getAsPointerType();
-  if (!PT) return false;
+  const ObjCObjectPointerType* PT =
+    PPT->getPointeeType()->getAsObjCObjectPointerType();
+
+  if (!PT)
+    return false;
   
-  const ObjCInterfaceType *IT =
-  PT->getPointeeType()->getAsObjCInterfaceType();
+  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
   
-  if (!IT) return false;
-  return IT->getDecl()->getIdentifier() == II;
+  // FIXME: Can ID ever be NULL?
+  if (ID)
+    return II == ID->getIdentifier();
+  
+  return false;
 }
 
 bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp
index 2881486..c4e586d 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -30,8 +30,8 @@
 
   // Right now don't compare the compatibility of pointers.  That involves
   // looking at subtyping relationships.  FIXME: Future patch.
-  if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType())  && 
-      (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType()))
+  if ((Derived->isPointerType() || Derived->isObjCObjectPointerType())  && 
+      (Ancestor->isPointerType() || Ancestor->isObjCObjectPointerType()))
     return true;
 
   return C.typesAreCompatible(Derived, Ancestor);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 8fa1e9c..e45fa55 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -761,8 +761,10 @@
     // Unsupported types
     return llvm::DIType();
   case Type::ObjCObjectPointer:   // Encode id<p> in debug info just like id.
-    return Slot = getOrCreateType(M->getContext().getObjCIdType(), Unit);
-      
+    {
+    ObjCObjectPointerType *OPT = cast<ObjCObjectPointerType>(Ty);
+    return Slot = CreateType(OPT->getInterfaceType(), Unit);
+    }
   case Type::ObjCQualifiedInterface:  // Drop protocols from interface.
   case Type::ObjCInterface: 
     return Slot = CreateType(cast<ObjCInterfaceType>(Ty), Unit);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 0951019..d42ca17 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -257,7 +257,6 @@
       Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
     }
   }
-  
   Builder.CreateStore(Value, Addr, Volatile);  
 }
 
@@ -758,11 +757,11 @@
   default: assert(0 && "Unknown unary operator lvalue!");
   case UnaryOperator::Deref:
     {
-      QualType T =
-        E->getSubExpr()->getType()->getAsPointerType()->getPointeeType();
+      QualType T = E->getSubExpr()->getType()->getPointeeType();
+      assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
+        
       LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()),
-                                   ExprTy->getAsPointerType()->getPointeeType()
-                                      .getCVRQualifiers(), 
+                                   T.getCVRQualifiers(), 
                                    getContext().getObjCGCAttrKind(T));
      // We should not generate __weak write barrier on indirect reference
      // of a pointer to object; as in void foo (__weak id *param); *param = 0;
@@ -900,7 +899,10 @@
     Address = Builder.CreateGEP(Base, Idx, "arrayidx");
   }
   
-  QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType();
+  QualType T = E->getBase()->getType()->getPointeeType();
+  assert(!T.isNull() && 
+         "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type");
+    
   LValue LV = LValue::MakeAddr(Address,
                                T.getCVRQualifiers(),
                                getContext().getObjCGCAttrKind(T));
@@ -1261,8 +1263,7 @@
   QualType ObjectTy;
   if (E->isArrow()) {
     BaseValue = EmitScalarExpr(BaseExpr);
-    const PointerType *PTy = BaseExpr->getType()->getAsPointerType();
-    ObjectTy = PTy->getPointeeType();
+    ObjectTy = BaseExpr->getType()->getPointeeType();
     CVRQualifiers = ObjectTy.getCVRQualifiers();
   } else {
     LValue BaseLV = EmitLValue(BaseExpr);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 161cd57..94d0789 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -987,7 +987,7 @@
 }
 
 Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
-  if (!Ops.Ty->isPointerType()) {
+  if (!Ops.Ty->isPointerType() && !Ops.Ty->isObjCObjectPointerType()) {
     if (CGF.getContext().getLangOptions().OverflowChecking &&
         Ops.Ty->isSignedIntegerType())
       return EmitOverflowCheckedBinOp(Ops);
@@ -998,20 +998,24 @@
     return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
   }
 
-  if (Ops.Ty->getAsPointerType()->isVariableArrayType()) {
+  if (Ops.Ty->isPointerType() &&
+      Ops.Ty->getAsPointerType()->isVariableArrayType()) {
     // The amount of the addition needs to account for the VLA size
     CGF.ErrorUnsupported(Ops.E, "VLA pointer addition");
   }
   Value *Ptr, *Idx;
   Expr *IdxExp;
-  const PointerType *PT;
-  if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) {
+  const PointerType *PT = Ops.E->getLHS()->getType()->getAsPointerType();
+  const ObjCObjectPointerType *OPT = 
+    Ops.E->getLHS()->getType()->getAsObjCObjectPointerType();
+  if (PT || OPT) {
     Ptr = Ops.LHS;
     Idx = Ops.RHS;
     IdxExp = Ops.E->getRHS();
-  } else {                                           // int + pointer
+  } else {  // int + pointer
     PT = Ops.E->getRHS()->getType()->getAsPointerType();
-    assert(PT && "Invalid add expr");
+    OPT = Ops.E->getRHS()->getType()->getAsObjCObjectPointerType();
+    assert((PT || OPT) && "Invalid add expr");
     Ptr = Ops.RHS;
     Idx = Ops.LHS;
     IdxExp = Ops.E->getLHS();
@@ -1027,8 +1031,7 @@
     else
       Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
   }
-
-  const QualType ElementType = PT->getPointeeType();
+  const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType();
   // Handle interface types, which are not represented with a concrete
   // type.
   if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
@@ -1066,7 +1069,8 @@
     return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
   }
 
-  if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) {
+  if (Ops.E->getLHS()->getType()->isPointerType() &&
+      Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) {
     // The amount of the addition needs to account for the VLA size for
     // ptr-int
     // The amount of the division needs to account for the VLA size for
@@ -1075,7 +1079,7 @@
   }
 
   const QualType LHSType = Ops.E->getLHS()->getType();
-  const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
+  const QualType LHSElementType = LHSType->getPointeeType();
   if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
     // pointer - int
     Value *Idx = Ops.RHS;
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 33cb5bc..5d37841 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -305,8 +305,8 @@
 QualType CodeGenFunction::TypeOfSelfObject() {
   const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
   ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
-  const PointerType *PTy = 
-    cast<PointerType>(getContext().getCanonicalType(selfDecl->getType()));
+  const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>(
+    getContext().getCanonicalType(selfDecl->getType()));
   return PTy->getPointeeType();
 }
 
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 46e948e..a75b39a 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -1338,7 +1338,7 @@
         Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
 
         // @catch() and @catch(id) both catch any ObjC exception
-        if (!CatchDecl || CGF.getContext().isObjCIdType(CatchDecl->getType())
+        if (!CatchDecl || CatchDecl->getType()->isObjCIdType()
             || CatchDecl->getType()->isObjCQualifiedIdType()) {
           // Use i8* null here to signal this is a catch all, not a cleanup.
           ESelArgs.push_back(NULLPtr);
@@ -1348,10 +1348,11 @@
         } 
 
         // All other types should be Objective-C interface pointer types.
-        const PointerType *PT = CatchDecl->getType()->getAsPointerType();
-        assert(PT && "Invalid @catch type.");
+        const ObjCObjectPointerType *OPT = 
+          CatchDecl->getType()->getAsObjCObjectPointerType();
+        assert(OPT && "Invalid @catch type.");
         const ObjCInterfaceType *IT = 
-          PT->getPointeeType()->getAsObjCInterfaceType();
+          OPT->getPointeeType()->getAsObjCInterfaceType();
         assert(IT && "Invalid @catch type.");
         llvm::Value *EHType =
           MakeConstantString(IT->getDecl()->getNameAsString());
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index fadbdd7..82ab88f 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2523,19 +2523,18 @@
       llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
 
       const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
-      const PointerType *PT = 0;
+      const ObjCObjectPointerType *OPT = 0;
 
       // catch(...) always matches.
       if (!CatchParam) {
         AllMatched = true;
       } else {
-        PT = CatchParam->getType()->getAsPointerType();
+        OPT = CatchParam->getType()->getAsObjCObjectPointerType();
         
         // catch(id e) always matches. 
         // FIXME: For the time being we also match id<X>; this should
         // be rejected by Sema instead.
-        if ((PT && CGF.getContext().isObjCIdStructType(PT->getPointeeType())) ||
-            CatchParam->getType()->isObjCQualifiedIdType())
+        if (OPT && (OPT->isObjCIdType()) || OPT->isObjCQualifiedIdType())
           AllMatched = true;
       }
       
@@ -2551,8 +2550,8 @@
         break;
       }
       
-      assert(PT && "Unexpected non-pointer type in @catch");
-      QualType T = PT->getPointeeType();
+      assert(OPT && "Unexpected non-object pointer type in @catch");
+      QualType T = OPT->getPointeeType();
       const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType();
       assert(ObjCType && "Catch parameter must have Objective-C type!");
 
@@ -5443,7 +5442,7 @@
           break;
         }
 
-        if (CGF.getContext().isObjCIdType(CatchDecl->getType()) ||
+        if (CatchDecl->getType()->isObjCIdType() ||
             CatchDecl->getType()->isObjCQualifiedIdType()) {
           llvm::Value *IDEHType = 
             CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
@@ -5459,10 +5458,10 @@
         } 
 
         // All other types should be Objective-C interface pointer types.
-        const PointerType *PT = CatchDecl->getType()->getAsPointerType();
+        const ObjCObjectPointerType *PT = 
+          CatchDecl->getType()->getAsObjCObjectPointerType();
         assert(PT && "Invalid @catch type.");
-        const ObjCInterfaceType *IT = 
-          PT->getPointeeType()->getAsObjCInterfaceType();
+        const ObjCInterfaceType *IT = PT->getInterfaceType();
         assert(IT && "Invalid @catch type.");
         llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
         SelectorArgs.push_back(EHType);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 1a30ea3..30a69f1 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -215,6 +215,7 @@
 const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
   const clang::Type &Ty = *Context.getCanonicalType(T);
   
+  //T->dump();
   switch (Ty.getTypeClass()) {
 #define TYPE(Class, Base)
 #define ABSTRACT_TYPE(Class, Base)
@@ -353,10 +354,14 @@
     return T;
   }
       
-  case Type::ObjCObjectPointer:
-    // Protocols don't influence the LLVM type.
-    return ConvertTypeRecursive(Context.getObjCIdType());
-
+  case Type::ObjCObjectPointer: {
+   // Qualified id types don't influence the LLVM type, here we always return
+   // an opaque type for 'id'.
+   const llvm::Type *&T = InterfaceTypes[0];
+   if (!T)
+       T = llvm::OpaqueType::get();
+   return llvm::PointerType::getUnqual(T);
+  }
   case Type::Record:
   case Type::Enum: {
     const TagDecl *TD = cast<TagType>(Ty).getDecl();
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 8018b4f..97c26f8 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -480,6 +480,11 @@
     Out << 'P';
     mangleType(PT->getPointeeType());
   }
+  else if (const ObjCObjectPointerType *PT = 
+           dyn_cast<ObjCObjectPointerType>(T.getTypePtr())) {
+    Out << 'P';
+    mangleType(PT->getPointeeType());
+  }
   //         ::= R <type>   # reference-to
   else if (const LValueReferenceType *RT =
            dyn_cast<LValueReferenceType>(T.getTypePtr())) {
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 47a7e62..c922b0d 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1531,6 +1531,7 @@
     Context->setObjCProtoType(GetType(Proto));
   if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS])
     Context->setObjCClassType(GetType(Class));
+
   if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING])
     Context->setCFConstantStringType(GetType(String));
   if (unsigned FastEnum 
@@ -1934,13 +1935,12 @@
 
   case pch::TYPE_OBJC_OBJECT_POINTER: {
     unsigned Idx = 0;
-    ObjCInterfaceDecl *ItfD = 
-      cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+    QualType OIT = GetType(Record[Idx++]);
     unsigned NumProtos = Record[Idx++];
     llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
     for (unsigned I = 0; I != NumProtos; ++I)
       Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
-    return Context->getObjCObjectPointerType(ItfD, Protos.data(), NumProtos);
+    return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos);
   }
   }
   // Suppress a GCC warning
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 0362e8a..57577b7 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -255,7 +255,7 @@
 
 void
 PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
-  Writer.AddDeclRef(T->getDecl(), Record);
+  Writer.AddTypeRef(T->getPointeeType(), Record);  
   Record.push_back(T->getNumProtocols());
   for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
        E = T->qual_end(); I != E; ++I)
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index cf31f2b..1bc7451 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -2163,9 +2163,10 @@
   if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0;
   
   if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) {
-      const PointerType *PT = Super->getType()->getAsPointerType();
-      assert(PT);
-      ObjCInterfaceType *IT = cast<ObjCInterfaceType>(PT->getPointeeType());
+      const ObjCObjectPointerType *OPT = 
+        Super->getType()->getAsObjCObjectPointerType();
+      assert(OPT);
+      const ObjCInterfaceType *IT = OPT->getInterfaceType();
       return IT->getDecl();
     }
   return 0;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 6cbb1c3..9b58e47 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -53,9 +53,9 @@
       
         // Don't desugar magic Objective-C types.
         Ty.getUnqualifiedType() != Context.getObjCIdType() &&
+        Ty.getUnqualifiedType() != Context.getObjCClassType() &&
         Ty.getUnqualifiedType() != Context.getObjCSelType() &&
         Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
-        Ty.getUnqualifiedType() != Context.getObjCClassType() &&
         
         // Not va_list.
         Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
@@ -140,17 +140,6 @@
     Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
   }
 
-  if (Context.getObjCClassType().isNull()) {
-    RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class");
-    QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
-    TypedefDecl *ClassTypedef = 
-      TypedefDecl::Create(Context, CurContext, SourceLocation(),
-                          &Context.Idents.get("Class"), ClassT);
-    PushOnScopeChains(ClassTag, TUScope);
-    PushOnScopeChains(ClassTypedef, TUScope);
-    Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
-  }
-
   // Synthesize "@class Protocol;
   if (Context.getObjCProtoType().isNull()) {
     ObjCInterfaceDecl *ProtocolDecl =
@@ -160,20 +149,38 @@
     Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
     PushOnScopeChains(ProtocolDecl, TUScope);
   }
-
-  // Synthesize "typedef struct objc_object { Class isa; } *id;"
+  // Create the built-in decls/typedefs for 'id' and 'Class'.
   if (Context.getObjCIdType().isNull()) {
-    RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object");
+    ObjCInterfaceDecl *IdIDecl =
+      ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
+                                &Context.Idents.get("id"), 
+                                SourceLocation(), true);
+    QualType IdIType = Context.getObjCInterfaceType(IdIDecl);
+    QualType ObjCIdType = Context.getObjCObjectPointerType(IdIType);
 
-    QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
-    PushOnScopeChains(ObjectTag, TUScope);
     TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext,
                                                  SourceLocation(),
                                                  &Context.Idents.get("id"),
-                                                 ObjT);
+                                                 ObjCIdType);
     PushOnScopeChains(IdTypedef, TUScope);
     Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
   }
+  // Create the built-in decls/typedefs and type for "Class".
+  if (Context.getObjCClassType().isNull()) {
+    ObjCInterfaceDecl *ClassIDecl =
+      ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
+                                &Context.Idents.get("Class"), 
+                                SourceLocation(), true);
+    QualType ClassIType = Context.getObjCInterfaceType(ClassIDecl);
+    QualType ObjCClassType = Context.getObjCObjectPointerType(ClassIType);
+    
+    TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext,
+                                                    SourceLocation(),
+                                                    &Context.Idents.get("Class"),
+                                                    ObjCClassType);
+    PushOnScopeChains(ClassTypedef, TUScope);
+    Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
+  }
 }
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 58fccc3..10ea514 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3037,6 +3037,8 @@
   // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
   AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, 
                                                    QualType rhsType);
+  AssignConvertType CheckPointeeTypesForAssignment(QualType lhsType, 
+                                                   QualType rhsType);
                                                    
   // Helper function for CheckAssignmentConstraints involving two
   // block pointer types.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1a8cec1..2c24dc9 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -516,8 +516,6 @@
   if (New->isInvalidDecl() || OldD->isInvalidDecl())
     return New->setInvalidDecl();
   
-  bool objc_types = false;
-  
   // Allow multiple definitions for ObjC built-in typedefs.
   // FIXME: Verify the underlying types are equivalent!
   if (getLangOptions().ObjC1) {
@@ -527,13 +525,15 @@
     case 2: 
       if (!TypeID->isStr("id"))
         break;
-      Context.setObjCIdType(Context.getTypeDeclType(New));
-      objc_types = true;
+      // Install the built-in type for 'id', ignoring the current definition.
+      New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
+      return;
       break;
     case 5:
       if (!TypeID->isStr("Class"))
         break;
-      Context.setObjCClassType(Context.getTypeDeclType(New));
+      // Install the built-in type for 'Class', ignoring the current definition.
+      New->setTypeForDecl(Context.getObjCClassType().getTypePtr());
       return;
     case 3:
       if (!TypeID->isStr("SEL"))
@@ -578,7 +578,7 @@
     return New->setInvalidDecl();
   }
   
-  if (objc_types || getLangOptions().Microsoft)
+  if (getLangOptions().Microsoft)
     return;
 
   // C++ [dcl.typedef]p2:
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2b71df7..bdf6ca1 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -117,7 +117,7 @@
 }
 
 static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
-  const PointerType *PT = T->getAsPointerType();
+  const ObjCObjectPointerType *PT = T->getAsObjCObjectPointerType();
   if (!PT)
     return false;
   
@@ -1690,7 +1690,8 @@
     return;
   }
   
-  if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) {
+  if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType()
+        || RetTy->getAsObjCObjectPointerType())) {
     S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
       << Attr.getName();
     return;    
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 62d28f3..b8a9834 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -2048,7 +2048,7 @@
         << property->getDeclName() << Ivar->getDeclName();
         // Fall thru - see previous comment
       }
-      if ((Context.isObjCObjectPointerType(property->getType()) || 
+      if ((property->getType()->isObjCObjectPointerType() || 
            PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
            getLangOptions().getGCMode() != LangOptions::NonGC) {
         Diag(PropertyLoc, diag::error_strong_property)
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 820c177..8611fd5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -925,8 +925,8 @@
       QualType T;
       
       if (getCurMethodDecl()->isInstanceMethod())
-        T = Context.getPointerType(Context.getObjCInterfaceType(
-                                   getCurMethodDecl()->getClassInterface()));
+        T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
+                                      getCurMethodDecl()->getClassInterface()));
       else
         T = Context.getObjCClassType();
       return Owned(new (Context) ObjCSuperExpr(Loc, T));
@@ -1844,6 +1844,17 @@
     BaseExpr = RHSExp;
     IndexExpr = LHSExp;
     ResultType = PTy->getPointeeType();
+  } else if (const ObjCObjectPointerType *PTy = 
+               LHSTy->getAsObjCObjectPointerType()) {
+    BaseExpr = LHSExp;
+    IndexExpr = RHSExp;
+    ResultType = PTy->getPointeeType();
+  } else if (const ObjCObjectPointerType *PTy = 
+               RHSTy->getAsObjCObjectPointerType()) {
+     // Handle the uncommon case of "123[Ptr]".
+    BaseExpr = RHSExp;
+    IndexExpr = LHSExp;
+    ResultType = PTy->getPointeeType();
   } else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
     BaseExpr = LHSExp;    // vectors: V[123]
     IndexExpr = RHSExp;
@@ -2089,6 +2100,8 @@
                                                          MemberLoc));
     else if (const PointerType *PT = BaseType->getAsPointerType())
       BaseType = PT->getPointeeType();
+    else if (BaseType->isObjCObjectPointerType())
+      ;
     else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
       return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
                                             MemberLoc, Member));
@@ -2212,12 +2225,71 @@
       << DeclarationName(&Member) << int(OpKind == tok::arrow));
   }
 
+  // Handle properties on ObjC 'Class' types.
+  if (OpKind == tok::period && (BaseType->isObjCClassType())) {
+    // Also must look for a getter name which uses property syntax.
+    Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+    if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+      ObjCInterfaceDecl *IFace = MD->getClassInterface();
+      ObjCMethodDecl *Getter;
+      // FIXME: need to also look locally in the implementation.
+      if ((Getter = IFace->lookupClassMethod(Sel))) {
+        // Check the use of this method.
+        if (DiagnoseUseOfDecl(Getter, MemberLoc))
+          return ExprError();
+      }
+      // If we found a getter then this may be a valid dot-reference, we
+      // will look for the matching setter, in case it is needed.
+      Selector SetterSel = 
+        SelectorTable::constructSetterName(PP.getIdentifierTable(), 
+                                           PP.getSelectorTable(), &Member);
+      ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
+      if (!Setter) {
+        // If this reference is in an @implementation, also check for 'private'
+        // methods.
+        Setter = FindMethodInNestedImplementations(IFace, SetterSel);
+      }
+      // Look through local category implementations associated with the class.
+      if (!Setter) {
+        for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
+          if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
+            Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
+        }
+      }
+
+      if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+        return ExprError();
+
+      if (Getter || Setter) {
+        QualType PType;
+
+        if (Getter)
+          PType = Getter->getResultType();
+        else {
+          for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
+               E = Setter->param_end(); PI != E; ++PI)
+            PType = (*PI)->getType();
+        }
+        // FIXME: we must check that the setter has property type.
+        return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
+                                        Setter, MemberLoc, BaseExpr));
+      }
+      return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+        << &Member << BaseType);
+    }
+  }
   // Handle access to Objective-C instance variables, such as "Obj->ivar" and
   // (*Obj).ivar.
-  if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) {
+  if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
+      (OpKind == tok::period && BaseType->isObjCInterfaceType())) {
+    const ObjCObjectPointerType *OPT = BaseType->getAsObjCObjectPointerType();
+    const ObjCInterfaceType *IFaceT = 
+      OPT ? OPT->getInterfaceType() : BaseType->getAsObjCInterfaceType();
+    ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
     ObjCInterfaceDecl *ClassDeclared;
-    if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member, 
-                                                             ClassDeclared)) {
+    
+    if (ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(&Member, 
+                                                         ClassDeclared)) {
       // If the decl being referenced had an error, return an error for this
       // sub-expr without emitting another error, in order to avoid cascading
       // error cases.
@@ -2249,12 +2321,12 @@
         }
         
         if (IV->getAccessControl() == ObjCIvarDecl::Private) { 
-          if (ClassDeclared != IFTy->getDecl() || 
+          if (ClassDeclared != IDecl || 
               ClassOfMethodDecl != ClassDeclared)
             Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
         }
         // @protected
-        else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl))
+        else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
           Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
       }
 
@@ -2263,18 +2335,46 @@
                                                  OpKind == tok::arrow));
     }
     return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
-                       << IFTy->getDecl()->getDeclName() << &Member
+                       << IDecl->getDeclName() << &Member
                        << BaseExpr->getSourceRange());
   }
+  // Handle properties on qualified "id" protocols.
+  const ObjCObjectPointerType *QIdTy;
+  if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
+    // Check protocols on qualified interfaces.
+    Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+    if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
+      if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
+        // Check the use of this declaration
+        if (DiagnoseUseOfDecl(PD, MemberLoc))
+          return ExprError();
+        
+        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+                                                       MemberLoc, BaseExpr));
+      }
+      if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
+        // Check the use of this method.
+        if (DiagnoseUseOfDecl(OMD, MemberLoc))
+          return ExprError();
+        
+        return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
+                                                   OMD->getResultType(), 
+                                                   OMD, OpLoc, MemberLoc, 
+                                                   NULL, 0));
+      }
+    }
 
+    return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+                       << &Member << BaseType);
+  }
   // Handle Objective-C property access, which is "Obj.property" where Obj is a
   // pointer to a (potentially qualified) interface type.
-  const PointerType *PTy;
-  const ObjCInterfaceType *IFTy;
-  if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) &&
-      (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) {
-    ObjCInterfaceDecl *IFace = IFTy->getDecl();
-
+  const ObjCObjectPointerType *OPT;
+  if (OpKind == tok::period && 
+      (OPT = BaseType->getAsObjCInterfacePointerType())) {
+    const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
+    ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+    
     // Search for a declared property first.
     if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
       // Check whether we can reference this property.
@@ -2288,10 +2388,9 @@
       return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
                                                      MemberLoc, BaseExpr));
     }
-
     // Check protocols on qualified interfaces.
-    for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
-         E = IFTy->qual_end(); I != E; ++I)
+    for (ObjCObjectPointerType::qual_iterator I = IFaceT->qual_begin(),
+         E = IFaceT->qual_end(); I != E; ++I)
       if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
         // Check whether we can reference this property.
         if (DiagnoseUseOfDecl(PD, MemberLoc))
@@ -2300,7 +2399,16 @@
         return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                        MemberLoc, BaseExpr));
       }
+    for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+         E = OPT->qual_end(); I != E; ++I)
+      if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
+        // Check whether we can reference this property.
+        if (DiagnoseUseOfDecl(PD, MemberLoc))
+          return ExprError();
 
+        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+                                                       MemberLoc, BaseExpr));
+      }
     // If that failed, look for an "implicit" property by seeing if the nullary
     // selector is implemented.
 
@@ -2365,88 +2473,6 @@
     return ExprError(Diag(MemberLoc, diag::err_property_not_found)
       << &Member << BaseType);
   }
-  // Handle properties on qualified "id" protocols.
-  const ObjCObjectPointerType *QIdTy;
-  if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
-    // Check protocols on qualified interfaces.
-    Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
-    if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
-      if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
-        // Check the use of this declaration
-        if (DiagnoseUseOfDecl(PD, MemberLoc))
-          return ExprError();
-        
-        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
-                                                       MemberLoc, BaseExpr));
-      }
-      if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
-        // Check the use of this method.
-        if (DiagnoseUseOfDecl(OMD, MemberLoc))
-          return ExprError();
-        
-        return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
-                                                   OMD->getResultType(), 
-                                                   OMD, OpLoc, MemberLoc, 
-                                                   NULL, 0));
-      }
-    }
-
-    return ExprError(Diag(MemberLoc, diag::err_property_not_found)
-                       << &Member << BaseType);
-  }
-  // Handle properties on ObjC 'Class' types.
-  if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) {
-    // Also must look for a getter name which uses property syntax.
-    Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
-    if (ObjCMethodDecl *MD = getCurMethodDecl()) {
-      ObjCInterfaceDecl *IFace = MD->getClassInterface();
-      ObjCMethodDecl *Getter;
-      // FIXME: need to also look locally in the implementation.
-      if ((Getter = IFace->lookupClassMethod(Sel))) {
-        // Check the use of this method.
-        if (DiagnoseUseOfDecl(Getter, MemberLoc))
-          return ExprError();
-      }
-      // If we found a getter then this may be a valid dot-reference, we
-      // will look for the matching setter, in case it is needed.
-      Selector SetterSel = 
-        SelectorTable::constructSetterName(PP.getIdentifierTable(), 
-                                           PP.getSelectorTable(), &Member);
-      ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
-      if (!Setter) {
-        // If this reference is in an @implementation, also check for 'private'
-        // methods.
-        Setter = FindMethodInNestedImplementations(IFace, SetterSel);
-      }
-      // Look through local category implementations associated with the class.
-      if (!Setter) {
-        for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
-          if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
-            Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
-        }
-      }
-
-      if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
-        return ExprError();
-
-      if (Getter || Setter) {
-        QualType PType;
-
-        if (Getter)
-          PType = Getter->getResultType();
-        else {
-          for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
-               E = Setter->param_end(); PI != E; ++PI)
-            PType = (*PI)->getType();
-        }
-        // FIXME: we must check that the setter has property type.
-        return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
-                                        Setter, MemberLoc, BaseExpr));
-      }
-      return ExprError(Diag(MemberLoc, diag::err_property_not_found)
-        << &Member << BaseType);
-    }
-  }
   
   // Handle 'field access' to vectors, such as 'V.xx'.
   if (BaseType->isExtVectorType()) {
@@ -3069,13 +3095,13 @@
   // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
   // the type of the other operand."
   if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
-       Context.isObjCObjectPointerType(LHSTy)) &&
+       LHSTy->isObjCObjectPointerType()) &&
       RHS->isNullPointerConstant(Context)) {
     ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
     return LHSTy;
   }
   if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
-       Context.isObjCObjectPointerType(RHSTy)) &&
+       RHSTy->isObjCObjectPointerType()) &&
       LHS->isNullPointerConstant(Context)) {
     ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
     return RHSTy;
@@ -3119,46 +3145,15 @@
     ImpCastExprToType(RHS, LHSTy);
     return LHSTy;
   }
-  // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
-  // evaluates to "struct objc_object *" (and is handled above when comparing
-  // id with statically typed objects).
-  if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) {
-    // GCC allows qualified id and any Objective-C type to devolve to
-    // id. Currently localizing to here until clear this should be
-    // part of ObjCQualifiedIdTypesAreCompatible.
-    if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) ||
-        (LHSTy->isObjCQualifiedIdType() &&
-         Context.isObjCObjectPointerType(RHSTy)) ||
-        (RHSTy->isObjCQualifiedIdType() &&
-         Context.isObjCObjectPointerType(LHSTy))) {
-      // FIXME: This is not the correct composite type. This only happens to
-      // work because id can more or less be used anywhere, however this may
-      // change the type of method sends.
-
-      // FIXME: gcc adds some type-checking of the arguments and emits
-      // (confusing) incompatible comparison warnings in some
-      // cases. Investigate.
-      QualType compositeType = Context.getObjCIdType();
-      ImpCastExprToType(LHS, compositeType);
-      ImpCastExprToType(RHS, compositeType);
-      return compositeType;
-    }
-  }
   // Check constraints for Objective-C object pointers types.
-  if (Context.isObjCObjectPointerType(LHSTy) &&
-      Context.isObjCObjectPointerType(RHSTy)) {
+  if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
     
     if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
       // Two identical object pointer types are always compatible.
       return LHSTy;
     }
-    // No need to check for block pointer types or qualified id types (they
-    // were handled above).
-    assert((LHSTy->isPointerType() && RHSTy->isPointerType()) &&
-           "Sema::CheckConditionalOperands(): Unexpected type");
-    QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
-    QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
-    
+    const ObjCObjectPointerType *LHSOPT = LHSTy->getAsObjCObjectPointerType();
+    const ObjCObjectPointerType *RHSOPT = RHSTy->getAsObjCObjectPointerType();
     QualType compositeType = LHSTy;
     
     // If both operands are interfaces and either operand can be
@@ -3174,16 +3169,19 @@
 
     // FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
     // It could return the composite type.
-    const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
-    const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
-    if (LHSIface && RHSIface &&
-        Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
+    if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
       compositeType = LHSTy;
-    } else if (LHSIface && RHSIface &&
-               Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
+    } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
       compositeType = RHSTy;
-    } else if (Context.isObjCIdStructType(lhptee) ||
-               Context.isObjCIdStructType(rhptee)) {
+    } else if ((LHSTy->isObjCQualifiedIdType() || 
+                RHSTy->isObjCQualifiedIdType()) &&
+                ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+      // Need to handle "id<xx>" explicitly. 
+      // GCC allows qualified id and any Objective-C type to devolve to
+      // id. Currently localizing to here until clear this should be
+      // part of ObjCQualifiedIdTypesAreCompatible.
+      compositeType = Context.getObjCIdType();
+    } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
       compositeType = Context.getObjCIdType();
     } else {
       Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
@@ -3312,6 +3310,11 @@
   lhptee = lhsType->getAsPointerType()->getPointeeType();
   rhptee = rhsType->getAsPointerType()->getPointeeType();
 
+  return CheckPointeeTypesForAssignment(lhptee, rhptee);
+}
+
+Sema::AssignConvertType
+Sema::CheckPointeeTypesForAssignment(QualType lhptee, QualType rhptee) {
   // make sure we operate on the canonical type
   lhptee = Context.getCanonicalType(lhptee);
   rhptee = Context.getCanonicalType(rhptee);
@@ -3443,7 +3446,7 @@
       return Compatible;
     return Incompatible;
   }
-
+  // FIXME: Look into removing. With ObjCObjectPointerType, I don't see a need.
   if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
     if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
       return Compatible;
@@ -3454,7 +3457,6 @@
       return PointerToInt;
     return IncompatibleObjCQualifiedId;
   }
-
   // Allow scalar to ExtVector assignments, and assignments of an ExtVector type
   // to the same ExtVector type.
   if (lhsType->isExtVectorType()) {
@@ -3486,13 +3488,18 @@
     if (isa<PointerType>(rhsType))
       return CheckPointerTypesForAssignment(lhsType, rhsType);
 
+    if (isa<ObjCObjectPointerType>(rhsType)) {
+      QualType rhptee = rhsType->getAsObjCObjectPointerType()->getPointeeType();
+      QualType lhptee = lhsType->getAsPointerType()->getPointeeType();
+      return CheckPointeeTypesForAssignment(lhptee, rhptee);
+    }
+
     if (rhsType->getAsBlockPointerType()) {
       if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
         return Compatible;
 
       // Treat block pointers as objects.
-      if (getLangOptions().ObjC1 &&
-          lhsType == Context.getCanonicalType(Context.getObjCIdType()))
+      if (getLangOptions().ObjC1 && lhsType->isObjCIdType())
         return Compatible;
     }
     return Incompatible;
@@ -3503,8 +3510,7 @@
       return IntToBlockPointer;
 
     // Treat block pointers as objects.
-    if (getLangOptions().ObjC1 &&
-        rhsType == Context.getCanonicalType(Context.getObjCIdType()))
+    if (getLangOptions().ObjC1 && rhsType->isObjCIdType())
       return Compatible;
 
     if (rhsType->isBlockPointerType())
@@ -3517,6 +3523,29 @@
     return Incompatible;
   }
 
+  if (isa<ObjCObjectPointerType>(lhsType)) {
+    if (rhsType->isIntegerType())
+      return IntToPointer;
+
+    if (isa<PointerType>(rhsType)) {
+      QualType lhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType();
+      QualType rhptee = rhsType->getAsPointerType()->getPointeeType();
+      return CheckPointeeTypesForAssignment(lhptee, rhptee);
+    }
+    if (rhsType->isObjCObjectPointerType()) {
+      QualType lhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType();
+      QualType rhptee = rhsType->getAsObjCObjectPointerType()->getPointeeType();
+      return CheckPointeeTypesForAssignment(lhptee, rhptee);
+    }
+    if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
+      if (RHSPT->getPointeeType()->isVoidType())
+        return Compatible;
+    }
+    // Treat block pointers as objects.
+    if (rhsType->isBlockPointerType())
+      return Compatible;
+    return Incompatible;
+  }
   if (isa<PointerType>(rhsType)) {
     // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
     if (lhsType == Context.BoolTy)
@@ -3533,6 +3562,24 @@
       return Compatible;
     return Incompatible;
   }
+  if (isa<ObjCObjectPointerType>(rhsType)) {
+    // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
+    if (lhsType == Context.BoolTy)
+      return Compatible;
+
+    if (lhsType->isIntegerType())
+      return PointerToInt;
+
+    if (isa<PointerType>(lhsType)) {
+      QualType rhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType();
+      QualType lhptee = rhsType->getAsPointerType()->getPointeeType();
+      return CheckPointeeTypesForAssignment(lhptee, rhptee);
+    }
+    if (isa<BlockPointerType>(lhsType) &&
+        rhsType->getAsPointerType()->getPointeeType()->isVoidType())
+      return Compatible;
+    return Incompatible;
+  }
 
   if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
     if (Context.typesAreCompatible(lhsType, rhsType))
@@ -3628,7 +3675,7 @@
   // C99 6.5.16.1p1: the left operand is a pointer and the right is
   // a null pointer constant.
   if ((lhsType->isPointerType() || 
-       lhsType->isObjCQualifiedIdType() || 
+       lhsType->isObjCObjectPointerType() || 
        lhsType->isBlockPointerType())
       && rExpr->isNullPointerConstant(Context)) {
     ImpCastExprToType(rExpr, lhsType);
@@ -3776,12 +3823,23 @@
 
   // Put any potential pointer into PExp
   Expr* PExp = lex, *IExp = rex;
-  if (IExp->getType()->isPointerType())
+  if (IExp->getType()->isPointerType() || 
+      IExp->getType()->isObjCObjectPointerType())
     std::swap(PExp, IExp);
 
-  if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
+  if (PExp->getType()->isPointerType() || 
+      PExp->getType()->isObjCObjectPointerType()) {
+    
     if (IExp->getType()->isIntegerType()) {
-      QualType PointeeTy = PTy->getPointeeType();
+      QualType PointeeTy;
+      const PointerType *PTy;
+      const ObjCObjectPointerType *OPT;
+      
+      if ((PTy = PExp->getType()->getAsPointerType()))
+        PointeeTy = PTy->getPointeeType();
+      else if ((OPT = PExp->getType()->getAsObjCObjectPointerType()))
+        PointeeTy = OPT->getPointeeType();
+                 
       // Check for arithmetic on pointers to incomplete types.
       if (PointeeTy->isVoidType()) {
         if (getLangOptions().CPlusPlus) {
@@ -3803,7 +3861,7 @@
         // GNU extension: arithmetic on pointer to function
         Diag(Loc, diag::ext_gnu_ptr_func_arith)
           << lex->getType() << lex->getSourceRange();
-      } else if (!PTy->isDependentType() &&
+      } else if (((PTy && !PTy->isDependentType()) || OPT) &&
                  RequireCompleteType(Loc, PointeeTy,
                                 diag::err_typecheck_arithmetic_incomplete_type,
                                      PExp->getSourceRange(), SourceRange(),
@@ -3855,10 +3913,16 @@
     if (CompLHSTy) *CompLHSTy = compType;
     return compType;
   }
-
+    
   // Either ptr - int   or   ptr - ptr.
-  if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
-    QualType lpointee = LHSPTy->getPointeeType();
+  if (lex->getType()->isPointerType() || 
+      lex->getType()->isObjCObjectPointerType()) {
+    QualType lpointee;
+    if (const PointerType *LHSPTy = lex->getType()->getAsPointerType())
+      lpointee = LHSPTy->getPointeeType();
+    else if (const ObjCObjectPointerType *OPT = 
+              lex->getType()->getAsObjCObjectPointerType())
+      lpointee = OPT->getPointeeType();
 
     // The LHS must be an completely-defined object type.
 
@@ -4156,8 +4220,7 @@
     if (!LHSIsNull && !RHSIsNull &&                       // C99 6.5.9p2
         !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
         !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
-                                    RCanPointeeTy.getUnqualifiedType()) &&
-        !Context.areComparableObjCPointerTypes(lType, rType)) {
+                                    RCanPointeeTy.getUnqualifiedType())) {
       Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
         << lType << rType << lex->getSourceRange() << rex->getSourceRange();
     }
@@ -4207,7 +4270,7 @@
     return ResultTy;
   }
 
-  if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
+  if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
     if (lType->isPointerType() || rType->isPointerType()) {
       const PointerType *LPT = lType->getAsPointerType();
       const PointerType *RPT = rType->getAsPointerType();
@@ -4226,19 +4289,27 @@
       ImpCastExprToType(rex, lType);
       return ResultTy;
     }
-    if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
+    if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
+      if (!Context.areComparableObjCPointerTypes(lType, rType)) {
+        Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
+          << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+      }
+      if (lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType()) {
+        if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
+          ImpCastExprToType(rex, lType);
+          return ResultTy;
+        } else {
+          Diag(Loc, diag::warn_incompatible_qualified_id_operands)
+            << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+          ImpCastExprToType(rex, lType);
+          return ResultTy;
+        }
+      }
       ImpCastExprToType(rex, lType);
       return ResultTy;
-    } else {
-      if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
-        Diag(Loc, diag::warn_incompatible_qualified_id_operands)
-          << lType << rType << lex->getSourceRange() << rex->getSourceRange();
-        ImpCastExprToType(rex, lType);
-        return ResultTy;
-      }
     }
   }
-  if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
+  if ((lType->isPointerType() || lType->isObjCObjectPointerType()) &&
        rType->isIntegerType()) {
     if (isRelational)
       Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
@@ -4250,7 +4321,7 @@
     return ResultTy;
   }
   if (lType->isIntegerType() &&
-      (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
+      (rType->isPointerType() || rType->isObjCObjectPointerType())) {
     if (isRelational)
       Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
         << lType << rType << lex->getSourceRange() << rex->getSourceRange();
@@ -4358,12 +4429,11 @@
     const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
     if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
       QualType BaseType = PropExpr->getBase()->getType();
-      if (const PointerType *PTy = BaseType->getAsPointerType())
-        if (const ObjCInterfaceType *IFTy =
-            PTy->getPointeeType()->getAsObjCInterfaceType())
-          if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
-            if (S.isPropertyReadonly(PDecl, IFace))
-              return true;
+      if (const ObjCObjectPointerType *OPT = 
+            BaseType->getAsObjCInterfacePointerType())
+        if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+          if (S.isPropertyReadonly(PDecl, IFace))
+            return true;
     }
   }
   return false;
@@ -4524,9 +4594,17 @@
     Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
   } else if (ResType->isRealType()) {
     // OK!
-  } else if (const PointerType *PT = ResType->getAsPointerType()) {
+  } else if (ResType->getAsPointerType() ||ResType->isObjCObjectPointerType()) {
+    QualType PointeeTy;
+    
+    if (const PointerType *PTy = ResType->getAsPointerType())
+      PointeeTy = PTy->getPointeeType();
+    else if (const ObjCObjectPointerType *OPT = 
+               ResType->getAsObjCObjectPointerType())
+      PointeeTy = OPT->getPointeeType();
+      
     // C99 6.5.2.4p2, 6.5.6p2
-    if (PT->getPointeeType()->isVoidType()) {
+    if (PointeeTy->isVoidType()) {
       if (getLangOptions().CPlusPlus) {
         Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
           << Op->getSourceRange();
@@ -4535,7 +4613,7 @@
 
       // Pointer to void is a GNU extension in C.
       Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
-    } else if (PT->getPointeeType()->isFunctionType()) {
+    } else if (PointeeTy->isFunctionType()) {
       if (getLangOptions().CPlusPlus) {
         Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
           << Op->getType() << Op->getSourceRange();
@@ -4544,7 +4622,7 @@
 
       Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
         << ResType << Op->getSourceRange();
-    } else if (RequireCompleteType(OpLoc, PT->getPointeeType(),
+    } else if (RequireCompleteType(OpLoc, PointeeTy,
                                diag::err_typecheck_arithmetic_incomplete_type,
                                    Op->getSourceRange(), SourceRange(),
                                    ResType))
@@ -4741,6 +4819,9 @@
   if (const PointerType *PT = Ty->getAsPointerType())
     return PT->getPointeeType();
 
+  if (const ObjCObjectPointerType *OPT = Ty->getAsObjCObjectPointerType())
+    return OPT->getPointeeType();
+
   Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
     << Ty << Op->getSourceRange();
   return QualType();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index b6c2d05..d522bf2 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1482,7 +1482,8 @@
 QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
   assert(getLangOptions().CPlusPlus && "This function assumes C++");
   QualType T1 = E1->getType(), T2 = E2->getType();
-  if(!T1->isPointerType() && !T2->isPointerType())
+  if(!T1->isPointerType() && !T2->isPointerType() &&
+     !T1->isObjCObjectPointerType() && !T2->isObjCObjectPointerType())
     return QualType();
 
   // C++0x 5.9p2
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 7bb6b44..cca4ce3 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -74,14 +74,14 @@
   // interface private (even though it appears in the header files).
   QualType Ty = Context.getObjCConstantStringInterface();
   if (!Ty.isNull()) {
-    Ty = Context.getPointerType(Ty);
+    Ty = Context.getObjCObjectPointerType(Ty);
   } else {
     IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
     NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName);
     if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
       Context.setObjCConstantStringInterface(StrIF);
       Ty = Context.getObjCConstantStringInterface();
-      Ty = Context.getPointerType(Ty);
+      Ty = Context.getObjCObjectPointerType(Ty);
     } else {
       // If there is no NSString interface defined then treat constant
       // strings as untyped objects and let the runtime figure it out later.
@@ -156,7 +156,7 @@
   QualType Ty = Context.getObjCProtoType();
   if (Ty.isNull())
     return true;
-  Ty = Context.getPointerType(Ty);
+  Ty = Context.getObjCObjectPointerType(Ty);
   return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
 }
 
@@ -390,7 +390,7 @@
         return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
       if (getCurMethodDecl()->isInstanceMethod()) {
         QualType superTy = Context.getObjCInterfaceType(ClassDecl);
-        superTy = Context.getPointerType(superTy);
+        superTy = Context.getObjCObjectPointerType(superTy);
         ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
                                                               superTy);
         // We are really in an instance method, redirect.
@@ -527,7 +527,7 @@
                                          rbrac, ArgExprs, NumArgs);
   }
 
-  // Handle messages to id.
+  // Handle messages to id.  
   if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
       ReceiverCType->isBlockPointerType() ||
       Context.isObjCNSObjectType(RExpr->getType())) {
@@ -602,11 +602,11 @@
       if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
         break;
     }
-  } else if (const ObjCInterfaceType *OCIType = 
-                ReceiverCType->getAsPointerToObjCInterfaceType()) {
+  } else if (const ObjCObjectPointerType *OCIType = 
+                ReceiverCType->getAsObjCInterfacePointerType()) {
     // We allow sending a message to a pointer to an interface (an object).
     
-    ClassDecl = OCIType->getDecl();
+    ClassDecl = OCIType->getInterfaceDecl();
     // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
     // faster than the following method (which can do *many* linear searches).
     // The idea is to add class info to InstanceMethodPool.
@@ -614,7 +614,7 @@
     
     if (!Method) {
       // Search protocol qualifiers.
-      for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(),
+      for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
            E = OCIType->qual_end(); QI != E; ++QI) {
         if ((Method = (*QI)->lookupInstanceMethod(Sel)))
           break;
@@ -631,9 +631,9 @@
         if (OCIType->qual_empty()) {
           Method = LookupInstanceMethodInGlobalPool(
                                Sel, SourceRange(lbrac,rbrac));
-          if (Method && !OCIType->getDecl()->isForwardDecl())
+          if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
             Diag(lbrac, diag::warn_maynot_respond) 
-              << OCIType->getDecl()->getIdentifier()->getName() << Sel;
+              << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel;
         }
       }
     }
@@ -741,60 +741,36 @@
 bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
                                              bool compare) {
   // Allow id<P..> and an 'id' or void* type in all cases.
-  if (const PointerType *PT = lhs->getAsPointerType()) {
-    QualType PointeeTy = PT->getPointeeType();
-    if (PointeeTy->isVoidType() ||
-        Context.isObjCIdStructType(PointeeTy) || 
-        Context.isObjCClassStructType(PointeeTy))
-      return true;
-  } else if (const PointerType *PT = rhs->getAsPointerType()) {
-    QualType PointeeTy = PT->getPointeeType();
-    if (PointeeTy->isVoidType() ||
-        Context.isObjCIdStructType(PointeeTy) || 
-        Context.isObjCClassStructType(PointeeTy))
-      return true;
-  }
-  
+  if (lhs->isVoidPointerType() || 
+      lhs->isObjCIdType() || lhs->isObjCClassType())
+    return true;
+  else if (rhs->isVoidPointerType() || 
+           rhs->isObjCIdType() || rhs->isObjCClassType())
+    return true;
+
   if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
-    const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
-    const ObjCQualifiedInterfaceType *rhsQI = 0;
-    QualType rtype;
+    const ObjCObjectPointerType *rhsOPT = rhs->getAsObjCObjectPointerType();
     
-    if (!rhsQID) {
-      // Not comparing two ObjCQualifiedIdType's?
-      if (!rhs->isPointerType()) return false;
-      
-      rtype = rhs->getAsPointerType()->getPointeeType();
-      rhsQI = rtype->getAsObjCQualifiedInterfaceType();
-      if (rhsQI == 0) {
-        // If the RHS is a unqualified interface pointer "NSString*", 
-        // make sure we check the class hierarchy.
-        if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
-          ObjCInterfaceDecl *rhsID = IT->getDecl();
-          for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
-               E = lhsQID->qual_end(); I != E; ++I) {
-            // when comparing an id<P> on lhs with a static type on rhs,
-            // see if static class implements all of id's protocols, directly or
-            // through its super class and categories.
-            if (!ClassImplementsProtocol(*I, rhsID, true))
-              return false;
-          }
-          return true;
+    if (!rhsOPT) return false;
+    
+    if (rhsOPT->qual_empty()) {
+      // If the RHS is a unqualified interface pointer "NSString*", 
+      // make sure we check the class hierarchy.
+      if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
+        for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
+             E = lhsQID->qual_end(); I != E; ++I) {
+          // when comparing an id<P> on lhs with a static type on rhs,
+          // see if static class implements all of id's protocols, directly or
+          // through its super class and categories.
+          if (!ClassImplementsProtocol(*I, rhsID, true))
+            return false;
         }
-      }      
+        return true;
+      }
+      // If there are no qualifiers and no interface, we have an 'id'.
+      return true;
     }
-    
-    ObjCObjectPointerType::qual_iterator RHSProtoI, RHSProtoE;
-    if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *").
-      RHSProtoI = rhsQI->qual_begin();
-      RHSProtoE = rhsQI->qual_end();
-    } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *").
-      RHSProtoI = rhsQID->qual_begin();
-      RHSProtoE = rhsQID->qual_end();
-    } else {
-      return false;
-    }
-    
+    // Both the right and left sides have qualifiers.    
     for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
          E = lhsQID->qual_end(); I != E; ++I) {
       ObjCProtocolDecl *lhsProto = *I;
@@ -803,28 +779,26 @@
       // when comparing an id<P> on lhs with a static type on rhs,
       // see if static class implements all of id's protocols, directly or
       // through its super class and categories.
-      for (; RHSProtoI != RHSProtoE; ++RHSProtoI) {
-        ObjCProtocolDecl *rhsProto = *RHSProtoI;
+      for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
+           E = rhsOPT->qual_end(); J != E; ++J) {
+        ObjCProtocolDecl *rhsProto = *J;
         if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
             (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
           match = true;
           break;
         }
       }
-      if (rhsQI) {
-        // If the RHS is a qualified interface pointer "NSString<P>*", 
-        // make sure we check the class hierarchy.
-        if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
-          ObjCInterfaceDecl *rhsID = IT->getDecl();
-          for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
-               E = lhsQID->qual_end(); I != E; ++I) {
-            // when comparing an id<P> on lhs with a static type on rhs,
-            // see if static class implements all of id's protocols, directly or
-            // through its super class and categories.
-            if (ClassImplementsProtocol(*I, rhsID, true)) {
-              match = true;
-              break;
-            }
+      // If the RHS is a qualified interface pointer "NSString<P>*", 
+      // make sure we check the class hierarchy.
+      if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
+        for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
+             E = lhsQID->qual_end(); I != E; ++I) {
+          // when comparing an id<P> on lhs with a static type on rhs,
+          // see if static class implements all of id's protocols, directly or
+          // through its super class and categories.
+          if (ClassImplementsProtocol(*I, rhsID, true)) {
+            match = true;
+            break;
           }
         }
       }
@@ -837,7 +811,52 @@
   
   const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
   assert(rhsQID && "One of the LHS/RHS should be id<x>");
-    
+
+  if (const ObjCObjectPointerType *lhsOPT = 
+        lhs->getAsObjCInterfacePointerType()) {
+    if (lhsOPT->qual_empty()) {
+      bool match = false;
+      if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
+        for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
+             E = rhsQID->qual_end(); I != E; ++I) {
+          // when comparing an id<P> on lhs with a static type on rhs,
+          // see if static class implements all of id's protocols, directly or
+          // through its super class and categories.
+          if (ClassImplementsProtocol(*I, lhsID, true)) {
+            match = true;
+            break;
+          }
+        }
+        if (!match)
+          return false;
+      }
+      return true;
+    }
+    // Both the right and left sides have qualifiers.    
+    for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
+         E = lhsOPT->qual_end(); I != E; ++I) {
+      ObjCProtocolDecl *lhsProto = *I;
+      bool match = false;
+
+      // when comparing an id<P> on lhs with a static type on rhs,
+      // see if static class implements all of id's protocols, directly or
+      // through its super class and categories.
+      for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
+           E = rhsQID->qual_end(); J != E; ++J) {
+        ObjCProtocolDecl *rhsProto = *J;
+        if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
+            (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
+          match = true;
+          break;
+        }
+      }
+      if (!match)
+        return false;
+    }
+    return true;
+  }
+  // FIXME: The code below will be removed when ObjCQualifiedInterfaceType is
+  // removed.
   if (!lhs->isPointerType())
     return false;
   
@@ -864,17 +883,6 @@
     return true;
   }
   
-  if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) {
-    // for static type vs. qualified 'id' type, check that class implements
-    // all of 'id's protocols.
-    ObjCInterfaceDecl *lhsID = IT->getDecl();
-    for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
-         E = rhsQID->qual_end(); I != E; ++I) {
-      if (!ClassImplementsProtocol(*I, lhsID, compare, true))
-        return false;
-    }
-    return true;
-  }
   return false;
 }
 
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index d10d32c..4021e54 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1005,77 +1005,64 @@
   if (!getLangOptions().ObjC1)
     return false;
 
-  // Conversions with Objective-C's id<...>.
-  if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
-      ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
-    ConvertedType = ToType;
-    return true;
-  }
+  // First, we handle all conversions on ObjC object pointer types.
+  const ObjCObjectPointerType* ToObjCPtr = ToType->getAsObjCObjectPointerType();
+  const ObjCObjectPointerType *FromObjCPtr = 
+    FromType->getAsObjCObjectPointerType();
 
-  // Beyond this point, both types need to be pointers or block pointers.
+  if (ToObjCPtr && FromObjCPtr) {
+    // Objective C++: We're able to convert between "id" and a pointer
+    // to any interface (in both directions).
+    if (ToObjCPtr->isObjCIdType() && FromObjCPtr->isObjCIdType()) {
+      ConvertedType = ToType;
+      return true;
+    }
+    // Objective C++: Allow conversions between the Objective-C "Class" and a
+    // pointer to any interface (in both directions).
+    if (ToObjCPtr->isObjCClassType() || FromObjCPtr->isObjCClassType()) {
+      ConvertedType = ToType;
+      return true;
+    }
+    // Conversions with Objective-C's id<...>.
+    if ((FromObjCPtr->isObjCQualifiedIdType() || 
+         ToObjCPtr->isObjCQualifiedIdType()) &&
+        ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
+      ConvertedType = ToType;
+      return true;
+    }
+    // Objective C++: We're able to convert from a pointer to an
+    // interface to a pointer to a different interface.
+    if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
+      ConvertedType = ToType;
+      return true;
+    }
+
+    if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) {
+      // Okay: this is some kind of implicit downcast of Objective-C
+      // interfaces, which is permitted. However, we're going to
+      // complain about it.
+      IncompatibleObjC = true;
+      ConvertedType = FromType;
+      return true;
+    }
+  } 
+  // Beyond this point, both types need to be C pointers or block pointers.
   QualType ToPointeeType;
-  const PointerType* ToTypePtr = ToType->getAsPointerType();
-  if (ToTypePtr)
-    ToPointeeType = ToTypePtr->getPointeeType();
+  if (const PointerType *ToCPtr = ToType->getAsPointerType())
+    ToPointeeType = ToCPtr->getPointeeType();
   else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType())
     ToPointeeType = ToBlockPtr->getPointeeType();
   else
     return false;
 
   QualType FromPointeeType;
-  const PointerType *FromTypePtr = FromType->getAsPointerType();
-  if (FromTypePtr)
-    FromPointeeType = FromTypePtr->getPointeeType();
-  else if (const BlockPointerType *FromBlockPtr 
-             = FromType->getAsBlockPointerType())
+  if (const PointerType *FromCPtr = FromType->getAsPointerType())
+    FromPointeeType = FromCPtr->getPointeeType();
+  else if (const BlockPointerType *FromBlockPtr = FromType->getAsBlockPointerType())
     FromPointeeType = FromBlockPtr->getPointeeType();
   else
     return false;
 
-  // Objective C++: We're able to convert from a pointer to an
-  // interface to a pointer to a different interface.
-  const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
-  const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType();
-  if (FromIface && ToIface && 
-      Context.canAssignObjCInterfaces(ToIface, FromIface)) {
-    ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
-                                                       ToPointeeType,
-                                                       ToType, Context);
-    return true;
-  }
-
-  if (FromIface && ToIface && 
-      Context.canAssignObjCInterfaces(FromIface, ToIface)) {
-    // Okay: this is some kind of implicit downcast of Objective-C
-    // interfaces, which is permitted. However, we're going to
-    // complain about it.
-    IncompatibleObjC = true;
-    ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
-                                                       ToPointeeType,
-                                                       ToType, Context);
-    return true;
-  }
-
-  // Objective C++: We're able to convert between "id" and a pointer
-  // to any interface (in both directions).
-  if ((FromIface && Context.isObjCIdStructType(ToPointeeType))
-      || (ToIface && Context.isObjCIdStructType(FromPointeeType))) {
-    ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, 
-                                                       ToPointeeType,
-                                                       ToType, Context);
-    return true;
-  } 
-
-  // Objective C++: Allow conversions between the Objective-C "id" and
-  // "Class", in either direction.
-  if ((Context.isObjCIdStructType(FromPointeeType) && 
-       Context.isObjCClassStructType(ToPointeeType)) ||
-      (Context.isObjCClassStructType(FromPointeeType) &&
-       Context.isObjCIdStructType(ToPointeeType))) {
-    ConvertedType = ToType;
-    return true;
-  }
-
   // If we have pointers to pointers, recursively check whether this
   // is an Objective-C conversion.
   if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
@@ -1086,7 +1073,6 @@
     ConvertedType = ToType;
     return true;
   }
-
   // If we have pointers to functions or blocks, check whether the only
   // differences in the argument and result types are in Objective-C
   // pointer conversions. If so, we permit the conversion (but
@@ -1167,15 +1153,6 @@
       QualType FromPointeeType = FromPtrType->getPointeeType(),
                ToPointeeType   = ToPtrType->getPointeeType();
 
-      // Objective-C++ conversions are always okay.
-      // FIXME: We should have a different class of conversions for the
-      // Objective-C++ implicit conversions.
-      if (Context.isObjCIdStructType(FromPointeeType) || 
-          Context.isObjCIdStructType(ToPointeeType) ||
-          Context.isObjCClassStructType(FromPointeeType) ||
-          Context.isObjCClassStructType(ToPointeeType))
-        return false;
-
       if (FromPointeeType->isRecordType() &&
           ToPointeeType->isRecordType()) {
         // We must have a derived-to-base conversion. Check an
@@ -1185,7 +1162,18 @@
                                             From->getSourceRange());
       }
     }
+  if (const ObjCObjectPointerType *FromPtrType = 
+        FromType->getAsObjCObjectPointerType())
+    if (const ObjCObjectPointerType *ToPtrType = 
+          ToType->getAsObjCObjectPointerType()) {
+      // Objective-C++ conversions are always okay.
+      // FIXME: We should have a different class of conversions for the
+      // Objective-C++ implicit conversions.
+      if (FromPtrType->isObjCIdType() || ToPtrType->isObjCIdType() ||
+          FromPtrType->isObjCClassType() || ToPtrType->isObjCClassType())
+        return false;
 
+  }
   return false;
 }
 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 8dcf4e4..7551d93 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -91,7 +91,8 @@
   case DeclSpec::TST_unspecified:
     // "<proto1,proto2>" is an objc qualified ID with a missing id.
     if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
-      Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
+      Result = Context.getObjCObjectPointerType(QualType(), 
+                                                (ObjCProtocolDecl**)PQ,
                                                 DS.getNumProtocolQualifiers());
       break;
     }
@@ -197,14 +198,16 @@
       // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have
       // this "hack" for now...
       if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType())
+        // FIXME: Remove ObjCQualifiedInterfaceType (by moving the list of
+        // protocols 'up' to ObjCInterfaceType).
         Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(),
                                                        (ObjCProtocolDecl**)PQ,
                                                DS.getNumProtocolQualifiers());
-      else if (Result == Context.getObjCIdType())
+      else if (Result->isObjCIdType())
         // id<protocol-list>
-        Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
-                                                 DS.getNumProtocolQualifiers());
-      else if (Result == Context.getObjCClassType()) {
+        Result = Context.getObjCObjectPointerType(QualType(), 
+                        (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
+      else if (Result->isObjCClassType()) {
         if (DeclLoc.isInvalid())
           DeclLoc = DS.getSourceRange().getBegin();
         // Class<protocol-list>
@@ -886,6 +889,13 @@
         D.setInvalidType(true);
         // Build the type anyway.
       }
+      if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
+        const ObjCInterfaceType *OIT = T->getAsObjCInterfaceType();
+        T = Context.getObjCObjectPointerType(T,
+                                       (ObjCProtocolDecl **)OIT->qual_begin(),
+                                       OIT->getNumProtocols());
+        break;
+      }
       T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
       break;
     case DeclaratorChunk::Reference: