public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c/114731] New: -Wincompatible-pointer-types false positive in combination with _Generic(3)
@ 2024-04-16  2:37 alx at kernel dot org
  2024-04-16  2:49 ` [Bug c/114731] " sjames at gcc dot gnu.org
                   ` (20 more replies)
  0 siblings, 21 replies; 22+ messages in thread
From: alx at kernel dot org @ 2024-04-16  2:37 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 114731
           Summary: -Wincompatible-pointer-types false positive in
                    combination with _Generic(3)
           Product: gcc
           Version: 13.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: alx at kernel dot org
  Target Milestone: ---

Hi!

I'm writing type-generic macros with two levels of _Generic(3), because I want
to act depending on the type of two arguments.  It's implemented as a
single-_Generic() macro, which calls other single-_Generic() macros,
effectively implementing two levels of switching.

Here's a small reproducer of these macros:


#define a2i(TYPE, ...)                                                        \
(                                                                             \
        _Generic((TYPE) 0,                                                    \
                long:               a2sl(__VA_ARGS__),                        \
                int:                a2si(__VA_ARGS__),                        \
        )                                                                     \
)


#define a2sl(n, s, endp, base, min, max)                                      \
(                                                                             \
        _Generic(endp,                                                        \
                const char **:  a2sl_c,                                       \
                char **:        a2sl_nc,                                      \
                void *:         a2sl_c                                        \
        )(n, s, endp, base, min, max)                                         \
)

#define a2si(n, s, endp, base, min, max)                                      \
(                                                                             \
        _Generic(endp,                                                        \
                const char **:  a2si_c,                                       \
                char **:        a2si_nc,                                      \
                void *:         a2si_c                                        \
        )(n, s, endp, base, min, max)                                         \
)


As long as you only use one _Generic, it's easy, because you can pass the
argument list outside of _Generic(), and it will call the right function. 
However, if you want to call a macro (the second level), you must write the
argument list inside the _Generic() switch.  This triggers warnings in all the
non-evaluated expressions.

These warnings should not be emitted, and only the evaluated expression in
_Generic() should emit warnings about types, I think.

Below is an entire reproducer program, and it's output:

$ cat g.c 
#include <bsd/inttypes.h>
#include <errno.h>
#include <time.h>


#define a2i(TYPE, ...)                                                        \
(                                                                             \
        _Generic((TYPE) 0,                                                    \
                long:               a2sl(__VA_ARGS__),                        \
                int:                a2si(__VA_ARGS__),                        \
        )                                                                     \
)


#define a2sl(n, s, endp, base, min, max)                                      \
(                                                                             \
        _Generic(endp,                                                        \
                const char **:  a2sl_c,                                       \
                char **:        a2sl_nc,                                      \
                void *:         a2sl_c                                        \
        )(n, s, endp, base, min, max)                                         \
)

#define a2si(n, s, endp, base, min, max)                                      \
(                                                                             \
        _Generic(endp,                                                        \
                const char **:  a2si_c,                                       \
                char **:        a2si_nc,                                      \
                void *:         a2si_c                                        \
        )(n, s, endp, base, min, max)                                         \
)


static inline int a2sl_c(long *restrict n, const char *s,
    const char **restrict endp, int base, long min, long max);
static inline int a2si_c(int *restrict n, const char *s,
    const char **restrict endp, int base, int min, int max);

static inline int a2sl_nc(long *restrict n, const char *s,
    char **restrict endp, int base, long min, long max);
static inline int a2si_nc(int *restrict n, const char *s,
    char **restrict endp, int base, int min, int max);


static inline int
a2sl_c(long *restrict n, const char *s,
    const char **restrict endp, int base, long min, long max)
{
        return a2sl_nc(n, s, (char **) endp, base, min, max);
}


static inline int
a2si_c(int *restrict n, const char *s,
    const char **restrict endp, int base, int min, int max)
{
        return a2si_nc(n, s, (char **) endp, base, min, max);
}


static inline int
a2sl_nc(long *restrict n, const char *s,
    char **restrict endp, int base, long min, long max)
{
        int  status;

        *n = strtoi(s, endp, base, min, max, &status);
        if (status != 0) {
                errno = status;
                return -1;
        }
        return 0;
}


static inline int
a2si_nc(int *restrict n, const char *s,
    char **restrict endp, int base, int min, int max)
{
        int  status;

        *n = strtoi(s, endp, base, min, max, &status);
        if (status != 0) {
                errno = status;
                return -1;
        }
        return 0;
}


int
main(void)
{
        time_t  t;

        a2i(time_t, &t, "42", NULL, 0, 0, 10);
}
$ gcc-13 -Wall -Wextra -Wincompatible-pointer-types g.c $(pkgconf --cflags
--libs libbsd)
g.c: In function ‘main’:
g.c:96:21: warning: passing argument 1 of ‘a2si_c’ from incompatible pointer
type [-Wincompatible-pointer-types]
   96 |         a2i(time_t, &t, "42", NULL, 0, 0, 10);
      |                     ^~
      |                     |
      |                     time_t * {aka long int *}
g.c:30:11: note: in definition of macro ‘a2si’
   30 |         )(n, s, endp, base, min, max)                                  
      \
      |           ^
g.c:96:9: note: in expansion of macro ‘a2i’
   96 |         a2i(time_t, &t, "42", NULL, 0, 0, 10);
      |         ^~~
g.c:54:22: note: expected ‘int * restrict’ but argument is of type ‘time_t *’
{aka ‘long int *’}
   54 | a2si_c(int *restrict n, const char *s,
      |        ~~~~~~~~~~~~~~^
g.c:11:9: error: expected specifier-qualifier-list before ‘)’ token
   11 |         )                                                              
      \
      |         ^
g.c:96:9: note: in expansion of macro ‘a2i’
   96 |         a2i(time_t, &t, "42", NULL, 0, 0, 10);
      |         ^~~

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2024-04-16 12:32 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-16  2:37 [Bug c/114731] New: -Wincompatible-pointer-types false positive in combination with _Generic(3) alx at kernel dot org
2024-04-16  2:49 ` [Bug c/114731] " sjames at gcc dot gnu.org
2024-04-16  2:56 ` alx at kernel dot org
2024-04-16  2:58 ` alx at kernel dot org
2024-04-16  2:59 ` sjames at gcc dot gnu.org
2024-04-16  3:02 ` alx at kernel dot org
2024-04-16  3:03 ` pinskia at gcc dot gnu.org
2024-04-16  3:05 ` pinskia at gcc dot gnu.org
2024-04-16  3:10 ` pinskia at gcc dot gnu.org
2024-04-16  3:11 ` alx at kernel dot org
2024-04-16  3:15 ` pinskia at gcc dot gnu.org
2024-04-16  3:17 ` alx at kernel dot org
2024-04-16 10:52 ` alx at kernel dot org
2024-04-16 10:55 ` uecker at gcc dot gnu.org
2024-04-16 11:01 ` alx at kernel dot org
2024-04-16 11:07 ` alx at kernel dot org
2024-04-16 11:17 ` uecker at gcc dot gnu.org
2024-04-16 11:26 ` alx at kernel dot org
2024-04-16 12:01 ` muecker at gwdg dot de
2024-04-16 12:05 ` muecker at gwdg dot de
2024-04-16 12:25 ` alx at kernel dot org
2024-04-16 12:32 ` alx at kernel dot org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).