par par - 5 months ago 21
Objective-C Question

Objective-C ARC and GCC ({}) extension compatibility?

I'm converting some Objective-C code to ARC that makes heavy use of the GCC "Statements and Declarations in Expressions" extension

({})
.

The GCC extension is being used in preprocessor macros to create Objective-C objects. The actual macros are fairly complex, so here is a contrived example to simplify things. Assume for the purposes of my example that the
_x
parameter is always
NSString *
:

#define f(_x) ({ NSString *x = (_x); [NSString stringWithString: x]; })


This macro would of course be called like so:

void foo() { NSString *s = f(@"foo"); }


In the pre-ARC environment this works just fine. The object created by the
stringWithString:
call is an autoreleased object and the GCC extension assigns it to
s
.

After converting to ARC (Xcode 4.4.1) however the object is released immediately when the statement block exits (I confirmed this by instantiating an object that
NSLog()
s it's
dealloc
).

I've tried modifying the macro with typecasts like:

#define f(_x) ({ NSString *x = (_x); (__autoreleasing id) [NSString stringWithString: x]; })


and

#define f(_x) ({ NSString *x = (_x); (NSString __autoreleasing *) [NSString stringWithString: x]; })


but both forms result in a compilation error:

Explicit ownership qualifier on cast has no effect


It appears then that ARC and this GCC extension are incompatible.

Is this so or am I missing something simple that tells ARC not to immediately release the object?

I do have some options, the most attractive of which at the moment seems to be to convert all of these macros to
__inline__
functions but I have quite a bit of code to deal with. I'm really hoping for a quick fix so any ideas are appreciated.

par par
Answer

I've been debugging this for a few hours now and found a solution so I'll answer my own question. FWIW I agree with CRD and think it's a bug--I'll file a report with Apple.

It happens that the "contrived example" I made up for my question actually works (doh). As I mentioned originally the macros I'm working with are much more complicated and they don't. I've discovered though that they will if I return the created object through a temporary as the last statement in the statement block. When written like that ARC doesn't release the object. I assume there's some very narrow RVO-type code in clang and it's colliding with the ARC parser.

At any rate, the workaround looks this (scroll to the very end of the line):

#define f(_x) ({ NSString *x = (_x); NSString *y = [NSString stringWithString: x]; y; })