diff options
author | Hristian Kirtchev <kirtchev@adacore.com> | 2018-05-23 10:22:52 +0000 |
---|---|---|
committer | Pierre-Marie de Rodat <pmderodat@gcc.gnu.org> | 2018-05-23 10:22:52 +0000 |
commit | 0c9849e18b134711873df3bccd93d6b6faa93c6f (patch) | |
tree | c4db8bc4ea28bcc4d537f6ecf823d7d698c20e1d /gcc | |
parent | 51ab2a39e9baae7fe1552daca02337050b11cfb6 (diff) | |
download | gcc-0c9849e18b134711873df3bccd93d6b6faa93c6f.zip gcc-0c9849e18b134711873df3bccd93d6b6faa93c6f.tar.gz gcc-0c9849e18b134711873df3bccd93d6b6faa93c6f.tar.bz2 |
[Ada] Suspension and elaboration warnings/checks
This patch modifies the static elaboration model to stop the inspection of
a task body when it contains a synchronous suspension call and restriction
No_Entry_Calls_In_Elaboration_Code or switch -gnatd_s is in effect.
------------
-- Source --
------------
-- suspension.ads
package Suspension is
procedure ABE;
task type Barrier_Task_1;
task type Barrier_Task_2;
task type Object_Task_1;
task type Object_Task_2;
end Suspension;
-- suspension.adb
with Ada.Synchronous_Barriers; use Ada.Synchronous_Barriers;
with Ada.Synchronous_Task_Control; use Ada.Synchronous_Task_Control;
package body Suspension is
Bar : Synchronous_Barrier (Barrier_Limit'Last);
Obj : Suspension_Object;
task body Barrier_Task_1 is
OK : Boolean;
begin
Wait_For_Release (Bar, OK);
ABE;
end Barrier_Task_1;
task body Barrier_Task_2 is
procedure Block is
OK : Boolean;
begin
Wait_For_Release (Bar, OK);
end Block;
begin
Block;
ABE;
end Barrier_Task_2;
task body Object_Task_1 is
begin
Suspend_Until_True (Obj);
ABE;
end Object_Task_1;
task body Object_Task_2 is
procedure Block is
begin
Suspend_Until_True (Obj);
end Block;
begin
Block;
ABE;
end Object_Task_2;
function Elaborator return Boolean is
BT_1 : Barrier_Task_1;
BT_2 : Barrier_Task_2;
OT_1 : Object_Task_1;
OT_2 : Object_Task_2;
begin
return True;
end Elaborator;
Elab : constant Boolean := Elaborator;
procedure ABE is begin null; end ABE;
end Suspension;
-- main.adb
with Suspension;
procedure Main is begin null; end Main;
----------------------------
-- Compilation and output --
----------------------------
$ gnatmake -q -gnatd_s main.adb
suspension.adb:23:07: warning: cannot call "ABE" before body seen
suspension.adb:23:07: warning: Program_Error may be raised at run time
suspension.adb:23:07: warning: body of unit "Suspension" elaborated
suspension.adb:23:07: warning: function "Elaborator" called at line 51
suspension.adb:23:07: warning: local tasks of "Elaborator" activated
suspension.adb:23:07: warning: procedure "ABE" called at line 23
suspension.adb:39:07: warning: cannot call "ABE" before body seen
suspension.adb:39:07: warning: Program_Error may be raised at run time
suspension.adb:39:07: warning: body of unit "Suspension" elaborated
suspension.adb:39:07: warning: function "Elaborator" called at line 51
suspension.adb:39:07: warning: local tasks of "Elaborator" activated
suspension.adb:39:07: warning: procedure "ABE" called at line 39
2018-05-23 Hristian Kirtchev <kirtchev@adacore.com>
gcc/ada/
* debug.adb: Switch -gnatd_s is now used to stop elaboration checks on
synchronized suspension.
* rtsfind.ads: Add entries for units Ada.Synchronous_Barriers and
Ada.Synchronous_Task_Control and routines Suspend_Until_True and
Wait_For_Release.
* sem_elab.adb: Document switch -gnatd_s.
(In_Task_Body): New routine.
(Is_Potential_Scenario): Code cleanup. Stop the traversal of a task
body when the current construct denotes a synchronous suspension call,
and restriction No_Entry_Calls_In_Elaboration_Code or switch -gnatd_s
is in effect.
(Is_Synchronous_Suspension_Call): New routine.
* switch-c.adb (Scan_Front_End_Switches): Switch -gnatJ now sets switch
-gnatd_s.
From-SVN: r260585
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ada/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/ada/debug.adb | 6 | ||||
-rw-r--r-- | gcc/ada/rtsfind.ads | 10 | ||||
-rw-r--r-- | gcc/ada/sem_elab.adb | 141 | ||||
-rw-r--r-- | gcc/ada/switch-c.adb | 3 |
5 files changed, 160 insertions, 17 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index abc289c..f24eda6 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,20 @@ +2018-05-23 Hristian Kirtchev <kirtchev@adacore.com> + + * debug.adb: Switch -gnatd_s is now used to stop elaboration checks on + synchronized suspension. + * rtsfind.ads: Add entries for units Ada.Synchronous_Barriers and + Ada.Synchronous_Task_Control and routines Suspend_Until_True and + Wait_For_Release. + * sem_elab.adb: Document switch -gnatd_s. + (In_Task_Body): New routine. + (Is_Potential_Scenario): Code cleanup. Stop the traversal of a task + body when the current construct denotes a synchronous suspension call, + and restriction No_Entry_Calls_In_Elaboration_Code or switch -gnatd_s + is in effect. + (Is_Synchronous_Suspension_Call): New routine. + * switch-c.adb (Scan_Front_End_Switches): Switch -gnatJ now sets switch + -gnatd_s. + 2018-05-23 Javier Miranda <miranda@adacore.com> * exp_disp.adb (Make_DT): Restrict the initialization of diff --git a/gcc/ada/debug.adb b/gcc/ada/debug.adb index c9b4aad..0324433 100644 --- a/gcc/ada/debug.adb +++ b/gcc/ada/debug.adb @@ -163,7 +163,7 @@ package body Debug is -- d_p Ignore assertion pragmas for elaboration -- d_q -- d_r - -- d_s + -- d_s Stop elaboration checks on synchronous suspension -- d_t -- d_u -- d_v @@ -839,6 +839,10 @@ package body Debug is -- semantics of invariants and postconditions in both the static and -- dynamic elaboration models. + -- d_s The compiler stops the examination of a task body once it reaches + -- a call to routine Ada.Synchronous_Task_Control.Suspend_Until_True + -- or Ada.Synchronous_Barriers.Wait_For_Release. + -- d_L Output trace information on elaboration checking. This debug switch -- causes output to be generated showing each call or instantiation as -- it is checked, and the progress of the recursive trace through diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads index b7d0766..5385258 100644 --- a/gcc/ada/rtsfind.ads +++ b/gcc/ada/rtsfind.ads @@ -131,6 +131,8 @@ package Rtsfind is Ada_Real_Time, Ada_Streams, Ada_Strings, + Ada_Synchronous_Barriers, + Ada_Synchronous_Task_Control, Ada_Tags, Ada_Task_Identification, Ada_Task_Termination, @@ -609,6 +611,10 @@ package Rtsfind is RE_Unbounded_String, -- Ada.Strings.Unbounded + RE_Wait_For_Release, -- Ada.Synchronous_Barriers + + RE_Suspend_Until_True, -- Ada.Synchronous_Task_Control + RE_Access_Level, -- Ada.Tags RE_Alignment, -- Ada.Tags RE_Address_Array, -- Ada.Tags @@ -1847,6 +1853,10 @@ package Rtsfind is RE_Unbounded_String => Ada_Strings_Unbounded, + RE_Wait_For_Release => Ada_Synchronous_Barriers, + + RE_Suspend_Until_True => Ada_Synchronous_Task_Control, + RE_Access_Level => Ada_Tags, RE_Alignment => Ada_Tags, RE_Address_Array => Ada_Tags, diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb index 72d80f8..0b369ea 100644 --- a/gcc/ada/sem_elab.adb +++ b/gcc/ada/sem_elab.adb @@ -500,6 +500,14 @@ package body Sem_Elab is -- As a result, the assertion expressions of the pragmas are not -- processed. -- + -- -gnatd_s stop elaboration checks on synchronous suspension + -- + -- The ABE mechanism stops the traversal of a task body when it + -- encounters a call to one of the following routines: + -- + -- Ada.Synchronous_Barriers.Wait_For_Release + -- Ada.Synchronous_Task_Control.Suspend_Until_True + -- -- -gnatd.U ignore indirect calls for static elaboration -- -- The ABE mechanism does not consider '[Unrestricted_]Access of @@ -554,6 +562,7 @@ package body Sem_Elab is -- -gnatd_i -- -gnatdL -- -gnatd_p + -- -gnatd_s -- -gnatd.U -- -gnatd.y -- @@ -1339,6 +1348,10 @@ package body Sem_Elab is -- context ignoring enclosing library levels. Nested_OK should be set when -- the context of N1 can enclose that of N2. + function In_Task_Body (N : Node_Id) return Boolean; + pragma Inline (In_Task_Body); + -- Determine whether arbitrary node N appears within a task body + procedure Info_Call (Call : Node_Id; Target_Id : Entity_Id; @@ -1592,6 +1605,14 @@ package body Sem_Elab is -- Determine whether arbitrary node N is a suitable variable reference for -- ABE processing. + function Is_Synchronous_Suspension_Call (N : Node_Id) return Boolean; + pragma Inline (Is_Synchronous_Suspension_Call); + -- Determine whether arbitrary node N denotes a call to one the following + -- routines: + -- + -- Ada.Synchronous_Barriers.Wait_For_Release + -- Ada.Synchronous_Task_Control.Suspend_Until_True + function Is_Task_Entry (Id : Entity_Id) return Boolean; pragma Inline (Is_Task_Entry); -- Determine whether arbitrary entity Id denotes a task entry @@ -6170,6 +6191,39 @@ package body Sem_Elab is return False; end In_Same_Context; + ------------------ + -- In_Task_Body -- + ------------------ + + function In_Task_Body (N : Node_Id) return Boolean is + Par : Node_Id; + + begin + -- Climb the parent chain looking for a task body [procedure] + + Par := N; + while Present (Par) loop + if Nkind (Par) = N_Task_Body then + return True; + + elsif Nkind (Par) = N_Subprogram_Body + and then Is_Task_Body_Procedure (Par) + then + return True; + + -- Prevent the search from going too far. Note that this predicate + -- shares nodes with the two cases above, and must come last. + + elsif Is_Body_Or_Package_Declaration (Par) then + return False; + end if; + + Par := Parent (Par); + end loop; + + return False; + end In_Task_Body; + ---------------- -- Initialize -- ---------------- @@ -7553,6 +7607,33 @@ package body Sem_Elab is return Nkind (N) = N_Variable_Reference_Marker; end Is_Suitable_Variable_Reference; + ------------------------------------ + -- Is_Synchronous_Suspension_Call -- + ------------------------------------ + + function Is_Synchronous_Suspension_Call (N : Node_Id) return Boolean is + Call_Attrs : Call_Attributes; + Target_Id : Entity_Id; + + begin + -- To qualify, the call must invoke one of the runtime routines which + -- perform synchronous suspension. + + if Is_Suitable_Call (N) then + Extract_Call_Attributes + (Call => N, + Target_Id => Target_Id, + Attrs => Call_Attrs); + + return + Is_RTE (Target_Id, RE_Suspend_Until_True) + or else + Is_RTE (Target_Id, RE_Wait_For_Release); + end if; + + return False; + end Is_Synchronous_Suspension_Call; + ------------------- -- Is_Task_Entry -- ------------------- @@ -7770,7 +7851,7 @@ package body Sem_Elab is return Decl; -- Otherwise the construct terminates the region where the - -- preelabortion-related pragma may appear. + -- preelaboration-related pragma may appear. else exit; @@ -11110,24 +11191,52 @@ package body Sem_Elab is if Is_Non_Library_Level_Encapsulator (Nod) then return Skip; - -- Terminate the traversal of a task body with an accept statement - -- when no entry calls in elaboration are allowed because the task - -- will block at run-time and the remaining statements will not be - -- executed. - - elsif Nkind_In (Original_Node (Nod), N_Accept_Statement, - N_Selective_Accept) + -- Terminate the traversal of a task body when encountering an + -- accept or select statement, and + -- + -- * Entry calls during elaboration are not allowed. In this + -- case the accept or select statement will cause the task + -- to block at elaboration time because there are no entry + -- calls to unblock it. + -- + -- or + -- + -- * Switch -gnatd_a (stop elaboration checks on accept or + -- select statement) is in effect. + + elsif (Debug_Flag_Underscore_A + or else Restriction_Active + (No_Entry_Calls_In_Elaboration_Code)) + and then Nkind_In (Original_Node (Nod), N_Accept_Statement, + N_Selective_Accept) then - if Restriction_Active (No_Entry_Calls_In_Elaboration_Code) then - return Abandon; + return Abandon; - -- The same behavior is achieved when switch -gnatd_a (stop - -- elabortion checks on accept or select statement) is in - -- effect. + -- Terminate the traversal of a task body when encountering a + -- suspension call, and + -- + -- * Entry calls during elaboration are not allowed. In this + -- case the suspension call emulates an entry call and will + -- cause the task to block at elaboration time. + -- + -- or + -- + -- * Switch -gnatd_s (stop elaboration checks on synchronous + -- suspension) is in effect. + -- + -- Note that the guard should not be checking the state of flag + -- Within_Task_Body because only suspension calls which appear + -- immediately within the statements of the task are supported. + -- Flag Within_Task_Body carries over to deeper levels of the + -- traversal. - elsif Debug_Flag_Underscore_A then - return Abandon; - end if; + elsif (Debug_Flag_Underscore_S + or else Restriction_Active + (No_Entry_Calls_In_Elaboration_Code)) + and then Is_Synchronous_Suspension_Call (Nod) + and then In_Task_Body (Nod) + then + return Abandon; -- Certain nodes carry semantic lists which act as repositories -- until expansion transforms the node and relocates the contents. diff --git a/gcc/ada/switch-c.adb b/gcc/ada/switch-c.adb index 94a2703..183d0ef 100644 --- a/gcc/ada/switch-c.adb +++ b/gcc/ada/switch-c.adb @@ -974,6 +974,8 @@ package body Switch.C is -- -gnatd_i (ignore activations and calls to instances for -- elaboration) -- -gnatd_p (ignore assertion pragmas for elaboration) + -- -gnatd_s (stop elaboration checks on synchronous + -- suspension) -- -gnatdL (ignore external calls from instances for -- elaboration) @@ -982,6 +984,7 @@ package body Switch.C is Debug_Flag_Underscore_E := True; Debug_Flag_Underscore_I := True; Debug_Flag_Underscore_P := True; + Debug_Flag_Underscore_S := True; Debug_Flag_LL := True; end if; |