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
}