Fix incorrect handling of Component_Size
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 25 May 2020 08:04:10 +0000 (10:04 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 25 May 2020 08:07:04 +0000 (10:07 +0200)
The compiler can mishandle a Component_Size clause on an array type
specifying a size multiple of the storage unit, when this size is
not a multiple of the alignment of the component type.

gcc/ada/ChangeLog
* gcc-interface/decl.c (gnat_to_gnu_component_type): Cap alignment
of the component type according to the component size.

gcc/testsuite/ChangeLog
* gnat.dg/array40.adb: New test.
* gnat.dg/array40_pkg.ads: New helper.

gcc/ada/ChangeLog
gcc/ada/gcc-interface/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/array40.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array40_pkg.ads [new file with mode: 0644]

index a900f53..e4892ee 100644 (file)
@@ -1,5 +1,10 @@
 2020-05-25  Eric Botcazou  <ebotcazou@adacore.com>
 
+       * gcc-interface/decl.c (gnat_to_gnu_component_type): Cap the alignment
+       of the component type according to the component size.
+
+2020-05-25  Eric Botcazou  <ebotcazou@adacore.com>
+
        * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Array_Type>: Add a
        description of the various types associated with the unconstrained
        type.  Declare the fat pointer earlier.  Set the current function
@@ -11,6 +16,7 @@
        fat pointer types and tidy up accordingly.
        * gcc-interface/utils.c (build_unc_object_type): Do not set the
        context on the template type.
+       (gnat_pushdecl): Mark the canonical fat pointer types as artificial.
 
 2020-05-25  Eric Botcazou  <ebotcazou@adacore.com>
 
index a36b129..ab6e79c 100644 (file)
@@ -5153,7 +5153,7 @@ gnat_to_gnu_component_type (Entity_Id gnat_array, bool definition,
   unsigned int max_align;
 
   /* If an alignment is specified, use it as a cap on the component type
-     so that it can be honored for the whole type.  But ignore it for the
+     so that it can be honored for the whole type, but ignore it for the
      original type of packed array types.  */
   if (No (Packed_Array_Impl_Type (gnat_array))
       && Known_Alignment (gnat_array))
@@ -5200,6 +5200,7 @@ gnat_to_gnu_component_type (Entity_Id gnat_array, bool definition,
   if (gnu_comp_size && !is_bit_packed)
     {
       tree orig_type = gnu_type;
+      unsigned int gnu_comp_align;
 
       gnu_type = make_type_from_size (gnu_type, gnu_comp_size, false);
       if (max_align > 0 && TYPE_ALIGN (gnu_type) > max_align)
@@ -5207,8 +5208,22 @@ gnat_to_gnu_component_type (Entity_Id gnat_array, bool definition,
       else
        orig_type = gnu_type;
 
-      gnu_type = maybe_pad_type (gnu_type, gnu_comp_size, 0, gnat_array,
-                                true, definition, true);
+      /* We need to make sure that the size is a multiple of the alignment.
+        But we do not misalign the component type because of the alignment
+        of the array type here; this either must have been done earlier in
+        the packed case or should be rejected in the non-packed case.  */
+      if (TREE_CODE (gnu_comp_size) == INTEGER_CST)
+       {
+         const unsigned HOST_WIDE_INT int_size = tree_to_uhwi (gnu_comp_size);
+         gnu_comp_align = int_size & -int_size;
+         if (gnu_comp_align > TYPE_ALIGN (gnu_type))
+           gnu_comp_align = 0;
+       }
+       else
+        gnu_comp_align = 0;
+
+      gnu_type = maybe_pad_type (gnu_type, gnu_comp_size, gnu_comp_align,
+                                gnat_array, true, definition, true);
 
       /* If a padding record was made, declare it now since it will never be
         declared otherwise.  This is necessary to ensure that its subtrees
index 3bbe2e3..6e839c1 100644 (file)
@@ -1,5 +1,10 @@
 2020-05-25  Eric Botcazou  <ebotcazou@adacore.com>
 
+       * gnat.dg/array40.adb: New test.
+       * gnat.dg/array40_pkg.ads: New helper.
+
+2020-05-25  Eric Botcazou  <ebotcazou@adacore.com>
+
        * gnat.dg/array39.adb: New test.
        * gnat.dg/array39_pkg.ads: New helper.
        * gnat.dg/array39_pkg.adb: Likewise.
diff --git a/gcc/testsuite/gnat.dg/array40.adb b/gcc/testsuite/gnat.dg/array40.adb
new file mode 100644 (file)
index 0000000..227288d
--- /dev/null
@@ -0,0 +1,21 @@
+-- { dg-do run }
+-- { dg-options "-gnatws" }
+
+with System.Storage_Elements;
+with Array40_Pkg; use Array40_Pkg;
+
+procedure Array40 is
+
+  use System;
+  use System.Storage_Elements;
+
+begin
+  if A(1)'Size /= 40 then
+    raise Program_Error;
+  end if;
+
+  if (A(2)'Address - A(1)'Address) * System.Storage_Unit /= 40 then
+    raise Program_Error;
+  end if;
+
+end;
diff --git a/gcc/testsuite/gnat.dg/array40_pkg.ads b/gcc/testsuite/gnat.dg/array40_pkg.ads
new file mode 100644 (file)
index 0000000..a3cec8b
--- /dev/null
@@ -0,0 +1,12 @@
+package Array40_Pkg is
+
+  type Rec is record
+    I : Integer;
+  end record;
+
+  type Arr is array (1 .. 4) of Rec;
+  for Arr'Component_Size use 40;
+
+  A : Arr;
+
+end Array40_Pkg;