[Ada] Warn on Unchecked_Conversion to zero-sized array
diff mbox series

Message ID 20190820095122.GA75458@adacore.com
State New
Headers show
Series
  • [Ada] Warn on Unchecked_Conversion to zero-sized array
Related show

Commit Message

Pierre-Marie de Rodat Aug. 20, 2019, 9:51 a.m. UTC
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.

Tested on x86_64-pc-linux-gnu, committed on trunk

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.

Patch
diff mbox series

--- gcc/ada/sem_ch13.adb
+++ gcc/ada/sem_ch13.adb
@@ -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);
 

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/unchecked_convert14.adb
@@ -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;