8
votes

In this code

id (^block)(void) = ^(void) {
    return nil;
};

I have this error

Incompatible block pointer types initializing 'id (^__strong)(void)' with an expression of type 'void *(^)(void)'

So I have to explicitly cast nil to id type

id (^block)(void) = ^(void) {
    return (id)nil;
};

to make compiler happy. Buy why nil is not id type?

And for this code

__typeof__(nil) dummy;
dummy = [NSObject new];

Implicit conversion of Objective-C pointer type 'NSObject *' to C pointer type 'typeof (((void *)0))' (aka 'void *') requires a bridged cast

which is saying nil is (void *)0, but isn't just same as NULL? I though nil should be (id)0 and Nil should be (Class)0?

I am using Xcode 4.6.2

Compiler: Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)

3
You can solve this by adding the following in your prefix header under the #import statements: #undef nil #undef Nil #define nil ((id)(NULL)) #define Nil ((Class)(NULL))JDS

3 Answers

3
votes

You're using an inferred return type for your block literal, but you don't have to.

The correct way to remove that error is to provide a return type for the block literal:

id (^block)(void) = ^id{
    return nil;
};
3
votes

When a block omits it's return type, it now becomes the job of the compiler to infer the type of the block based on the returns in its body. But, unfortunately, CLANG searches for the fully decayed forms of it's returned types, which leads to strange inconsistencies.

The most accessible example is sorting an array. The type of the comparator block is NSComparisonResult(^)(id obj, id obj2), but if you choose to omit the NSComparisonResult return type, the compiler gets whiny:

NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj, id obj2) {
    if (//...) return NSOrderedAscending;
    return NSOrderedDescending;
}];

This block decays into a block of type int(^)(id obj, id obj2), which the compiler sees as incompatible (arguably, enums are just named ints, so this should compile).

In the same way, id decays into objc_object* which decays on and on and on until it reaches void*, or "any generic pointer" (according to the C language spec). void* and id are most certainly not the same type. To get around this, you have to promise the compiler that the returned type truly is what it is, and the only way to do that is to cast.

LLVM 5.0 fixes this by making the compiler's inferences much smarter.

0
votes

I don't know why nil is #define nil NULL in the Apple header (that's a fact but I don't know the reason why it's not (id)0 as one would expect), but I never had the error you are mentionning in the latest version of Xcode and the compiler.

I think I remember though a bug in earlier versions of the legacy compiler that misinterpreted implicit casts like that in blocks return types and all.

Which compiler are you using ? LLVM-GCC 4.2 ? or Apple LLVM 4.2 ? An older compiler ? Check the build settings of your project. I recommend to switch to Apple LLVM, and check if that solves your problem.

(as a matter of fact, LLVM-GCC is only used for transition from the old GCC to the new LLVM since some versions of Xcode now, but is deprecated and is to be removed in the next version of Xcode)