Commit 75cfda8b by Hristian Kirtchev Committed by Pierre-Marie de Rodat

[Ada] Task-related circularities in Elaboration order v4.0

This patch adds another suggestion to the elaboration order diagnostics.
An elaboration circularity involving a task activation may be resolved
through pragma Restrictions (No_Entry_Calls_In_Elaboration_Code).

------------
-- Source --
------------

--  no_entry_calls.txt

pragma Restrictions (No_Entry_Calls_In_Elaboration_Code);

--  a.ads

package A is
   task type Task_Typ is
      entry Start;
   end Task_Typ;

   procedure Proc;
end A;

--  a.adb

with B;

package body A is
   task body Task_Typ is
   begin
      accept Start;
      B.Proc;
   end Task_Typ;

   Elab : Task_Typ;

   procedure Proc is null;
end A;

--  b.ads

package B is
   procedure Proc;
end B;

--  b.adb

with A;

package body B is
   procedure Proc is
   begin
      A.Proc;
   end Proc;
end B;

--  main.adb

with A;

--  +--> A spec               B spec
--  |      ^                  ^ ^
--  |      |        with      | |
--  |  sbb | +----------------+ | sbb
--  |      | |                  |
--  |      | |   Invocation     |
--  |    A body ------------> B body
--  |      ^                  | |
--  |      |     Invocation   | |
--  |      +------------------+ |
--  |                           |
--  |            Invocation     |
--  +---------------------------+
--
--  The cycle is:
--
--    A body --> A body

procedure Main is begin null; end Main;

----------------------------
-- Compilation and output --
----------------------------

$ gnatmake -f -q main.adb -gnatd_F
$ gnatmake -f -q main.adb -gnatec=no_entry_calls.txt
error: Elaboration circularity detected
info:
info:    Reason:
info:
info:      unit "a (body)" depends on its own elaboration
info:
info:    Circularity:
info:
info:      unit "a (body)" invokes a construct of unit "a (body)" at
             elaboration time
info:        path 1:
info:          elaboration of unit "a (body)"
info:          activation of local task declared at "a.ads":2:14
info:          call to subprogram "proc" declared at "b.ads":2:14
info:          call to subprogram "proc" declared at "a.ads":6:14
info:
info:    Suggestions:
info:
info:      use pragma Restrictions (No_Entry_Calls_In_Elaboration_Code)
info:      use the dynamic elaboration model (compiler switch -gnatE)
info:
gnatmake: *** bind failed.

2019-07-09  Hristian Kirtchev  <kirtchev@adacore.com>

gcc/ada/

	* bindo.ads: Move type Precedence_Kind from the private to the
	visible part of the unit.
	* bindo-augmentors.adb: Remove the use of global data as it is
	bad practice.
	(Augment_Library_Graph): Update the parameter profile.
	(Is_Visited, Set_Is_Visited): Remove.
	(Visit_Elaboration_Root, Visit_Elaboration_Roots): Update the
	parameter profile and comment on usage.
	(Visit_Vertex): Likewise.  Also keep track of which invocation
	edge activates a task.
	* bindo-augmentors.ads (Augment_Library_Graph): Update the
	parameter profile and comment on usage.
	* bindo-builders.adb (Create_Forced_Edge,
	Create_Spec_And_Body_Edge, Create_With_Edge): Update the call to
	Add_Edge.
	* bindo-diagnostics.adb: Add with end use clauses for Restrict
	and Rident.
	(Output_Dynamic_Model_Suggestions): Remove.
	(Output_Invocation_Related_Suggestions): New routine.
	(Output_Suggestions): Output all invocation-related suggestions
	together.
	* bindo-elaborators.adb: Remove types Comparator_Ptr and
	Predicate_Ptr.
	(Find_Best_Vertex): Update the parameter profile.
	* bindo-graphs.adb (Activates_Task): New routine.
	(Add_Body_Before_Spec_Edge): Update the call to
	Add_Edge_With_Return.
	(Add_Edge): Update the parameter profile and the call to
	Add_Edge_With_Return.
	(Add_Edge_With_Return): Update the parameter profile and comment
	on usage.
	(At_Least_One_Edge_Satisfies): New routine.
	(Contains_Elaborate_All_Edge): Reimplement.
	(Contains_Static_Successor_Edge, Contains_Task_Activation): New
	routine.
	(Contains_Weak_Static_Successor): Remove.
	(Is_Static_Successor_Edge): New routine.
	* bindo-graphs.ads: Add types LGE_Predicate_Ptr,
	LGV_Comparator_Ptr, and LGV_Predicate_Ptr.  Update type
	Library_Graph_Edge_Attributes to capture whether an invocation
	edge activates a task.  Update the value of
	No_Library_Graph_Edge_Attributes.
	(Activates_Task): Update the parameter profile and comment on
	usage.
	(Contains_Static_Successor_Edge, Contains_Task_Activation): New
	routines.
	(Contains_Weak_Static_Successor): Remove.
	* doc/gnat_ugn/elaboration_order_handling_in_gnat.rst:
	Update the documentation to reflect the new task-related advice.
	* gnat_ugn.texi: Regenerate.

From-SVN: r273286
parent 727e4d37
2019-07-09 Hristian Kirtchev <kirtchev@adacore.com>
* bindo.ads: Move type Precedence_Kind from the private to the
visible part of the unit.
* bindo-augmentors.adb: Remove the use of global data as it is
bad practice.
(Augment_Library_Graph): Update the parameter profile.
(Is_Visited, Set_Is_Visited): Remove.
(Visit_Elaboration_Root, Visit_Elaboration_Roots): Update the
parameter profile and comment on usage.
(Visit_Vertex): Likewise. Also keep track of which invocation
edge activates a task.
* bindo-augmentors.ads (Augment_Library_Graph): Update the
parameter profile and comment on usage.
* bindo-builders.adb (Create_Forced_Edge,
Create_Spec_And_Body_Edge, Create_With_Edge): Update the call to
Add_Edge.
* bindo-diagnostics.adb: Add with end use clauses for Restrict
and Rident.
(Output_Dynamic_Model_Suggestions): Remove.
(Output_Invocation_Related_Suggestions): New routine.
(Output_Suggestions): Output all invocation-related suggestions
together.
* bindo-elaborators.adb: Remove types Comparator_Ptr and
Predicate_Ptr.
(Find_Best_Vertex): Update the parameter profile.
* bindo-graphs.adb (Activates_Task): New routine.
(Add_Body_Before_Spec_Edge): Update the call to
Add_Edge_With_Return.
(Add_Edge): Update the parameter profile and the call to
Add_Edge_With_Return.
(Add_Edge_With_Return): Update the parameter profile and comment
on usage.
(At_Least_One_Edge_Satisfies): New routine.
(Contains_Elaborate_All_Edge): Reimplement.
(Contains_Static_Successor_Edge, Contains_Task_Activation): New
routine.
(Contains_Weak_Static_Successor): Remove.
(Is_Static_Successor_Edge): New routine.
* bindo-graphs.ads: Add types LGE_Predicate_Ptr,
LGV_Comparator_Ptr, and LGV_Predicate_Ptr. Update type
Library_Graph_Edge_Attributes to capture whether an invocation
edge activates a task. Update the value of
No_Library_Graph_Edge_Attributes.
(Activates_Task): Update the parameter profile and comment on
usage.
(Contains_Static_Successor_Edge, Contains_Task_Activation): New
routines.
(Contains_Weak_Static_Successor): Remove.
* doc/gnat_ugn/elaboration_order_handling_in_gnat.rst:
Update the documentation to reflect the new task-related advice.
* gnat_ugn.texi: Regenerate.
2019-07-09 Piotr Trojanek <trojanek@adacore.com>
* exp_util.adb (Containing_Package_With_Ext_Axioms): Replace
......
......@@ -43,10 +43,10 @@ package Bindo.Augmentors is
package Library_Graph_Augmentors is
procedure Augment_Library_Graph
(Inv_G : Invocation_Graph;
Lib_G : Library_Graph);
-- Augment library graph Lib_G with information from invocation graph
-- Inv_G as follows:
(Inv_Graph : Invocation_Graph;
Lib_Graph : Library_Graph);
-- Augment library graph Lib_Graph with information from invocation
-- graph Inv_Graph as follows:
--
-- 1) Traverse the invocation graph starting from each elaboration
-- procedure of unit Root.
......
......@@ -415,10 +415,11 @@ package body Bindo.Builders is
Write_Eol;
Add_Edge
(G => Lib_Graph,
Pred => Pred_Vertex,
Succ => Succ_Vertex,
Kind => Forced_Edge);
(G => Lib_Graph,
Pred => Pred_Vertex,
Succ => Succ_Vertex,
Kind => Forced_Edge,
Activates_Task => False);
end Create_Forced_Edge;
-------------------------
......@@ -497,10 +498,11 @@ package body Bindo.Builders is
Set_Corresponding_Item (Lib_Graph, Vertex, Extra_Vertex);
Add_Edge
(G => Lib_Graph,
Pred => Extra_Vertex,
Succ => Vertex,
Kind => Spec_Before_Body_Edge);
(G => Lib_Graph,
Pred => Extra_Vertex,
Succ => Vertex,
Kind => Spec_Before_Body_Edge,
Activates_Task => False);
-- The unit denotes a spec with a completing body. Link the spec and
-- body.
......@@ -570,12 +572,13 @@ package body Bindo.Builders is
if Is_Spec_With_Body (Lib_Graph, Withed_Vertex) then
Add_Edge
(G => Lib_Graph,
Pred =>
(G => Lib_Graph,
Pred =>
Corresponding_Vertex
(Lib_Graph, Corresponding_Body (Withed_U_Id)),
Succ => Succ,
Kind => Kind);
Succ => Succ,
Kind => Kind,
Activates_Task => False);
end if;
-- The with comes with pragma Elaborate_All. Treat the edge as a with
......@@ -597,10 +600,11 @@ package body Bindo.Builders is
-- successor.
Add_Edge
(G => Lib_Graph,
Pred => Withed_Vertex,
Succ => Succ,
Kind => Kind);
(G => Lib_Graph,
Pred => Withed_Vertex,
Succ => Succ,
Kind => Kind,
Activates_Task => False);
end Create_With_Edge;
-----------------------
......
......@@ -23,9 +23,11 @@
-- --
------------------------------------------------------------------------------
with Binderr; use Binderr;
with Debug; use Debug;
with Types; use Types;
with Binderr; use Binderr;
with Debug; use Debug;
with Restrict; use Restrict;
with Rident; use Rident;
with Types; use Types;
with Bindo.Validators;
use Bindo.Validators;
......@@ -77,13 +79,6 @@ package body Bindo.Diagnostics is
-- Suggest the diagnostic of all cycles in library graph G if circumstances
-- allow it.
procedure Output_Dynamic_Model_Suggestions
(G : Library_Graph;
Cycle : Library_Graph_Cycle_Id);
pragma Inline (Output_Dynamic_Model_Suggestions);
-- Suggest the use of the dynamic elaboration model to break cycle Cycle of
-- library graph G if circumstances allow it.
procedure Output_Elaborate_All_Suggestions
(G : Library_Graph;
Pred : Library_Graph_Vertex_Id;
......@@ -192,6 +187,13 @@ package body Bindo.Diagnostics is
-- Output a transition through edge Edge of invocation graph G, which is
-- part of an invocation path. Lib_Graph is the related library graph.
procedure Output_Invocation_Related_Suggestions
(G : Library_Graph;
Cycle : Library_Graph_Cycle_Id);
pragma Inline (Output_Invocation_Related_Suggestions);
-- Suggest ways to break cycle Cycle of library graph G that involves at
-- least one invocation edge.
procedure Output_Invocation_Transition
(Inv_Graph : Invocation_Graph;
Lib_Graph : Library_Graph;
......@@ -523,30 +525,6 @@ package body Bindo.Diagnostics is
end Output_All_Cycles_Suggestions;
--------------------------------------
-- Output_Dynamic_Model_Suggestions --
--------------------------------------
procedure Output_Dynamic_Model_Suggestions
(G : Library_Graph;
Cycle : Library_Graph_Cycle_Id)
is
begin
pragma Assert (Present (G));
pragma Assert (Present (Cycle));
-- The cycle contains at least one invocation edge where the successor
-- was statically elaborated. Using the dynamic model may eliminate an
-- invocation edge, and thus the cycle.
if Invocation_Edge_Count (G, Cycle) > 0
and then Contains_Weak_Static_Successor (G, Cycle)
then
Error_Msg_Info
(" use the dynamic elaboration model (compiler switch -gnatE)");
end if;
end Output_Dynamic_Model_Suggestions;
--------------------------------------
-- Output_Elaborate_All_Suggestions --
--------------------------------------
......@@ -1155,6 +1133,48 @@ package body Bindo.Diagnostics is
end case;
end Output_Invocation_Path_Transition;
-------------------------------------------
-- Output_Invocation_Related_Suggestions --
-------------------------------------------
procedure Output_Invocation_Related_Suggestions
(G : Library_Graph;
Cycle : Library_Graph_Cycle_Id)
is
begin
pragma Assert (Present (G));
pragma Assert (Present (Cycle));
-- Nothing to do when the cycle does not contain an invocation edge
if Invocation_Edge_Count (G, Cycle) = 0 then
return;
end if;
-- The cycle contains at least one invocation edge, where at least
-- one of the paths the edge represents activates a task. The use of
-- restriction No_Entry_Calls_In_Elaboration_Code may halt the flow
-- within the task body on a select or accept statement, eliminating
-- subsequent invocation edges, thus breaking the cycle.
if not Restriction_Active (No_Entry_Calls_In_Elaboration_Code)
and then Contains_Task_Activation (G, Cycle)
then
Error_Msg_Info
(" use pragma Restrictions "
& "(No_Entry_Calls_In_Elaboration_Code)");
end if;
-- The cycle contains at least one invocation edge where the successor
-- was statically elaborated. The use of the dynamic model may remove
-- one of the invocation edges in the cycle, thus breaking the cycle.
if Contains_Static_Successor_Edge (G, Cycle) then
Error_Msg_Info
(" use the dynamic elaboration model (compiler switch -gnatE)");
end if;
end Output_Invocation_Related_Suggestions;
----------------------------------
-- Output_Invocation_Transition --
----------------------------------
......@@ -1257,7 +1277,7 @@ package body Bindo.Diagnostics is
-- Output general purpose suggestions
Output_Dynamic_Model_Suggestions
Output_Invocation_Related_Suggestions
(G => G,
Cycle => Cycle);
......
......@@ -180,20 +180,11 @@ package body Bindo.Elaborators is
-- can be elaborated. Step is the current step in the elaboration order.
-- Indent is the desired indentation level for tracing.
type Comparator_Ptr is access function
(G : Library_Graph;
Vertex : Library_Graph_Vertex_Id;
Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind;
type Predicate_Ptr is access function
(G : Library_Graph;
Vertex : Library_Graph_Vertex_Id) return Boolean;
function Find_Best_Vertex
(G : Library_Graph;
Set : LGV_Sets.Membership_Set;
Is_Suitable_Vertex : Predicate_Ptr;
Compare_Vertices : Comparator_Ptr;
Is_Suitable_Vertex : LGV_Predicate_Ptr;
Compare_Vertices : LGV_Comparator_Ptr;
Initial_Best_Msg : String;
Subsequent_Best_Msg : String;
Step : Elaboration_Order_Step;
......@@ -917,8 +908,8 @@ package body Bindo.Elaborators is
function Find_Best_Vertex
(G : Library_Graph;
Set : LGV_Sets.Membership_Set;
Is_Suitable_Vertex : Predicate_Ptr;
Compare_Vertices : Comparator_Ptr;
Is_Suitable_Vertex : LGV_Predicate_Ptr;
Compare_Vertices : LGV_Comparator_Ptr;
Initial_Best_Msg : String;
Subsequent_Best_Msg : String;
Step : Elaboration_Order_Step;
......
......@@ -732,18 +732,33 @@ package Bindo.Graphs is
type Library_Graph is private;
Nil : constant Library_Graph;
type LGE_Predicate_Ptr is access function
(G : Library_Graph;
Edge : Library_Graph_Edge_Id) return Boolean;
type LGV_Comparator_Ptr is access function
(G : Library_Graph;
Vertex : Library_Graph_Vertex_Id;
Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind;
type LGV_Predicate_Ptr is access function
(G : Library_Graph;
Vertex : Library_Graph_Vertex_Id) return Boolean;
----------------------
-- Graph operations --
----------------------
procedure Add_Edge
(G : Library_Graph;
Pred : Library_Graph_Vertex_Id;
Succ : Library_Graph_Vertex_Id;
Kind : Library_Graph_Edge_Kind);
(G : Library_Graph;
Pred : Library_Graph_Vertex_Id;
Succ : Library_Graph_Vertex_Id;
Kind : Library_Graph_Edge_Kind;
Activates_Task : Boolean);
pragma Inline (Add_Edge);
-- Create a new edge in library graph G with source vertex Pred and
-- destination vertex Succ. Kind denotes the nature of the edge.
-- destination vertex Succ. Kind denotes the nature of the edge. Flag
-- Activates_Task should be set when the edge involves task activation.
procedure Add_Vertex
(G : Library_Graph;
......@@ -895,6 +910,12 @@ package Bindo.Graphs is
-- Edge attributes --
---------------------
function Activates_Task
(G : Library_Graph;
Edge : Library_Graph_Edge_Id) return Boolean;
pragma Inline (Activates_Task);
-- Determine whether edge Edge of library graph G activates a task
function Kind
(G : Library_Graph;
Edge : Library_Graph_Edge_Id) return Library_Graph_Edge_Kind;
......@@ -987,13 +1008,21 @@ package Bindo.Graphs is
-- Determine whether cycle Cycle of library graph G contains an
-- Elaborate_All edge.
function Contains_Weak_Static_Successor
function Contains_Static_Successor_Edge
(G : Library_Graph;
Cycle : Library_Graph_Cycle_Id) return Boolean;
pragma Inline (Contains_Weak_Static_Successor);
-- Determine whether cycle Cycle of library graph G contains a weak edge
pragma Inline (Contains_Static_Successor_Edge);
-- Determine whether cycle Cycle of library graph G contains an edge
-- where the successor was compiled using the static model.
function Contains_Task_Activation
(G : Library_Graph;
Cycle : Library_Graph_Cycle_Id) return Boolean;
pragma Inline (Contains_Task_Activation);
-- Determine whether cycle Cycle of library graph G contains an
-- invocation edge where the path it represents involves a task
-- activation.
function Has_Elaborate_All_Cycle (G : Library_Graph) return Boolean;
pragma Inline (Has_Elaborate_All_Cycle);
-- Determine whether library graph G contains a cycle involving pragma
......@@ -1439,13 +1468,18 @@ package Bindo.Graphs is
-- The following type represents the attributes of a library graph edge
type Library_Graph_Edge_Attributes is record
Activates_Task : Boolean := False;
-- Set for an invocation edge, where at least one of the paths the
-- edge represents activates a task.
Kind : Library_Graph_Edge_Kind := No_Edge;
-- The nature of the library graph edge
end record;
No_Library_Graph_Edge_Attributes :
constant Library_Graph_Edge_Attributes :=
(Kind => No_Edge);
(Activates_Task => False,
Kind => No_Edge);
procedure Destroy_Library_Graph_Edge_Attributes
(Attrs : in out Library_Graph_Edge_Attributes);
......
......@@ -31,6 +31,14 @@ with Namet; use Namet;
package Bindo is
-- The following type represents the various kinds of precedence between
-- two items.
type Precedence_Kind is
(Lower_Precedence,
Equal_Precedence,
Higher_Precedence);
procedure Find_Elaboration_Order
(Order : out Unit_Id_Table;
Main_Lib_File : File_Name_Type);
......@@ -41,14 +49,4 @@ package Bindo is
-- exists, it is returned in Order, otherwise Unrecoverable_Error is
-- raised.
private
-- The following type represents the various kinds of precedence between
-- two items.
type Precedence_Kind is
(Lower_Precedence,
Equal_Precedence,
Higher_Precedence);
end Bindo;
......@@ -1014,6 +1014,23 @@ following tactics to eliminate the circularity:
The programmer should remove the pragma as advised, and rebuild the program.
* Use of pragma Restrictions
::
use pragma Restrictions (No_Entry_Calls_In_Elaboration_Code)
This tactic is suggested when the binder has determined that a task
activation at elaboration time
- Prevents a set of units from being elaborated.
Note that the binder cannot determine with certainty whether the task will
block at elaboration time.
The programmer should create a configuration file, place the pragma within,
update the general compilation arguments, and rebuild the program.
* Use of dynamic elaboration model
::
......
......@@ -28458,6 +28458,29 @@ declared in the spec by elaboration code in the body.
The programmer should remove the pragma as advised, and rebuild the program.
@item
Use of pragma Restrictions
@example
use pragma Restrictions (No_Entry_Calls_In_Elaboration_Code)
@end example
This tactic is suggested when the binder has determined that a task
activation at elaboration time
@itemize -
@item
Prevents a set of units from being elaborated.
@end itemize
Note that the binder cannot determine with certainty whether the task will
block at elaboration time.
The programmer should create a configuration file, place the pragma within,
update the general compilation arguments, and rebuild the program.
@item
Use of dynamic elaboration model
@example
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment