How to stop 'noreturn' functions disabling '-Wreturn-type' warning with GCC?

740 Views Asked by At

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)
1

There are 1 best solutions below

4
On

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:

#include <stdlib.h>

#include <signal.h>
void myabort() {
    raise(SIGABRT);
}

#define abort() myabort()

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 in asserts become unused. Thus working around abort would not solve the problem of debug/release inconsistency.