When using a macro that might expand to a function with a noreturn
attribute, is there a way to stop it from suppressing -Wreturn-type
?
Simple example:
/* Defined in a separate header. */
#ifndef NDEBUG
# define MY_ASSERT_MACRO(test) ((void)((test) ? 0 : abort()))
#else
# define MY_ASSERT_MACRO(test) ((void)(0 ? 0 : (test)))
#endif
/* C source file. */
int function(enum MyEnum foo)
{
switch (foo) {
case A: return 1;
case B: return 1;
}
MY_ASSERT_MACRO(0);
/* <-- Missing return! This should always warn! */
}
The problem with this is in release builds this gives a -Wreturn-type
warning, and in debug builds it gives no warning at all, since abort has a noreturn
attrubute.
I would like to get the warning in both cases so developers using debug builds don't break release builds.
Is there a (clean*) way to stop the abort function from disabling the -Wreturn-type
warning?
Not very clean ways:
- Call abort with a cast to remove the
noreturn
attribute:((void (*)(void))(*(((void **)abort))))()
- Compare two things which could theoretically be the same:
(((const void *)(abort) != (const void *)(stderr)) ? abort() : 0)
One obvious way is to simply disable noreturn attribute on
abort
by compiling with-D__noreturn__= -fno-builtin-abort
. You could also use a custom wrapper:and compile with
-include myabort.h
.But I suggest not to do that and instead do release builds under
-Wall -Werror
in your CI and/or precommit hooks. Release builds can emit useful warnings for many reasons e.g. because_FORTIFY_SOURCE
static checks are enabled or some variables that were used inassert
s become unused. Thus working aroundabort
would not solve the problem of debug/release inconsistency.