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

'NSCopying' protocol when diagnosing block to ObjC pointer conversion.
// rdar://16739120

llvm-svn: 210491
This commit is contained in:
Fariborz Jahanian 2014-06-09 21:42:01 +00:00
parent 28f3ca66a9
commit 7ea91b2892
2 changed files with 54 additions and 2 deletions

View 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;

View 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
}