diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2014-06-09 21:42:01 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2014-06-09 21:42:01 +0000 |
commit | 7ea91b2892c6ce88c8df6be46e198ff271a03705 (patch) | |
tree | bdbada9087572f98ca019ab7e7ebe124be79e557 | |
parent | 28f3ca66a932354b6edc2fc5c9df1871d7b5e8d6 (diff) | |
download | bcm5719-llvm-7ea91b2892c6ce88c8df6be46e198ff271a03705.tar.gz bcm5719-llvm-7ea91b2892c6ce88c8df6be46e198ff271a03705.zip |
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
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 35 | ||||
-rw-r--r-- | clang/test/SemaObjC/block-type-safety.m | 21 |
2 files changed, 54 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d767b3c8e79..1e56410bd47 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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; diff --git a/clang/test/SemaObjC/block-type-safety.m b/clang/test/SemaObjC/block-type-safety.m index 45866704b56..b2c4398dc3c 100644 --- a/clang/test/SemaObjC/block-type-safety.m +++ b/clang/test/SemaObjC/block-type-safety.m @@ -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 +} |