Patchwork [Ada] Delay all aspects

login
register
mail settings
Submitter Arnaud Charlet
Date Aug. 1, 2011, 9:28 a.m.
Message ID <20110801092801.GA14203@adacore.com>
Download mbox | patch
Permalink /patch/107699/
State New
Headers show

Comments

Arnaud Charlet - Aug. 1, 2011, 9:28 a.m.
This patch implements delay of all aspects till the freeze point
as finally decided in the Ada 2012 design. It also corrects a
couple of errors in handling delayed aspects (now that we have
many more of them, these errors showed up).

Here is a test program (compiled with -gnatws)

     1. pragma Ada_2012;
     2. with Ada.Text_IO; use Ada.Text_IO;
     3. procedure DelayAllAspect is
     4.    Outer_X : constant Integer := 8;
     5.    Outer_Y : constant Integer := 8;
     6.
     7.    package X1 is
     8.       type X1T is range 1 .. 2 with
     9.         Size => Outer_X;
    10.       Outer_X : constant Integer := 16;
    11.    end;
    12.
    13.    package X2 is
    14.       type X2T is range 1 .. 2 with
    15.         Size => Outer_X;
    16.       V2T : X2T; -- freezes
    17.       Outer_X : constant Integer := 16;
    18.       --  Should give error!
    19.    end X2;
    20.
    21.    package X3 is
    22.       type X3T is range 1 .. 2 with
    23.         Size => Outer_X + Outer_Y;
    24.       Outer_Y : constant Integer := 24;
    25.       V3T : X3T; -- freezes
    26.       Outer_X : constant Integer := 40;
    27.       --  Should give error!
    28.    end X3;
    29.
    30. begin
    31.    Put_Line (X1.X1T'Size'Img & " should be 16");
    32.    Put_Line (X2.X2T'Size'Img & "  should be 8");
    33.    Put_Line (X3.X3T'Size'Img & " should be 32");
    34. end DelayAllAspect;

The output with this patch is:

 16 should be 16
 8  should be 8
 32 should be 32

Note the two lines marked "Should give error", These reflect
the requirement under discussion that if the freeze point is
before the end of the declarative region, and the visibility
changes between the freeze point and the end of this region,
the program is illegal.

This seems very hard to do, and we will wait on this till
(a) the final decision is to go in this direction and
(b) we figure out how the heck to implement this (sees
awfully difficult).

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

2011-08-01  Robert Dewar  <dewar@adacore.com>

	* aspects.ads (Boolean_Aspects): New subtype.
	* exp_ch13.adb (Expand_Freeze_Entity): Fix errors in handling aspects
	for derived types in cases where the parent type and derived type have
	aspects.
	* freeze.adb (Freeze_Entity): Fix problems in handling derived type
	with aspects when parent type also has aspects.
	(Freeze_Entity): Deal with delay of boolean aspects (must evaluate
	boolean expression at this point).
	* sem_ch13.adb (Analyze_Aspect_Specifications): Delay all aspects in
	accordance with final decision on the Ada 2012 feature.
	* sinfo.ads, sinfo.adb (Is_Boolean_Aspect): New flag.

Patch

Index: sinfo.adb
===================================================================
--- sinfo.adb	(revision 176998)
+++ sinfo.adb	(working copy)
@@ -1696,6 +1696,14 @@ 
       return Flag7 (N);
    end Is_Asynchronous_Call_Block;
 
+   function Is_Boolean_Aspect
+      (N : Node_Id) return Boolean is
+   begin
+      pragma Assert (False
+        or else NT (N).Nkind = N_Aspect_Specification);
+      return Flag16 (N);
+   end Is_Boolean_Aspect;
+
    function Is_Component_Left_Opnd
       (N : Node_Id) return Boolean is
    begin
@@ -4716,6 +4724,14 @@ 
       Set_Flag7 (N, Val);
    end Set_Is_Asynchronous_Call_Block;
 
+   procedure Set_Is_Boolean_Aspect
+      (N : Node_Id; Val : Boolean := True) is
+   begin
+      pragma Assert (False
+        or else NT (N).Nkind = N_Aspect_Specification);
+      Set_Flag16 (N, Val);
+   end Set_Is_Boolean_Aspect;
+
    procedure Set_Is_Component_Left_Opnd
       (N : Node_Id; Val : Boolean := True) is
    begin
Index: sinfo.ads
===================================================================
--- sinfo.ads	(revision 176998)
+++ sinfo.ads	(working copy)
@@ -1252,6 +1252,10 @@ 
    --    expansion of an asynchronous entry call. Such a block needs cleanup
    --    handler to assure that the call is cancelled.
 
+   --  Is_Boolean_Aspect (Flag16-Sem)
+   --    Present in N_Aspect_Specification node. Set if the aspect is for a
+   --    boolean aspect (i.e. Aspect_Id is in Boolean_Aspect subtype).
+
    --  Is_Component_Left_Opnd  (Flag13-Sem)
    --  Is_Component_Right_Opnd (Flag14-Sem)
    --    Present in concatenation nodes, to indicate that the corresponding
@@ -6543,6 +6547,7 @@ 
       --  Class_Present (Flag6) Set if 'Class present
       --  Next_Rep_Item (Node5-Sem)
       --  Split_PPC (Flag17) Set if split pre/post attribute
+      --  Is_Boolean_Aspect (Flag16-Sem)
 
       --  Note: Aspect_Specification is an Ada 2012 feature
 
@@ -8487,6 +8492,9 @@ 
    function Is_Asynchronous_Call_Block
      (N : Node_Id) return Boolean;    -- Flag7
 
+   function Is_Boolean_Aspect
+     (N : Node_Id) return Boolean;    -- Flag16
+
    function Is_Component_Left_Opnd
      (N : Node_Id) return Boolean;    -- Flag13
 
@@ -9450,6 +9458,9 @@ 
    procedure Set_Is_Asynchronous_Call_Block
      (N : Node_Id; Val : Boolean := True);    -- Flag7
 
+   procedure Set_Is_Boolean_Aspect
+     (N : Node_Id; Val : Boolean := True);    -- Flag16
+
    procedure Set_Is_Component_Left_Opnd
      (N : Node_Id; Val : Boolean := True);    -- Flag13
 
@@ -11793,6 +11804,7 @@ 
    pragma Inline (Iterator_Specification);
    pragma Inline (Is_Accessibility_Actual);
    pragma Inline (Is_Asynchronous_Call_Block);
+   pragma Inline (Is_Boolean_Aspect);
    pragma Inline (Is_Component_Left_Opnd);
    pragma Inline (Is_Component_Right_Opnd);
    pragma Inline (Is_Controlling_Actual);
@@ -12110,6 +12122,7 @@ 
    pragma Inline (Set_Iterator_Specification);
    pragma Inline (Set_Is_Accessibility_Actual);
    pragma Inline (Set_Is_Asynchronous_Call_Block);
+   pragma Inline (Set_Is_Boolean_Aspect);
    pragma Inline (Set_Is_Component_Left_Opnd);
    pragma Inline (Set_Is_Component_Right_Opnd);
    pragma Inline (Set_Is_Controlling_Actual);
Index: freeze.adb
===================================================================
--- freeze.adb	(revision 176998)
+++ freeze.adb	(working copy)
@@ -2370,24 +2370,58 @@ 
          end;
       end if;
 
-      --  Deal with delayed aspect specifications. At the point of occurrence
-      --  of the aspect definition, we preanalyzed the argument, to capture
-      --  the visibility at that point, but the actual analysis of the aspect
+      --  Deal with delayed aspect specifications. The analysis of the aspect
       --  is required to be delayed to the freeze point, so we evaluate the
       --  pragma or attribute definition clause in the tree at this point.
 
+      --  We also have to deal with the case of Boolean aspects, where the
+      --  value of the Boolean expression is represented by the setting of
+      --  the Aspect_Cancel flag on the pragma.
+
       if Has_Delayed_Aspects (E) then
          declare
             Ritem : Node_Id;
             Aitem : Node_Id;
 
          begin
+            --  Look for aspect specification entries for this entity
+
             Ritem := First_Rep_Item (E);
             while Present (Ritem) loop
-               if Nkind (Ritem) = N_Aspect_Specification then
+               if Nkind (Ritem) = N_Aspect_Specification
+                 and then Entity (Ritem) = E
+               then
                   Aitem := Aspect_Rep_Item (Ritem);
                   pragma Assert (Is_Delayed_Aspect (Aitem));
                   Set_Parent (Aitem, Ritem);
+
+                  --  Deal with Boolean case, if no expression, True, otherwise
+                  --  analyze the expression, check it is static, and if its
+                  --  value is False, set Aspect_Cancel for the related pragma.
+
+                  if Is_Boolean_Aspect (Ritem) then
+                     declare
+                        Expr : constant Node_Id := Expression (Ritem);
+
+                     begin
+                        if Present (Expr) then
+                           Analyze_And_Resolve (Expr, Standard_Boolean);
+
+                           if not Is_OK_Static_Expression (Expr) then
+                              Error_Msg_Name_1 := Chars (Identifier (Ritem));
+                              Error_Msg_N
+                                ("expression for % aspect must be static",
+                                 Expr);
+
+                           elsif Is_False (Expr_Value (Expr)) then
+                              Set_Aspect_Cancel (Aitem);
+                           end if;
+                        end if;
+                     end;
+                  end if;
+
+                  --  Analyze the pragma after possibly setting Aspect_Cancel
+
                   Analyze (Aitem);
                end if;
 
Index: exp_ch13.adb
===================================================================
--- exp_ch13.adb	(revision 176998)
+++ exp_ch13.adb	(working copy)
@@ -232,9 +232,13 @@ 
             Ritem : Node_Id;
 
          begin
+            --  Look for aspect specs for this entity
+
             Ritem := First_Rep_Item (E);
             while Present (Ritem) loop
-               if Nkind (Ritem) = N_Aspect_Specification then
+               if Nkind (Ritem) = N_Aspect_Specification
+                 and then Entity (Ritem) = E
+               then
                   Aitem := Aspect_Rep_Item (Ritem);
                   pragma Assert (Is_Delayed_Aspect (Aitem));
                   Insert_Before (N, Aitem);
@@ -288,7 +292,7 @@ 
 
       if Ekind (E_Scope) = E_Protected_Type
         or else (Ekind (E_Scope) = E_Task_Type
-                   and then not Has_Completion (E_Scope))
+                  and then not Has_Completion (E_Scope))
       then
          E_Scope := Scope (E_Scope);
 
Index: aspects.ads
===================================================================
--- aspects.ads	(revision 176998)
+++ aspects.ads	(working copy)
@@ -43,51 +43,56 @@ 
 
    type Aspect_Id is
      (No_Aspect,                            -- Dummy entry for no aspect
-      Aspect_Ada_2005,                      -- GNAT
-      Aspect_Ada_2012,                      -- GNAT
       Aspect_Address,
       Aspect_Alignment,
-      Aspect_Atomic,
-      Aspect_Atomic_Components,
       Aspect_Bit_Order,
       Aspect_Component_Size,
-      Aspect_Discard_Names,
       Aspect_External_Tag,
-      Aspect_Favor_Top_Level,               -- GNAT
-      Aspect_Inline,
-      Aspect_Inline_Always,                 -- GNAT
       Aspect_Input,
       Aspect_Invariant,
       Aspect_Machine_Radix,
-      Aspect_No_Return,
       Aspect_Object_Size,                   -- GNAT
       Aspect_Output,
-      Aspect_Pack,
-      Aspect_Persistent_BSS,                -- GNAT
       Aspect_Post,
       Aspect_Pre,
-      Aspect_Predicate,                     -- GNAT???
-      Aspect_Preelaborable_Initialization,
-      Aspect_Pure_Function,                 -- GNAT
+      Aspect_Predicate,
       Aspect_Read,
-      Aspect_Shared,                        -- GNAT (equivalent to Atomic)
       Aspect_Size,
       Aspect_Storage_Pool,
       Aspect_Storage_Size,
       Aspect_Stream_Size,
       Aspect_Suppress,
+      Aspect_Unsuppress,
+      Aspect_Value_Size,                    -- GNAT
+      Aspect_Warnings,
+      Aspect_Write,
+
+      --  Remaining aspects have a static boolean value that turns the aspect
+      --  on or off. They all correspond to pragmas, and the flag Aspect_Cancel
+      --  is set on the pragma if the corresponding aspect is False.
+
+      Aspect_Ada_2005,                      -- GNAT
+      Aspect_Ada_2012,                      -- GNAT
+      Aspect_Atomic,
+      Aspect_Atomic_Components,
+      Aspect_Discard_Names,
+      Aspect_Favor_Top_Level,               -- GNAT
+      Aspect_Inline,
+      Aspect_Inline_Always,                 -- GNAT
+      Aspect_No_Return,
+      Aspect_Pack,
+      Aspect_Persistent_BSS,                -- GNAT
+      Aspect_Preelaborable_Initialization,
+      Aspect_Pure_Function,                 -- GNAT
+      Aspect_Shared,                        -- GNAT (equivalent to Atomic)
       Aspect_Suppress_Debug_Info,           -- GNAT
       Aspect_Unchecked_Union,
       Aspect_Universal_Aliasing,            -- GNAT
       Aspect_Unmodified,                    -- GNAT
       Aspect_Unreferenced,                  -- GNAT
       Aspect_Unreferenced_Objects,          -- GNAT
-      Aspect_Unsuppress,
-      Aspect_Value_Size,                    -- GNAT
       Aspect_Volatile,
-      Aspect_Volatile_Components,
-      Aspect_Warnings,
-      Aspect_Write);                        -- GNAT
+      Aspect_Volatile_Components);
 
    --  The following array indicates aspects that accept 'Class
 
@@ -98,6 +103,16 @@ 
                         Aspect_Post          => True,
                         others               => False);
 
+   --  The following subtype defines aspects accepting an optional static
+   --  boolean parameter indicating if the aspect should be active or
+   --  cancelling. If the parameter is missing the effective value is True,
+   --  enabling the aspect. If the parameter is present it must be a static
+   --  expression of type Standard.Boolean. If the value is True, then the
+   --  aspect is enabled. If it is False, the aspect is disabled.
+
+   subtype Boolean_Aspects is
+     Aspect_Id range Aspect_Ada_2005 .. Aspect_Id'Last;
+
    --  The following type is used for indicating allowed expression forms
 
    type Aspect_Expression is
@@ -109,51 +124,30 @@ 
 
    Aspect_Argument : constant array (Aspect_Id) of Aspect_Expression :=
                        (No_Aspect                           => Optional,
-                        Aspect_Ada_2005                     => Optional,
-                        Aspect_Ada_2012                     => Optional,
                         Aspect_Address                      => Expression,
                         Aspect_Alignment                    => Expression,
-                        Aspect_Atomic                       => Optional,
-                        Aspect_Atomic_Components            => Optional,
                         Aspect_Bit_Order                    => Expression,
                         Aspect_Component_Size               => Expression,
-                        Aspect_Discard_Names                => Optional,
                         Aspect_External_Tag                 => Expression,
-                        Aspect_Favor_Top_Level              => Optional,
-                        Aspect_Inline                       => Optional,
-                        Aspect_Inline_Always                => Optional,
                         Aspect_Input                        => Name,
                         Aspect_Invariant                    => Expression,
                         Aspect_Machine_Radix                => Expression,
-                        Aspect_No_Return                    => Optional,
                         Aspect_Object_Size                  => Expression,
                         Aspect_Output                       => Name,
-                        Aspect_Persistent_BSS               => Optional,
-                        Aspect_Pack                         => Optional,
                         Aspect_Post                         => Expression,
                         Aspect_Pre                          => Expression,
                         Aspect_Predicate                    => Expression,
-                        Aspect_Preelaborable_Initialization => Optional,
-                        Aspect_Pure_Function                => Optional,
                         Aspect_Read                         => Name,
-                        Aspect_Shared                       => Optional,
                         Aspect_Size                         => Expression,
                         Aspect_Storage_Pool                 => Name,
                         Aspect_Storage_Size                 => Expression,
                         Aspect_Stream_Size                  => Expression,
                         Aspect_Suppress                     => Name,
-                        Aspect_Suppress_Debug_Info          => Optional,
-                        Aspect_Unchecked_Union              => Optional,
-                        Aspect_Universal_Aliasing           => Optional,
-                        Aspect_Unmodified                   => Optional,
-                        Aspect_Unreferenced                 => Optional,
-                        Aspect_Unreferenced_Objects         => Optional,
                         Aspect_Unsuppress                   => Name,
                         Aspect_Value_Size                   => Expression,
-                        Aspect_Volatile                     => Optional,
-                        Aspect_Volatile_Components          => Optional,
                         Aspect_Warnings                     => Name,
-                        Aspect_Write                        => Name);
+                        Aspect_Write                        => Name,
+                        Boolean_Aspects                     => Optional);
 
    function Get_Aspect_Id (Name : Name_Id) return Aspect_Id;
    pragma Inline (Get_Aspect_Id);
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 176998)
+++ sem_ch13.adb	(working copy)
@@ -740,7 +740,6 @@ 
             Nam  : constant Name_Id    := Chars (Id);
             A_Id : constant Aspect_Id  := Get_Aspect_Id (Nam);
             Anod : Node_Id;
-            T    : Entity_Id;
 
             Eloc : Source_Ptr := Sloc (Expr);
             --  Source location of expression, modified when we split PPC's
@@ -811,31 +810,12 @@ 
                   raise Program_Error;
 
                --  Aspects taking an optional boolean argument. For all of
-               --  these we just create a matching pragma and insert it,
-               --  setting flag Cancel_Aspect if the expression is False.
+               --  these we just create a matching pragma and insert it. When
+               --  the aspect is processed to insert the pragma, the expression
+               --  is analyzed, setting Cancel_Aspect if the value is False.
 
-               when Aspect_Ada_2005                     |
-                    Aspect_Ada_2012                     |
-                    Aspect_Atomic                       |
-                    Aspect_Atomic_Components            |
-                    Aspect_Discard_Names                |
-                    Aspect_Favor_Top_Level              |
-                    Aspect_Inline                       |
-                    Aspect_Inline_Always                |
-                    Aspect_No_Return                    |
-                    Aspect_Pack                         |
-                    Aspect_Persistent_BSS               |
-                    Aspect_Preelaborable_Initialization |
-                    Aspect_Pure_Function                |
-                    Aspect_Shared                       |
-                    Aspect_Suppress_Debug_Info          |
-                    Aspect_Unchecked_Union              |
-                    Aspect_Universal_Aliasing           |
-                    Aspect_Unmodified                   |
-                    Aspect_Unreferenced                 |
-                    Aspect_Unreferenced_Objects         |
-                    Aspect_Volatile                     |
-                    Aspect_Volatile_Components          =>
+               when Boolean_Aspects =>
+                  Set_Is_Boolean_Aspect (Aspect);
 
                   --  Build corresponding pragma node
 
@@ -845,32 +825,17 @@ 
                       Pragma_Identifier            =>
                         Make_Identifier (Sloc (Id), Chars (Id)));
 
-                  --  Deal with missing expression case, delay never needed
+                  --  No delay required if no expression (nothing to delay!)
 
                   if No (Expr) then
                      Delay_Required := False;
 
-                  --  Expression is present
+                  --  Expression is present, delay is required. Note that
+                  --  even if the expression is "True", some idiot might
+                  --  define True as False before the freeze point!
 
                   else
-                     Preanalyze_Spec_Expression (Expr, Standard_Boolean);
-
-                     --  If preanalysis gives a static expression, we don't
-                     --  need to delay (this will happen often in practice).
-
-                     if Is_OK_Static_Expression (Expr) then
-                        Delay_Required := False;
-
-                        if Is_False (Expr_Value (Expr)) then
-                           Set_Aspect_Cancel (Aitem);
-                        end if;
-
-                     --  If we don't get a static expression, then delay, the
-                     --  expression may turn out static by freeze time.
-
-                     else
-                        Delay_Required := True;
-                     end if;
+                     Delay_Required := True;
                   end if;
 
                --  Aspects corresponding to attribute definition clauses
@@ -880,31 +845,18 @@ 
                     Aspect_Bit_Order      |
                     Aspect_Component_Size |
                     Aspect_External_Tag   |
+                    Aspect_Input          |
                     Aspect_Machine_Radix  |
                     Aspect_Object_Size    |
+                    Aspect_Output         |
+                    Aspect_Read           |
                     Aspect_Size           |
                     Aspect_Storage_Pool   |
                     Aspect_Storage_Size   |
                     Aspect_Stream_Size    |
-                    Aspect_Value_Size     =>
+                    Aspect_Value_Size     |
+                    Aspect_Write          =>
 
-                  --  Preanalyze the expression with the appropriate type
-
-                  case A_Id is
-                     when Aspect_Address      =>
-                        T := RTE (RE_Address);
-                     when Aspect_Bit_Order    =>
-                        T := RTE (RE_Bit_Order);
-                     when Aspect_External_Tag =>
-                        T := Standard_String;
-                     when Aspect_Storage_Pool =>
-                        T := Class_Wide_Type (RTE (RE_Root_Storage_Pool));
-                     when others              =>
-                        T := Any_Integer;
-                  end case;
-
-                  Preanalyze_Spec_Expression (Expr, T);
-
                   --  Construct the attribute definition clause
 
                   Aitem :=
@@ -913,16 +865,9 @@ 
                       Chars      => Chars (Id),
                       Expression => Relocate_Node (Expr));
 
-                  --  We do not need a delay if we have a static expression
-
-                  if Is_OK_Static_Expression (Expression (Aitem)) then
-                     Delay_Required := False;
-
                   --  Here a delay is required
 
-                  else
-                     Delay_Required := True;
-                  end if;
+                  Delay_Required := True;
 
                --  Aspects corresponding to pragmas with two arguments, where
                --  the first argument is a local name referring to the entity,
@@ -946,27 +891,6 @@ 
 
                   Delay_Required := False;
 
-               --  Aspects corresponding to stream routines
-
-               when Aspect_Input  |
-                    Aspect_Output |
-                    Aspect_Read   |
-                    Aspect_Write  =>
-
-                  --  Construct the attribute definition clause
-
-                  Aitem :=
-                    Make_Attribute_Definition_Clause (Loc,
-                      Name       => Ent,
-                      Chars      => Chars (Id),
-                      Expression => Relocate_Node (Expr));
-
-                  --  These are always delayed (typically the subprogram that
-                  --  is referenced cannot have been declared yet, since it has
-                  --  a reference to the type for which this aspect is defined.
-
-                  Delay_Required := True;
-
                --  Aspects corresponding to pragmas with two arguments, where
                --  the second argument is a local name referring to the entity,
                --  and the first argument is the aspect definition expression.
@@ -985,7 +909,7 @@ 
                       Class_Present                => Class_Present (Aspect));
 
                   --  We don't have to play the delay game here, since the only
-                  --  values are check names which don't get analyzed anyway.
+                  --  values are ON/OFF which don't get analyzed anyway.
 
                   Delay_Required := False;
 
@@ -1015,7 +939,7 @@ 
                   --  these conditions together in a complex OR expression
 
                   if Pname = Name_Postcondition
-                       or else not Class_Present (Aspect)
+                    or else not Class_Present (Aspect)
                   then
                      while Nkind (Expr) = N_And_Then loop
                         Insert_After (Aspect,