Fix thinko in new warning on type punning for storage order purposes
authorEric Botcazou <ebotcazou@adacore.com>
Sun, 6 Jun 2021 09:37:45 +0000 (11:37 +0200)
committerEric Botcazou <ebotcazou@adacore.com>
Sun, 6 Jun 2021 09:41:30 +0000 (11:41 +0200)
In C, unlike in Ada, the storage order of arrays is that of their component
type, so you need to look at it when deciding to warn.  And the PR complains
about a bogus warning on the assignment of a pointer returned by alloca or
malloc, so this also fixes that.

gcc/c
PR c/100920
* c-decl.c (finish_struct): Fix thinko in previous change.
* c-typeck.c (convert_for_assignment): Do not warn on pointer
assignment and initialization for storage order purposes if the
RHS is a call to a DECL_IS_MALLOC function.
gcc/testsuite/
* gcc.dg/sso-14.c: New test.

gcc/c/c-decl.c
gcc/c/c-typeck.c
gcc/testsuite/gcc.dg/sso-14.c [new file with mode: 0644]

index 28f851b..a86792b 100644 (file)
@@ -8854,12 +8854,21 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
            }
        }
 
+      /* Warn on problematic type punning for storage order purposes.  */
       if (TREE_CODE (t) == UNION_TYPE
-         && AGGREGATE_TYPE_P (TREE_TYPE (field))
-         && TYPE_REVERSE_STORAGE_ORDER (t)
-            != TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (field)))
-       warning_at (DECL_SOURCE_LOCATION (field), OPT_Wscalar_storage_order,
-                   "type punning toggles scalar storage order");
+         && TREE_CODE (field) == FIELD_DECL
+         && AGGREGATE_TYPE_P (TREE_TYPE (field)))
+       {
+         tree ftype = TREE_TYPE (field);
+         if (TREE_CODE (ftype) == ARRAY_TYPE)
+           ftype = strip_array_types (ftype);
+         if (RECORD_OR_UNION_TYPE_P (ftype)
+             && TYPE_REVERSE_STORAGE_ORDER (ftype)
+                != TYPE_REVERSE_STORAGE_ORDER (t))
+           warning_at (DECL_SOURCE_LOCATION (field),
+                       OPT_Wscalar_storage_order,
+                       "type punning toggles scalar storage order");
+       }
     }
 
   /* Now we have the truly final field list.
index be3f4f0..daa2e12 100644 (file)
@@ -7295,6 +7295,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
          && (AGGREGATE_TYPE_P (ttl) && TYPE_REVERSE_STORAGE_ORDER (ttl))
             != (AGGREGATE_TYPE_P (ttr) && TYPE_REVERSE_STORAGE_ORDER (ttr)))
        {
+         tree t;
+
          switch (errtype)
          {
          case ic_argpass:
@@ -7307,14 +7309,23 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
                          "scalar storage order", parmnum, rname);
            break;
          case ic_assign:
-           warning_at (location, OPT_Wscalar_storage_order,
-                       "assignment to %qT from pointer type %qT with "
-                       "incompatible scalar storage order", type, rhstype);
+           /* Do not warn if the RHS is a call to a function that returns a
+              pointer that is not an alias.  */
+           if (TREE_CODE (rhs) != CALL_EXPR
+               || (t = get_callee_fndecl (rhs)) == NULL_TREE
+               || !DECL_IS_MALLOC (t))
+             warning_at (location, OPT_Wscalar_storage_order,
+                         "assignment to %qT from pointer type %qT with "
+                         "incompatible scalar storage order", type, rhstype);
            break;
          case ic_init:
-           warning_at (location, OPT_Wscalar_storage_order,
-                       "initialization of %qT from pointer type %qT with "
-                       "incompatible scalar storage order", type, rhstype);
+           /* Likewise.  */
+           if (TREE_CODE (rhs) != CALL_EXPR
+               || (t = get_callee_fndecl (rhs)) == NULL_TREE
+               || !DECL_IS_MALLOC (t))
+             warning_at (location, OPT_Wscalar_storage_order,
+                         "initialization of %qT from pointer type %qT with "
+                         "incompatible scalar storage order", type, rhstype);
            break;
          case ic_return:
            warning_at (location, OPT_Wscalar_storage_order,
diff --git a/gcc/testsuite/gcc.dg/sso-14.c b/gcc/testsuite/gcc.dg/sso-14.c
new file mode 100644 (file)
index 0000000..af98145
--- /dev/null
@@ -0,0 +1,53 @@
+/* PR c/100920 */
+/* Testcase by George Thopas <george.thopas@gmail.com> */
+
+/* { dg-do compile } */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define REV_ENDIANNESS __attribute__((scalar_storage_order("big-endian")))
+#else
+#define REV_ENDIANNESS __attribute__((scalar_storage_order("little-endian")))
+#endif
+
+struct s_1 {
+    int val;
+} REV_ENDIANNESS;
+
+typedef struct s_1 t_1;
+
+struct s_2 {
+    char val;
+} REV_ENDIANNESS;
+
+typedef struct s_2 t_2;
+
+struct s12 {
+    t_1 a[1];
+    t_2 b[1]; 
+} REV_ENDIANNESS;
+
+typedef struct s12 t_s12;
+
+union u12 {
+    t_1 a[1];
+    t_2 b[1];
+} REV_ENDIANNESS;
+
+typedef union u12 t_u12;
+
+int main(void)
+{
+  t_s12 *msg1 = __builtin_alloca(10);
+  t_u12 *msg2 = __builtin_alloca(10);
+
+  msg1 = malloc (sizeof (t_s12));
+  msg2 = malloc (sizeof (t_u12));
+
+  msg1->a[0].val = 0;
+  msg2->a[0].val = 0;
+
+  return 0;
+}