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/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;
 }