mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
C: allow aliasing of compatible types derived from enumeral types [PR115157]
Aliasing of enumeral types with the underlying integer is now allowed by setting the aliasing set to zero. But this does not allow aliasing of derived types which are compatible as required by ISO C. Instead, initially set structural equality. Then set TYPE_CANONICAL and update pointers and main variants when the type is completed (as done for structures and unions in C23). PR tree-optimization/115157 PR tree-optimization/115177 gcc/c/ * c-decl.cc (shadow_tag-warned,parse_xref_tag,start_enum, finish_enum): Set SET_TYPE_STRUCTURAL_EQUALITY / TYPE_CANONICAL. * c-objc-common.cc (get_alias_set): Remove special case. (get_aka_type): Add special case. gcc/c-family/ * c-attribs.cc (handle_hardbool_attribute): Set TYPE_CANONICAL for hardbools. gcc/ * godump.cc (go_output_typedef): Use TYPE_MAIN_VARIANT instead of TYPE_CANONICAL. gcc/testsuite/ * gcc.dg/enum-alias-1.c: New test. * gcc.dg/enum-alias-2.c: New test. * gcc.dg/enum-alias-3.c: New test. * gcc.dg/enum-alias-4.c: New test.
This commit is contained in:
parent
3a873c0a7b
commit
867d1264fe
@ -1074,6 +1074,7 @@ handle_hardbool_attribute (tree *node, tree name, tree args,
|
||||
|
||||
TREE_SET_CODE (*node, ENUMERAL_TYPE);
|
||||
ENUM_UNDERLYING_TYPE (*node) = orig;
|
||||
TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig);
|
||||
|
||||
tree false_value;
|
||||
if (args)
|
||||
|
@ -5051,7 +5051,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
|
||||
if (t == NULL_TREE)
|
||||
{
|
||||
t = make_node (code);
|
||||
if (flag_isoc23 && code != ENUMERAL_TYPE)
|
||||
if (flag_isoc23 || code == ENUMERAL_TYPE)
|
||||
SET_TYPE_STRUCTURAL_EQUALITY (t);
|
||||
pushtag (input_location, name, t);
|
||||
}
|
||||
@ -8828,7 +8828,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name,
|
||||
the forward-reference will be altered into a real type. */
|
||||
|
||||
ref = make_node (code);
|
||||
if (flag_isoc23 && code != ENUMERAL_TYPE)
|
||||
if (flag_isoc23 || code == ENUMERAL_TYPE)
|
||||
SET_TYPE_STRUCTURAL_EQUALITY (ref);
|
||||
if (code == ENUMERAL_TYPE)
|
||||
{
|
||||
@ -9919,6 +9919,7 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
|
||||
{
|
||||
enumtype = make_node (ENUMERAL_TYPE);
|
||||
TYPE_SIZE (enumtype) = NULL_TREE;
|
||||
SET_TYPE_STRUCTURAL_EQUALITY (enumtype);
|
||||
pushtag (loc, name, enumtype);
|
||||
if (fixed_underlying_type != NULL_TREE)
|
||||
{
|
||||
@ -9935,6 +9936,8 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
|
||||
TYPE_SIZE (enumtype) = NULL_TREE;
|
||||
TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type);
|
||||
ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type;
|
||||
TYPE_CANONICAL (enumtype) = TYPE_CANONICAL (fixed_underlying_type);
|
||||
c_update_type_canonical (enumtype);
|
||||
layout_type (enumtype);
|
||||
}
|
||||
}
|
||||
@ -10094,6 +10097,10 @@ finish_enum (tree enumtype, tree values, tree attributes)
|
||||
ENUM_UNDERLYING_TYPE (enumtype) =
|
||||
c_common_type_for_size (TYPE_PRECISION (tem), TYPE_UNSIGNED (tem));
|
||||
|
||||
TYPE_CANONICAL (enumtype) =
|
||||
TYPE_CANONICAL (ENUM_UNDERLYING_TYPE (enumtype));
|
||||
c_update_type_canonical (enumtype);
|
||||
|
||||
layout_type (enumtype);
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,8 @@ get_aka_type (tree type)
|
||||
|
||||
result = get_aka_type (orig_type);
|
||||
}
|
||||
else if (TREE_CODE (type) == ENUMERAL_TYPE)
|
||||
return type;
|
||||
else
|
||||
{
|
||||
tree canonical = TYPE_CANONICAL (type);
|
||||
@ -418,11 +420,6 @@ c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED)
|
||||
alias_set_type
|
||||
c_get_alias_set (tree t)
|
||||
{
|
||||
/* Allow aliasing between enumeral types and the underlying
|
||||
integer type. This is required since those are compatible types. */
|
||||
if (TREE_CODE (t) == ENUMERAL_TYPE)
|
||||
return get_alias_set (ENUM_UNDERLYING_TYPE (t));
|
||||
|
||||
/* Structs with variable size can alias different incompatible
|
||||
structs. Let them alias anything. */
|
||||
if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t))
|
||||
|
@ -1118,10 +1118,8 @@ go_output_typedef (class godump_container *container, tree decl)
|
||||
separately. */
|
||||
if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
|
||||
&& TYPE_SIZE (TREE_TYPE (decl)) != 0
|
||||
&& !container->decls_seen.contains (TREE_TYPE (decl))
|
||||
&& (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
|
||||
|| !container->decls_seen.contains
|
||||
(TYPE_CANONICAL (TREE_TYPE (decl)))))
|
||||
&& !container->decls_seen.contains
|
||||
(TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
|
||||
{
|
||||
tree element;
|
||||
|
||||
@ -1163,9 +1161,7 @@ go_output_typedef (class godump_container *container, tree decl)
|
||||
mhval->value = xstrdup (buf);
|
||||
*slot = mhval;
|
||||
}
|
||||
container->decls_seen.add (TREE_TYPE (decl));
|
||||
if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
|
||||
container->decls_seen.add (TYPE_CANONICAL (TREE_TYPE (decl)));
|
||||
container->decls_seen.add (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
|
||||
}
|
||||
|
||||
if (DECL_NAME (decl) != NULL_TREE)
|
||||
|
24
gcc/testsuite/gcc.dg/enum-alias-1.c
Normal file
24
gcc/testsuite/gcc.dg/enum-alias-1.c
Normal file
@ -0,0 +1,24 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
enum E { E1 = -1, E2 = 0, E3 = 1 };
|
||||
|
||||
typedef int A;
|
||||
typedef enum E B;
|
||||
|
||||
_Static_assert(_Generic((A){ 0 }, B: 1), "");
|
||||
|
||||
void* foo(void* a, void *b, A *c, B *d)
|
||||
{
|
||||
*(A**)a = c;
|
||||
*(B**)b = d;
|
||||
return *(A**)a;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A *a, b, c;
|
||||
if (&c != (A*)foo(&a, &a, &b, &c))
|
||||
__builtin_abort();
|
||||
}
|
||||
|
25
gcc/testsuite/gcc.dg/enum-alias-2.c
Normal file
25
gcc/testsuite/gcc.dg/enum-alias-2.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef int A;
|
||||
|
||||
void* foo(void* a, void *b, void *c, void *d)
|
||||
{
|
||||
*(A**)a = c;
|
||||
|
||||
{
|
||||
typedef enum E B;
|
||||
enum E { E1 = -1, E2 = 0, E3 = 1 };
|
||||
*(B**)b = d;
|
||||
}
|
||||
|
||||
return *(A**)a;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A *a, b, c;
|
||||
if (&c != (A*)foo(&a, &a, &b, &c))
|
||||
__builtin_abort();
|
||||
}
|
||||
|
26
gcc/testsuite/gcc.dg/enum-alias-3.c
Normal file
26
gcc/testsuite/gcc.dg/enum-alias-3.c
Normal file
@ -0,0 +1,26 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -flto" } */
|
||||
|
||||
typedef int *A;
|
||||
|
||||
void* foo(void* a, void *b, void *c, void *d)
|
||||
{
|
||||
*(A**)a = c;
|
||||
|
||||
typedef enum E *B;
|
||||
enum E { E1 = -1, E2 = 0, E3 = 1 };
|
||||
{
|
||||
*(B**)b = d;
|
||||
}
|
||||
|
||||
return *(A**)a;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A *a, b, c;
|
||||
if (&c != (A*)foo(&a, &a, &b, &c))
|
||||
__builtin_abort();
|
||||
}
|
||||
|
||||
|
22
gcc/testsuite/gcc.dg/enum-alias-4.c
Normal file
22
gcc/testsuite/gcc.dg/enum-alias-4.c
Normal file
@ -0,0 +1,22 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef int A;
|
||||
typedef int __attribute__ (( hardbool(0, 1) )) B;
|
||||
|
||||
_Static_assert(_Generic((A*){ 0 }, B*: 1), "");
|
||||
|
||||
void* foo(void* a, void *b, A *c, B *d)
|
||||
{
|
||||
*(A**)a = c;
|
||||
*(B**)b = d;
|
||||
return *(A**)a;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
A *a, b, c;
|
||||
if (&c != (A*)foo(&a, &a, &b, &c))
|
||||
__builtin_abort();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user