Instance variables in implementation error?

Hi folks,

I am working on a code-base that for various reasons has instance variables declared in both the @interface and the @implementation section. Using gcc 4.2, this is OK, but clang in 64 bit aborts with the following error:

[elided] …/…/src/Error.m:13:10: error: instance variable is already declared [3]
BOOL _isExceptional;
^

Which is true, that is exactly what’s happening, it was just OK (if questionable) before.

In 32 bit mode, clang is OK with this, as is gcc 4.2 in both 32 bit and 64 bit mode. Any way to turn this error off in clang 64 bit mode?

I tried setting the Objective-C language level using the (gcc) flag ‘-fobjc-std=objc1’ but that doesn’t seem to make a difference. I did a search of the clang pages at http://clang.llvm.org/docs/UsersManual.html but the link to “Objective-C language features” is a dead link ( http://clang.llvm.org/docs/UsersManual.html#objc ), as is the C++ link. The C language features link works.

I also tried to search the code via the error message, but that wasn’t too illuminating either.

For now, I can probably get by with using gcc 4.2, but I’d much prefer to use clang.

Thanks!

Marcel

How old is this codebase? That was never allowed in Objective-C 4: GCC just accepts it to ease migration of legacy Objective-C 3.3 code (yes, Objective-C 2.0 is the one that comes after Objective-C 4. Blame Apple marketing for that one). Since Objective-C 4 was released about 20 years ago, that's expected to be long enough for most people to update their code...

If you're on Darwin, then 64-bit mode is enabling the non-fragile ABI implicitly. This means that defining instance variables in @implementation contexts actually does define new instance variables.

Can you not simply delete them from the @implementation? They aren't actually doing anything there - GCC and clang with the fragile ABI will not accept definitions of new ivars there, because without the non-fragile ABI class layouts had to be public so that each class new where its superclass's ivars were.

David

I am working on a code-base that for various reasons has instance variables declared in both the @interface and the @implementation section

How old is this codebase?

Its origins are mid 90-ies, so quite old, but actively developed, if not on OSX.

That was never allowed in Objective-C 4: GCC just accepts it to ease migration of legacy Objective-C 3.3 code (yes, Objective-C 2.0 is the one that comes after Objective-C 4. Blame Apple marketing for that one). Since Objective-C 4 was released about 20 years ago, that’s expected to be long enough for most people to update their code…

:slight_smile:

If you’re on Darwin, then 64-bit mode is enabling the non-fragile ABI implicitly. This means that defining instance variables in @implementation contexts actually does define new instance variables.

Yep. The question is wether I can undo/override the implicit enabling explicitly, for example by using ‘-fobjc-std=objc1’.

Can you not simply delete them from the @implementation?

Not simply, no, although that would be my goal. The reason is that the headers with the interfaces are actually generated from the .m files (which also means there can’t be conflicts). This has some interesting benefits, though I myself found the costs to outweigh the benefits and abandoned the practice years ago.

They aren’t actually doing anything there - GCC and clang with the fragile ABI will not accept definitions of new ivars there, because without the non-fragile ABI class layouts had to be public so that each class new where its superclass’s ivars were.

Yep. One solution would be to have the header-generator skip generating the variables for the @interfaces when compiling for 64 bit, and maintain the generation of the variables for 32 bit, but that’s also pretty nasty.

Thanks,

Marcel

Two quasi-solutions:
1. Generate #ifndef __OBJC2__ around the generated ivar section, for maximum simplicity.
2. Use #if HEADER_GENERATOR around the ivar section in the @implementation, for cleaner headers.

Wouldn't #if !__has_feature(objc_nonfragile_abi) be better? We use something similar for ABI-breaking changes in classes via some horrible macros.

This has the advantage that it lets you incrementally migrate to the non-fragile ABI - eventually you can just drop the ivar generating part of the header generator entirely, unless you have some ivars that are supposed to be shared.

Wrapping the ivars in the @implementation in the same conditional would have the same effect.

David

-- Sent from my brain

Hi folks,

I am working on a code-base that for various reasons has instance variables declared in both the @interface and the @implementation section. Using gcc 4.2, this is OK, but clang in 64 bit aborts with the following error:

[elided] …/…/src/Error.m:13:10: error: instance variable is already declared [3]
BOOL _isExceptional;
^

Which is true, that is exactly what’s happening, it was just OK (if questionable) before.

In 32 bit mode, clang is OK with this, as is gcc 4.2 in both 32 bit and 64 bit mode. Any way to turn this error off in clang 64 bit mode?

-m64 uses the non-fragile abi. This mode has a few language extensions, one of which is allowing to add ‘private’ ivars
to the class via @implementation. So, each ivar is checked against existing ivars and diagnostic is issued for a redeclaration.
You can work around this problem by adding -fno-objc-nonfragile-abi to your command line. But I should caution that
we don’t test nonfragile-abi in 64bit mode. And you may likely run into other issues.

  • fariborz

Hi folks,

I am working on a code-base that for various reasons has instance variables declared in both the @interface and the @implementation section. Using gcc 4.2, this is OK, but clang in 64 bit aborts with the following error:

[elided] …/…/src/Error.m:13:10: error: instance variable is already declared [3]
BOOL _isExceptional;
^

Which is true, that is exactly what’s happening, it was just OK (if questionable) before.

In 32 bit mode, clang is OK with this, as is gcc 4.2 in both 32 bit and 64 bit mode. Any way to turn this error off in clang 64 bit mode?

-m64 uses the non-fragile abi. This mode has a few language extensions, one of which is allowing to add ‘private’ ivars
to the class via @implementation. So, each ivar is checked against existing ivars and diagnostic is issued for a redeclaration.
You can work around this problem by adding -fno-objc-nonfragile-abi to your command line. But I should caution that
we don’t test nonfragile-abi in 64bit mode. And you may likely run into other issues.

Meant to say with don’t check fragile-abi (usually 32bit abi) in 64bit mode.

  • Fariborz

I am working on a code-base that for various reasons has instance variables declared in both the @interface and the @implementation section. Using gcc 4.2, this is OK, but clang in 64 bit aborts with the following error:

[…]

In 32 bit mode, clang is OK with this, as is gcc 4.2 in both 32 bit and 64 bit mode. Any way to turn this error off in clang 64 bit mode?

-m64 uses the non-fragile abi. This mode has a few language extensions, one of which is allowing to add ‘private’ ivars
to the class via @implementation. So, each ivar is checked against existing ivars and diagnostic is issued for a redeclaration.

Yep.

You can work around this problem by adding -fno-objc-nonfragile-abi to your command line. But I should caution that
we don’t test nonfragile-abi in 64bit mode. And you may likely run into other issues.

Ahh, that was the flag I was looking for! Tried it and the errors go away, except that the linker now fails (without even an error message). Which makes sense considering all the libs it is trying to link against were almost certainly compiled with the non-fragile ABI…so I guess I should have seen that one coming.

Thanks for the pointer, learn something new every day!

Marcel