[Ada] Warn on Unchecked_Conversion to zero-sized array
authorBob Duff <duff@adacore.com>
Tue, 20 Aug 2019 09:49:12 +0000 (09:49 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Tue, 20 Aug 2019 09:49:12 +0000 (09:49 +0000)
The compiler usually warns on Unchecked_Conversion between types with
mismatched sizes. This warning is now extended to the case where the
target type is a zero-sized array.

2019-08-20  Bob Duff  <duff@adacore.com>

gcc/ada/

* sem_ch13.adb (Is_Null_Array): New function, used to detect the
null array case; used to warn about uncheckedly converting to a
zero-sized array.  It is unfortunate that we can't just check
the size, and warn on all cases of converting from a
nonzero-sized type to a zero-sized one. That's because "0" means
two different things: "size is zero" and "size is unknown".
Until we fix that design flaw, we need this more targeted fix.

gcc/testsuite/

* gnat.dg/unchecked_convert14.adb: New testcase.

From-SVN: r274725

gcc/ada/ChangeLog
gcc/ada/sem_ch13.adb
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/unchecked_convert14.adb [new file with mode: 0644]

index f8f43c00441c2913b77ec35b15aefef12ea00cc0..8ab2eddd64643dff7a369f00c46ee6fc83a18960 100644 (file)
@@ -1,3 +1,13 @@
+2019-08-20  Bob Duff  <duff@adacore.com>
+
+       * sem_ch13.adb (Is_Null_Array): New function, used to detect the
+       null array case; used to warn about uncheckedly converting to a
+       zero-sized array.  It is unfortunate that we can't just check
+       the size, and warn on all cases of converting from a
+       nonzero-sized type to a zero-sized one. That's because "0" means
+       two different things: "size is zero" and "size is unknown".
+       Until we fix that design flaw, we need this more targeted fix.
+
 2019-08-20  Bob Duff  <duff@adacore.com>
 
        * libgnat/a-cborma.adb, libgnat/a-cborse.adb (Clear): Repeatedly
index 415687922df042d19fbfa542b5c0606c7e28490b..2538c1da982fad8e49dae4680a9283a315a42830 100644 (file)
@@ -14625,6 +14625,39 @@ package body Sem_Ch13 is
    ------------------------------------
 
    procedure Validate_Unchecked_Conversions is
+      function Is_Null_Array (T : Entity_Id) return Boolean;
+      --  We want to warn in the case of converting to a wrong-sized array of
+      --  bytes, including the zero-size case. This returns True in that case,
+      --  which is necessary because a size of 0 is used to indicate both an
+      --  unknown size and a size of 0. It's OK for this to return True in
+      --  other zero-size cases, but we don't go out of our way; for example,
+      --  we don't bother with multidimensional arrays.
+
+      function Is_Null_Array (T : Entity_Id) return Boolean is
+      begin
+         if Is_Array_Type (T) and then Is_Constrained (T) then
+            declare
+               Index : constant Node_Id := First_Index (T);
+               R : Node_Id; -- N_Range
+            begin
+               case Nkind (Index) is
+                  when N_Range =>
+                     R := Index;
+                  when N_Subtype_Indication =>
+                     R := Range_Expression (Constraint (Index));
+                  when N_Identifier | N_Expanded_Name =>
+                     R := Scalar_Range (Entity (Index));
+                  when others =>
+                     raise Program_Error;
+               end case;
+
+               return Is_Null_Range (Low_Bound (R), High_Bound (R));
+            end;
+         end if;
+
+         return False;
+      end Is_Null_Array;
+
    begin
       for N in Unchecked_Conversions.First .. Unchecked_Conversions.Last loop
          declare
@@ -14641,28 +14674,28 @@ package body Sem_Ch13 is
          begin
             --  Skip if function marked as warnings off
 
-            if Warnings_Off (Act_Unit) then
+            if Warnings_Off (Act_Unit) or else Serious_Errors_Detected > 0 then
                goto Continue;
             end if;
 
-            --  This validation check, which warns if we have unequal sizes for
-            --  unchecked conversion, and thus potentially implementation
-            --  dependent semantics, is one of the few occasions on which we
-            --  use the official RM size instead of Esize. See description in
-            --  Einfo "Handling of Type'Size Values" for details.
-
-            if Serious_Errors_Detected = 0
-              and then Known_Static_RM_Size (Source)
-              and then Known_Static_RM_Size (Target)
+           --  Don't do the check if warnings off for either type, note the
+           --  deliberate use of OR here instead of OR ELSE to get the flag
+           --  Warnings_Off_Used set for both types if appropriate.
 
-              --  Don't do the check if warnings off for either type, note the
-              --  deliberate use of OR here instead of OR ELSE to get the flag
-              --  Warnings_Off_Used set for both types if appropriate.
+            if Has_Warnings_Off (Source) or Has_Warnings_Off (Target) then
+               goto Continue;
+            end if;
 
-              and then not (Has_Warnings_Off (Source)
-                              or
-                            Has_Warnings_Off (Target))
+            if (Known_Static_RM_Size (Source)
+                  and then Known_Static_RM_Size (Target))
+              or else Is_Null_Array (Target)
             then
+               --  This validation check, which warns if we have unequal sizes
+               --  for unchecked conversion, and thus implementation dependent
+               --  semantics, is one of the few occasions on which we use the
+               --  official RM size instead of Esize. See description in Einfo
+               --  "Handling of Type'Size Values" for details.
+
                Source_Siz := RM_Size (Source);
                Target_Siz := RM_Size (Target);
 
index 89406642e92fdac5577c12e8c9b75c8f3531f551..61e37dad25ba8b680d861dc6e8330e9a8fa74d8d 100644 (file)
@@ -1,3 +1,7 @@
+2019-08-20  Bob Duff  <duff@adacore.com>
+
+       * gnat.dg/unchecked_convert14.adb: New testcase.
+
 2019-08-20  Bob Duff  <duff@adacore.com>
 
        * gnat.dg/object_size1.adb: New testcase.
diff --git a/gcc/testsuite/gnat.dg/unchecked_convert14.adb b/gcc/testsuite/gnat.dg/unchecked_convert14.adb
new file mode 100644 (file)
index 0000000..756d836
--- /dev/null
@@ -0,0 +1,30 @@
+--  { dg-do compile }
+
+with Ada.Unchecked_Conversion;
+with System.Storage_Elements; use System.Storage_Elements;
+
+procedure Unchecked_Convert14 is
+
+    type R is record
+       I : Integer;
+       C : Character;
+    end record;
+
+    subtype Buffer is Storage_Array (1 .. 0);
+
+    function As_Buffer is new Ada.Unchecked_Conversion  --  { dg-warning "types for unchecked conversion have different sizes" }
+      (Source => R, Target => Buffer);
+
+    type Buffer_1 is array (Storage_Offset range 1 .. 1) of Storage_Element;
+
+    function As_Buffer_1 is new Ada.Unchecked_Conversion  --  { dg-warning "types for unchecked conversion have different sizes" }
+      (Source => R, Target => Buffer_1);
+
+    B : Buffer;
+    B_1 : Buffer_1;
+    My_R : R := (1, 'x');
+
+begin
+   B := As_Buffer (My_R);
+   B_1 := As_Buffer_1 (My_R);
+end Unchecked_Convert14;