Reputation: 2746
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.
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
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:
-Wnon-literal-null-conversion
to your “Other C Flags” build setting.NO
instead of false
._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