r210491 - Objective-C. Consider block pointer as NSObject as well as conforming to

Fariborz Jahanian fjahanian at apple.com
Mon Jun 9 14:42:02 PDT 2014


Author: fjahanian
Date: Mon Jun  9 16:42:01 2014
New Revision: 210491

URL: http://llvm.org/viewvc/llvm-project?rev=210491&view=rev
Log:
Objective-C. Consider block pointer as NSObject as well as conforming to
'NSCopying' protocol when diagnosing block to ObjC pointer conversion.
// rdar://16739120

Modified:
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaObjC/block-type-safety.m

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=210491&r1=210490&r2=210491&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jun  9 16:42:01 2014
@@ -5478,6 +5478,36 @@ static QualType checkConditionalPointerC
   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(QualTyp
       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;

Modified: cfe/trunk/test/SemaObjC/block-type-safety.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/block-type-safety.m?rev=210491&r1=210490&r2=210491&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/block-type-safety.m (original)
+++ cfe/trunk/test/SemaObjC/block-type-safety.m Mon Jun  9 16:42:01 2014
@@ -23,6 +23,7 @@ void r1(Sub* (^f)()) { // expected-note{
 }
 
 @protocol NSObject;
+ at 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
+}





More information about the cfe-commits mailing list