A special rule was introduced in Ada 2005 (RM 13.5.2(2/2-4/2)) that
specifies that if Position, First_Bit or Last_Bit are applied to
a component with a component clause, and the default record bit
ordering applies, then the results correspond to the exact values
given in the component clause, not normalized versions of them.
This patch implements this feature.

The following test program (compiled with -gnatws)

     1. pragma Ada_2005;
     2.
     3. with Ada.Streams;
     4. with Ada.Streams.Stream_Io;
     5. with Ada.Text_Io; use Ada.Text_IO;
     6. with system;
     7.
     8. procedure Bit_Test is
     9.
    10.    subtype Int_16 is Standard.Short_Integer;
    11.    type Int_10 is new Int_16 range 0 .. 9;
    12.    type Int_22 is new Int_16 range 10 .. 31;
    13.
    14.    type A_Rec_Base is
    15.       record
    16.          Comp_A : Int_16;
    17.          Comp_B : Int_16;
    18.          Comp_C : Int_10;
    19.          Comp_D : Int_22;
    20.       end record;
    21.
    22.    type B_Rec is new A_Rec_Base;
    23.    type C_Rec is new A_Rec_Base;
    24.
    25.    for B_Rec use
    26.       record
    27.          Comp_A at 0 range  0 .. 15;
    28.          Comp_B at 0 range 16 .. 31;
    29.          Comp_C at 4 range  0 .. 9;
    30.          Comp_D at 4 range 11 .. 31;
    31.       end record;
    32.
    33.    for C_Rec use
    34.       record
    35.          Comp_A at 0 range  0 .. 15;
    36.          Comp_B at 0 range 16 .. 31;
    37.          Comp_C at 4 range  0 ..  9;
    38.          Comp_D at 4 range 11 .. 31;
    39.       end record;
    40.
    41.    for B_Rec'Bit_Order use
    42.      System.Default_Bit_Order;
    43.
    44.    for C_Rec'Bit_Order use
    45.      System.Bit_Order'Val
    46.        (1 - System.Bit_Order'Pos
    47.               (System.Default_Bit_Order));
    48.
    49.    Obj_1 : B_Rec;
    50.    Obj_2 : C_Rec;
    51.
    52. begin
    53.    Obj_1.Comp_A := 1;
    54.    Obj_1.Comp_B := 2;
    55.    Obj_1.Comp_C := 3;
    56.    Obj_1.Comp_D := 11;
    57.
    58.    Obj_2.Comp_A := 1;
    59.    Obj_2.Comp_B := 2;
    60.    Obj_2.Comp_C := 3;
    61.    Obj_2.Comp_D := 12;
    62.
    63.    Put_Line ("B_Rec: ");
    64.    Put_Line ("Comp_A Pos: " &
    65.      Integer'Image (Obj_1.Comp_A'Position));
    66.    Put_Line ("       FB: " &
    67.      Integer'Image (Obj_1.Comp_A'First_Bit));
    68.    Put_Line ("       LB: " &
    69.      Integer'Image (Obj_1.Comp_A'Last_Bit));
    70.    Put_Line ("Comp_B Pos: " &
    71.      Integer'Image (Obj_1.Comp_B'Position));
    72.    Put_Line ("       FB: " &
    73.      Integer'Image (Obj_1.Comp_B'First_Bit));
    74.    Put_Line ("       LB: " &
    75.      Integer'Image (Obj_1.Comp_B'Last_Bit));
    76.    Put_Line ("Comp_C Pos: " &
    77.      Integer'Image (Obj_1.Comp_C'Position));
    78.    Put_Line ("       FB: " &
    79.      Integer'Image (Obj_1.Comp_C'First_Bit));
    80.    Put_Line ("       LB: " &
    81.      Integer'Image (Obj_1.Comp_C'Last_Bit));
    82.    Put_Line ("Comp_D Pos: " &
    83.      Integer'Image (Obj_1.Comp_D'Position));
    84.    Put_Line ("       FB: " &
    85.      Integer'Image (Obj_1.Comp_D'First_Bit));
    86.    Put_Line ("       LB: " &
    87.      Integer'Image (Obj_1.Comp_D'Last_Bit));
    88.
    89.    Put_Line ("C_Rec: ");
    90.    Put_Line ("Comp_A Pos: " &
    91.      Integer'Image (Obj_2.Comp_A'Position));
    92.    Put_Line ("       FB: " &
    93.      Integer'Image (Obj_2.Comp_A'First_Bit));
    94.    Put_Line ("       LB: " &
    95.      Integer'Image (Obj_2.Comp_A'Last_Bit));
    96.    Put_Line ("Comp_B Pos: " &
    97.      Integer'Image (Obj_2.Comp_B'Position));
    98.    Put_Line ("       FB: " &
    99.      Integer'Image (Obj_2.Comp_B'First_Bit));
   100.    Put_Line ("       LB: " &
   101.      Integer'Image (Obj_2.Comp_B'Last_Bit));
   102.    Put_Line ("Comp_C Pos: " &
   103.      Integer'Image (Obj_2.Comp_C'Position));
   104.    Put_Line ("       FB: " &
   105.      Integer'Image (Obj_2.Comp_C'First_Bit));
   106.    Put_Line ("       LB: " &
   107.      Integer'Image (Obj_2.Comp_C'Last_Bit));
   108.    Put_Line ("Comp_D Pos: " &
   109.      Integer'Image (Obj_2.Comp_D'Position));
   110.    Put_Line ("       FB: " &
   111.      Integer'Image (Obj_2.Comp_D'First_Bit));
   112.    Put_Line ("       LB: " &
   113.      Integer'Image (Obj_2.Comp_D'Last_Bit));
   114.
   115. end Bit_Test;

 115 lines: No errors

Generates the output:

B_Rec:
Comp_A Pos:  0
       FB:  0
       LB:  15
Comp_B Pos:  0
       FB:  16
       LB:  31
Comp_C Pos:  4
       FB:  0
       LB:  9
Comp_D Pos:  4
       FB:  11
       LB:  31
C_Rec:
Comp_A Pos:  2
       FB:  0
       LB:  15
Comp_B Pos:  0
       FB:  0
       LB:  15
Comp_C Pos:  6
       FB:  6
       LB:  15
Comp_D Pos:  4
       FB:  0
       LB:  20

And as seen in these results, for B_Rec, which has the default
bit_ordering, the output matches exactly the values given in the
component clauses of the record representation clause (in Ada 95
mode these values would be normalized).

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

2011-11-21  Robert Dewar  <de...@adacore.com>

        * exp_attr.adb (Expand_N_Attribute_Reference, case First_Bit,
        Last_Bit, Position): Handle 2005 case.

Index: exp_attr.adb
===================================================================
--- exp_attr.adb        (revision 181556)
+++ exp_attr.adb        (working copy)
@@ -2117,21 +2117,38 @@
       --  computation to be completed in the back-end, since we don't know what
       --  layout will be chosen.
 
-      when Attribute_First_Bit => First_Bit : declare
+      when Attribute_First_Bit => First_Bit_Attr : declare
          CE : constant Entity_Id := Entity (Selector_Name (Pref));
 
       begin
-         if Known_Static_Component_Bit_Offset (CE) then
+         --  In Ada 2005 (or later) if we have the standard nondefault
+         --  bit order, then we return the original value as given in
+         --  the component clause (RM 2005 13.5.2(3/2)).
+
+         if Present (Component_Clause (CE))
+           and then Ada_Version >= Ada_2005
+           and then not Reverse_Bit_Order (Scope (CE))
+         then
             Rewrite (N,
               Make_Integer_Literal (Loc,
+                Intval => Expr_Value (First_Bit (Component_Clause (CE)))));
+            Analyze_And_Resolve (N, Typ);
+
+         --  Otherwise (Ada 83/95 or Ada 2005 or later with reverse bit order),
+         --  rewrite with normalized value if we know it statically.
+
+         elsif Known_Static_Component_Bit_Offset (CE) then
+            Rewrite (N,
+              Make_Integer_Literal (Loc,
                 Component_Bit_Offset (CE) mod System_Storage_Unit));
-
             Analyze_And_Resolve (N, Typ);
 
+         --  Otherwise left to back end, just do universal integer checks
+
          else
             Apply_Universal_Integer_Attribute_Checks (N);
          end if;
-      end First_Bit;
+      end First_Bit_Attr;
 
       -----------------
       -- Fixed_Value --
@@ -2680,24 +2697,41 @@
       --  the computation up to the back end, since we don't know what layout
       --  will be chosen.
 
-      when Attribute_Last_Bit => Last_Bit : declare
+      when Attribute_Last_Bit => Last_Bit_Attr : declare
          CE : constant Entity_Id := Entity (Selector_Name (Pref));
 
       begin
-         if Known_Static_Component_Bit_Offset (CE)
+         --  In Ada 2005 (or later) if we have the standard nondefault
+         --  bit order, then we return the original value as given in
+         --  the component clause (RM 2005 13.5.2(4/2)).
+
+         if Present (Component_Clause (CE))
+           and then Ada_Version >= Ada_2005
+           and then not Reverse_Bit_Order (Scope (CE))
+         then
+            Rewrite (N,
+              Make_Integer_Literal (Loc,
+                Intval => Expr_Value (Last_Bit (Component_Clause (CE)))));
+            Analyze_And_Resolve (N, Typ);
+
+         --  Otherwise (Ada 83/95 or Ada 2005 or later with reverse bit order),
+         --  rewrite with normalized value if we know it statically.
+
+         elsif Known_Static_Component_Bit_Offset (CE)
            and then Known_Static_Esize (CE)
          then
             Rewrite (N,
               Make_Integer_Literal (Loc,
                Intval => (Component_Bit_Offset (CE) mod System_Storage_Unit)
                                 + Esize (CE) - 1));
-
             Analyze_And_Resolve (N, Typ);
 
+         --  Otherwise leave to back end, just apply universal integer checks
+
          else
             Apply_Universal_Integer_Attribute_Checks (N);
          end if;
-      end Last_Bit;
+      end Last_Bit_Attr;
 
       ------------------
       -- Leading_Part --
@@ -3495,21 +3529,41 @@
       --  the computation up to the back end, since we don't know what layout
       --  will be chosen.
 
-      when Attribute_Position => Position :
+      when Attribute_Position => Position_Attr :
       declare
          CE : constant Entity_Id := Entity (Selector_Name (Pref));
 
       begin
          if Present (Component_Clause (CE)) then
-            Rewrite (N,
-              Make_Integer_Literal (Loc,
-                Intval => Component_Bit_Offset (CE) / System_Storage_Unit));
+
+            --  In Ada 2005 (or later) if we have the standard nondefault
+            --  bit order, then we return the original value as given in
+            --  the component clause (RM 2005 13.5.2(2/2)).
+
+            if Ada_Version >= Ada_2005
+              and then not Reverse_Bit_Order (Scope (CE))
+            then
+               Rewrite (N,
+                  Make_Integer_Literal (Loc,
+                    Intval => Expr_Value (Position (Component_Clause (CE)))));
+
+            --  Otherwise (Ada 83 or 95, or reverse bit order specified in
+            --  later Ada version), return the normalized value.
+
+            else
+               Rewrite (N,
+                 Make_Integer_Literal (Loc,
+                   Intval => Component_Bit_Offset (CE) / System_Storage_Unit));
+            end if;
+
             Analyze_And_Resolve (N, Typ);
 
+         --  If back end is doing things, just apply universal integer checks
+
          else
             Apply_Universal_Integer_Attribute_Checks (N);
          end if;
-      end Position;
+      end Position_Attr;
 
       ----------
       -- Pred --

Reply via email to