This patch modifies the generation of validity checks to generate a renaming of
the expression being verified when the expression denotes a name. For all other
kinds of expressions, the validity check machinery creates a constant to store
the value of the expression. The use of renaming prevents the generation of a
redundant copy and acts as a proper alias of the name.

------------
-- Source --
------------

--  pack.ads

package Pack is
   type Int is mod 2 ** 32;
   for Int'Size use 32;

   function Swap_All_Bits (Val : Int) return Int;
end Pack;

--  pack.adb

package body Pack is
   type Bit_Map is record
      Bit_1  : Boolean;
      Bit_2  : Boolean;
      Bit_3  : Boolean;
      Bit_4  : Boolean;
      Bit_5  : Boolean;
      Bit_6  : Boolean;
      Bit_7  : Boolean;
      Bit_8  : Boolean;
      Bit_9  : Boolean;
      Bit_10 : Boolean;
      Bit_11 : Boolean;
      Bit_12 : Boolean;
      Bit_13 : Boolean;
      Bit_14 : Boolean;
      Bit_15 : Boolean;
      Bit_16 : Boolean;
      Bit_17 : Boolean;
      Bit_18 : Boolean;
      Bit_19 : Boolean;
      Bit_20 : Boolean;
      Bit_21 : Boolean;
      Bit_22 : Boolean;
      Bit_23 : Boolean;
      Bit_24 : Boolean;
      Bit_25 : Boolean;
      Bit_26 : Boolean;
      Bit_27 : Boolean;
      Bit_28 : Boolean;
      Bit_29 : Boolean;
      Bit_30 : Boolean;
      Bit_31 : Boolean;
      Bit_32 : Boolean;
   end record;

   for Bit_Map'Size use 32;

   for Bit_Map use record
      Bit_1  at 0 range  0 .. 0;
      Bit_2  at 0 range  1 .. 1;
      Bit_3  at 0 range  2 .. 2;
      Bit_4  at 0 range  3 .. 3;
      Bit_5  at 0 range  4 .. 4;
      Bit_6  at 0 range  5 .. 5;
      Bit_7  at 0 range  6 .. 6;
      Bit_8  at 0 range  7 .. 7;
      Bit_9  at 0 range  8 .. 8;
      Bit_10 at 0 range  9 .. 9;
      Bit_11 at 0 range 10 .. 10;
      Bit_12 at 0 range 11 .. 11;
      Bit_13 at 0 range 12 .. 12;
      Bit_14 at 0 range 13 .. 13;
      Bit_15 at 0 range 14 .. 14;
      Bit_16 at 0 range 15 .. 15;
      Bit_17 at 0 range 16 .. 16;
      Bit_18 at 0 range 17 .. 17;
      Bit_19 at 0 range 18 .. 18;
      Bit_20 at 0 range 19 .. 19;
      Bit_21 at 0 range 20 .. 20;
      Bit_22 at 0 range 21 .. 21;
      Bit_23 at 0 range 22 .. 22;
      Bit_24 at 0 range 23 .. 23;
      Bit_25 at 0 range 24 .. 24;
      Bit_26 at 0 range 25 .. 25;
      Bit_27 at 0 range 26 .. 26;
      Bit_28 at 0 range 27 .. 27;
      Bit_29 at 0 range 28 .. 28;
      Bit_30 at 0 range 29 .. 29;
      Bit_31 at 0 range 30 .. 30;
      Bit_32 at 0 range 31 .. 31;
   end record;

   function Swap_All_Bits (Val : Int) return Int is
      procedure Swap_One_Bit (L : in out Boolean; R : in out Boolean) is
         Temp : Boolean := L;
      begin
         L := R;
         R := Temp;
      end Swap_One_Bit;

      Result : Int;

      Map : Bit_Map;
      for Map'Address use Result'Address;
      pragma Volatile (Map);

   begin
      Result := Val;

      Swap_One_Bit (Map.Bit_1, Map.Bit_8);
      Swap_One_Bit (Map.Bit_2, Map.Bit_7);
      Swap_One_Bit (Map.Bit_3, Map.Bit_6);
      Swap_One_Bit (Map.Bit_4, Map.Bit_5);

      Swap_One_Bit (Map.Bit_9,  Map.Bit_16);
      Swap_One_Bit (Map.Bit_10, Map.Bit_15);
      Swap_One_Bit (Map.Bit_11, Map.Bit_14);
      Swap_One_Bit (Map.Bit_12, Map.Bit_13);

      Swap_One_Bit (Map.Bit_17, Map.Bit_24);
      Swap_One_Bit (Map.Bit_18, Map.Bit_23);
      Swap_One_Bit (Map.Bit_19, Map.Bit_22);
      Swap_One_Bit (Map.Bit_20, Map.Bit_21);

      Swap_One_Bit (Map.Bit_25, Map.Bit_32);
      Swap_One_Bit (Map.Bit_26, Map.Bit_31);
      Swap_One_Bit (Map.Bit_27, Map.Bit_30);
      Swap_One_Bit (Map.Bit_28, Map.Bit_29);

      return Result;
   end Swap_All_Bits;
end Pack;

--  swapper.adb

with Ada.Text_IO; use Ada.Text_IO;
with Pack;        use Pack;

procedure Swapper is
   Expect : constant Int := 16#55555555#;
   Output : constant Int := Swap_All_Bits (16#AAAAAAAA#);

begin
   if Output /= Expect then
      Put_Line ("ERROR");
   end if;
end Swapper;

-----------------
-- Compilation --
-----------------

$ gnatmake -q -gnatVa swapper.adb
$ ./swapper

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

2017-01-23  Hristian Kirtchev  <kirtc...@adacore.com>

        * checks.adb (Insert_Valid_Check): Ensure that the prefix of
        attribute 'Valid is a renaming of the original expression when
        the expression denotes a name. For all other kinds of expression,
        use a constant to capture the value.
        * exp_util.adb (Is_Name_Reference): Moved to Sem_Util.
        * sem_util.ads, sem_util.adb (Is_Name_Reference): Moved from Exp_Util.

Index: exp_util.adb
===================================================================
--- exp_util.adb        (revision 244790)
+++ exp_util.adb        (working copy)
@@ -9014,12 +9014,6 @@
       --  is present (xxx is taken from the Chars field of Related_Nod),
       --  otherwise it generates an internal temporary.
 
-      function Is_Name_Reference (N : Node_Id) return Boolean;
-      --  Determine if the tree referenced by N represents a name. This is
-      --  similar to Is_Object_Reference but returns true only if N can be
-      --  renamed without the need for a temporary, the typical example of
-      --  an object not in this category being a function call.
-
       ---------------------
       -- Build_Temporary --
       ---------------------
@@ -9050,61 +9044,6 @@
          end if;
       end Build_Temporary;
 
-      -----------------------
-      -- Is_Name_Reference --
-      -----------------------
-
-      function Is_Name_Reference (N : Node_Id) return Boolean is
-      begin
-         if Is_Entity_Name (N) then
-            return Present (Entity (N)) and then Is_Object (Entity (N));
-         end if;
-
-         case Nkind (N) is
-            when N_Indexed_Component
-               | N_Slice
-            =>
-               return
-                 Is_Name_Reference (Prefix (N))
-                   or else Is_Access_Type (Etype (Prefix (N)));
-
-            --  Attributes 'Input, 'Old and 'Result produce objects
-
-            when N_Attribute_Reference =>
-               return
-                 Nam_In
-                   (Attribute_Name (N), Name_Input, Name_Old, Name_Result);
-
-            when N_Selected_Component =>
-               return
-                 Is_Name_Reference (Selector_Name (N))
-                   and then
-                     (Is_Name_Reference (Prefix (N))
-                       or else Is_Access_Type (Etype (Prefix (N))));
-
-            when N_Explicit_Dereference =>
-               return True;
-
-            --  A view conversion of a tagged name is a name reference
-
-            when N_Type_Conversion =>
-               return
-                 Is_Tagged_Type (Etype (Subtype_Mark (N)))
-                   and then Is_Tagged_Type (Etype (Expression (N)))
-                   and then Is_Name_Reference (Expression (N));
-
-            --  An unchecked type conversion is considered to be a name if
-            --  the operand is a name (this construction arises only as a
-            --  result of expansion activities).
-
-            when N_Unchecked_Type_Conversion =>
-               return Is_Name_Reference (Expression (N));
-
-            when others =>
-               return False;
-         end case;
-      end Is_Name_Reference;
-
       --  Local variables
 
       Loc          : constant Source_Ptr      := Sloc (Exp);
Index: checks.adb
===================================================================
--- checks.adb  (revision 244782)
+++ checks.adb  (working copy)
@@ -7206,12 +7206,18 @@
             Force_Evaluation (Exp, Name_Req => False);
          end if;
 
-         --  Build the prefix for the 'Valid call
+         --  Build the prefix for the 'Valid call. If the expression denotes
+         --  a name, use a renaming to alias it, otherwise use a constant to
+         --  capture the value of the expression.
 
+         --    Temp : ... renames Expr;      --  reference to a name
+         --    Temp : constant ... := Expr;  --  all other cases
+
          PV :=
            Duplicate_Subexpr_No_Checks
              (Exp           => Exp,
               Name_Req      => False,
+              Renaming_Req  => Is_Name_Reference (Exp),
               Related_Id    => Related_Id,
               Is_Low_Bound  => Is_Low_Bound,
               Is_High_Bound => Is_High_Bound);
Index: sem_util.adb
===================================================================
--- sem_util.adb        (revision 244789)
+++ sem_util.adb        (working copy)
@@ -13405,6 +13405,60 @@
       end if;
    end Is_Local_Variable_Reference;
 
+   -----------------------
+   -- Is_Name_Reference --
+   -----------------------
+
+   function Is_Name_Reference (N : Node_Id) return Boolean is
+   begin
+      if Is_Entity_Name (N) then
+         return Present (Entity (N)) and then Is_Object (Entity (N));
+      end if;
+
+      case Nkind (N) is
+         when N_Indexed_Component
+            | N_Slice
+         =>
+            return
+              Is_Name_Reference (Prefix (N))
+                or else Is_Access_Type (Etype (Prefix (N)));
+
+         --  Attributes 'Input, 'Old and 'Result produce objects
+
+         when N_Attribute_Reference =>
+            return
+              Nam_In (Attribute_Name (N), Name_Input, Name_Old, Name_Result);
+
+         when N_Selected_Component =>
+            return
+              Is_Name_Reference (Selector_Name (N))
+                and then
+                  (Is_Name_Reference (Prefix (N))
+                    or else Is_Access_Type (Etype (Prefix (N))));
+
+         when N_Explicit_Dereference =>
+            return True;
+
+         --  A view conversion of a tagged name is a name reference
+
+         when N_Type_Conversion =>
+            return
+              Is_Tagged_Type (Etype (Subtype_Mark (N)))
+                and then Is_Tagged_Type (Etype (Expression (N)))
+                and then Is_Name_Reference (Expression (N));
+
+         --  An unchecked type conversion is considered to be a name if the
+         --  operand is a name (this construction arises only as a result of
+         --  expansion activities).
+
+         when N_Unchecked_Type_Conversion =>
+            return Is_Name_Reference (Expression (N));
+
+         when others =>
+            return False;
+      end case;
+   end Is_Name_Reference;
+
    ---------------------------------
    -- Is_Nontrivial_DIC_Procedure --
    ---------------------------------
Index: sem_util.ads
===================================================================
--- sem_util.ads        (revision 244773)
+++ sem_util.ads        (working copy)
@@ -1548,6 +1548,12 @@
    --  parameter of the current enclosing subprogram.
    --  Why are OUT parameters not considered here ???
 
+   function Is_Name_Reference (N : Node_Id) return Boolean;
+   --  Determine whether arbitrary node N is a reference to a name. This is
+   --  similar to Is_Object_Reference but returns True only if N can be renamed
+   --  without the need for a temporary, the typical example of an object not
+   --  in this category being a function call.
+
    function Is_Nontrivial_DIC_Procedure (Id : Entity_Id) return Boolean;
    --  Determine whether entity Id denotes the procedure that verifies the
    --  assertion expression of pragma Default_Initial_Condition and if it does,

Reply via email to