Alyoshak
Alyoshak

Reputation: 2746

How to get Xcode to generate warning (or error) on Mismatched Return Type?

I just made a code change in the type for a method's return type and was counting on the compiler to show warnings which would allow me to find and fix wherever the mismatch now occurs. But no warnings. In my Settings I discovered that "Mismatched Return Type" was already "Yes" for all build types, so I decided to change it to "Yes (treat as error)" and did a rebuild. Still no indication in build results.

I then changed "Treat Warnings as Errors" to "Yes" and that produced a few helpful error messages, but no mismatch warnings. Perhaps I do not understand something about the compiler and Objective-C return types, but it seems that a bool should not be acceptable when my method specifies that is should return an NSNumber*.

Here is my code:

+(NSNumber*) compilerCompletelyFineWithThis
{
    if ([m_session tryThis])
    {
        return [m_session goGetSumthin];
    }
    else
        return false;
}

The docs suggest that Mismatched Return Type is associated with GCC_WARN_ABOUT_RETURN_TYPE, but it is not clear what rules this enforces.

In the pic below of the warnings section(s) of my Build Settings, notice the relevant settings. I have "Treat Warnings as Errors" and "Mismatched Return Type" turned on for all my builds.

enter image description here

Is there a way to get Xcode to let me know when I am violating this kind of contract between a method definition and the calling code?

Upvotes: 2

Views: 2172

Answers (1)

rob mayoff
rob mayoff

Reputation: 385500

Sad news… the problem here is not with the “Mismatched Return Type” warning/error setting.

The problem is that false is actually a #define for 0. You can find the definition in stdbool.h, hidden away at this path in Xcode 8.3.3:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/include/stdbool.h

Since it's a preprocessor define, it gets changed from false to 0 before the semantic analysis part of the compiler sees it.

In C, you're allowed to use a bare literal 0 as a null pointer. So in your case, false is treated as a null pointer to NSNumber and is a legal return value.

Even if you use the preferred Objective-C boolean NO, that alone won't fix the problem. NO is a #define for __objc_no (see /usr/include/objc/objc.h), which is a clang extension that effectively acts as a literal 0 (but which allows the compiler uses to convert @YES and @NO to the proper singletons).

To get a warning, you need to take three steps:

  1. Add -Wnon-literal-null-conversion to your “Other C Flags” build setting.
  2. Return NO instead of false.
  3. Declare your function to return _Nonnull.

Result:

+(NSNumber * _Nonnull) compilerCompletelyFineWithThis {
    return NO;
    // error: Expression which evaluates to zero treated as a null pointer constant of type 'NSNumber * _Nonnull'
}

Starting in Xcode 9, you can turn on the “Implicit Non-Literal Null Conversions” build setting instead of modifying “Other C Flags”.

Upvotes: 7

Related Questions