[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
rjmccall closed this revision. rjmccall added a comment. Committed as r329508. Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT added a comment. Thank you for the review! I don't have the means to check this in myself. Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
rjmccall accepted this revision. rjmccall added a comment. This revision is now accepted and ready to land. Okay, LGTM with the reduced set of changes to the functionality. Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT updated this revision to Diff 138996. DHowett-MSFT added a comment. Ran `clang-format` over changed lines. Reuploaded diff with full context. Repository: rC Clang https://reviews.llvm.org/D44580 Files: lib/Sema/SemaExpr.cpp test/SemaObjC/block-compare.mm Index: test/SemaObjC/block-compare.mm === --- /dev/null +++ test/SemaObjC/block-compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -10028,6 +10028,19 @@ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return ResultTy; } + +if (!IsRelational && LHSType->isBlockPointerType() && +RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, + CK_BlockPointerToObjCPointerCast); + return ResultTy; +} else if (!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, + CK_BlockPointerToObjCPointerCast); + return ResultTy; +} } if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { Index: test/SemaObjC/block-compare.mm === --- /dev/null +++ test/SemaObjC/block-compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -10028,6 +10028,19 @@ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return ResultTy; } + +if (!IsRelational && LHSType->isBlockPointerType() && +RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, + CK_BlockPointerToObjCPointerCast); + return ResultTy; +} else if (!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, + CK_B
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT updated this revision to Diff 138868. DHowett-MSFT marked an inline comment as done. DHowett-MSFT added a comment. Backed out changes to block type assignment. Repository: rC Clang https://reviews.llvm.org/D44580 Files: lib/Sema/SemaExpr.cpp test/SemaObjC/block-compare.mm Index: test/SemaObjC/block-compare.mm === --- /dev/null +++ test/SemaObjC/block-compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -10028,6 +10028,18 @@ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return ResultTy; } + +if(!IsRelational && + LHSType->isBlockPointerType() && + RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} else if(!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} } if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { Index: test/SemaObjC/block-compare.mm === --- /dev/null +++ test/SemaObjC/block-compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -10028,6 +10028,18 @@ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return ResultTy; } + +if(!IsRelational && + LHSType->isBlockPointerType() && + RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} else if(!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} } if ((LHSType->isAnyPointerTy
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT planned changes to this revision. DHowett-MSFT marked an inline comment as done. DHowett-MSFT added inline comments. Comment at: lib/Sema/SemaExpr.cpp:7749 +// id (or strictly compatible object type) -> T^ +if (getLangOpts().ObjC1 && RHSType->isBlockCompatibleObjCPointerType(Context)) { Kind = CK_AnyPointerToBlockPointerCast; theraven wrote: > Do we want to allow implicit casts for all object types to block types for > assignment, or only for null pointers? We definitely want to allow `nil` to > be assigned to a block type, but I would lean slightly to requiring an > implicit cast. > > Ideally, I think we'd allow this but warn, because casting from an arbitrary > ObjC type to a block incorrectly can cause exciting security vulnerabilities > if it's done incorrectly and we should encourage people to check these casts > (`nil` is always safe though - as long as somewhere else checks the > nullability attributes). I don't actually have a compelling use case for widening assignability here. I'm dropping this part of the patch. I do think it should be valid, perhaps with a warning. It feels incorrect for there to be valid comparison cases that are not valid assignment cases (here), but that position doesn't hold up under scrutiny. Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
theraven added a comment. We seem to be missing tests for the assignment part of this patch. Comment at: lib/Sema/SemaExpr.cpp:7749 +// id (or strictly compatible object type) -> T^ +if (getLangOpts().ObjC1 && RHSType->isBlockCompatibleObjCPointerType(Context)) { Kind = CK_AnyPointerToBlockPointerCast; Do we want to allow implicit casts for all object types to block types for assignment, or only for null pointers? We definitely want to allow `nil` to be assigned to a block type, but I would lean slightly to requiring an implicit cast. Ideally, I think we'd allow this but warn, because casting from an arbitrary ObjC type to a block incorrectly can cause exciting security vulnerabilities if it's done incorrectly and we should encourage people to check these casts (`nil` is always safe though - as long as somewhere else checks the nullability attributes). Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT updated this revision to Diff 138759. DHowett-MSFT removed a subscriber: lebedev.ri. DHowett-MSFT added a comment. Moved files around slightly. Repository: rC Clang https://reviews.llvm.org/D44580 Files: lib/Sema/SemaExpr.cpp test/SemaObjC/block-compare.mm Index: test/SemaObjC/block-compare.mm === --- /dev/null +++ test/SemaObjC/block-compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7745,8 +7745,8 @@ return IntToBlockPointer; } -// id -> T^ -if (getLangOpts().ObjC1 && RHSType->isObjCIdType()) { +// id (or strictly compatible object type) -> T^ +if (getLangOpts().ObjC1 && RHSType->isBlockCompatibleObjCPointerType(Context)) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; } @@ -10028,6 +10028,18 @@ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return ResultTy; } + +if(!IsRelational && + LHSType->isBlockPointerType() && + RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} else if(!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} } if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { Index: test/SemaObjC/block-compare.mm === --- /dev/null +++ test/SemaObjC/block-compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7745,8 +7745,8 @@ return IntToBlockPointer; } -// id -> T^ -if (getLangOpts().ObjC1 && RHSType->isObjCIdType()) { +// id (or strictly compatible object type) -> T^ +if (getLangOpts().ObjC1 && RHSType->isBlockCompatibleObjCPointerType(Context)) { Kind = CK_AnyPointerToBlockPoint
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT added a subscriber: lebedev.ri. DHowett-MSFT added a comment. In https://reviews.llvm.org/D44580#1040540, @lebedev.ri wrote: > Why not `test/SemaObjC/block_compare.mm` ? I wasn't are that it existed. It may even be a good fit for `test/SemaObjC/block-type-safety.m`, which already exists. Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
lebedev.ri added a comment. Why not `test/SemaObjC/block_compare.mm` ? Repository: rC Clang https://reviews.llvm.org/D44580 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D44580: Sema: allow comparison between blocks & block-compatible objc types
DHowett-MSFT created this revision. DHowett-MSFT added reviewers: theraven, rjmccall. DHowett-MSFT added a project: clang. Herald added a subscriber: cfe-commits. This commit makes valid the following code: // objective-c++ #define nil ((id)nullptr) ... void (^f)() = ^{}; if (f == nil) { } … Where it would previously fail with the error `invalid operands to binary expression ('void (^)()' and 'id')`. Comparisons are now allowed between block types and `id`, `id`, `id`, and `NSObject*`. No other comparisons are changed. Repository: rC Clang https://reviews.llvm.org/D44580 Files: lib/Sema/SemaExpr.cpp test/Sema/objc_block_compare.mm Index: test/Sema/objc_block_compare.mm === --- /dev/null +++ test/Sema/objc_block_compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp === --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7745,8 +7745,8 @@ return IntToBlockPointer; } -// id -> T^ -if (getLangOpts().ObjC1 && RHSType->isObjCIdType()) { +// id (or strictly compatible object type) -> T^ +if (getLangOpts().ObjC1 && RHSType->isBlockCompatibleObjCPointerType(Context)) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; } @@ -10028,6 +10028,18 @@ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return ResultTy; } + +if(!IsRelational && + LHSType->isBlockPointerType() && + RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} else if(!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BlockPointerToObjCPointerCast); + return ResultTy; +} } if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { Index: test/Sema/objc_block_compare.mm === --- /dev/null +++ test/Sema/objc_block_compare.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -S -o - -triple i686-windows -verify -fblocks \ +// RUN: -Wno-unused-comparison %s + +#pragma clang diagnostic ignored "-Wunused-comparison" + +#define nil ((id)nullptr) + +@protocol NSObject +@end + +@protocol NSCopying +@end + +@protocol OtherProtocol +@end + +__attribute__((objc_root_class)) +@interface NSObject +@end + +__attribute__((objc_root_class)) +@interface Test +@end + +int main() { + void (^block)() = ^{}; + NSObject *object; + id qualifiedId; + + id poorlyQualified1; + Test *objectOfWrongType; + + block == nil; + block == object; + block == qualifiedId; + + nil == block; + object == block; + qualifiedId == block; + + // these are still not valid: blocks must be compared with id, NSObject*, or a protocol-qualified id + // conforming to NSCopying or NSObject. + + block == poorlyQualified1; // expected-error {{invalid operands to binary expression ('void (^)()' and 'id')}} + block == objectOfWrongType; // expected-error {{invalid operands to binary expression ('void (^)()' and 'Test *')}} + + poorlyQualified1 == block; // expected-error {{invalid operands to binary expression ('id' and 'void (^)()')}} + objectOfWrongType == block; // expected-error {{invalid operands to binary expression ('Test *' and 'void (^)()')}} + + return 0; +} Index: lib/Sema/SemaExpr.cpp ===