-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Description
Currently clang
does not produce a warning if the value of a tagged union that doesn't correspond to its type tag is accessed.
For example, this code:
// warn.c
#include <stdio.h>
enum T { I, F };
union U { int i; float f; };
struct S { enum T t; union U u; };
int main(void) {
struct S s = { .t = F, .u.f = 12345.67890f };
switch (s.t) {
case I:
printf("%d\n", s.u.i);
break;
case F:
// copied the above case
// but neglected to update the code
printf("%d\n", s.u.i);
break;
}
}
Does not produce any warning when compiled, leading to incorrect results:
$ clang -Weverything -o warn warn.c && ./warn
1178658487
I understand that union
s are typically used for type punning and that such accesses are often intended by the programmer but compiler checks would still be beneficial when that's not the case. People have created C preprocessor solutions to use tagged unions safely in C. I've also seen support for safe tagged unions in newer languages like Zig.
A compiler mechanism to establish a relationship between the union
values and their corresponding enum
tags would be extremely useful. Something like this, perhaps:
struct S {
enum T t;
union U {
int i __attribute__((tag(t, I)));
float f __attribute__((tag(t, F)));
} u;
};
Then clang
would be able to warn when union
values are accessed in a context where their specified tags are not known to be the correct value:
switch (s.t) {
case I:
// i is accessed
// the tag of i is t
// t is supposed to equal I
// compiler knows t equals I because of switch case
// correct, no warning is emitted
printf("%d\n", s.u.i);
break;
case F:
// i is accessed
// the tag of i is t
// t is supposed to equal I
// compiler knows t equals F because of switch case
// incorrect, a warning is emitted
printf("%d\n", s.u.i);
break;
}
Relevant links: