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 <[email protected]>
* 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,