]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix handling of non-integral bit-fields in native_encode_initializer
authorEric Botcazou <ebotcazou@adacore.com>
Tue, 23 May 2023 08:15:35 +0000 (10:15 +0200)
committerEric Botcazou <ebotcazou@adacore.com>
Tue, 23 May 2023 08:17:13 +0000 (10:17 +0200)
The encoder for CONSTRUCTORs assumes that all bit-fields (DECL_BIT_FIELD)
have integral types, but that's not the case in Ada where they may have
pretty much any type, resulting in a wrong encoding for them

gcc/
* fold-const.cc (native_encode_initializer) <CONSTRUCTOR>: Apply the
specific treatment for bit-fields only if they have an integral type
and filter out non-integral bit-fields that do not start and end on
a byte boundary.

gcc/testsuite/
* gnat.dg/opt101.adb: New test.
* gnat.dg/opt101_pkg.ads: New helper.

gcc/fold-const.cc
gcc/testsuite/gnat.dg/opt101.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/opt101_pkg.ads [new file with mode: 0644]

index 25466e97220573a1ef9783980850c44dc9f8d3f0..57521501fff2678d7cacb44f666ac8ebde5bc104 100644 (file)
@@ -8360,20 +8360,26 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
              if (fieldsize == 0)
                continue;
 
+             /* Prepare to deal with integral bit-fields and filter out other
+                bit-fields that do not start and end on a byte boundary.  */
              if (DECL_BIT_FIELD (field))
                {
                  if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field)))
                    return 0;
-                 fieldsize = TYPE_PRECISION (TREE_TYPE (field));
                  bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field));
-                 if (bpos % BITS_PER_UNIT)
-                   bpos %= BITS_PER_UNIT;
-                 else
-                   bpos = 0;
-                 fieldsize += bpos;
-                 epos = fieldsize % BITS_PER_UNIT;
-                 fieldsize += BITS_PER_UNIT - 1;
-                 fieldsize /= BITS_PER_UNIT;
+                 if (INTEGRAL_TYPE_P (TREE_TYPE (field)))
+                   {
+                     bpos %= BITS_PER_UNIT;
+                     fieldsize = TYPE_PRECISION (TREE_TYPE (field)) + bpos;
+                     epos = fieldsize % BITS_PER_UNIT;
+                     fieldsize += BITS_PER_UNIT - 1;
+                     fieldsize /= BITS_PER_UNIT;
+                   }
+                 else if (bpos % BITS_PER_UNIT
+                          || DECL_SIZE (field) == NULL_TREE
+                          || !tree_fits_shwi_p (DECL_SIZE (field))
+                          || tree_to_shwi (DECL_SIZE (field)) % BITS_PER_UNIT)
+                   return 0;
                }
 
              if (off != -1 && pos + fieldsize <= off)
@@ -8382,7 +8388,8 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
              if (val == NULL_TREE)
                continue;
 
-             if (DECL_BIT_FIELD (field))
+             if (DECL_BIT_FIELD (field)
+                 && INTEGRAL_TYPE_P (TREE_TYPE (field)))
                {
                  /* FIXME: Handle PDP endian.  */
                  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
diff --git a/gcc/testsuite/gnat.dg/opt101.adb b/gcc/testsuite/gnat.dg/opt101.adb
new file mode 100644 (file)
index 0000000..68773bb
--- /dev/null
@@ -0,0 +1,23 @@
+-- { dg-do run }
+-- { dg-options "-O" }
+
+pragma Optimize_Alignment (Space);
+
+with Opt101_Pkg; use Opt101_Pkg;
+
+procedure Opt101 is
+
+  C1 : Cont1;
+  C2 : Cont2;
+
+begin
+  C1 := ((1234, 1, 2), 1, 2);
+  if C1.R.I1 /= 1 or C1.I2 /= 2 then
+    raise Program_Error;
+  end if;
+
+  C2 := (1, (1234, 1, 2), 2);
+  if C2.R.I1 /= 1 or C2.I2 /= 2 then
+    raise Program_Error;
+  end if;
+end;
diff --git a/gcc/testsuite/gnat.dg/opt101_pkg.ads b/gcc/testsuite/gnat.dg/opt101_pkg.ads
new file mode 100644 (file)
index 0000000..0c843df
--- /dev/null
@@ -0,0 +1,26 @@
+package Opt101_Pkg is
+
+  type Int is mod 16;
+
+  type Rec is record
+    S : Short_Integer;
+    I1, I2 : Int;
+  end record;
+  pragma Pack (Rec);
+  for Rec'Alignment use 4;
+
+  type Cont1 is record
+    R : Rec;
+    I1, I2 : Int;
+  end record;
+  pragma Pack (Cont1);
+
+  type Cont2 is record
+    I1 : Int;
+    R  : Rec;
+    I2 : Int;
+  end record;
+  pragma Pack (Cont2);
+  pragma No_Component_Reordering (Cont2);
+
+end Opt101_Pkg;