objective-cobjective-c-blockscocos3dxcode12

Xcode12 compile error against Cocos3D: Incompatible block pointer types


"Xcode 12.0 (12A7209)" shows compile error against Cocos3D library (written in Objective-C) in the following code:
(The past versions of Xcode ((ie ver.11, 10), including ver 11.7(11801a)) don't have this problems but Xcode 12.0 does.)

Error message:
Incompatible block pointer types sending 'void (^)(CC3ShaderProgram *, BOOL *)' to parameter of type 'void (^)(id, BOOL *)'

// CC3Shaders.m
+(void) willBeginDrawingScene {
    [_programCache enumerateObjectsUsingBlock: ^(CC3ShaderProgram* prog, BOOL* stop) {
        [prog willBeginDrawingScene];
    }];
}

// CC3Cache.m
-(void) enumerateObjectsUsingBlock: (void (^) (id<CC3Cacheable> obj, BOOL* stop)) block {
    [self lock];
    [_objectsByName enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL* stop) {
        block([obj resolveWeakReference], stop);
    }];
    [self unlock];
}

Basically Xcode 12.0's ObjC compiler complains about mismatching of object types of the input argument of the block "enumerateObjectsUsingBlock:".

But "CC3ShaderProgram" is inherited from "NSObject with CC3Cacheable protocol" as follows:

@interface CC3ShaderProgram : CC3Identifiable 
@interface CC3Identifiable : NSObject <CC3Cacheable, NSCopying>

So, "CC3ShaderProgram" is a matching type with "id" so compiler shouldn't complain but Xcode12.0 does.

Not only at "willBeginDrawingScene" but in other places in the library where "enumerateObjectsUsingBlock:" is being used have same problems.

I have been using Cocos3D library for past few years with several different versions of Xcode without this problem.

Are there any changes made in CLANG or SDK of "Xcode 12.0" to become stricter in terms of block argument type checking (something like "using generic object pointer "id" is not allowed") ? Otherwise, I don't understand why those two matching types are regarded as mis-matching types by the compiler and cause compile error in Xcode 12.0.

Would you be able to provide any good solution for this? It will be much appreciated.

Thank you.

Update: After changing the argument type to include "NSCopying" protocol in the block (to make the argument type's protocol set as same as "CC3ShaderProgram"), Xcode12 compiler has stopped complaining. (Previsouly, only CC3Cacheable protocol was included.)

-(void) enumerateObjectsUsingBlock: (void (^) (id<CC3Cacheable, NSCopying> obj, BOOL* stop)) block

For now, the code binary builds without this compile error. However, still I don't understand why Xcode 12.0 complains this, unless Xcode12's CLANG has become a lot stricter than its previous versions in terms of type checking.


Solution

  • There are two ways to fix this in Cocos3D.

    It can be fixed in code in CC3Cache.h, by adding __kindof to the definition of [CC3Cache enumerateObjectsUsingBlock:] as follows:

    -(void) enumerateObjectsUsingBlock: (void (^) (__kindof id<CC3Cacheable> obj, BOOL* stop)) block;
    

    which is where it should be fixed.

    Alternately, the error can be muted at build time without code changes by including:

    -Xclang -fcompatibility-qualified-id-block-type-checking
    

    in the OTHER_CFLAGS build setting.

    The original source of these solutions can be found here and here.