https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116871

--- Comment #7 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by David Malcolm <dmalc...@gcc.gnu.org>:

https://gcc.gnu.org/g:bbc7900ce7e2c3d906286674f80789f057e86c0a

commit r15-6886-gbbc7900ce7e2c3d906286674f80789f057e86c0a
Author: David Malcolm <dmalc...@redhat.com>
Date:   Mon Jan 13 19:47:25 2025 -0500

    c: improve UX for -Wincompatible-pointer-types (v3) [PR116871]

    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);
    }

    Before this patch, 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);
          |                ^~~~~~~~~~~~~~
    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")

    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.  */
    static RETSIGTYPE signal_handler (int sig)
    {
    }

    static void print_fps (int final)
    {
      signal (42, signal_handler);
    }

    Before 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)
          |                                          ~~~~~~~~~~~~~~~^~~~~~~~~

    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.

    My hope is that this make it easier for users to decipher build failures
    seen with the new C23 default.

    Further improvements could be made to colorization in
    convert_for_assignment, and similar improvements to C++, but I'm punting
    those to GCC 16.

    gcc/c/ChangeLog:
            PR c/116871
            * c-typeck.cc (pedwarn_permerror_init): Return bool for whether a
            warning was emitted.  Only call print_spelling if we warned.
            (pedwarn_init): Return bool for whether a warning was emitted.
            (permerror_init): Likewise.
            (warning_init): Return bool for whether a
            warning was emitted.  Only call print_spelling if we warned.
            (class pp_element_quoted_decl): New.
            (maybe_inform_typedef_location): New.
            (convert_for_assignment): For OPT_Wincompatible_pointer_types,
            move auto_diagnostic_group to cover all cases.  Use %e and
            pp_element rather than %qT and tree to colorize the types.
            Capture whether a warning was emitted, and, if it was,
            show various notes: for a pointer to a function, show the
            function decl, for typedef types, and show the decls.

    gcc/testsuite/ChangeLog:
            PR c/116871
            * gcc.dg/c23-mismatching-fn-ptr-a52dec.c: New test.
            * gcc.dg/c23-mismatching-fn-ptr-alsatools.c: New test.
            * gcc.dg/c23-mismatching-fn-ptr.c: New test.

    Signed-off-by: David Malcolm <dmalc...@redhat.com>

Reply via email to