Patchwork [Ada] Implement restriction No_Allocators_After_Elaboration

login
register
mail settings
Submitter Arnaud Charlet
Date Oct. 8, 2010, 12:54 p.m.
Message ID <20101008125447.GA3742@adacore.com>
Download mbox | patch
Permalink /patch/67190/
State New
Headers show

Comments

Arnaud Charlet - Oct. 8, 2010, 12:54 p.m.
This patch implements AI 0189, which introduces a new restriction
No_Allocators_After_Elaboration. We do not implement any attempt
at run-time checks, but we perform the required static checks if
the restriction is active (no allocators in main program body,
and no allocators in task bodies).

The following program:

pragma Restrictions (No_Allocators_After_Elaboration);
with NAAE_Tasks;
procedure NAAE_Main is
   type R is access all Integer;
   B : R := new Integer'(12);  -- OK
   C : R;
begin
   C := new Integer'(12); -- FLAGGED BY BINDER
end;

package NAAE_Tasks is
   task type R;
end NAAE_Tasks;

pragma Restrictions (No_Allocators_After_Elaboration);
with NAAE_Tasks;
procedure NAAE_Main is
   type R is access all Integer;
   B : R := new Integer'(12);  -- OK
   C : R;
begin
   C := new Integer'(12); -- FLAGGED BY BINDER
end;

compiles without errors, but the binder complains about the
violations of the restriction as follows:

error: "naae_main.adb" has restriction No_Allocators_After_Elaboration
error: but the following files violate this restriction:
error:   "naae_tasks.adb"

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

2010-10-08  Robert Dewar  <dewar@adacore.com>

	* ali.adb: Set Allocator_In_Body if AB parameter present on M line
	* ali.ads (Allocator_In_Body): New flag
	* bcheck.adb (Check_Consistent_Restrictions): Handle case of main
	program violating No_Allocators_After_Elaboration restriction.
	* gnatbind.adb (No_Restriction_List): Add entries for
	No_Anonymous_Allocators, and No_Allocators_After_Elaboration.
	* lib-load.adb: Initialize Has_Allocator flag
	* lib-writ.adb: Initialize Has_Allocator flag
	(M_Parameters): Set AB switch if Has_Allocator flag set
	* lib-writ.ads: Document AB flag on M line
	* lib.adb (Has_Allocator): New function
	(Set_Has_Allocator): New procedure
	* lib.ads (Has_Allocator): New function
	(Set_Has_Allocator): New procedure
	(Has_Allocator): New flag in Unit_Record
	* sem_ch4.adb (Analyze_Allocator): Add processing for
	No_Allocators_After_Elaboration.

Patch

Index: lib.adb
===================================================================
--- lib.adb	(revision 165080)
+++ lib.adb	(working copy)
@@ -113,6 +113,11 @@  package body Lib is
       return Units.Table (U).Generate_Code;
    end Generate_Code;
 
+   function Has_Allocator (U : Unit_Number_Type) return Boolean is
+   begin
+      return Units.Table (U).Has_Allocator;
+   end Has_Allocator;
+
    function Has_RACW (U : Unit_Number_Type) return Boolean is
    begin
       return Units.Table (U).Has_RACW;
@@ -198,6 +203,11 @@  package body Lib is
       Units.Table (U).Generate_Code := B;
    end Set_Generate_Code;
 
+   procedure Set_Has_Allocator (U : Unit_Number_Type; B : Boolean := True) is
+   begin
+      Units.Table (U).Has_Allocator := B;
+   end Set_Has_Allocator;
+
    procedure Set_Has_RACW (U : Unit_Number_Type; B : Boolean := True) is
    begin
       Units.Table (U).Has_RACW := B;
Index: lib.ads
===================================================================
--- lib.ads	(revision 165080)
+++ lib.ads	(working copy)
@@ -357,6 +357,10 @@  package Lib is
    --      that the default priority is to be used (and is also used for
    --      entries that do not correspond to possible main programs).
 
+   --    Has_Allocator
+   --      This flag is set if a subprogram unit has an allocator after the
+   --      BEGIN (it is used to set the AB flag in the M ALI line).
+
    --    OA_Setting
    --      This is a character field containing L if Optimize_Alignment mode
    --      was set locally, and O/T/S for Off/Time/Space default if not.
@@ -397,6 +401,7 @@  package Lib is
    function Fatal_Error      (U : Unit_Number_Type) return Boolean;
    function Generate_Code    (U : Unit_Number_Type) return Boolean;
    function Ident_String     (U : Unit_Number_Type) return Node_Id;
+   function Has_Allocator    (U : Unit_Number_Type) return Boolean;
    function Has_RACW         (U : Unit_Number_Type) return Boolean;
    function Is_Compiler_Unit (U : Unit_Number_Type) return Boolean;
    function Loading          (U : Unit_Number_Type) return Boolean;
@@ -415,6 +420,7 @@  package Lib is
    procedure Set_Fatal_Error      (U : Unit_Number_Type; B : Boolean := True);
    procedure Set_Generate_Code    (U : Unit_Number_Type; B : Boolean := True);
    procedure Set_Has_RACW         (U : Unit_Number_Type; B : Boolean := True);
+   procedure Set_Has_Allocator    (U : Unit_Number_Type; B : Boolean := True);
    procedure Set_Is_Compiler_Unit (U : Unit_Number_Type; B : Boolean := True);
    procedure Set_Ident_String     (U : Unit_Number_Type; N : Node_Id);
    procedure Set_Loading          (U : Unit_Number_Type; B : Boolean := True);
@@ -653,6 +659,7 @@  private
    pragma Inline (Dependency_Num);
    pragma Inline (Fatal_Error);
    pragma Inline (Generate_Code);
+   pragma Inline (Has_Allocator);
    pragma Inline (Has_RACW);
    pragma Inline (Is_Compiler_Unit);
    pragma Inline (Increment_Serial_Number);
@@ -664,6 +671,7 @@  private
    pragma Inline (Set_Cunit_Entity);
    pragma Inline (Set_Fatal_Error);
    pragma Inline (Set_Generate_Code);
+   pragma Inline (Set_Has_Allocator);
    pragma Inline (Set_Has_RACW);
    pragma Inline (Set_Loading);
    pragma Inline (Set_Main_Priority);
@@ -693,6 +701,7 @@  private
       Is_Compiler_Unit : Boolean;
       Dynamic_Elab     : Boolean;
       Loading          : Boolean;
+      Has_Allocator    : Boolean;
       OA_Setting       : Character;
    end record;
 
@@ -720,7 +729,8 @@  private
       Dynamic_Elab     at 55 range 0 ..  7;
       Is_Compiler_Unit at 56 range 0 ..  7;
       OA_Setting       at 57 range 0 ..  7;
-      Loading          at 58 range 0 .. 15;
+      Loading          at 58 range 0 ..  7;
+      Has_Allocator    at 59 range 0 ..  7;
    end record;
 
    for Unit_Record'Size use 60 * 8;
Index: lib-writ.adb
===================================================================
--- lib-writ.adb	(revision 165080)
+++ lib-writ.adb	(working copy)
@@ -80,6 +80,7 @@  package body Lib.Writ is
          Dynamic_Elab     => False,
          Fatal_Error      => False,
          Generate_Code    => False,
+         Has_Allocator    => False,
          Has_RACW         => False,
          Is_Compiler_Unit => False,
          Ident_String     => Empty,
@@ -135,6 +136,7 @@  package body Lib.Writ is
         Dynamic_Elab     => False,
         Fatal_Error      => False,
         Generate_Code    => False,
+        Has_Allocator    => False,
         Has_RACW         => False,
         Is_Compiler_Unit => False,
         Ident_String     => Empty,
@@ -925,6 +927,10 @@  package body Lib.Writ is
                Write_Info_Nat (Opt.Time_Slice_Value);
             end if;
 
+            if Has_Allocator (Main_Unit) then
+               Write_Info_Str (" AB");
+            end if;
+
             Write_Info_Str (" W=");
             Write_Info_Char
               (WC_Encoding_Letters (Wide_Character_Encoding_Method));
Index: lib-writ.ads
===================================================================
--- lib-writ.ads	(revision 165080)
+++ lib-writ.ads	(working copy)
@@ -116,7 +116,7 @@  package Lib.Writ is
    --  -- M  Main Program --
    --  ---------------------
 
-   --    M type [priority] [T=time-slice] W=?
+   --    M type [priority] [T=time-slice] [AB] W=?
 
    --      This line appears only if the main unit for this file is suitable
    --      for use as a main program. The parameters are:
@@ -141,6 +141,15 @@  package Lib.Writ is
    --          milliseconds. The actual significance of this parameter is
    --          target dependent.
 
+   --        AB
+
+   --          Present if there is an allocator in the body of the procedure
+   --          after the BEGIN. This will be a violation of the restriction
+   --          No_Allocators_After_Elaboration if it is present, and this
+   --          unit is used as a main program (only the binder can find the
+   --          violation, since only the binder knows the main program).
+   --
+
    --        W=?
 
    --          This parameter indicates the wide character encoding method used
Index: sem_ch4.adb
===================================================================
--- sem_ch4.adb	(revision 165154)
+++ sem_ch4.adb	(working copy)
@@ -364,15 +364,60 @@  package body Sem_Ch4 is
       E        : Node_Id             := Expression (N);
       Acc_Type : Entity_Id;
       Type_Id  : Entity_Id;
+      P        : Node_Id;
+      C        : Node_Id;
 
    begin
+      --  Deal with allocator restrictions
+
       --  In accordance with H.4(7), the No_Allocators restriction only applies
-      --  to user-written allocators.
+      --  to user-written allocators. The same consideration applies to the
+      --  No_Allocators_Before_Elaboration restriction.
 
       if Comes_From_Source (N) then
          Check_Restriction (No_Allocators, N);
+
+         --  Processing for No_Allocators_After_Elaboration, loop to look at
+         --  enclosing context, checking task case and main subprogram case.
+
+         C := N;
+         P := Parent (C);
+         while Present (P) loop
+
+            --  In both cases we need a handled sequence of statements, where
+            --  the occurrence of the allocator is within the statements.
+
+            if Nkind (P) = N_Handled_Sequence_Of_Statements
+              and then Is_List_Member (C)
+              and then List_Containing (C) = Statements (P)
+            then
+               --  Check for allocator within task body, this is a definite
+               --  violation of No_Allocators_After_Elaboration we can detect.
+
+               if Nkind (Original_Node (Parent (P))) = N_Task_Body then
+                  Check_Restriction (No_Allocators_After_Elaboration, N);
+                  exit;
+               end if;
+
+               --  The other case is appearence in a subprogram body. This may
+               --  be a violation if this is a library level subprogram, and it
+               --  turns out to be used as the main program, but only the
+               --  binder knows that, so just record the occurrence.
+
+               if Nkind (Original_Node (Parent (P))) = N_Subprogram_Body
+                 and then Nkind (Parent (Parent (P))) = N_Compilation_Unit
+               then
+                  Set_Has_Allocator (Current_Sem_Unit);
+               end if;
+            end if;
+
+            C := P;
+            P := Parent (C);
+         end loop;
       end if;
 
+      --  Analyze the allocator
+
       if Nkind (E) = N_Qualified_Expression then
          Acc_Type := Create_Itype (E_Allocator_Type, N);
          Set_Etype (Acc_Type, Acc_Type);
Index: ali.adb
===================================================================
--- ali.adb	(revision 165080)
+++ ali.adb	(working copy)
@@ -828,6 +828,7 @@  package body ALI is
         Sfile                      => No_File,
         Task_Dispatching_Policy    => ' ',
         Time_Slice_Value           => -1,
+        Allocator_In_Body          => False,
         WC_Encoding                => 'b',
         Unit_Exception_Table       => False,
         Ver                        => (others => ' '),
@@ -910,6 +911,14 @@  package body ALI is
 
                Skip_Space;
 
+               if Nextc = 'A' then
+                  P := P + 1;
+                  Checkc ('B');
+                  ALIs.Table (Id).Allocator_In_Body := True;
+               end if;
+
+               Skip_Space;
+
                Checkc ('W');
                Checkc ('=');
                ALIs.Table (Id).WC_Encoding := Getc;
Index: ali.ads
===================================================================
--- ali.ads	(revision 165080)
+++ ali.ads	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 S p e c                                  --
 --                                                                          --
---          Copyright (C) 1992-2009, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2010, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -136,6 +136,10 @@  package ALI is
       --  line. A value of -1 indicates that no T=xxx parameter was found, or
       --  no M line was present. Not set if 'M' appears in Ignore_Lines.
 
+      Allocator_In_Body : Boolean;
+      --  Set True if an AB switch appears on the main program line. False
+      --  if no M line, or AB not present, or 'M appears in Ignore_Lines.
+
       WC_Encoding : Character;
       --  Wide character encoding if main procedure. Otherwise not relevant.
       --  Not set if 'M' appears in Ignore_Lines.
Index: lib-load.adb
===================================================================
--- lib-load.adb	(revision 165080)
+++ lib-load.adb	(working copy)
@@ -214,6 +214,7 @@  package body Lib.Load is
         Expected_Unit    => Spec_Name,
         Fatal_Error      => True,
         Generate_Code    => False,
+        Has_Allocator    => False,
         Has_RACW         => False,
         Is_Compiler_Unit => False,
         Ident_String     => Empty,
@@ -318,6 +319,7 @@  package body Lib.Load is
            Expected_Unit    => No_Unit_Name,
            Fatal_Error      => False,
            Generate_Code    => False,
+           Has_Allocator    => False,
            Has_RACW         => False,
            Is_Compiler_Unit => False,
            Ident_String     => Empty,
@@ -647,6 +649,7 @@  package body Lib.Load is
               Expected_Unit    => Uname_Actual,
               Fatal_Error      => False,
               Generate_Code    => False,
+              Has_Allocator    => False,
               Has_RACW         => False,
               Is_Compiler_Unit => False,
               Ident_String     => Empty,
Index: gnatbind.adb
===================================================================
--- gnatbind.adb	(revision 165080)
+++ gnatbind.adb	(working copy)
@@ -143,34 +143,40 @@  procedure Gnatbind is
       --  should not be listed.
 
       No_Restriction_List : constant array (All_Restrictions) of Boolean :=
-        (No_Exception_Propagation => True,
+        (No_Allocators_After_Elaboration => True,
+         --  This involves run-time conditions not checkable at compile time
+
+         No_Anonymous_Allocators         => True,
+         --  Premature, since we have not implemented this yet
+
+         No_Exception_Propagation        => True,
          --  Modifies code resulting in different exception semantics
 
-         No_Exceptions            => True,
+         No_Exceptions                   => True,
          --  Has unexpected Suppress (All_Checks) effect
 
-         No_Implicit_Conditionals => True,
+         No_Implicit_Conditionals        => True,
          --  This could modify and pessimize generated code
 
-         No_Implicit_Dynamic_Code => True,
+         No_Implicit_Dynamic_Code        => True,
          --  This could modify and pessimize generated code
 
-         No_Implicit_Loops        => True,
+         No_Implicit_Loops               => True,
          --  This could modify and pessimize generated code
 
-         No_Recursion             => True,
+         No_Recursion                    => True,
          --  Not checkable at compile time
 
-         No_Reentrancy            => True,
+         No_Reentrancy                   => True,
          --  Not checkable at compile time
 
-         Max_Entry_Queue_Length    => True,
+         Max_Entry_Queue_Length           => True,
          --  Not checkable at compile time
 
-         Max_Storage_At_Blocking  => True,
+         Max_Storage_At_Blocking         => True,
          --  Not checkable at compile time
 
-         others => False);
+         others                          => False);
 
       Additional_Restrictions_Listed : Boolean := False;
       --  Set True if we have listed header for restrictions
Index: bcheck.adb
===================================================================
--- bcheck.adb	(revision 165080)
+++ bcheck.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2009, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2010, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -854,6 +854,22 @@  package body Bcheck is
    --  Start of processing for Check_Consistent_Restrictions
 
    begin
+      --  A special test, if we have a main program, then if it has an
+      --  allocator in the body, this is considered to be a violation of
+      --  the restriction No_Allocators_After_Elaboration. We just mark
+      --  this restriction and then the normal circuit will flag it.
+
+      if Bind_Main_Program
+        and then ALIs.Table (ALIs.First).Main_Program /= None
+        and then not No_Main_Subprogram
+        and then ALIs.Table (ALIs.First).Allocator_In_Body
+      then
+         Cumulative_Restrictions.Violated
+           (No_Allocators_After_Elaboration) := True;
+         ALIs.Table (ALIs.First).Restrictions.Violated
+           (No_Allocators_After_Elaboration) := True;
+      end if;
+
       --  Loop through all restriction violations
 
       for R in All_Restrictions loop