]> granicus.if.org Git - clang/commitdiff
This patch concludes implementation of dynamic objective-c type qualified by
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 19 Dec 2007 17:45:58 +0000 (17:45 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 19 Dec 2007 17:45:58 +0000 (17:45 +0000)
protocol list.

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

AST/ASTContext.cpp
Sema/SemaExpr.cpp
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
test/Sema/protocol-id-test-3.m [new file with mode: 0644]

index 4382574c4c82717b798e768b27e27a3303e1baba..06d6888e19e3e8355df6b8689287c54ec724eb5d 100644 (file)
@@ -1265,12 +1265,100 @@ bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs,
   return true;
 }
 
-// TODO: id<P1,...> vs. id<P,...>
-#if 0
-bool ASTContext::QualifiedIdTypesAreCompatible(QualType lhs, 
-                                                      QualType rhs) {
+/// ObjcQualifiedIdTypesAreCompatible - Compares two types, at least
+/// one of which is a protocol qualified 'id' type.
+bool ASTContext::ObjcQualifiedIdTypesAreCompatible(QualType lhs, 
+                                                   QualType rhs) {
+  // match id<P..> with an 'id' type in all cases.
+  if (const PointerType *PT = lhs->getAsPointerType()) {
+    QualType PointeeTy = PT->getPointeeType();
+    if (isObjcIdType(PointeeTy))
+      return true;
+        
+  }
+  else if (const PointerType *PT = rhs->getAsPointerType()) {
+    QualType PointeeTy = PT->getPointeeType();
+    if (isObjcIdType(PointeeTy))
+      return true;
+    
+  }
+  
+  ObjcQualifiedInterfaceType *lhsQI = 0;
+  ObjcQualifiedInterfaceType *rhsQI = 0;
+  ObjcQualifiedIdType *lhsQID = dyn_cast<ObjcQualifiedIdType>(lhs);
+  ObjcQualifiedIdType *rhsQID = dyn_cast<ObjcQualifiedIdType>(rhs);
+  
+  if (lhsQID) {
+    if (!rhsQID && rhs->getTypeClass() == Type::Pointer) {
+      QualType rtype = 
+        cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+      rhsQI = 
+        dyn_cast<ObjcQualifiedInterfaceType>(
+          rtype.getCanonicalType().getTypePtr());
+    }
+    if (!rhsQI && !rhsQID)
+      return false;
+    
+    for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) {
+      bool match = false;
+      ObjcProtocolDecl *lhsProto = lhsQID->getProtocols(i);
+      unsigned numRhsProtocols;
+      ObjcProtocolDecl **rhsProtoList;
+      if (rhsQI) {
+        numRhsProtocols = rhsQI->getNumProtocols();
+        rhsProtoList = rhsQI->getReferencedProtocols();
+      }
+      else {
+        numRhsProtocols = rhsQID->getNumProtocols();
+        rhsProtoList = rhsQID->getReferencedProtocols();
+      }
+      for (unsigned j = 0; j < numRhsProtocols; j++) {
+        ObjcProtocolDecl *rhsProto = rhsProtoList[j];
+        if (lhsProto == rhsProto) {
+          match = true;
+          break;
+        }
+      }
+      if (!match)
+        return false;
+    }    
+  }
+  else if (rhsQID) {
+    if (!lhsQID && lhs->getTypeClass() == Type::Pointer) {
+      QualType ltype = 
+      cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+      lhsQI = 
+      dyn_cast<ObjcQualifiedInterfaceType>(
+        ltype.getCanonicalType().getTypePtr());
+    }
+    if (!lhsQI && !lhsQID)
+      return false;
+    unsigned numLhsProtocols;
+    ObjcProtocolDecl **lhsProtoList;
+    if (lhsQI) {
+      numLhsProtocols = lhsQI->getNumProtocols();
+      lhsProtoList = lhsQI->getReferencedProtocols();
+    }
+    else {
+      numLhsProtocols = lhsQID->getNumProtocols();
+      lhsProtoList = lhsQID->getReferencedProtocols();
+    }
+    for (unsigned i =0; i < numLhsProtocols; i++) {
+      bool match = false;
+      ObjcProtocolDecl *lhsProto = lhsProtoList[i];
+      for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
+        ObjcProtocolDecl *rhsProto = rhsQID->getProtocols(j);
+        if (lhsProto == rhsProto) {
+          match = true;
+          break;
+        }
+      }
+      if (!match)
+        return false;
+    }    
+  }
+  return true;
 }
-#endif
 
 bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) {
   const VectorType *lVector = lhs->getAsVectorType();
index 8eedd37fe50151997ab90a8281f5119a8d02fe19..bf5d71fd080314ca40d6a7ad8e61698e1c46bcbf 100644 (file)
@@ -1103,6 +1103,8 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
 ///
 Sema::AssignmentCheckResult
 Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
+
+  
   if (lhsType.getCanonicalType().getUnqualifiedType() == 
       rhsType.getCanonicalType().getUnqualifiedType())
     return Compatible; // common case, fast path...
@@ -1110,7 +1112,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
   if (lhsType->isReferenceType() || rhsType->isReferenceType()) {
     if (Context.referenceTypesAreCompatible(lhsType, rhsType))
       return Compatible;
-  } else if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) {
+  }
+  else if (lhsType->isObjcQualifiedIdType() 
+           || rhsType->isObjcQualifiedIdType()) {
+    if (Context.ObjcQualifiedIdTypesAreCompatible(lhsType, rhsType))
+      return Compatible;
+  }
+  else if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) {
     if (lhsType->isVectorType() || rhsType->isVectorType()) {
       if (!getLangOptions().LaxVectorConversions) {
         if (lhsType.getCanonicalType() != rhsType.getCanonicalType())
index 15f2ba9ac7ae8168d37ca8e49d9dcf6820ef73c0..80188e25cf54c04f72e1eab189f373346e5c6668 100644 (file)
@@ -297,6 +297,7 @@ public:
   /// Objective-C specific type checking.
   bool interfaceTypesAreCompatible(QualType, QualType);
   bool QualifiedInterfaceTypesAreCompatible(QualType, QualType);
+  bool ObjcQualifiedIdTypesAreCompatible(QualType, QualType);
   bool objcTypesAreCompatible(QualType, QualType);
   bool isObjcIdType(QualType T) const {
     if (!IdStructType) // ObjC isn't enabled
index ee21d885d4501a07197c56b22947dd278b1a3574..7c9391080630998defa8a77a6964d2a64b8f4676 100644 (file)
@@ -943,7 +943,9 @@ public:
   unsigned getNumProtocols() const {
     return Protocols.size();
   }
-    
+  ObjcProtocolDecl **getReferencedProtocols() {
+    return &Protocols[0];
+  }  
   virtual void getAsStringInternal(std::string &InnerString) const;
   
   void Profile(llvm::FoldingSetNodeID &ID);
@@ -975,6 +977,9 @@ public:
   unsigned getNumProtocols() const {
     return Protocols.size();
   }
+  ObjcProtocolDecl **getReferencedProtocols() {
+    return &Protocols[0];
+  } 
     
   virtual void getAsStringInternal(std::string &InnerString) const;
     
@@ -1024,7 +1029,8 @@ inline bool Type::isFunctionType() const {
   return isa<FunctionType>(CanonicalType);
 }
 inline bool Type::isPointerType() const {
-  return isa<PointerType>(CanonicalType);
+  return isa<PointerType>(CanonicalType) || 
+        isa<ObjcQualifiedIdType>(CanonicalType);
 }
 inline bool Type::isFunctionPointerType() const {
   if (const PointerType* T = getAsPointerType())
diff --git a/test/Sema/protocol-id-test-3.m b/test/Sema/protocol-id-test-3.m
new file mode 100644 (file)
index 0000000..058be26
--- /dev/null
@@ -0,0 +1,94 @@
+// RUN: clang -pedantic -fsyntax-only -verify %s
+
+@protocol MyProto1 
+@end
+
+@protocol MyProto2 
+@end
+
+@interface INTF @end
+
+id<MyProto1> Func(INTF <MyProto1, MyProto2> *p2)
+{
+       return p2;
+}
+
+
+
+
+ id<MyProto1> Gunc(id <MyProto1, MyProto2>p2)
+{
+       return p2;
+}
+
+
+ id<MyProto1> Gunc1(id <MyProto1, MyProto2>p2)
+{
+       return p2;
+}
+
+id<MyProto1, MyProto2> Gunc2(id <MyProto1>p2)
+{
+       Func(p2);       // expected-error {{incompatible types passing 'id<MyProto1>' to function expecting 'INTF<MyProto1,MyProto2> *'}}
+       return p2;      // expected-error {{incompatible type returning 'id<MyProto1>', expected 'id<MyProto1,MyProto2>'}}
+}
+
+
+
+id<MyProto1> Gunc3(id <MyProto2>p2)
+{
+       return p2;       // expected-error {{incompatible type returning 'id<MyProto2>', expected 'id<MyProto1>'}}
+}
+
+
+id<MyProto1, MyProto2> Gunc4(id <MyProto2, MyProto1>p2)
+{
+       return p2;
+}
+
+
+
+INTF<MyProto1> * Hunc(id <MyProto1, MyProto2>p2)
+{
+       return p2;
+}
+
+
+INTF<MyProto1> * Hunc1(id <MyProto1, MyProto2>p2)
+{
+       return p2;
+}
+
+INTF<MyProto1, MyProto2> * Hunc2(id <MyProto1>p2)
+{
+       Func(p2);       // expected-error {{incompatible types passing 'id<MyProto1>' to function expecting 'INTF<MyProto1,MyProto2> *'}}
+       return p2;      // expected-error {{incompatible type returning 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
+}
+
+INTF<MyProto1> * Hunc3(id <MyProto2>p2)
+{
+       return p2;       // expected-error {{incompatible type returning 'id<MyProto2>', expected 'INTF<MyProto1> *'}}
+}
+
+
+INTF<MyProto1, MyProto2> * Hunc4(id <MyProto2, MyProto1>p2)
+{
+       return p2;
+}
+
+id Iunc(id <MyProto1, MyProto2>p2)
+{
+       return p2;
+}
+
+
+id<MyProto1> Iunc1(id p2)
+{
+       return p2;
+}
+
+id<MyProto1, MyProto2> Iunc2(id p2)
+{
+       Iunc(p2);       
+       return p2;
+}