]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
C: allow aliasing of compatible types derived from enumeral types [PR115157]
authorMartin Uecker <uecker@tugraz.at>
Sun, 19 May 2024 21:13:22 +0000 (23:13 +0200)
committerMartin Uecker <uecker@tugraz.at>
Fri, 31 May 2024 05:12:15 +0000 (07:12 +0200)
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.

gcc/c-family/c-attribs.cc
gcc/c/c-decl.cc
gcc/c/c-objc-common.cc
gcc/godump.cc
gcc/testsuite/gcc.dg/enum-alias-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/enum-alias-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/enum-alias-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/enum-alias-4.c [new file with mode: 0644]

index 605469dd7dd42c0be5f77a257eb8f223751d44c5..e3833ed5f201d60f92c70bf5500e3086594de3eb 100644 (file)
@@ -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)
index b691b91b3db410ad7ed3c6ca6397214bf2c51229..6e6606c9570854f8907162f78f3f071e5836c1e4 100644 (file)
@@ -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);
     }
 
index 42a62c84fe7c752840cf9619cb2f249adf580e0b..283f6a8ae2652877b8ec3476e26da6792020c006 100644 (file)
@@ -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))
index 66e73ade7df8f3e9abdc9c16776733a67ce97d95..6784bd70e379e8bcc8e1e811ec75643f34c08bf8 100644 (file)
@@ -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)
diff --git a/gcc/testsuite/gcc.dg/enum-alias-1.c b/gcc/testsuite/gcc.dg/enum-alias-1.c
new file mode 100644 (file)
index 0000000..8fa30eb
--- /dev/null
@@ -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();
+}
+
diff --git a/gcc/testsuite/gcc.dg/enum-alias-2.c b/gcc/testsuite/gcc.dg/enum-alias-2.c
new file mode 100644 (file)
index 0000000..7ca3f3b
--- /dev/null
@@ -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();
+}
+
diff --git a/gcc/testsuite/gcc.dg/enum-alias-3.c b/gcc/testsuite/gcc.dg/enum-alias-3.c
new file mode 100644 (file)
index 0000000..36a4f02
--- /dev/null
@@ -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();
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/enum-alias-4.c b/gcc/testsuite/gcc.dg/enum-alias-4.c
new file mode 100644 (file)
index 0000000..b78d045
--- /dev/null
@@ -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();
+}
+