The following is an attempt to fix PR71598 where C (and C++?) have an implementation-defined compatible integer type for each enum and the TBAA rules mandate that accesses using a compatible type are allowed.
The fix is applied to all C family frontends and the LTO frontend but not Fortran, Ada or other languages. Bootstrap & regtest running on x86_64-unknown-linux-gnu. I've tried to cover most cases even those with -fshort-enums. OK for trunk? It's probably a regression to some ancient GCC that didn't perform TBAA and given it's wrong-code a backport is probably mandated - do you agree? (after a while with no reported issues, of course) Thanks, Richard. 2019-03-15 Richard Biener <rguent...@suse.de> PR c/71598 * gimple.c: Include langhooks.h. (gimple_get_alias_set): Treat enumeral types as the underlying integer type. c-family/ * c-common.c (c_common_get_alias_set): Treat enumeral types as the underlying integer type. * c-c++-common/torture/pr71598-1.c: New testcase. * c-c++-common/torture/pr71598-2.c: Likewise. Index: gcc/gimple.c =================================================================== --- gcc/gimple.c (revision 269704) +++ gcc/gimple.c (working copy) @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. #include "stringpool.h" #include "attribs.h" #include "asan.h" +#include "langhooks.h" /* All the tuples have their operand vector (if present) at the very bottom @@ -2587,6 +2588,16 @@ gimple_get_alias_set (tree t) return get_alias_set (t1); } + /* Allow aliasing between enumeral types and the underlying + integer type. This is required for C since those are + compatible types. */ + else if (TREE_CODE (t) == ENUMERAL_TYPE) + { + tree t1 = lang_hooks.types.type_for_size (tree_to_uhwi (TYPE_SIZE (t)), + false /* short-cut above */); + return get_alias_set (t1); + } + return -1; } Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c (revision 269704) +++ gcc/c-family/c-common.c (working copy) @@ -3681,6 +3681,15 @@ c_common_get_alias_set (tree t) return get_alias_set (t1); } + /* Allow aliasing between enumeral types and the underlying + integer type. This is required since those are compatible types. */ + else if (TREE_CODE (t) == ENUMERAL_TYPE) + { + tree t1 = c_common_type_for_size (tree_to_uhwi (TYPE_SIZE (t)), + false /* short-cut above */); + return get_alias_set (t1); + } + return -1; } Index: gcc/testsuite/c-c++-common/torture/pr71598-1.c =================================================================== --- gcc/testsuite/c-c++-common/torture/pr71598-1.c (nonexistent) +++ gcc/testsuite/c-c++-common/torture/pr71598-1.c (working copy) @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fno-short-enums" } */ + +enum e1 { c1 }; + +__attribute__((noinline,noclone)) +int f(enum e1 *p, unsigned *q) +{ + *p = c1; + *q = 2; + return *p; +} + +int main() +{ + unsigned x; + + if (f((enum e1 *)&x, &x) != 2) + __builtin_abort(); + return 0; +} Index: gcc/testsuite/c-c++-common/torture/pr71598-2.c =================================================================== --- gcc/testsuite/c-c++-common/torture/pr71598-2.c (nonexistent) +++ gcc/testsuite/c-c++-common/torture/pr71598-2.c (working copy) @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fshort-enums" } */ + +enum e1 { c1 = -__INT_MAX__ }; + +__attribute__((noinline,noclone)) +int f(enum e1 *p, signed int *q) +{ + *p = c1; + *q = 2; + return *p; +} + +enum e2 { c2 = __SHRT_MAX__ + 1}; + +__attribute__((noinline,noclone)) +int g(enum e2 *p, unsigned short *q) +{ + *p = c2; + *q = 2; + return *p; +} + +enum e3 { c3 = __SCHAR_MAX__ }; + +__attribute__((noinline,noclone)) +int h(enum e3 *p, unsigned char *q) +{ + *p = c3; + *q = 2; + return *p; +} + +int main() +{ + signed x; + unsigned short y; + unsigned char z; + + if (f((enum e1 *)&x, &x) != 2) + __builtin_abort(); + if (g((enum e2 *)&y, &y) != 2) + __builtin_abort(); + if (h((enum e3 *)&z, &z) != 2) + __builtin_abort(); + return 0; +}