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/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: