https://gcc.gnu.org/g:867d1264fe71d4291194373d1a1c409cac97a597

commit r15-933-g867d1264fe71d4291194373d1a1c409cac97a597
Author: Martin Uecker <uec...@tugraz.at>
Date:   Sun May 19 23:13:22 2024 +0200

    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.

Diff:
---
 gcc/c-family/c-attribs.cc           |  1 +
 gcc/c/c-decl.cc                     | 11 +++++++++--
 gcc/c/c-objc-common.cc              |  7 ++-----
 gcc/godump.cc                       | 10 +++-------
 gcc/testsuite/gcc.dg/enum-alias-1.c | 24 ++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/enum-alias-2.c | 25 +++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/enum-alias-3.c | 26 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/enum-alias-4.c | 22 ++++++++++++++++++++++
 8 files changed, 112 insertions(+), 14 deletions(-)

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 605469dd7dd..e3833ed5f20 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -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)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b691b91b3db..6e6606c9570 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -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);
     }
 
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 42a62c84fe7..283f6a8ae26 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -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))
diff --git a/gcc/godump.cc b/gcc/godump.cc
index 66e73ade7df..6784bd70e37 100644
--- a/gcc/godump.cc
+++ b/gcc/godump.cc
@@ -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
index 00000000000..8fa30eb7897
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/enum-alias-1.c
@@ -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
index 00000000000..7ca3f3b2db8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/enum-alias-2.c
@@ -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
index 00000000000..36a4f02a455
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/enum-alias-3.c
@@ -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
index 00000000000..b78d0451e3e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/enum-alias-4.c
@@ -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();
+}
+

Reply via email to