I am using C99
under GCC
.
I have a function declared static
inline
in a header that I cannot modify.
The function never returns but is not marked __attribute__((noreturn))
.
How can I call the function in a way that tells the compiler it will not return?
I am calling it from my own noreturn function, and partly want to suppress the "noreturn function returns" warning but also want to help the optimizer etc.
I have tried including a declaration with the attribute but get a warning about the repeated declaration.
I have tried creating a function pointer and applying the attribute to that, but it says the function attribute cannot apply to a pointed function.
Several solutions:
redeclaring your function with the
__attribute__
You should try to modify that function in its header by adding
__attribute__((noreturn))
to it.You can redeclare some functions with new attribute, as this stupid test demonstrates (adding an attribute to
fopen
) :overriding with a macro
At last, you could define a macro like
(this uses the fact that inside a macro, the macro name is not macro-expanded).
If your never-returning
func
is declaring as returning e.g.int
you'll use a statement expression likeMacro-based solutions like above won't always work, e.g. if
func
is passed as a function pointer, or simply if some guy codes(func)(1)
which is legal but ugly.redeclaring a static inline with the
noreturn
attributeAnd the following example:
when compiled with GCC 4.9 (from Debian/Sid/x86-64) as
gcc -S -fverbose-asm -O2 ex.c
) gives an assembly file containing the expected optimization:You could play with #pragma GCC diagnostic to selectively disable a warning.
Customizing GCC with MELT
Finally, you could customize your recent
gcc
using the MELT plugin and coding your simple extension (in the MELT domain specific language) to add the attributenoreturn
when encoutering the desired function. It is probably a dozen of MELT lines, usingregister_finish_decl_first
and a match on the function name.Since I am the main author of MELT (free software GPLv3+) I could perhaps even code that for you if you ask, e.g. here or preferably on
gcc-melt@googlegroups.com
; give the concrete name of your never-returning function.Probably the MELT code is looking like:
The real MELT code is slightly more complex. You want to define
your_adding_attr_mode
there. Ask me for more.Once you coded your MELT extension
your_melt_mode.melt
for your needs (and compiled that MELT extension intoyour_melt_mode.quicklybuilt.so
as documented in the MELT tutorials) you'll compile your code withIn other words, you just add a few
-fplugin-*
flags to yourCFLAGS
in yourMakefile
!BTW, I'm just coding in the MELT monitor (on github: https://github.com/bstarynk/melt-monitor ..., file
meltmom-process.melt
something quite similar.With a MELT extension, you won't get any additional warning, since the MELT extension would alter the internal GCC AST (a GCC Tree) of the declared function on the fly!
Customizing GCC with MELT is probably the most bullet-proof solution, since it is modifying the GCC internal AST. Of course, it is probably the most costly solution (and it is GCC specific and might need -small- changes when GCC is evolving, e.g. when using the next version of GCC), but as I am trying to show it is quite easy in your case.
From the function you defined, and which calls the external function, add a call to
__builtin_unreachable
which is built into at least GCC and Clang compilers and is markednoreturn
. In fact, this function does nothing else and should not be called. It's only here so that the compiler can infer that program execution will stop at this point.Edit: Just to clarify a few points raised in the comments, and generally give a bit of context:
__attribute__((noreturn))
is an annotation (likeconst
) which is a way for the programmer to inform the compiler that he's absolutely sure a function will not return. Following the trust but verify principle, the compiler tries to prove that the function does indeed not return. If may then issue an error if it proves the function may return, or a warning if it was not able to prove whether the function returns or not.__builtin_unreachable
has undefined behaviour because it is not meant to be called. It's only meant to help the compiler's static analysis. Indeed the compiler knows that this function does not return, so any following code is provably unreachable (except through a jump).Once the compiler has established (either by itself, or with the programmer's help) that some code is unreachable, it may use this information to do optimizations like these:
__builtin_unreachable()
is unreachable.noreturn
. That's what happens foryour_function
.pure
functions) may be removed.Illustration: - The call to
external_function
cannot be removed because it might have side-effects. In fact, it probably has at least the side effect of terminating the process! - The return boiler plate ofyour_function
may be removedHere's another example showing how code before the unreachable point may be removed