]> granicus.if.org Git - clang/commitdiff
merge compatibility testing of qualified/unqualified interfaces together
authorChris Lattner <sabre@nondot.org>
Mon, 7 Apr 2008 06:38:24 +0000 (06:38 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 7 Apr 2008 06:38:24 +0000 (06:38 +0000)
and fix a bug.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49322 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ASTContext.cpp
test/Sema/objc-comptypes-5.m

index c071e5ebd62a2fad67aa56f3ef95b37f5327e8f7..f6330f67ab5f1ce0a6c6375e78bdce0355a1dc5e 100644 (file)
@@ -839,7 +839,7 @@ QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
   SortAndUniqueProtocols(Protocols, NumProtocols);
   
   llvm::FoldingSetNodeID ID;
-  ObjCQualifiedInterfaceType::Profile(ID, Protocols, NumProtocols);
+  ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
   
   void *InsertPos = 0;
   if (ObjCQualifiedInterfaceType *QT =
@@ -1435,40 +1435,40 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
   ObjCConstantStringType = getObjCInterfaceType(Decl);
 }
 
-/// areCompatObjCInterfaces - This routine is called when we are testing
-/// compatibility of two different [potentially qualified] ObjCInterfaceType's.
-static bool areCompatObjCInterfaces(const ObjCInterfaceType *LHS,
-                                    const ObjCInterfaceType *RHS) {
-  // II is compatible with II<P> if the base is the same.  Otherwise, no two
-  // qualified interface types are the same.
-  if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
-    return false;
-  
-  // If the base decls match and one is a qualified interface and one isn't,
-  // then they are compatible.
-  return isa<ObjCQualifiedInterfaceType>(LHS) != 
-         isa<ObjCQualifiedInterfaceType>(RHS);
-}
 
-/// areCompatObjCQualInterfaces - Return true if the two qualified interface
-/// types are compatible for assignment from RHS to LHS.
+/// areCompatObjCInterfaces - Return true if the two interface types are
+/// compatible for assignment from RHS to LHS.  This handles validation of any
+/// protocol qualifiers on the LHS or RHS.
 ///
 static bool 
-areCompatObjCQualInterfaces(const ObjCQualifiedInterfaceType *LHS, 
-                            const ObjCQualifiedInterfaceType *RHS) {
+areCompatObjCInterfaces(const ObjCInterfaceType *LHS, 
+                        const ObjCInterfaceType *RHS) {
   // Verify that the base decls are compatible: the RHS must be a subclass of
   // the LHS.
   if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
     return false;
+
+  // RHS must have a superset of the protocols in the LHS.  If the LHS is not
+  // protocol qualified at all, then we are good.
+  if (!isa<ObjCQualifiedInterfaceType>(LHS))
+    return true;
+  
+  // Okay, we know the LHS has protocol qualifiers.  If the RHS doesn't, then it
+  // isn't a superset.
+  if (!isa<ObjCQualifiedInterfaceType>(RHS))
+    return true;  // FIXME: should return false!
+
+  // Finally, we must have two protocol-qualified interfaces.
+  const ObjCQualifiedInterfaceType *LHSP =cast<ObjCQualifiedInterfaceType>(LHS);
+  const ObjCQualifiedInterfaceType *RHSP =cast<ObjCQualifiedInterfaceType>(RHS);
+  ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin();
+  ObjCQualifiedInterfaceType::qual_iterator LHSPE = LHSP->qual_end();
+  ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin();
+  ObjCQualifiedInterfaceType::qual_iterator RHSPE = RHSP->qual_end();
   
   // All protocols in LHS must have a presence in RHS.  Since the protocol lists
   // are both sorted alphabetically and have no duplicates, we can scan RHS and
   // LHS in a single parallel scan until we run out of elements in LHS.
-  ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHS->qual_begin();
-  ObjCQualifiedInterfaceType::qual_iterator LHSPE = LHS->qual_end();
-  ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHS->qual_begin();
-  ObjCQualifiedInterfaceType::qual_iterator RHSPE = RHS->qual_end();
-  
   assert(LHSPI != LHSPE && "Empty LHS protocol list?");
   ObjCProtocolDecl *LHSProto = *LHSPI;
   
@@ -1653,19 +1653,17 @@ bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) {
   if (LHSClass == Type::OCUVector) LHSClass = Type::Vector;
   if (RHSClass == Type::OCUVector) RHSClass = Type::Vector;
   
+  // Consider qualified interfaces and interfaces the same.
+  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) {
-    // For Objective-C, it is possible for two types to be compatible
-    // when their classes don't match (when dealing with "id"). If either type
-    // is an interface, we defer to areCompatObjCIDType(). 
-    if (const ObjCInterfaceType *LHSIT = LHS->getAsObjCInterfaceType()) {
-      if (const ObjCInterfaceType *RHSIT = RHS->getAsObjCInterfaceType())
-        return areCompatObjCInterfaces(LHSIT, RHSIT);
-      return isObjCIdType(RHS);    // ID is compatible with all interface types.
-    }
-    
-    if (RHS->isObjCInterfaceType())
-      return isObjCIdType(LHS);    // ID is compatible with all interface types.
+    // ID is compatible with all interface types.
+    if (isa<ObjCInterfaceType>(LHS))
+      return isObjCIdType(RHS);
+    if (isa<ObjCInterfaceType>(RHS))
+      return isObjCIdType(LHS);
     
     // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
     // a signed integer type, or an unsigned integer type. 
@@ -1688,6 +1686,7 @@ bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) {
   case Type::VariableArray:
   case Type::IncompleteArray:
   case Type::Reference:
+  case Type::ObjCQualifiedInterface:
     assert(0 && "Canonicalized away above");
   case Type::Pointer:
     return pointerTypesAreCompatible(LHS, RHS);
@@ -1703,12 +1702,8 @@ bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) {
   case Type::Vector:
     return areCompatVectorTypes(cast<VectorType>(LHS), cast<VectorType>(RHS));
   case Type::ObjCInterface:
-    // The LHS must be a superclass of the RHS.
-    return cast<ObjCInterfaceType>(LHS)->getDecl()->isSuperClassOf(
-                                   cast<ObjCInterfaceType>(RHS)->getDecl());
-  case Type::ObjCQualifiedInterface:
-    return areCompatObjCQualInterfaces(cast<ObjCQualifiedInterfaceType>(LHS),
-                                       cast<ObjCQualifiedInterfaceType>(RHS));
+    return areCompatObjCInterfaces(cast<ObjCInterfaceType>(LHS),
+                                   cast<ObjCInterfaceType>(RHS));
   default:
     assert(0 && "unexpected type");
   }
index 7101e9604384d7a6b453bce4e04b3a29821c0030..f12fa9ab5d4411a07c8c4e6ec22f02a2224b480b 100644 (file)
@@ -24,6 +24,7 @@ int main()
   MyClass *obj_c_cat_p = nil;
   MyOtherClass *obj_c_super_p = nil;
   MyOtherClass<MyProtocol> *obj_c_super_p_q = nil;
+  MyClass<MyProtocol> *obj_c_cat_p_q = nil;
 
   obj_c_cat_p = obj_id_p;   // expected-error {{incompatible type assigning 'id<MyProtocol>', expected 'MyClass *'}}
   obj_c_super_p = obj_id_p;  // expected-error {{incompatible type assigning 'id<MyProtocol>', expected 'MyOtherClass *'}}
@@ -37,6 +38,7 @@ int main()
 
   obj_c_cat_p = obj_c_super_p; // ok.
   obj_c_cat_p = obj_c_super_p_q; // ok.
-  
+  obj_c_super_p = obj_c_cat_p_q; // expected-warning {{incompatible pointer types}}
+  obj_c_cat_p_q = obj_c_super_p;
   return 0;
 }