On Sat, 2025-01-11 at 13:55 -0500, David Malcolm wrote:
> PR c/116871 notes that our diagnostics about incompatible function
> types
> could be improved.
> 
> In particular, for the case of migrating to C23 I'm seeing a lot of
> build failures with signal handlers similar to this (simplified from
> alsa-tools-1.2.11, envy24control/profiles.c; see rhbz#2336278):
> 
> typedef void (*__sighandler_t) (int);
> 
> extern __sighandler_t signal (int __sig, __sighandler_t __handler)
>      __attribute__ ((__nothrow__ , __leaf__));
> 
> void new_process(void)
> {
>   void (*int_stat)();
> 
>   int_stat = signal(2,  ((__sighandler_t) 1));
> 
>   signal(2, int_stat);
> }
> 
> With trunk, cc1 fails with this message:
> 
> t.c: In function 'new_process':
> t.c:18:12: error: assignment to 'void (*)(void)' from incompatible
> pointer type '__sighandler_t' {aka 'void (*)(int)'} [-Wincompatible-
> pointer-types]
>    18 |   int_stat = signal(2,  ((__sighandler_t) 1));
>       |            ^
> t.c:20:13: error: passing argument 2 of 'signal' from incompatible
> pointer type [-Wincompatible-pointer-types]
>    20 |   signal(2, int_stat);
>       |             ^~~~~~~~
>       |             |
>       |             void (*)(void)
> t.c:11:57: note: expected '__sighandler_t' {aka 'void (*)(int)'} but
> argument is of type 'void (*)(void)'
>    11 | extern __sighandler_t signal (int __sig, __sighandler_t
> __handler)
>       |                                         
> ~~~~~~~~~~~~~~~^~~~~~~~~
> 
> With this patch, cc1 emits:
> 
> t.c: In function 'new_process':
> t.c:18:12: error: assignment to 'void (*)(void)' from incompatible
> pointer type '__sighandler_t' {aka 'void (*)(int)'} [-Wincompatible-
> pointer-types]
>    18 |   int_stat = signal(2,  ((__sighandler_t) 1));
>       |            ^
> t.c:9:16: note: '__sighandler_t' declared here
>     9 | typedef void (*__sighandler_t) (int);
>       |                ^~~~~~~~~~~~~~
> cc1: note: the meaning of '()' in function declarations changed in
> C23 from '(int)' to '(void)'
> t.c:20:13: error: passing argument 2 of 'signal' from incompatible
> pointer type [-Wincompatible-pointer-types]
>    20 |   signal(2, int_stat);
>       |             ^~~~~~~~
>       |             |
>       |             void (*)(void)
> t.c:11:57: note: expected '__sighandler_t' {aka 'void (*)(int)'} but
> argument is of type 'void (*)(void)'
>    11 | extern __sighandler_t signal (int __sig, __sighandler_t
> __handler)
>       |                                         
> ~~~~~~~~~~~~~~~^~~~~~~~~
> t.c:9:16: note: '__sighandler_t' declared here
>     9 | typedef void (*__sighandler_t) (int);
>       |                ^~~~~~~~~~~~~~
> 
> showing the location of the pertinent typedef ("__sighandler_t"), and
> emitting the note
>   "the meaning of '()' in function declarations changed in C23
>   from '(int)' to '(void)'"
> 
> Another example, simplfied from a52dec-0.7.4: src/a52dec.c
> (rhbz#2336013):
> 
> typedef void (*__sighandler_t) (int);
> 
> extern __sighandler_t signal (int __sig, __sighandler_t __handler)
>      __attribute__ ((__nothrow__ , __leaf__));
> 
> /* Mismatching return type.  */
> #define RETSIGTYPE int
> static RETSIGTYPE signal_handler (int sig)
> {
> }
> 
> static void print_fps (int final)
> {
>   signal (42, signal_handler);
> }
> 
> With trunk, cc1 emits:
> 
> t2.c: In function 'print_fps':
> t2.c:22:15: error: passing argument 2 of 'signal' from incompatible
> pointer type [-Wincompatible-pointer-types]
>    22 |   signal (42, signal_handler);
>       |               ^~~~~~~~~~~~~~
>       |               |
>       |               int (*)(int)
> t2.c:11:57: note: expected '__sighandler_t' {aka 'void (*)(int)'} but
> argument is of type 'int (*)(int)'
>    11 | extern __sighandler_t signal (int __sig, __sighandler_t
> __handler)
>       |                                         
> ~~~~~~~~~~~~~~~^~~~~~~~~
> 
> With this patch cc1 emits:
> 
> t2.c: In function 'print_fps':
> t2.c:22:15: error: passing argument 2 of 'signal' from incompatible
> pointer type [-Wincompatible-pointer-types]
>    22 |   signal (42, signal_handler);
>       |               ^~~~~~~~~~~~~~
>       |               |
>       |               int (*)(int)
> t2.c:11:57: note: expected '__sighandler_t' {aka 'void (*)(int)'} but
> argument is of type 'int (*)(int)'
>    11 | extern __sighandler_t signal (int __sig, __sighandler_t
> __handler)
>       |                                         
> ~~~~~~~~~~~~~~~^~~~~~~~~
> t2.c:16:19: note: 'signal_handler' declared here
>    16 | static RETSIGTYPE signal_handler (int sig)
>       |                   ^~~~~~~~~~~~~~
> t2.c:9:16: note: '__sighandler_t' declared here
>     9 | typedef void (*__sighandler_t) (int);
>       |                ^~~~~~~~~~~~~~
> 
> showing the location of the pertinent fndecl ("signal_handler"), and,
> as before, the pertinent typedef.
> 
> The patch also updates the colorization in the messages to visually
> link and contrast the different types and typedefs; I'm going to
> upload screenshots to the bug.

I've uploaded screenshots as attachments to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116871

cc1 output from before the patch:
  https://gcc.gnu.org/bugzilla/attachment.cgi?id=60117

cc1 output from after the patch:
  https://gcc.gnu.org/bugzilla/attachment.cgi?id=60118
> 
> [...snip...]

Dave

Reply via email to