]> granicus.if.org Git - clang/commitdiff
Objective-C. Consider block pointer as NSObject as well as conforming to
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 9 Jun 2014 21:42:01 +0000 (21:42 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 9 Jun 2014 21:42:01 +0000 (21:42 +0000)
'NSCopying' protocol when diagnosing block to ObjC pointer conversion.
// rdar://16739120

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

lib/Sema/SemaExpr.cpp
test/SemaObjC/block-type-safety.m

index d767b3c8e79e134758577f36564cb151349acb0d..1e56410bd4705795474c2ced9e0a45fb96bff052 100644 (file)
@@ -5478,6 +5478,36 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
   return ResultTy;
 }
 
+/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or
+/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally
+/// implements 'NSObject' and/or NSCopying' protocols (and nothing else).
+static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) {
+  if (QT->isObjCIdType())
+    return true;
+  
+  const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>();
+  if (!OPT)
+    return false;
+
+  if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl())
+    if (ID->getIdentifier() != &C.Idents.get("NSObject"))
+      return false;
+  
+  ObjCProtocolDecl* PNSCopying =
+    S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation());
+  ObjCProtocolDecl* PNSObject =
+    S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation());
+
+  for (auto *Proto : OPT->quals()) {
+    if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) ||
+        (PNSObject && declaresSameEntity(Proto, PNSObject)))
+      ;
+    else
+      return false;
+  }
+  return true;
+}
+
 /// \brief Return the resulting type when the operands are both block pointers.
 static QualType checkConditionalBlockPointerCompatibility(Sema &S,
                                                           ExprResult &LHS,
@@ -6435,8 +6465,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
       return IncompatiblePointer;
     }
 
-    // T^ -> id; not T^ ->A* and not T^ -> id<P>
-    if (RHSType->isBlockPointerType() && LHSType->isObjCIdType()) {
+    // Only under strict condition T^ is compatible with an Objective-C pointer.
+    if (RHSType->isBlockPointerType() &&
+        isObjCPtrBlockCompatible(*this, Context, LHSType)) {
       maybeExtendBlockObject(*this, RHS);
       Kind = CK_BlockPointerToObjCPointerCast;
       return Compatible;
index 45866704b56d173714d8d968a75c71495c618ed0..b2c4398dc3c51133552c5b800a4dc34c706bc5b2 100644 (file)
@@ -23,6 +23,7 @@ void r1(Sub* (^f)()) { // expected-note{{passing argument to parameter 'f' here}
 }
 
 @protocol NSObject;
+@class NSObject;
 
 void r2 (id<NSObject> (^f) (void)) {
   id o = f();
@@ -177,3 +178,23 @@ NSArray* anArray1;
 aBlock = anArray1; // expected-error {{assigning to 'void (^)()' from incompatible type 'NSArray *'}}
 }
 
+void Test2() {
+  void (^aBlock)();
+  id<NSObject> anQualId1 = aBlock; // Ok
+  id<NSObject, NSCopying> anQualId2 = aBlock; // Ok
+  id<NSObject, NSCopying, NSObject, NSCopying> anQualId3 = aBlock; // Ok
+  id <P1>  anQualId4  = aBlock; // expected-error {{initializing 'id<P1>' with an expression of incompatible type 'void (^)()'}}
+  id<NSObject, P1, NSCopying> anQualId5 = aBlock; // expected-error {{initializing 'id<NSObject,P1,NSCopying>' with an expression of incompatible type 'void (^)()'}}
+  id<NSCopying> anQualId6 = aBlock; // Ok
+}
+
+void Test3() {
+  void (^aBlock)();
+  NSObject *NSO = aBlock; // Ok
+  NSObject<NSObject> *NSO1 = aBlock; // Ok
+  NSObject<NSObject, NSCopying> *NSO2 = aBlock; // Ok
+  NSObject<NSObject, NSCopying, NSObject, NSCopying> *NSO3 = aBlock; // Ok
+  NSObject <P1>  *NSO4  = aBlock; // expected-error {{initializing 'NSObject<P1> *' with an expression of incompatible type 'void (^)()'}}
+  NSObject<NSObject, P1, NSCopying> *NSO5 = aBlock; // expected-error {{initializing 'NSObject<NSObject,P1,NSCopying> *' with an expression of incompatible type 'void (^)()'}}
+  NSObject<NSCopying> *NSO6 = aBlock; // Ok
+}