Commit 9795b203 by Hristian Kirtchev Committed by Pierre-Marie de Rodat

[Ada] Diagnostics in Elaboration order v4.0

This patch introduces several changes to the new elaboration order
mechanism:

  * The library graph can now discover, store, and organize the various
    cycles it contains.

  * The elaboration order mechanism can now diagnose one or all cycles
    within the library graph. Diagnostics consist of describing the
    reason for the cycle, listing all units comprising the circuit, and
    offering suggestions on how to break the cycle.

The patch also modifies unit ALI to hide all invocation-related data
structures and several implementation-specific types by relocating them
in the body of the unit.

The patch cleans up most children of Bindo by using better names of
routines and formal parameters.

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

--  a.ads

with B; pragma Elaborate_All (B);
with C; pragma Elaborate_All (C);

package A is
end A;

--  b.ads

package B is
   procedure Force_Body;
end B;

--  b.adb

with D;

package body B is
   procedure Force_Body is null;

   Elab : constant Integer := D.Func;
end B;

--  c.ads

package C is
   procedure Force_Body;
end C;

--  c.adb

with E;

package body C is
   procedure Force_Body is null;
end C;

--  d.ads

package D is
   function Func return Integer;
end D;

--  d.adb

with A;

package body D is
   Local : Integer := 123;

   function Func return Integer is
   begin
      return Local;
   end Func;
end D;

--  e.ads

with A;

package E is
end E;

--  main.adb

with B;

--             Elaborate_All             Elaborate_All               with
--    C spec <--------------- A spec ---------------------> B spec <------ Main
--      ^                      ^  ^                           ^
--      |                      |  |                           |
--  sbb |                      |  |                           | sbb
--      |                      |  |                           |
--    C body -----------> E spec  |       D spec <--------- B body
--               with             |         ^       with      |
--                                |         |                 |
--                                |     sbb |                 |
--                                |         |                 |
--                                +------ D body <------------+
--                                  with           Invocation
--
--  The cycles are
--
--    A spec --> C spec --> E spec --> A spec
--               C body
--
--    A spec --> B spec --> D body --> A spec
--               B body

procedure Main is begin null; end Main;

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

$ gnatmake -q main.adb -bargs -d_C -d_N
error: Elaboration circularity detected
info:
info:    Reason:
info:
info:      unit "a (spec)" depends on its own elaboration
info:
info:    Circularity:
info:
info:      unit "a (spec)" has with clause and pragma Elaborate_All for unit
             "b (spec)"
info:      unit "b (body)" is in the closure of pragma Elaborate_All
info:      unit "b (body)" has with clause for unit "d (spec)"
info:      unit "d (body)" is in the closure of pragma Elaborate_All
info:      unit "d (body)" has with clause for unit "a (spec)"
info:
info:    Suggestions:
info:
info:      change pragma Elaborate_All for unit "b (spec)" to Elaborate in unit
             "a (spec)"
info:      remove pragma Elaborate_All for unit "b (spec)" in unit "a (spec)"
info:
error: Elaboration circularity detected
info:
info:    Reason:
info:
info:      unit "a (spec)" depends on its own elaboration
info:
info:    Circularity:
info:
info:      unit "a (spec)" has with clause and pragma Elaborate_All for unit
             "c (spec)"
info:      unit "c (body)" is in the closure of pragma Elaborate_All
info:      unit "c (body)" has with clause for unit "e (spec)"
info:      unit "e (spec)" has with clause for unit "a (spec)"
info:
info:    Suggestions:
info:
info:      change pragma Elaborate_All for unit "c (spec)" to Elaborate in unit
             "a (spec)"
info:      remove pragma Elaborate_All for unit "c (spec)" in unit "a (spec)"
info:
gnatmake: *** bind failed.

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

gcc/ada/

	* ali.adb: Relocate types Invocation_Construct_Record,
	Invocation_Relation_Record, and Invocation_Signature_Record to
	the body of ALI.  Relocate tables Invocation_Constructs,
	Invocation_Relations, and Invocation_Signatures to the body of
	ALI.  Remove type Body_Placement_Codes.  Add new types
	Declaration_Placement_Codes, and
	Invocation_Graph_Encoding_Codes.  Update the literals of type
	Invocation_Graph_Line_Codes.
	(Add_Invocation_Construct): Update the parameter profile. Add an
	invocation construct built from all attributes provided.
	(Add_Invocation_Relation): Update the parameter profile. Add an
	invocation relation built from all attributes provided.
	(Body_Placement): New routine.
	(Body_Placement_Kind_To_Code, Code_To_Body_Placement_Kind):
	Removed.
	(Code_To_Declaration_Placement_Kind,
	Code_To_Invocation_Graph_Encoding_Kind, Column,
	Declaration_Placement_Kind_To_Code, Extra,
	For_Each_Invocation_Construct, For_Each_Invocation_Relation,
	Invocation_Graph_Encoding,
	Invocation_Graph_Encoding_Kind_To_Code, Invoker, Kind, Line,
	Locations, Name): New routine.
	(Scan_Invocation_Construct_Line): Reimplement the scanning
	mechanism.
	(Scan_Invocation_Graph_Attributes_Line): New routine.
	(Scan_Invocation_Graph_Line): Use a case statement to dispatch.
	(Scan_Invocation_Relation_Line): Reimplement the scanning
	mechanism.
	(Scope): New routine.
	(Set_Invocation_Graph_Encoding, Signature, Spec_Placement,
	Target): New routine.
	* ali.ads: Add new type Invocation_Graph_Encoding_Kind.  Add
	component Invocation_Graph_Encoding to type Unit_Record.
	Relocate various types and data structures to the body of ALI.
	(Add_Invocation_Construct, Add_Invocation_Relation): Update the
	parameter profile.
	(Body_Placement): New routine.
	(Body_Placement_Kind_To_Code, Code_To_Body_Placement_Kind):
	Removed.
	(Code_To_Declaration_Placement_Kind,
	Code_To_Invocation_Graph_Encoding_Kind, Column,
	Declaration_Placement_Kind_To_Code, Extra,
	For_Each_Invocation_Construct, For_Each_Invocation_Relation,
	Invocation_Graph_Encoding,
	Invocation_Graph_Encoding_Kind_To_Code, Invoker, Kind, Line,
	Locations, Name, Scope, Set_Invocation_Graph_Encoding,
	Signature, Spec_Placement, Target): New routine.
	* bindo.adb: Add with clause for Binde.  Add with and use
	clauses for Debug.  Update the documentation.  Add new switches.
	(Find_Elaboration_Order): Dispatch to the proper elaboration
	mechanism.
	* bindo-augmentors.adb:
	Remove with and use clauses for GNAT and GNAT.Sets.  Remove
	membership set VS.  Update the parameter profiles of most
	routines to use better parameter names.  Update the
	implementation of most routine to use the new parameter names.
	Remove various redundant assertions.
	* bindo-builders.adb: Use better names for instantiated data
	structures. Update all references to these names.  Update the
	parameter profiles of most routines to use better parameter
	names.  Update the implementation of most routine to use the new
	parameter names.
	(Build_Library_Graph): Update the parameter profile. Update the
	call to Create.
	(Create_Vertex): Reimplemented.
	(Declaration_Placement_Vertex): New routine.
	* bindo-builders.ads (Build_Library_Graph): Update the parameter
	profile and comment on usage.
	* bindo-diagnostics.adb: Almost a new unit.
	* bindo-diagnostics.ads: Add a use clause for
	Bindo.Graphs.Invocation_Graphs.  Remove package
	Cycle_Diagnostics.
	(Diagnose_Circularities): New routine.
	* bindo-elaborators.adb: Remove the with and use clauses for
	Binderr and GNAT.Sets.  Remove the use clause for
	Bindo.Diagnostics.Cycle_Diagnostics.  Remove membership set VS.
	Update the parameter profiles of most routines to use better
	parameter names.  Update the implementation of most routine to
	use the new parameter names.  (Elaborate_Units_Common): Update
	the parameter profile. Pass an infication to the library graph
	builder whether the dynamic model is in effect.
	(Elaborate_Units_Dynamic, Elaborate_Units_Static): Use
	Diagnose_Circularities to provide diagnostics.
	(Update_Successor): Use routine In_Same_Component to determine
	whether the predecessor and successor reside in different
	components.
	* bindo-graphs.adb: Add with and use clauses for Butil, Debug,
	Output, and Bindo.Writers.  Remove with and use clauses for
	GNAT.Lists.  Update the parameter profiles of most routines to
	use better parameter names.  Update the implementation of most
	routine to use the new parameter names.  Remove various
	redundant assertions.  Remove doubly linked list EL.  Add new
	type Precedence_Kind.
	(Add_Cycle): New routine.
	(Add_Vertex): Update the parameter profile. Update the creation
	of vertex attributes.
	(Add_Vertex_And_Complement, Body_Vertex, Column,
	Complementary_Vertex, Copy_Cycle_Path, Cycle_Kind_Of): New
	routines.
	(Destroy_Invocation_Graph_Edge, Destroy_Library_Graph_Cycle,
	Destroy_Library_Graph_Edge, Extra, File_Name,
	Find_All_Cycles_Through_Vertex, Find_All_Cycles_With_Edge,
	Find_Cycles, Find_First_Lower_Precedence_Cycle,
	Get_LGC_Attributes, Has_Next, Hash_Library_Graph_Cycle,
	Hash_Library_Graph_Cycle_Attributes, Highest_Precedence_Cycle,
	Highest_Precedence_Edge, In_Same_Component, Insert_And_Sort,
	Invocation_Edge_Count, Invocation_Graph_Encoding,
	Is_Cycle_Initiating_Edge, Is_Cyclic_Edge,
	Is_Cyclic_Elaborate_All_Edge, Is_Cyclic_Elaborate_Body_Edge,
	Is_Cyclic_Elaborate_Edge, Is_Cyclic_Forced_Edge,
	Is_Cyclic_Invocation_Edge, Is_Cyclic_With_Edge,
	Is_Dynamically_Elaborated, Is_Elaborate_All_Edge,
	Is_Elaborate_Body_Edge, Is_Elaborate_Edge: New routines.
	(Is_Existing_Predecessor_Successor_Relation): Removed.
	(Is_Forced_Edge, Is_Invocation_Edge, Is_Recorded_Cycle,
	Is_Recorded_Edge, Is_With_Edge, Iterate_Edges_Of_Cycle, Kind,
	Length): New routine.
	(Lib_Vertex): Removed.
	(Line, Links_Vertices_In_Same_Component,
	Maximum_Invocation_Edge_Count, Next, Normalize_And_Add_Cycle,
	Normalize_Cycle_Path, Number_Of_Cycles, Path, Precedence,
	Remove_Vertex_And_Complement, Sequence_Next_Cycle): New routines.
	(Sequence_Next_IGE_Id): Renamed to Sequence_Next_Edge.
	(Sequence_Next_IGV_Id): Renamed to Sequence_Next_Vertex.
	(Sequence_Next_LGE_Id): Renamed to Sequence_Next_Edge.
	(Sequence_Next_LGV_Id): Renamed to Sequence_Next_Vertex.
	(Set_Is_Existing_Predecessor_Successor_Relation): Removed.
	(Set_Is_Recorded_Cycle, Set_Is_Recorded_Edge,
	Set_LGC_Attributes, Spec_Vertex, Trace_Cycle, Trace_Edge,
	Trace_Eol, Trace_Vertex): New routines.
	* bindo-graphs.ads: Add with and use clauses for Types and
	GNAT.Lists.  Update the parameter profiles of most routines to
	use better parameter names.  Update the implementation of most
	routine to use the new parameter names.  Add the new
	instantiated data structures IGE_Lists, IGV_Sets, LGC_Lists,
	LGE_Lists, LGE_Sets, LGV_Sets, and RC_Sets.  Add new type
	Library_Graph_Cycle_Id along with an empty and initial value.
	Remove component Lib_Vertex and add new components Body_Vertex
	and Spec_Vertex to type Invocation_Graph_Vertex_Attributes.  Add
	new type Library_Graph_Cycle_Kind.  Add new iterators
	All_Cycle_Iterator and Edges_Of_Cycle_Iterator.  Add new type
	Library_Graph_Cycle_Attributes.  Add new components
	Cycle_Attributes, Cycles, and Dynamically_Elaborated to type
	Library_Graph_Attributes.
	(Body_Vertex, Column, Destroy_Invocation_Graph_Edge,
	Destroy_Library_Graph_Cycle_Attributes,
	Destroy_Library_Graph_Edge, Extra, File_Name, Find_Cycles,
	Has_Elaborate_All_Cycle, Has_Next, Hash_Library_Graph_Cycle,
	Hash_Library_Graph_Cycle_Attributes, Highest_Precedence_Cycle,
	In_Same_Component, Invocation_Edge_Count,
	Invocation_Graph_Encoding, Is_Dynamically_Elaborated,
	Is_Elaborate_All_Edge, Is_Elaborate_Body_Edge,
	Is_Elaborate_Edge, Is_Forced_Edge, Is_Invocation_Edge,
	Is_With_Edge, Iterate_All_Cycles, Iterate_Edges_Of_Cycle, Kind):
	New routines.
	(Length, Lib_Vertex, (Line, Next, Number_Of_Cycles, Present,
	Same_Library_Graph_Cycle_Attributes, Spec_Vertex): New routines.
	* bindo-units.adb (File_Name, Invocation_Graph_Encoding): New
	routines.
	* bindo-units.ads: Add new instantiated data structure
	Unit_Sets.
	(File_Name, Invocation_Graph_Encoding): New routine.
	* bindo-validators.adb: Remove with and use clauses for GNAT and
	GNAT.Sets.  Remove membership set US.  Update the parameter
	profiles of most routines to use better parameter names.  Update
	the implementation of most routine to use the new parameter
	names.
	(Validate_Cycle, Validate_Cycle_Path, Validate_Cycles,
	Validate_Invocation_Graph_Vertex): Remove the validation of
	component Lib_Vertex. Add the validation of components
	Body_Vertex and Spec_Vertex.
	(Write_Error): New routine.
	* bindo-validators.ads (Validate_Cycles): New routine.
	* bindo-writers.adb: Update the parameter profiles of most
	routines to use better parameter names.  Update the
	implementation of most routine to use the new parameter names.
	(Write_Cycle, Write_Cyclic_Edge, Write_Cycles): New routines.
	(Write_Invocation_Graph_Vertex): Remove the output of component
	Lib_Vertex. Add the output of components Body_Vertex and
	Spec_Vertex.
	* bindo-writers.ads (Write_Cycles): New routine.
	* debug.adb: Use binder switches -d_C and -d_P, add
	documentation on their usage.
	* gnatbind.adb: Remove with and use clauses for Binde.  Delegate
	the choice of elaboration mechanism to Bindo.
	* lib-writ.adb (Column, Extra, Invoker, Kind, Line, Locations,
	Name, Placement, Scope, Signature, Target): Removed.
	(Write_Invocation_Graph): Moved at the top level.
	(Write_Invocation_Graph_Attributes): New routine.
	(Write_Invocation_Relation, Write_Invocation_Signature): Moved
	at the top level.
	* lib-writ.ads: Add a documentation section on invocation graph
	attributes.
	* sem_elab.adb (Body_Placement_Of): New routine.
	(Declare_Invocation_Construct): Update the call to
	Add_Invocation_Construct.
	(Declaration_Placement_Of_Node): New routine.
	(Get_Invocation_Attributes): Correct the retrieval of the
	enclosing subprogram where the postcondition procedure lives.
	(Placement_Of, Placement_Of_Node): Removed.
	(Record_Invocation_Graph): Record the encoding format used.
	(Record_Invocation_Graph_Encoding): New routine.
	(Record_Invocation_Relation): Update the call to
	Add_Invocation_Relation.
	(Spec_Placement_Of): Removed.
	* libgnat/g-lists.ads, libgnat/g-lists.adb (Equal): New routine.

From-SVN: r273107
parent db626148
......@@ -56,9 +56,11 @@ package Bindo.Builders is
----------------------------
package Library_Graph_Builders is
function Build_Library_Graph return Library_Graph;
function Build_Library_Graph
(Dynamically_Elaborated : Boolean) return Library_Graph;
-- Return a new library graph that reflects the dependencies between
-- all units of the bind.
-- all units of the bind. Flag Dynamically_Elaborated must be set when
-- the main library unit was compiled using the dynamic model.
end Library_Graph_Builders;
......
......@@ -30,6 +30,7 @@
with Bindo.Graphs;
use Bindo.Graphs;
use Bindo.Graphs.Invocation_Graphs;
use Bindo.Graphs.Library_Graphs;
package Bindo.Diagnostics is
......@@ -46,16 +47,15 @@ package Bindo.Diagnostics is
Order_Has_Elaborate_All_Circularity,
Order_OK);
-----------------------
-- Cycle_Diagnostics --
-----------------------
---------
-- API --
---------
package Cycle_Diagnostics is
function Has_Elaborate_All_Cycle (G : Library_Graph) return Boolean;
pragma Inline (Has_Elaborate_All_Cycle);
-- Determine whether library graph G contains a cycle where pragma
-- Elaborate_All appears within a component.
end Cycle_Diagnostics;
procedure Diagnose_Circularities
(Inv_Graph : Invocation_Graph;
Lib_Graph : Library_Graph);
pragma Inline (Diagnose_Circularities);
-- Diagnose all cycles of library graph Lib_Graph with matching invocation
-- graph Inv_Graph.
end Bindo.Diagnostics;
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -29,7 +29,7 @@ package body Bindo.Units is
-- Signature set --
-------------------
package SS is new Membership_Sets
package Signature_Sets is new Membership_Sets
(Element_Type => Invocation_Signature_Id,
"=" => "=",
Hash => Hash_Invocation_Signature);
......@@ -41,11 +41,13 @@ package body Bindo.Units is
-- The following set stores all invocation signatures that appear in
-- elaborable units.
Elaborable_Constructs : SS.Membership_Set := SS.Nil;
Elaborable_Constructs : Signature_Sets.Membership_Set := Signature_Sets.Nil;
-- The following set stores all units the need to be elaborated
Elaborable_Units : US.Membership_Set := US.Nil;
-- Kirchev
Elaborable_Units : Unit_Sets.Membership_Set := Unit_Sets.Nil;
-----------------------
-- Local subprograms --
......@@ -139,14 +141,27 @@ package body Bindo.Units is
return Corresponding_Unit (Name_Id (UNam));
end Corresponding_Unit;
---------------
-- File_Name --
---------------
function File_Name (U_Id : Unit_Id) return File_Name_Type is
pragma Assert (Present (U_Id));
U_Rec : Unit_Record renames ALI.Units.Table (U_Id);
begin
return U_Rec.Sfile;
end File_Name;
--------------------
-- Finalize_Units --
--------------------
procedure Finalize_Units is
begin
SS.Destroy (Elaborable_Constructs);
US.Destroy (Elaborable_Units);
Signature_Sets.Destroy (Elaborable_Constructs);
Unit_Sets.Destroy (Elaborable_Units);
end Finalize_Units;
------------------------------
......@@ -183,7 +198,7 @@ package body Bindo.Units is
function Has_Next (Iter : Elaborable_Units_Iterator) return Boolean is
begin
return US.Has_Next (US.Iterator (Iter));
return Unit_Sets.Has_Next (Unit_Sets.Iterator (Iter));
end Has_Next;
-------------------------------
......@@ -216,11 +231,26 @@ package body Bindo.Units is
procedure Initialize_Units is
begin
Elaborable_Constructs := SS.Create (Number_Of_Units);
Elaborable_Units := US.Create (Number_Of_Units);
Elaborable_Constructs := Signature_Sets.Create (Number_Of_Units);
Elaborable_Units := Unit_Sets.Create (Number_Of_Units);
end Initialize_Units;
-------------------------------
-- Invocation_Graph_Encoding --
-------------------------------
function Invocation_Graph_Encoding
(U_Id : Unit_Id) return Invocation_Graph_Encoding_Kind
is
pragma Assert (Present (U_Id));
U_Rec : Unit_Record renames ALI.Units.Table (U_Id);
begin
return U_Rec.Invocation_Graph_Encoding;
end Invocation_Graph_Encoding;
-------------------------------
-- Is_Dynamically_Elaborated --
-------------------------------
......@@ -278,7 +308,7 @@ package body Bindo.Units is
function Iterate_Elaborable_Units return Elaborable_Units_Iterator is
begin
return Elaborable_Units_Iterator (US.Iterate (Elaborable_Units));
return Elaborable_Units_Iterator (Unit_Sets.Iterate (Elaborable_Units));
end Iterate_Elaborable_Units;
----------
......@@ -304,7 +334,7 @@ package body Bindo.Units is
begin
pragma Assert (Present (IS_Id));
return SS.Contains (Elaborable_Constructs, IS_Id);
return Signature_Sets.Contains (Elaborable_Constructs, IS_Id);
end Needs_Elaboration;
-----------------------
......@@ -315,7 +345,7 @@ package body Bindo.Units is
begin
pragma Assert (Present (U_Id));
return US.Contains (Elaborable_Units, U_Id);
return Unit_Sets.Contains (Elaborable_Units, U_Id);
end Needs_Elaboration;
----------
......@@ -327,7 +357,7 @@ package body Bindo.Units is
U_Id : out Unit_Id)
is
begin
US.Next (US.Iterator (Iter), U_Id);
Unit_Sets.Next (Unit_Sets.Iterator (Iter), U_Id);
end Next;
--------------------------------
......@@ -336,7 +366,7 @@ package body Bindo.Units is
function Number_Of_Elaborable_Units return Natural is
begin
return US.Size (Elaborable_Units);
return Unit_Sets.Size (Elaborable_Units);
end Number_Of_Elaborable_Units;
---------------------
......@@ -355,14 +385,12 @@ package body Bindo.Units is
procedure Process_Invocation_Construct (IC_Id : Invocation_Construct_Id) is
pragma Assert (Present (IC_Id));
IC_Rec : Invocation_Construct_Record renames
Invocation_Constructs.Table (IC_Id);
IC_Sig : constant Invocation_Signature_Id := IC_Rec.Signature;
IS_Id : constant Invocation_Signature_Id := Signature (IC_Id);
pragma Assert (Present (IC_Sig));
pragma Assert (Present (IS_Id));
begin
SS.Insert (Elaborable_Constructs, IC_Sig);
Signature_Sets.Insert (Elaborable_Constructs, IS_Id);
end Process_Invocation_Construct;
-----------------------------------
......@@ -402,7 +430,7 @@ package body Bindo.Units is
-- signatures of constructs it declares.
else
US.Insert (Elaborable_Units, U_Id);
Unit_Sets.Insert (Elaborable_Units, U_Id);
Process_Invocation_Constructs (U_Id);
end if;
end Process_Unit;
......
......@@ -33,6 +33,19 @@ with GNAT.Sets; use GNAT.Sets;
package Bindo.Units is
---------------
-- Unit sets --
---------------
function Hash_Unit (U_Id : Unit_Id) return Bucket_Range_Type;
pragma Inline (Hash_Unit);
-- Obtain the hash value of key U_Id
package Unit_Sets is new Membership_Sets
(Element_Type => Unit_Id,
"=" => "=",
Hash => Hash_Unit);
procedure Collect_Elaborable_Units;
pragma Inline (Collect_Elaborable_Units);
-- Gather all units in the bind that require elaboration. The units are
......@@ -54,6 +67,10 @@ package Bindo.Units is
pragma Inline (Corresponding_Unit);
-- Obtain the unit which corresponds to name FNam
function File_Name (U_Id : Unit_Id) return File_Name_Type;
pragma Inline (File_Name);
-- Obtain the file name of unit U_Id
type Unit_Processor_Ptr is access procedure (U_Id : Unit_Id);
procedure For_Each_Elaborable_Unit (Processor : Unit_Processor_Ptr);
......@@ -69,9 +86,11 @@ package Bindo.Units is
pragma Inline (Hash_Invocation_Signature);
-- Obtain the hash value of key IS_Id
function Hash_Unit (U_Id : Unit_Id) return Bucket_Range_Type;
pragma Inline (Hash_Unit);
-- Obtain the hash value of key U_Id
function Invocation_Graph_Encoding
(U_Id : Unit_Id) return Invocation_Graph_Encoding_Kind;
pragma Inline (Invocation_Graph_Encoding);
-- Obtain the encoding format used to capture invocation constructs and
-- relations in the ALI file of unit U_Id.
function Is_Dynamically_Elaborated (U_Id : Unit_Id) return Boolean;
pragma Inline (Is_Dynamically_Elaborated);
......@@ -144,11 +163,6 @@ package Bindo.Units is
-- Initialize the internal structures of this unit
private
package US is new Membership_Sets
(Element_Type => Unit_Id,
"=" => "=",
Hash => Hash_Unit);
type Elaborable_Units_Iterator is new US.Iterator;
type Elaborable_Units_Iterator is new Unit_Sets.Iterator;
end Bindo.Units;
......@@ -35,6 +35,26 @@ use Bindo.Graphs.Library_Graphs;
package Bindo.Validators is
----------------------
-- Cycle_Validators --
----------------------
package Cycle_Validators is
Invalid_Cycle : exception;
-- Exception raised when the library graph contains an invalid cycle
procedure Validate_Cycles (G : Library_Graph);
-- Ensure that all cycles of library graph G meet the following
-- requirements:
--
-- * Are of proper kind
-- * Have enough edges to form a circuit
-- * No edge is repeated
--
-- Diagnose issues and raise Invalid_Cycle if this is not the case.
end Cycle_Validators;
----------------------------------
-- Elaboration_Order_Validators --
----------------------------------
......
......@@ -81,6 +81,16 @@ package Bindo.Writers is
end ALI_Writers;
-------------------
-- Cycle_Writers --
-------------------
package Cycle_Writers is
procedure Write_Cycles (G : Library_Graph);
-- Write all cycles of library graph G to standard output
end Cycle_Writers;
-------------------------------
-- Elaboration_Order_Writers --
-------------------------------
......
......@@ -23,8 +23,11 @@
-- --
------------------------------------------------------------------------------
with Binde;
with Debug; use Debug;
with Bindo.Elaborators;
use Bindo.Elaborators.Invocation_And_Library_Graph_Elaborators;
use Bindo.Elaborators;
package body Bindo is
......@@ -47,30 +50,44 @@ package body Bindo is
-- - The flow of execution at elaboration time.
--
-- - Additional dependencies between units supplied to the binder by
-- means of a file.
-- means of a forced-elaboration-order file.
--
-- The high-level idea empoyed by the EO mechanism is to construct two
-- graphs and use the information they represent to find an ordering of
-- all units.
--
-- The high-level idea is to construct two graphs:
-- The invocation graph represents the flow of execution at elaboration
-- time.
--
-- - Invocation graph - Models the flow of execution at elaboration
-- time.
-- The library graph captures the dependencies between units expressed
-- by with clause and elaboration-related pragmas. The library graph is
-- further augmented with additional information from the invocation
-- graph by exploring the execution paths from a unit with elaboration
-- code to other external units.
--
-- - Library graph - Represents with clause and pragma dependencies
-- between units.
-- The strongly connected components of the library graph are computed.
--
-- The library graph is further augmented with additional information
-- from the invocation graph by exploring the execution paths from a
-- unit with elaboration code to other external units. All strongly
-- connected components of the library graph are discovered. Finally,
-- the order is obtained via a topological sort-like algorithm which
-- attempts to order available units while enabling other units to be
-- The order is obtained using a topological sort-like algorithm which
-- traverses the library graph and its strongly connected components in
-- an attempt to order available units while enabling other units to be
-- ordered.
--
-- * Diagnose elaboration circularities between units
--
-- The library graph may contain at least one cycle, in which case no
-- ordering is possible.
-- An elaboration circularity arrises when either
--
-- - At least one unit cannot be ordered, or
--
-- - All units can be ordered, but an edge with an Elaborate_All
-- pragma links two vertices within the same component of the
-- library graph.
--
-- ??? more on this later
-- The library graph is traversed to discover, collect, and sort all
-- cycles that hinder the elaboration order.
--
-- The most important cycle is diagnosed by describing its effects on
-- the elaboration order and listing all units comprising the circuit.
-- Various suggestions on how to break the cycle are offered.
-----------------
-- Terminology --
......@@ -78,6 +95,8 @@ package body Bindo is
-- * Component - A strongly connected component of a graph.
--
-- * Elaboration circularity - A cycle involving units from the bind.
--
-- * Elaboration root - A special invocation construct which denotes the
-- elaboration procedure of a unit.
--
......@@ -162,7 +181,11 @@ package body Bindo is
-- |
-- +------ | -------------- Diagnostics phase -------------------------+
-- | | |
-- | +--> ??? more on this later |
-- | +--> Find_Cycles |
-- | +--> Validate_Cycles |
-- | +--> Write_Cycles |
-- | | |
-- | +--> Diagnose_Cycle / Diagnose_All_Cycles |
-- | |
-- +-------------------------------------------------------------------+
......@@ -225,7 +248,37 @@ package body Bindo is
-- Diagnostics phase --
-----------------------
-- ??? more on this later
-- The Diagnostics phase has the following objectives:
--
-- * Discover, save, and sort all cycles in the library graph. The cycles
-- are sorted based on the following heiristics:
--
-- - A cycle with higher precedence is preferred.
--
-- - A cycle with fewer invocation edges is preferred.
--
-- - A cycle with a shorter length is preferred.
--
-- * Validate the consistency of cycles, only when switch -d_V is in
-- effect.
--
-- * Write the contents of all cycles in human-readable form to standard
-- output when switch -d_O is in effect.
--
-- * Diagnose the most important cycle, or all cycles when switch -d_C is
-- in effect. The diagnostic consists of:
--
-- - The reason for the existance of the cycle, along with the unit
-- whose elaboration cannot be guaranteed.
--
-- - A detailed traceback of the cycle, showcasing the transition
-- between units, along with any other elaboration order-related
-- information.
--
-- - A set of suggestions on how to break the cycle considering the
-- the edges coprising the circuit, the elaboration model used to
-- compile the units, the availability of invocation information,
-- and the state of various relevant switches.
--------------
-- Switches --
......@@ -236,6 +289,11 @@ package body Bindo is
-- GNATbind outputs the contents of ALI table Invocation_Constructs
-- and Invocation_Edges in textual format to standard output.
--
-- -d_C Diagnose all cycles
--
-- GNATbind outputs diagnostics for all unique cycles in the bind,
-- rather than just the most important one.
--
-- -d_I Output invocation graph
--
-- GNATbind outputs the invocation graph in text format to standard
......@@ -255,16 +313,20 @@ package body Bindo is
-- GNATbind outputs the elaboration order in text format to standard
-- output.
--
-- -d_P Output cycle paths
--
-- GNATbind output the cycle paths in text format to standard output
--
-- -d_T Output elaboration order trace information
--
-- GNATbind outputs trace information on elaboration order activities
-- to standard output.
-- GNATbind outputs trace information on elaboration order and cycle
-- detection activities to standard output.
--
-- -d_V Validate bindo graphs and order
-- -d_V Validate bindo cycles, graphs, and order
--
-- GNATbind validates the invocation graph, library graph, SCC graph
-- and elaboration order by detecting inconsistencies and producing
-- error reports.
-- GNATbind validates the invocation graph, library graph along with
-- its cycles, and elaboration order by detecting inconsistencies and
-- producing error reports.
----------------------------------------
-- Debugging elaboration order issues --
......@@ -281,7 +343,20 @@ package body Bindo is
Main_Lib_File : File_Name_Type)
is
begin
Elaborate_Units (Order, Main_Lib_File);
-- Use the invocation and library graph-based elaboration order when
-- switch -d_N (new bindo order) is in effect.
if Debug_Flag_Underscore_NN then
Invocation_And_Library_Graph_Elaborators.Elaborate_Units
(Order => Order,
Main_Lib_File => Main_Lib_File);
-- Otherwise use the library graph and heuristic-based elaboration
-- order.
else
Binde.Find_Elab_Order (Order, Main_Lib_File);
end if;
end Find_Elaboration_Order;
end Bindo;
......@@ -378,7 +378,7 @@ package body Debug is
-- d_A Output ALI invocation tables
-- d_B
-- d_C
-- d_C Diagnose all cycles
-- d_D
-- d_F
-- d_G
......@@ -390,13 +390,13 @@ package body Debug is
-- d_M
-- d_N New bindo order
-- d_O Output elaboration order
-- d_P
-- d_P Output cycle paths
-- d_Q
-- d_R
-- d_S
-- d_T Output elaboration order trace information
-- d_T Output elaboration order and cycle detection trace information
-- d_U
-- d_V Validate bindo graphs and order
-- d_V Validate bindo cycles, graphs, and order
-- d_W
-- d_X
-- d_Y
......@@ -1150,22 +1150,27 @@ package body Debug is
-- d_A GNATBIND output the contents of all ALI invocation-related tables
-- in textual format to standard output.
--
-- d_C GNATBIND diagnoses all unique cycles within the bind, rather than
-- just the most important one.
-- d_I GNATBIND outputs the contents of the invocation graph in textual
-- format to standard output.
--
-- d_L GNATBIND outputs the contents of the library graph in textual
-- format to standard output.
--
-- d_N GNATBIND utilizes the elaboration order provided by bindo
--
-- d_O GNATBIND outputs the elaboration order of units to standard output
--
-- d_T GNATBIND outputs trace information of elaboration order activities
-- to standard output.
--
-- d_V GNATBIND validates the invocation graph, library graph, SCC graph
-- and elaboration order.
-- d_P GNATBIND outputs the cycle paths to standard output
-- d_T GNATBIND outputs trace information of elaboration order and cycle
-- detection activities to standard output.
-- d_V GNATBIND validates the invocation graph, library graph along with
-- its cycles, and the elaboration order.
--------------------------------------------
-- Documentation for gnatmake Debug Flags --
......
......@@ -26,7 +26,6 @@
with ALI; use ALI;
with ALI.Util; use ALI.Util;
with Bcheck; use Bcheck;
with Binde; use Binde;
with Binderr; use Binderr;
with Bindgen; use Bindgen;
with Bindo; use Bindo;
......@@ -883,14 +882,7 @@ begin
Elab_Order : Unit_Id_Table;
begin
-- Use the invocation and library graph-based elaboration order
-- when switch -d_N (new bindo order) is in effect.
if Debug_Flag_Underscore_NN then
Find_Elaboration_Order (Elab_Order, First_Main_Lib_File);
else
Find_Elab_Order (Elab_Order, First_Main_Lib_File);
end if;
Find_Elaboration_Order (Elab_Order, First_Main_Lib_File);
if Errors_Detected = 0 and then not Check_Only then
Gen_Output_File
......
......@@ -880,18 +880,32 @@ package Lib.Writ is
-- locations of all instances where the initial declaration of the
-- construct appears.
--
-- When the line-kind denotes invocation graph attributes, line-attributes
-- are set as follows:
--
-- encoding-kind
--
-- Attribute encoding-kind is a Character which specifies the encoding
-- kind used when collecting invocation constructs and relations. Table
-- ALI.Invocation_Graph_Encoding_Codes lists all legal values.
--
-- When the line-kind denotes an invocation construct, line-attributes are
-- set as follows:
--
-- construct-kind construct-body-placement construct-signature
-- construct-kind construct-spec-placement construct-body-placement
-- construct-signature
--
-- Attribute construct-kind is a Character which denotes the nature of
-- the construct. Table ALI.Invocation_Construct_Codes lists all legal
-- values.
--
-- Attribute construct-spec-placement is a Character which denotes the
-- placement of the construct's spec within the unit. All legal values
-- are listed in table ALI.Spec_And_Body_Placement_Codes.
--
-- Attribute construct-body-placement is a Character which denotes the
-- placement of the construct's body within the unit. All legal values
-- are listed in table ALI.Body_Placement_Codes.
-- are listed in table ALI.Spec_And_Body_Placement_Codes.
--
-- Attribute construct-signature is the invocation signature of the
-- construct.
......@@ -925,7 +939,7 @@ package Lib.Writ is
-- Postcondition_Verification - related routine
-- Protected_Entry_Call - not present
-- Protected_Subprogram_Call - not present
-- Task_Activation - related task object
-- Task_Activation - not present
-- Task_Entry_Call - not present
-- Type_Initialization - related type
--
......
......@@ -337,6 +337,57 @@ package body GNAT.Lists is
end if;
end Ensure_Unlocked;
-----------
-- Equal --
-----------
function Equal
(Left : Doubly_Linked_List;
Right : Doubly_Linked_List) return Boolean
is
Left_Head : Node_Ptr;
Left_Nod : Node_Ptr;
Right_Head : Node_Ptr;
Right_Nod : Node_Ptr;
begin
-- Two non-existent lists are considered equal
if Left = Nil and then Right = Nil then
return True;
-- A non-existent list is never equal to an already created list
elsif Left = Nil or else Right = Nil then
return False;
-- The two lists must contain the same number of elements to be equal
elsif Size (Left) /= Size (Right) then
return False;
end if;
-- Compare the two lists element by element
Left_Head := Left.Nodes'Access;
Left_Nod := Left_Head.Next;
Right_Head := Right.Nodes'Access;
Right_Nod := Right_Head.Next;
while Is_Valid (Left_Nod, Left_Head)
and then
Is_Valid (Right_Nod, Right_Head)
loop
if Left_Nod.Elem /= Right_Nod.Elem then
return False;
end if;
Left_Nod := Left_Nod.Next;
Right_Nod := Right_Nod.Next;
end loop;
return True;
end Equal;
---------------
-- Find_Node --
---------------
......
......@@ -117,6 +117,12 @@ package GNAT.Lists is
-- end of a list's lifetime. This action will raise Iterated if the
-- list has outstanding iterators.
function Equal
(Left : Doubly_Linked_List;
Right : Doubly_Linked_List) return Boolean;
-- Determine whether lists Left and Right have the same characteristics
-- and contain the same elements.
function First (L : Doubly_Linked_List) return Element_Type;
-- Obtain an element from the start of list L. This action will raise
-- List_Empty if the list is empty.
......
......@@ -11689,6 +11689,11 @@ package body Sem_Elab is
-- active scenarios. In_State is the current state of the Processing
-- phase.
procedure Record_Invocation_Graph_Encoding;
pragma Inline (Record_Invocation_Graph_Encoding);
-- Record the encoding format used to capture information related to
-- invocation constructs and relations.
procedure Record_Invocation_Path (In_State : Processing_In_State);
pragma Inline (Record_Invocation_Path);
-- Record the invocation relations found within the path represented in
......@@ -11938,40 +11943,32 @@ package body Sem_Elab is
(Constr_Id : Entity_Id;
In_State : Processing_In_State)
is
function Body_Placement_Of
(Id : Entity_Id) return Declaration_Placement_Kind;
pragma Inline (Body_Placement_Of);
-- Obtain the placement of arbitrary entity Id's body
function Declaration_Placement_Of_Node
(N : Node_Id) return Declaration_Placement_Kind;
pragma Inline (Declaration_Placement_Of_Node);
-- Obtain the placement of arbitrary node N
function Kind_Of (Id : Entity_Id) return Invocation_Construct_Kind;
pragma Inline (Kind_Of);
-- Obtain the invocation construct kind of arbitrary entity Id
function Placement_Of (Id : Entity_Id) return Body_Placement_Kind;
pragma Inline (Placement_Of);
-- Obtain the body placement of arbitrary entity Id
function Placement_Of_Node (N : Node_Id) return Body_Placement_Kind;
pragma Inline (Placement_Of_Node);
-- Obtain the body placement of arbitrary node N
-------------
-- Kind_Of --
-------------
function Kind_Of (Id : Entity_Id) return Invocation_Construct_Kind is
begin
if Id = Elab_Body_Id then
return Elaborate_Body_Procedure;
elsif Id = Elab_Spec_Id then
return Elaborate_Spec_Procedure;
else
return Regular_Construct;
end if;
end Kind_Of;
function Spec_Placement_Of
(Id : Entity_Id) return Declaration_Placement_Kind;
pragma Inline (Spec_Placement_Of);
-- Obtain the placement of arbitrary entity Id's spec
------------------
-- Placement_Of --
------------------
-----------------------
-- Body_Placement_Of --
-----------------------
function Placement_Of (Id : Entity_Id) return Body_Placement_Kind is
function Body_Placement_Of
(Id : Entity_Id) return Declaration_Placement_Kind
is
Id_Rep : constant Target_Rep_Id :=
Target_Representation_Of (Id, In_State);
Body_Decl : constant Node_Id := Body_Declaration (Id_Rep);
......@@ -11981,21 +11978,23 @@ package body Sem_Elab is
-- The entity has a body
if Present (Body_Decl) then
return Placement_Of_Node (Body_Decl);
return Declaration_Placement_Of_Node (Body_Decl);
-- Otherwise the entity must have a spec
else
pragma Assert (Present (Spec_Decl));
return Placement_Of_Node (Spec_Decl);
return Declaration_Placement_Of_Node (Spec_Decl);
end if;
end Placement_Of;
end Body_Placement_Of;
-----------------------
-- Placement_Of_Node --
-----------------------
-----------------------------------
-- Declaration_Placement_Of_Node --
-----------------------------------
function Placement_Of_Node (N : Node_Id) return Body_Placement_Kind is
function Declaration_Placement_Of_Node
(N : Node_Id) return Declaration_Placement_Kind
is
Main_Unit_Id : constant Entity_Id := Cunit_Entity (Main_Unit);
N_Unit_Id : constant Entity_Id := Find_Top_Unit (N);
......@@ -12039,11 +12038,50 @@ package body Sem_Elab is
else
return In_Body;
end if;
end Placement_Of_Node;
end Declaration_Placement_Of_Node;
-- Local variables
-------------
-- Kind_Of --
-------------
function Kind_Of (Id : Entity_Id) return Invocation_Construct_Kind is
begin
if Id = Elab_Body_Id then
return Elaborate_Body_Procedure;
elsif Id = Elab_Spec_Id then
return Elaborate_Spec_Procedure;
else
return Regular_Construct;
end if;
end Kind_Of;
IC_Rec : Invocation_Construct_Record;
-----------------------
-- Spec_Placement_Of --
-----------------------
function Spec_Placement_Of
(Id : Entity_Id) return Declaration_Placement_Kind
is
Id_Rep : constant Target_Rep_Id :=
Target_Representation_Of (Id, In_State);
Body_Decl : constant Node_Id := Body_Declaration (Id_Rep);
Spec_Decl : constant Node_Id := Spec_Declaration (Id_Rep);
begin
-- The entity has a spec
if Present (Spec_Decl) then
return Declaration_Placement_Of_Node (Spec_Decl);
-- Otherwise the entity must have a body
else
pragma Assert (Present (Body_Decl));
return Declaration_Placement_Of_Node (Body_Decl);
end if;
end Spec_Placement_Of;
-- Start of processing for Declare_Invocation_Construct
......@@ -12059,15 +12097,14 @@ package body Sem_Elab is
Set_Is_Saved_Construct (Constr_Id);
IC_Rec.Kind := Kind_Of (Constr_Id);
IC_Rec.Placement := Placement_Of (Constr_Id);
IC_Rec.Signature := Signature_Of (Constr_Id);
-- Add the construct in the ALI file
Add_Invocation_Construct
(IC_Rec => IC_Rec,
Update_Units => False);
(Body_Placement => Body_Placement_Of (Constr_Id),
Kind => Kind_Of (Constr_Id),
Signature => Signature_Of (Constr_Id),
Spec_Placement => Spec_Placement_Of (Constr_Id),
Update_Units => False);
end Declare_Invocation_Construct;
-------------------------------
......@@ -12809,6 +12846,12 @@ package body Sem_Elab is
return;
end if;
-- Save the encoding format used to capture information about the
-- invocation constructs and relations in the ALI file of the main
-- unit.
Record_Invocation_Graph_Encoding;
-- Examine all library level invocation scenarios and perform DFS
-- traversals from each one. Encode a path in the ALI file of the
-- main unit if it reaches into an external unit.
......@@ -12824,6 +12867,30 @@ package body Sem_Elab is
Process_Main_Unit;
end Record_Invocation_Graph;
--------------------------------------
-- Record_Invocation_Graph_Encoding --
--------------------------------------
procedure Record_Invocation_Graph_Encoding is
Kind : Invocation_Graph_Encoding_Kind := No_Encoding;
begin
-- Switch -gnatd_F (encode full invocation paths in ALI files) is in
-- effect.
if Debug_Flag_Underscore_FF then
Kind := Full_Path_Encoding;
else
Kind := Endpoints_Encoding;
end if;
-- Save the encoding format in the ALI file of the main unit
Set_Invocation_Graph_Encoding
(Kind => Kind,
Update_Units => False);
end Record_Invocation_Graph_Encoding;
----------------------------
-- Record_Invocation_Path --
----------------------------
......@@ -12882,6 +12949,10 @@ package body Sem_Elab is
(Extra : out Entity_Id;
Kind : out Invocation_Kind)
is
Targ_Rep : constant Target_Rep_Id :=
Target_Representation_Of (Targ_Id, In_State);
Spec_Decl : constant Node_Id := Spec_Declaration (Targ_Rep);
begin
-- Accept within a task body
......@@ -12970,7 +13041,7 @@ package body Sem_Elab is
-- Postcondition verification
elsif Is_Postconditions_Proc (Targ_Id) then
Extra := Find_Enclosing_Scope (Targ_Id);
Extra := Find_Enclosing_Scope (Spec_Decl);
Kind := Postcondition_Verification;
-- Protected entry call
......@@ -13013,7 +13084,6 @@ package body Sem_Elab is
Extra : Entity_Id;
Extra_Nam : Name_Id;
IR_Rec : Invocation_Relation_Record;
Kind : Invocation_Kind;
Rel : Invoker_Target_Relation;
......@@ -13052,15 +13122,13 @@ package body Sem_Elab is
Extra_Nam := No_Name;
end if;
IR_Rec.Extra := Extra_Nam;
IR_Rec.Invoker := Signature_Of (Invk_Id);
IR_Rec.Kind := Kind;
IR_Rec.Target := Signature_Of (Targ_Id);
-- Add the relation in the ALI file
Add_Invocation_Relation
(IR_Rec => IR_Rec,
(Extra => Extra_Nam,
Invoker => Signature_Of (Invk_Id),
Kind => Kind,
Target => Signature_Of (Targ_Id),
Update_Units => False);
end Record_Invocation_Relation;
......
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