22

The following code generates 2 warnings which are described in the question's title.

#include <stdio.h>

static void _print_f(float *f){printf("float : %f\n", *f);}
static void _print_i(int *i)  {printf("int   : %d\n", *i);}

#define print(num) _Generic((num), \
    int*   : _print_i(num),        \
    float* : _print_f(num))


int main(void)
{
    print((&(int){10}));
    print((&(float){10.f}));

    return 0;
}

OUTPUT:

int   : 10
float : 10.000000

I know, this macro could be written like the following:

#define print(num) _Generic((num), \
    int*   : _print_i,             \
    float* : _print_f)(num)

and in that case, there won't be any warnings, however my example is a dummy snippet which I wrote to demonstrate the problem. In my real code base I chose the former solution, because some other "default" but type specific arguments needs to be passed to the selected function.

So the question is: Even if the macro is working as it should, and the output is exactly what I expect, why are the warnings generated?


Flags and Environment:

/* Mac OS X 10.9.4
   Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn) */
cc -Wall -v -g -std=c11 -fmacro-backtrace-limit=0 -I/usr/local/include
   -c -o build/tmp/main.o main.c

Update1:

I forgot to paste the full traceback! Here is the first one:

main.c:39:11: warning: incompatible pointer types passing 'int *'
to parameter of type 'float *' [-Wincompatible-pointer-types]
    print((&(int){10}));
          ^~~~~~~~~~~~
main.c:31:23: note: expanded from macro 'print'
    float* : _print_f(num))
                      ^
main.c:26:29: note: passing argument to parameter 'f' here
static void _print_f(float *f){printf("float : %f\n", *f);}
                            ^

And here is the second one:

main.c:40:11: warning: incompatible pointer types passing 'float *'
to parameter of type 'int *' [-Wincompatible-pointer-types]
    print((&(float){10.f}));
          ^~~~~~~~~~~~~~~~
main.c:30:23: note: expanded from macro 'print'
    int*   : _print_i(num),        \
                      ^
main.c:27:27: note: passing argument to parameter 'i' here
static void _print_i(int *i)  {printf("int   : %d\n", *i);}
                          ^

Update2:

Until the developers of clang fix this bug, here is an ugly piece of workaround to mute the warnings, which will work if all keys in the assoc-list are types, OR all are pointers to types; and will fail if types AND pointers to types are in the keys too:

/* HACK: re-casting pointers to mute warnings */
#define print(num) _Generic((num), \
    int*   : _print_i((int*)num),  \
    float* : _print_f((float*)num))
Peter Varo
  • 11,726
  • 7
  • 55
  • 77
  • 4
    `_Generic` would completely deserve its own tag, but apparently StackOverflow won't let me create it. – Pascal Cuoq Jul 14 '14 at 18:48
  • @PascalCuoq I did, look at the => Flags & Envs – Peter Varo Jul 14 '14 at 18:50
  • 2
    Looks like a false positive. There is a remark somewhere on the Clang website (at the bottom of http://clang-analyzer.llvm.org ) to the effect that they treat the emission of false positives as bugs, so this is worth reporting. – Pascal Cuoq Jul 14 '14 at 18:58
  • Your workaround works in this case, but not in cases where the cast itself triggers a warning; see the example I posted. – Keith Thompson Jul 14 '14 at 20:13
  • @KeithThompson interesting. My workaround works if all the keys in the assoc-list are pointers to types or all are bare types. I changed your example to `int` and `float` and `print_i((int)i)` and `print_f((float)f)` and it is working for that too.. My hack will only fail if the assoc-list's keys are a mix of bare types and pointers to types. – Peter Varo Jul 14 '14 at 20:23
  • The warning I get on my example with your workaround is `cast to 'int *' from smaller integer type 'int'`. Pointer-to-pointer casts don't generally trigger warnings. Casting from `long` to `int*` probably wouldn't trigger a warning either (because they happen to be the same size). – Keith Thompson Jul 14 '14 at 20:25
  • yepp, I have the same here, although `int`s and `float`s are not the same length.. so.. it is still very curious and interesting :D – Peter Varo Jul 14 '14 at 20:26
  • @PeterVaro: I believe you should (a) *not* submit a bug report, and (b) accept [Jens Gustedt's answer](http://stackoverflow.com/a/24746034/827263). – Keith Thompson Jul 14 '14 at 22:09
  • It's now 2020, this bug is still present – rokstar May 18 '20 at 16:45
  • @PeterVaro FYI: the similar [question](https://stackoverflow.com/q/70672947/1778275). – pmor Jan 26 '22 at 21:54

2 Answers2

19

This is not a bug in clang, but unfortunately what the C11 standard requires. All branches of a _Generic primary expression must be a valid expressions, and thus valid under all circumstances. The fact that only one of the branches will ever be evaluated, is not related to this.

Your alternative version is what C11 foresees for situations as this: chose the function (and not the evaluated call) as a result of the type generic expression, and apply that function to the arguments.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • 2
    The problem with what you are saying -- although you mentioned it has nothing to do with the branching -- is that in 6.5.1.1§3: *"The controlling expression of a generic selection is not evaluated."* ... *"None of the expressions from any other generic association of the generic selection is evaluated."* => so it can't be "invalid" at all, because there were no arguments actually passed to the assignment-expression! Anyway, this whole "validity" is way too abstract-phrase in a situation like this, also wondering where does the standard specifies "validity" about assignment-expressions? – Peter Varo Jul 14 '14 at 23:41
  • 1
    @PeterVaro, the expressions in question must be "assignment-expression" as specified in the syntax tree. If they aren't such expressions, they aren't valid. An expression that is not evaluated must still be syntactically correct. You have the same for `sizeof` expressions. In `sizeof *a`, the subexpression `*a` is not evaluated so if `a` would be a null pointer the program wouldn't crash. Nevertheless `*a` must be a valid expression such that the compiler may parse it correctly and also may determine the resulting type (and from that its size). – Jens Gustedt Jul 15 '14 at 14:32
  • now I kinda understand what you meant by "valid" expression, and probably this also explains why my workaround is working when I re-cast the `num` variable directly. However does not explain why the workaround is not working for both types and pointers to types at the same time in the assoc-list! Anyway, what I also don't understand is why is calling a function and passing a variable as argument with a known type (basically == valid syntax) not recognised as valid in the first place (`_print_i(num)`)? – Peter Varo Jul 15 '14 at 14:42
  • @PeterVaro, section 6.5.2.2 "Function calls" has a "constraint" that requires that parameters to functions calls must have the correct type as specified by the prototype for the function. Any "constraint violation" makes a program invalid and requires a diagnostic from the compiler. – Jens Gustedt Jul 15 '14 at 22:35
  • That's of course valid for "regular" function calls, however in "conditional" function calls, I believe it doesn't necessary have to meet those requirements. You see, if only one of the assignment expressions will evaluate (which is the case according to the standard), `num` cannot reach the functions which have different argument types, therefore all statements are valid in their "own situations", so this still looks like a bug to me rather than a proper implementation. – Peter Varo Jul 15 '14 at 22:48
  • @PeterVaro, if execution can reach a statement or not is irrelevant. Dead branches always have to be correct C. E.g in `if (1) { _print_i(num); } else { _print_f(num); }` there is only one branch taken and this fact is known at compile time. Nevertheless this gives you a compile error if `num` is `int*`. (BTW, you shouldn't use function names starting with an underscores, these are reserved by the C standard.) – Jens Gustedt Jul 16 '14 at 06:39
  • Aaaaand yes, you are right, if in the conditional above both of the two functions need pointers to types, the compiler will raise the `-Wincompatible-pointer-types` warning. Thank you for your time, energy and patience! – Peter Varo Jul 16 '14 at 11:30
2

CORRECTION : This is not (as far as I can tell) a bug in clang, but a correct interpretation of how _Generic is supposed to behave. Only one of the generic associations in a generic-selection expression is evaluated, but all of them must be valid expressions. (_Generic does not act like a macro.)

See Jens Gustedt's answer.


This definitely looks like a bug in clang. I'm reasonably sure your code is valid C11. I see the same thing with version 3.4 on Linux Mint.

I've put together a slightly simplified demo :

#include <stdio.h>

static void print_i(int i)   { puts("int"); }
static void print_ip(int *i) { puts("int*"); }

#define print(num) _Generic((num), \
    int    : print_i(num),         \
    int*   : print_ip(num))

int main(void) {
    int i = 10;
    print(i);
    print(&i);
}

The output is correct, but I get the following warnings:

c.c:12:11: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'int *'; take the address with & [-Wint-conversion]
    print(i);
          ^
          &
c.c:8:23: note: expanded from macro 'print'
    int*   : print_ip(num))
                      ^
c.c:4:27: note: passing argument to parameter 'i' here
static void print_ip(int *i) { puts("int*"); }
                          ^
c.c:13:11: warning: incompatible pointer to integer conversion passing 'int *' to parameter of type 'int'; remove & [-Wint-conversion]
    print(&i);
          ^~
c.c:7:22: note: expanded from macro 'print'
    int    : print_i(num),         \
                     ^
c.c:3:25: note: passing argument to parameter 'i' here
static void print_i(int i)   { puts("int"); }
                        ^
2 warnings generated.

Community
  • 1
  • 1
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631