Debarshi's den

About -Wextra and -Wcast-function-type

leave a comment »

About eight months ago, around the time when GCC 8.x started showing up on my computers, I started moving my code away from using -Wextra. This aligns nicely with the move to the Meson build system, which is nice; but went against the flow of Autotools’ AX_COMPILER_FLAGS, which isn’t ideal but is an acceptable trade-off.

But why?

GCC 8.x added a warning called -Wcast-function-type to the -Wextra umbrella. It warns when a function pointer is cast to an incompatible function. At a glance, this seems desirable, but it isn’t. It runs contrary to one of the widely used C idioms in GNOME. For example, it’s triggered by this text book use of g_list_copy_deep to copy a list of reference counted objects:

another_list = g_list_copy_deep (list, (GCopyFunc) g_object_ref, NULL);

Note that this is different from -Wincompatible-pointer-types, which would’ve triggered if the cast to GCopyFunc was missing:

another_list = g_list_copy_deep (list, g_object_ref, NULL);

It’s easy to imagine similar examples with uses of gtk_container_forall or gtk_container_foreach with gtk_widget_destroy, and so on.

The C standard (eg., see article 6.5.2.2 of the C11 standard) steps around the issue of passing more arguments to a function than it actually has parameters for by calling it undefined behaviour. However, the calling conventions of all the platforms supported by GLib are defined in a way to make this work.

So how do we disable -Wcast-function-type?

One option is to use a compiler directive with #pragma as suggested by AX_COMPILER_FLAGS. However, attempts to ignore it through a #pragma on older versions of GCC that didn’t have this specific warning will trigger -Wpragmas, and, ironically, using G_GNUC_CHECK_VERSION to conditionally disable it on newer compilers will trigger -Wexpansion-to-defined, again, because of -Wextra and the fact that the implementation of the macro has a #ifdef around __GNUC__. Regardless, for a warning that gets triggered by such a widely used programming construct, it would lead to a ton of boilerplate all over the codebase, instead of being a solitary exception tucked away in one corner of the project.

Therefore, my preference has been to append -Wno-cast-function-type and -Wno-error=cast-function-type to the list of compiler flags of modules using -Wextra. This avoids almost all of the above problems. One small wrinkle is that if a translation unit or file does trigger some other unrelated diagnostic, then an older compiler will also emit -Wunknown-warning for the presence of the unknown -Wno-cast-function-type flag. I find this acceptable because, in the first place, a file shouldn’t trigger any other diagnostic, especially on an older compiler, and if there does happen to be something, say a deprecation warning, then it’s likely something that needs to be fixed anyway.

Given that this can repeat with future versions of GCC, it seems wiser to avoid -Wextra and instead explicitly list out the desired compiler warnings. This isn’t hard to do because the GCC documentation clearly marks which warnings are turned on by -Wextra, -Wpedantic, etc..

Written by Debarshi Ray

1 April, 2019 at 13:05

Posted in C, GNOME, GNU

Leave a comment