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,
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;
}
@protocol NSObject;
+@class NSObject;
void r2 (id<NSObject> (^f) (void)) {
id o = f();
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
+}