<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/74205>74205</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
`clang` feature request: warn on incorrect tagged union value access
</td>
</tr>
<tr>
<th>Labels</th>
<td>
clang
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
matheusmoreira
</td>
</tr>
</table>
<pre>
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:
```C
// 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:
```shell
$ 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][1] 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:
```C
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:
```C
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:
- lone-lang/lone#1
[1]: https://github.com/Hirrolot/datatype99
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMVk1v4zYQ_TX0ZRBBpizLOviQ2DWaW9HdokAvAUWNLDYUqSWHyfrfF6RsR8lm06LoAg0Mh5aGw_l47w2F9-poELesvGPlfiEC9dZtB0E9Bj9Yh8qJRWPb03YXnEND-gRsnUstzJGtc2gtejCWYHS2DRJBwLNwRpkjqA6oR3gSOiDYDgSQOB6xhWCUNUC9oLTdMF4RSOsc-tGaFsiCIg90GjFuAeVBSIneY5uxfM_y2-n7YB3gVzGMGhnfAfXKg7QtsuJ2bsbW-fTZnX_zA-OHFGYmL48KZaQOLQIrdp5aZbOeFT_N3aAJA3wGVt3BfTzuAKzas-Juejvl9Ft6rQyBYsUddNoKgi4u57aeXJAEn5Lx2S1Fo4uT8HbH9B39DkIZxjdPVrWM19HDxaK-uvXAin1ynlFaHmK8Wci69GvJi1WZratNnXdvTqn9syLZA-Mbn9HbA6TwCPez6tYsr0enDHWMbxjnjJctK3cmLXfgs5Apxuv5ASyvG4ficf4s-T288XvukrSjwjYBSTT2CSEav2PXBAKDR42SMCEojK0gTBsTJv7bkGPZpvV1cUHZvGP7b9hhTld-PPdoQNphVBrbeLhG0cYXEf8m8UESOPRBk_8epn2PWl9AvILES7j5HZ_QnaiP3m5sOvGMd2B8zfgaMsYP8cm0dbmsNutys9pUHyRzD8G06DyJyNHIXrbOE2RjHCAcRsoqKbQ-QfDYQmfdxOIxmJTydacPsr-QetpqO0ITqYOmxRaaU2rd6OzRiWFAlzp8rpYD2aN89PBsg27Bk9IaGoQGDXZKKqGn4sajGK-mFiQkCI8ZsPLuF7SjRuhFRJRDEUGzg9Hh6GwMyjrwVgdS1nhW7ll5t2TlPuHK4ysd8-BFh_oEysAui9JQPSEI7S14RAM-jKN1lGoRLd9sVgYMPqOD2LggjuhBq0eEP9TxldbdvuQ-oOyFUX6I4aAn0WjlexDgUIsUca9GaJCeMdUA532a5NifO4HKzYQ3doit86hI0ZLE8VLhBgG_ksMBp9Z2QWfwyQ44QSxFHOU3onhE14vxu4DdfauBV1bNtPD6bCasc0YmjYWHB0HkVBMIHx4SoTckjvE7RnIfiTx9XtP5rMsQ_z52cXjfRbVPGv0iAdf1e8T5HLE4H5rXoopGY-ziRNCz2TetcnidfxEvAqQ1hF8p7nB4bqMfUaouaWXsW9wUUf9o7LOJRzQXLZxkJfn-u0H5b-bBWY_VfGq_8z7GEme77SZTes8mvkj88ZOm45cgNNy_OybO5Ij5eqDJ1MM9NChF5Kzt4JzMdybIuTKx68a-XGI84KCIXifxg4fe_6R4h39evOu8iiUQP756H4_dX1HjkzAEWpnHt0oEN6CtwZtERn6Ia8aL5SsiTHLPilvoiSYtS3keFfWhyaQdGD_8rJyz2hLjh1aQiIOurhfttmjrohYL3C6rfFmuik1eLPptUZVNuWyXcrVZ16u6bqqyEZVcSbFuZLUsF2rLc14sec6XdV7wIqu53OT1Om-61bJdd2u2ynEQSmdaPw2ZdceF8j7gtlrxvFxo0aD26R7P-aQ0nMcrvdtG-5smHD1b5Vp58i8eSJHG7VybOhQUHILDLwE9xRokdbJmdil5dZGfLvgTXBfB6e0HNYsHn__djM7-mRBzSHl4xg8plb8CAAD__zdIvlc">