Search code examples
iosobjective-ccocoapodsxcode11

Too many arguments to function call, expected 0, have 2


Last year we moved from Pixate to StylingKit

https://github.com/StylingKit/StylingKit a fork of Pixate which is still being developed as far as I can tell.

However we are having problems with it now with the release of XCode 11, in pior versions it worked just fine but now it won't compile.

    void* callSuper0(id self, Class superClass, SEL _cmd)
    {
        struct objc_super super;
        super.receiver = (__bridge void *)self;
        super.class = superClass != NULL ? superClass : class_getSuperclass(object_getClass(self));
        return objc_msgSendSuper(&super, preprocessSEL(_cmd));
    }

return objc_msgSendSuper(&super, preprocessSEL(_cmd));

Throws error "Too many arguments to function call, expected 0, have 2"

I tried changing some Building Settings as seen in Too many arguments to function call, expected 0, have 3 specifically "Enable strict checking of objc_msgSend Calls to NO" but it didn't help.

Any help would be appreciated.


Solution

  • Note: The code below has not been executed as it is just a fragment, however it has been compiled by Xcode 10 & 11. There may be mistakes or other issues.

    In Xcode right-click on objc_super and objc_msgSendSuper and select "Jump to Definition" which will open the system files containing the definitions. This will show two things:

    1. Both field names and types of objc_super have changed since your code was written, some of this is documented in the comments.
    2. The prototype for objc_msgSendSuper has also changed to just void objc_msgSendSuper(void), the previous prototype is also there id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...). Using the previous prototype the call to this function in the code could be made without a cast, with this new prototype a cast is needed.

    Making the changes indicated to the code gives:

    // A typedef for objc_msgSendSuper which takes only the required (first two) arguments
    typedef void *(*NoAdditionalArgMsgSendSuper)(struct objc_super *super_class, SEL selector);
    
    void* callSuper0(id self, Class superClass, SEL _cmd)
    {
       struct objc_super super;
       // .receiver is now defined as "__unsafe_unretained _Nonnull id" so no bridge cast required
       super.receiver = self;
       // .super_class is new name for .class
       super.super_class = superClass != NULL ? superClass : class_getSuperclass(object_getClass(self));
       // cast objc_msgSendSuper to the correct type and then call
       return ((NoAdditionalArgMsgSendSuper)objc_msgSendSuper)(&super, preprocessSEL(_cmd));
    }
    

    HTH

    Addendum

    Following on from your comment and code post as another answer.

    In your code you write:

    void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
    return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
    

    Making a typed copy of the function pointer, rather than just casting on use as our earlier code, is fine. However your code should produce an error from Xcode as you are trying to case a non-retained type (&super - a struct pointer) to a retained one (id) – which requires a bridge cast.

    The solution here is to give objc_msgSendSuperTyped the correct type, its first argument should be a struct pointer:

    void* (*objc_msgSendSuperTyped)(struct objc_super *self, SEL _cmd) = (void*)objc_msgSendSuper;
    return objc_msgSendSuperTyped(&super, preprocessSEL(_cmd));
    

    From your comment:

    I had to change super.super_class to super.class for it to work, it now throws other errors unrelated.

    This suggests you've some unusual settings, in the declaration of objc_super we find:

    #if !defined(__cplusplus)  &&  !__OBJC2__
       /* For compatibility with old objc-runtime.h header */
       __unsafe_unretained _Nonnull Class class;
    #else
       __unsafe_unretained _Nonnull Class super_class;
    #endif
    

    __OBJC2__ is defined by default in Xcode 11 (and plenty of earlier versions) for .m and .mm files, __cplusplus is defined for .mm files only. So the condition !defined(__cplusplus) && !__OBJC2__ is false and the field is therefore named super_class...

    You might wish to determine why __OBJC2__ is apparently not defined for the source you are trying to convert...