Clang allows automatic conversion of lambdas to ObjC blocks and C function pointers (the latter only when nothing is captured). If a lambda returns an ObjC object with arc enabled then it gets over-released. You can see the bad behavior in the program below:
typedef id (^Go)(); int main() { Go g = []() -> id { return [NSObject new]; }; id sss = nil; @autoreleasepool { id ss = g(); sss = ss; } NSLog(@"%@", sss); return 0; }
(and if you change the Go typedef to be a function pointer then the same error occurs, which is a crash).
The test I wrote relies on the optimizer inlining the lambda invocation -- I'm not sure if that's an ok assumption to make. The IR generated previous to this patch is kind of fun:
define internal i8* @___Z5test0P11objc_object_block_invoke(i8* nocapture readonly %.block_descriptor) #0 { entry: %block.capture.addr = getelementptr inbounds i8, i8* %.block_descriptor, i64 32 %0 = bitcast i8* %block.capture.addr to i8** %1 = load i8*, i8** %0, align 8, !tbaa !7 %2 = tail call i8* @objc_retain(i8* %1) #2 %3 = tail call i8* @objc_autoreleaseReturnValue(i8* %1) #2 %4 = tail call i8* @objc_autoreleaseReturnValue(i8* %1) #2 ret i8* %1 }