Remove obsolete ECOFF support.
[official-gcc.git] / gcc / ada / binde.adb
blob5a78bc824994eb315ededbc1af9c70ef8b0e6967
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- B I N D E --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2017, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Binderr; use Binderr;
27 with Butil; use Butil;
28 with Debug; use Debug;
29 with Fname; use Fname;
30 with Opt; use Opt;
31 with Osint;
32 with Output; use Output;
33 with Table;
35 with System.Case_Util; use System.Case_Util;
36 with System.OS_Lib;
38 package body Binde is
40 -- We now have Elab_New, a new elaboration-order algorithm.
42 -- However, any change to elaboration order can break some programs.
43 -- Therefore, we are keeping the old algorithm in place, to be selected
44 -- by switches.
46 -- The new algorithm has the following interesting properties:
48 -- * The static and dynamic models use the same elaboration order. The
49 -- static model might get an error, but if it does not, it will use
50 -- the same order as the dynamic model.
52 -- * Each SCC (see below) is elaborated together; that is, units from
53 -- different SCCs are not interspersed.
55 -- * In particular, this implies that if an SCC contains just a spec and
56 -- the corresponding body, and nothing else, the body will be
57 -- elaborated immediately after the spec. This is expected to result
58 -- in a better elaboration order for most programs, because in this
59 -- case, a call from outside the library unit cannot get ABE.
61 -- * Pragmas Elaborate_All (explicit and implicit) are ignored. Instead,
62 -- we behave as if every legal pragma Elaborate_All were present. That
63 -- is, if it would be legal to have "pragma Elaborate_All(Y);" on X,
64 -- then we behave as if such a pragma exists, even if it does not.
66 Do_Old : constant Boolean := False;
67 Do_New : constant Boolean := True;
68 -- True to enable the old and new algorithms, respectively. Used for
69 -- debugging/experimentation.
71 Doing_New : Boolean := False;
72 -- True if we are currently doing the new algorithm. Print certain
73 -- messages only when doing the "new" elab order algorithm, so we don't get
74 -- duplicates. And use different heuristics in Better_Choice_Optimistic.
76 -- The following data structures are used to represent the graph that is
77 -- used to determine the elaboration order (using a topological sort).
79 -- The following structures are used to record successors. If B is a
80 -- successor of A in this table, it means that A must be elaborated before
81 -- B is elaborated. For example, if Y (body) says "with X;", then Y (body)
82 -- will be a successor of X (spec), and X (spec) will be a predecessor of
83 -- Y (body).
85 -- Note that we store the successors of each unit explicitly. We don't
86 -- store the predecessors, but we store a count of them.
88 -- The basic algorithm is to first compute a directed graph of units (type
89 -- Unit_Node_Record, below), with successors as edges. A unit is "ready"
90 -- (to be chosen as the next to be elaborated) if it has no predecessors
91 -- that have not yet been chosen. We use heuristics to decide which of the
92 -- ready units should be elaborated next, and "choose" that one (which
93 -- means we append it to the elaboration-order table).
95 type Successor_Id is new Nat;
96 -- Identification of single successor entry
98 No_Successor : constant Successor_Id := 0;
99 -- Used to indicate end of list of successors
101 type Elab_All_Id is new Nat;
102 -- Identification of Elab_All entry link
104 No_Elab_All_Link : constant Elab_All_Id := 0;
105 -- Used to indicate end of list
107 -- Succ_Reason indicates the reason for a particular elaboration link
109 type Succ_Reason is
110 (Withed,
111 -- After directly with's Before, so the spec of Before must be
112 -- elaborated before After is elaborated.
114 Forced,
115 -- Before and After come from a pair of lines in the forced elaboration
116 -- order file.
118 Elab,
119 -- After directly mentions Before in a pragma Elaborate, so the body of
120 -- Before must be elaborated before After is elaborated.
122 Elab_All,
123 -- After either mentions Before directly in a pragma Elaborate_All, or
124 -- mentions a third unit, X, which itself requires that Before be
125 -- elaborated before unit X is elaborated. The Elab_All_Link list traces
126 -- the dependencies in the latter case.
128 Elab_All_Desirable,
129 -- This is just like Elab_All, except that the Elaborate_All was not
130 -- explicitly present in the source, but rather was created by the front
131 -- end, which decided that it was "desirable".
133 Elab_Desirable,
134 -- This is just like Elab, except that the Elaborate was not explicitly
135 -- present in the source, but rather was created by the front end, which
136 -- decided that it was "desirable".
138 Spec_First);
139 -- After is a body, and Before is the corresponding spec
141 -- Successor_Link contains the information for one link
143 type Successor_Link is record
144 Before : Unit_Id;
145 -- Predecessor unit
147 After : Unit_Id;
148 -- Successor unit
150 Next : Successor_Id;
151 -- Next successor on this list
153 Reason : Succ_Reason;
154 -- Reason for this link
156 Elab_Body : Boolean;
157 -- Set True if this link is needed for the special Elaborate_Body
158 -- processing described below.
160 Reason_Unit : Unit_Id;
161 -- For Reason = Elab, or Elab_All or Elab_Desirable, records the unit
162 -- containing the pragma leading to the link.
164 Elab_All_Link : Elab_All_Id;
165 -- If Reason = Elab_All or Elab_Desirable, then this points to the
166 -- first element in a list of Elab_All entries that record the with
167 -- chain resulting in this particular dependency.
168 end record;
170 -- Note on handling of Elaborate_Body. Basically, if we have a pragma
171 -- Elaborate_Body in a unit, it means that the spec and body have to be
172 -- handled as a single entity from the point of view of determining an
173 -- elaboration order. What we do is to essentially remove the body from
174 -- consideration completely, and transfer all its links (other than the
175 -- spec link) to the spec. Then when the spec gets chosen, we choose the
176 -- body right afterwards. We mark the links that get moved from the body to
177 -- the spec by setting their Elab_Body flag True, so that we can understand
178 -- what is going on.
180 Succ_First : constant := 1;
182 package Succ is new Table.Table
183 (Table_Component_Type => Successor_Link,
184 Table_Index_Type => Successor_Id,
185 Table_Low_Bound => Succ_First,
186 Table_Initial => 500,
187 Table_Increment => 200,
188 Table_Name => "Succ");
190 -- For the case of Elaborate_All, the following table is used to record
191 -- chains of with relationships that lead to the Elab_All link. These are
192 -- used solely for diagnostic purposes
194 type Elab_All_Entry is record
195 Needed_By : Unit_Name_Type;
196 -- Name of unit from which referencing unit was with'ed or otherwise
197 -- needed as a result of Elaborate_All or Elaborate_Desirable.
199 Next_Elab : Elab_All_Id;
200 -- Link to next entry on chain (No_Elab_All_Link marks end of list)
201 end record;
203 package Elab_All_Entries is new Table.Table
204 (Table_Component_Type => Elab_All_Entry,
205 Table_Index_Type => Elab_All_Id,
206 Table_Low_Bound => 1,
207 Table_Initial => 2000,
208 Table_Increment => 200,
209 Table_Name => "Elab_All_Entries");
211 type Unit_Id_Array_Ptr is access Unit_Id_Array;
213 -- A Unit_Node_Record is built for each active unit
215 type Unit_Node_Record is record
216 Successors : Successor_Id;
217 -- Pointer to list of links for successor nodes
219 Num_Pred : Int;
220 -- Number of predecessors for this unit that have not yet been chosen.
221 -- Normally non-negative, but can go negative in the case of units
222 -- chosen by the diagnose error procedure (when cycles are being removed
223 -- from the graph).
225 Nextnp : Unit_Id;
226 -- Forward pointer for list of units with no predecessors
228 Visited : Boolean;
229 -- Used in computing transitive closure for Elaborate_All and also in
230 -- locating cycles and paths in the diagnose routines.
232 Elab_Position : Nat;
233 -- Initialized to zero. Set non-zero when a unit is chosen and placed in
234 -- the elaboration order. The value represents the ordinal position in
235 -- the elaboration order.
237 -- The following are for Elab_New. We compute the strongly connected
238 -- components (SCCs) of the directed graph of units. The edges are the
239 -- Successors, which do not include pragmas Elaborate_All (explicit or
240 -- implicit) in Elab_New. In addition, we assume there is a edge
241 -- pointing from a body to its corresponding spec; this edge is not
242 -- included in Successors, because of course a spec is elaborated BEFORE
243 -- its body, not after.
245 SCC_Root : Unit_Id;
246 -- Each unit points to the root of its SCC, which is just an arbitrary
247 -- member of the SCC. Two units are in the same SCC if and only if their
248 -- SCC_Roots are equal. U is the root of its SCC if and only if
249 -- SCC(U)=U.
251 Nodes : Unit_Id_Array_Ptr;
252 -- Present only in the root of an SCC. This is the set of units in the
253 -- SCC, in no particular order.
255 SCC_Num_Pred : Int;
256 -- Present only in the root of an SCC. This is the number of predecessor
257 -- units of the SCC that are in other SCCs, and that have not yet been
258 -- chosen.
260 Validate_Seen : Boolean := False;
261 -- See procedure Validate below
262 end record;
264 package UNR is new Table.Table
265 (Table_Component_Type => Unit_Node_Record,
266 Table_Index_Type => Unit_Id,
267 Table_Low_Bound => First_Unit_Entry,
268 Table_Initial => 500,
269 Table_Increment => 200,
270 Table_Name => "UNR");
272 No_Pred : Unit_Id;
273 -- Head of list of items with no predecessors
275 Num_Left : Int;
276 -- Number of entries not yet dealt with
278 Cur_Unit : Unit_Id;
279 -- Current unit, set by Gather_Dependencies, and picked up in Build_Link to
280 -- set the Reason_Unit field of the created dependency link.
282 Num_Chosen : Nat;
283 -- Number of units chosen in the elaboration order so far
285 Diagnose_Elaboration_Problem_Called : Boolean := False;
286 -- True if Diagnose_Elaboration_Problem was called. Used in an assertion.
288 -----------------------
289 -- Local Subprograms --
290 -----------------------
292 function Debug_Flag_Older return Boolean;
293 function Debug_Flag_Old return Boolean;
294 -- True if debug flags select the old or older algorithms. Pretty much any
295 -- change to elaboration order can break some programs. For example,
296 -- programs can depend on elaboration order even without failing
297 -- access-before-elaboration checks. A trivial example is a program that
298 -- prints text during elaboration. Therefore, we have flags to revert to
299 -- the old(er) algorithms.
301 procedure Validate (Order : Unit_Id_Array; Doing_New : Boolean);
302 -- Assert that certain properties are true
304 function Better_Choice_Optimistic
305 (U1 : Unit_Id;
306 U2 : Unit_Id) return Boolean;
307 -- U1 and U2 are both permitted candidates for selection as the next unit
308 -- to be elaborated. This function determines whether U1 is a better choice
309 -- than U2, i.e. should be elaborated in preference to U2, based on a set
310 -- of heuristics that establish a friendly and predictable order (see body
311 -- for details). The result is True if U1 is a better choice than U2, and
312 -- False if it is a worse choice, or there is no preference between them.
314 function Better_Choice_Pessimistic
315 (U1 : Unit_Id;
316 U2 : Unit_Id) return Boolean;
317 -- This is like Better_Choice_Optimistic, and has the same interface, but
318 -- returns true if U1 is a worse choice than U2 in the sense of the -p
319 -- (pessimistic elaboration order) switch. We still have to obey Ada rules,
320 -- so it is not quite the direct inverse of Better_Choice_Optimistic.
322 function Better_Choice (U1 : Unit_Id; U2 : Unit_Id) return Boolean;
323 -- Calls Better_Choice_Optimistic or Better_Choice_Pessimistic as
324 -- appropriate. Also takes care of the U2 = No_Unit_Id case.
326 procedure Build_Link
327 (Before : Unit_Id;
328 After : Unit_Id;
329 R : Succ_Reason;
330 Ea_Id : Elab_All_Id := No_Elab_All_Link);
331 -- Establish a successor link, Before must be elaborated before After, and
332 -- the reason for the link is R. Ea_Id is the contents to be placed in the
333 -- Elab_All_Link of the entry.
335 procedure Choose
336 (Elab_Order : in out Unit_Id_Table;
337 Chosen : Unit_Id;
338 Msg : String);
339 -- Chosen is the next entry chosen in the elaboration order. This procedure
340 -- updates all data structures appropriately.
342 function Corresponding_Body (U : Unit_Id) return Unit_Id;
343 pragma Inline (Corresponding_Body);
344 -- Given a unit that is a spec for which there is a separate body, return
345 -- the unit id of the body. It is an error to call this routine with a unit
346 -- that is not a spec, or that does not have a separate body.
348 function Corresponding_Spec (U : Unit_Id) return Unit_Id;
349 pragma Inline (Corresponding_Spec);
350 -- Given a unit that is a body for which there is a separate spec, return
351 -- the unit id of the spec. It is an error to call this routine with a unit
352 -- that is not a body, or that does not have a separate spec.
354 procedure Diagnose_Elaboration_Problem
355 (Elab_Order : in out Unit_Id_Table);
356 pragma No_Return (Diagnose_Elaboration_Problem);
357 -- Called when no elaboration order can be found. Outputs an appropriate
358 -- diagnosis of the problem, and then abandons the bind.
360 procedure Elab_All_Links
361 (Before : Unit_Id;
362 After : Unit_Id;
363 Reason : Succ_Reason;
364 Link : Elab_All_Id);
365 -- Used to compute the transitive closure of elaboration links for an
366 -- Elaborate_All pragma (Reason = Elab_All) or for an indication of
367 -- Elaborate_All_Desirable (Reason = Elab_All_Desirable). Unit After has a
368 -- pragma Elaborate_All or the front end has determined that a reference
369 -- probably requires Elaborate_All, and unit Before must be previously
370 -- elaborated. First a link is built making sure that unit Before is
371 -- elaborated before After, then a recursive call ensures that we also
372 -- build links for any units needed by Before (i.e. these units must/should
373 -- also be elaborated before After). Link is used to build a chain of
374 -- Elab_All_Entries to explain the reason for a link. The value passed is
375 -- the chain so far.
377 procedure Elab_Error_Msg (S : Successor_Id);
378 -- Given a successor link, outputs an error message of the form
379 -- "$ must be elaborated before $ ..." where ... is the reason.
381 procedure Force_Elab_Order;
382 -- Gather dependencies from the forced elaboration order file (-f switch)
384 procedure Gather_Dependencies;
385 -- Compute dependencies, building the Succ and UNR tables
387 procedure Init;
388 -- Initialize global data structures in this package body
390 function Is_Body_Unit (U : Unit_Id) return Boolean;
391 pragma Inline (Is_Body_Unit);
392 -- Determines if given unit is a body
394 function Is_Pure_Or_Preelab_Unit (U : Unit_Id) return Boolean;
395 -- Returns True if corresponding unit is Pure or Preelaborate. Includes
396 -- dealing with testing flags on spec if it is given a body.
398 function Is_Waiting_Body (U : Unit_Id) return Boolean;
399 pragma Inline (Is_Waiting_Body);
400 -- Determines if U is a waiting body, defined as a body that has
401 -- not been elaborated, but whose spec has been elaborated.
403 function Make_Elab_All_Entry
404 (Unam : Unit_Name_Type;
405 Link : Elab_All_Id) return Elab_All_Id;
406 -- Make an Elab_All_Entries table entry with the given Unam and Link
408 function Unit_Id_Of (Uname : Unit_Name_Type) return Unit_Id;
409 -- This function uses the Info field set in the names table to obtain
410 -- the unit Id of a unit, given its name id value.
412 procedure Write_Closure (Order : Unit_Id_Array);
413 -- Write the closure. This is for the -R and -Ra switches, "list closure
414 -- display".
416 procedure Write_Dependencies;
417 -- Write out dependencies (called only if appropriate option is set)
419 procedure Write_Elab_All_Chain (S : Successor_Id);
420 -- If the reason for the link S is Elaborate_All or Elaborate_Desirable,
421 -- then this routine will output the "needed by" explanation chain.
423 procedure Write_Elab_Order (Order : Unit_Id_Array; Title : String);
424 -- Display elaboration order. This is for the -l switch. Title is a heading
425 -- to print; an empty string is passed to indicate Zero_Formatting.
427 package Elab_New is
429 -- Implementation of the new algorithm
431 procedure Write_SCC (U : Unit_Id);
432 -- Write the unit names of the units in the SCC in which U lives
434 procedure Find_Elab_Order (Elab_Order : out Unit_Id_Table);
436 Elab_Cycle_Found : Boolean := False;
437 -- Set True if Find_Elab_Order found a cycle (usually an illegal pragma
438 -- Elaborate_All, explicit or implicit).
440 function SCC (U : Unit_Id) return Unit_Id;
441 -- The root of the strongly connected component containing U
443 function SCC_Num_Pred (U : Unit_Id) return Int;
444 -- The SCC_Num_Pred of the SCC in which U lives
446 function Nodes (U : Unit_Id) return Unit_Id_Array_Ptr;
447 -- The nodes of the strongly connected component containing U
449 end Elab_New;
451 use Elab_New;
453 package Elab_Old is
455 -- Implementation of the old algorithm
457 procedure Find_Elab_Order (Elab_Order : out Unit_Id_Table);
459 end Elab_Old;
461 -- Most of the code is shared between old and new; such code is outside
462 -- packages Elab_Old and Elab_New.
464 -------------------
465 -- Better_Choice --
466 -------------------
468 function Better_Choice (U1 : Unit_Id; U2 : Unit_Id) return Boolean is
469 pragma Assert (U1 /= No_Unit_Id);
470 begin
471 if U2 = No_Unit_Id then
472 return True;
473 end if;
475 if Pessimistic_Elab_Order then
476 return Better_Choice_Pessimistic (U1, U2);
477 else
478 return Better_Choice_Optimistic (U1, U2);
479 end if;
480 end Better_Choice;
482 ------------------------------
483 -- Better_Choice_Optimistic --
484 ------------------------------
486 function Better_Choice_Optimistic
487 (U1 : Unit_Id;
488 U2 : Unit_Id) return Boolean
490 UT1 : Unit_Record renames Units.Table (U1);
491 UT2 : Unit_Record renames Units.Table (U2);
493 begin
494 if Debug_Flag_B then
495 Write_Str ("Better_Choice_Optimistic (");
496 Write_Unit_Name (UT1.Uname);
497 Write_Str (", ");
498 Write_Unit_Name (UT2.Uname);
499 Write_Line (")");
500 end if;
502 -- Note: the checks here are applied in sequence, and the ordering is
503 -- significant (i.e. the more important criteria are applied first).
505 -- Prefer a waiting body to one that is not a waiting body
507 if Is_Waiting_Body (U1) and then not Is_Waiting_Body (U2) then
508 if Debug_Flag_B then
509 Write_Line (" True: u1 is waiting body, u2 is not");
510 end if;
512 return True;
514 elsif Is_Waiting_Body (U2) and then not Is_Waiting_Body (U1) then
515 if Debug_Flag_B then
516 Write_Line (" False: u2 is waiting body, u1 is not");
517 end if;
519 return False;
521 -- Prefer a predefined unit to a non-predefined unit
523 elsif UT1.Predefined and then not UT2.Predefined then
524 if Debug_Flag_B then
525 Write_Line (" True: u1 is predefined, u2 is not");
526 end if;
528 return True;
530 elsif UT2.Predefined and then not UT1.Predefined then
531 if Debug_Flag_B then
532 Write_Line (" False: u2 is predefined, u1 is not");
533 end if;
535 return False;
537 -- Prefer an internal unit to a non-internal unit
539 elsif UT1.Internal and then not UT2.Internal then
540 if Debug_Flag_B then
541 Write_Line (" True: u1 is internal, u2 is not");
542 end if;
543 return True;
545 elsif UT2.Internal and then not UT1.Internal then
546 if Debug_Flag_B then
547 Write_Line (" False: u2 is internal, u1 is not");
548 end if;
550 return False;
552 -- Prefer a pure or preelaborated unit to one that is not. Pure should
553 -- come before preelaborated.
555 elsif Is_Pure_Or_Preelab_Unit (U1)
556 and then not
557 Is_Pure_Or_Preelab_Unit (U2)
558 then
559 if Debug_Flag_B then
560 Write_Line (" True: u1 is pure/preelab, u2 is not");
561 end if;
563 return True;
565 elsif Is_Pure_Or_Preelab_Unit (U2)
566 and then not
567 Is_Pure_Or_Preelab_Unit (U1)
568 then
569 if Debug_Flag_B then
570 Write_Line (" False: u2 is pure/preelab, u1 is not");
571 end if;
573 return False;
575 -- Prefer a body to a spec
577 elsif Is_Body_Unit (U1) and then not Is_Body_Unit (U2) then
578 if Debug_Flag_B then
579 Write_Line (" True: u1 is body, u2 is not");
580 end if;
582 return True;
584 elsif Is_Body_Unit (U2) and then not Is_Body_Unit (U1) then
585 if Debug_Flag_B then
586 Write_Line (" False: u2 is body, u1 is not");
587 end if;
589 return False;
591 -- If both are waiting bodies, then prefer the one whose spec is more
592 -- recently elaborated. Consider the following:
594 -- spec of A
595 -- spec of B
596 -- body of A or B?
598 -- The normal waiting body preference would have placed the body of A
599 -- before the spec of B if it could. Since it could not, then it must be
600 -- the case that A depends on B. It is therefore a good idea to put the
601 -- body of B first.
603 elsif Is_Waiting_Body (U1) and then Is_Waiting_Body (U2) then
604 declare
605 Result : constant Boolean :=
606 UNR.Table (Corresponding_Spec (U1)).Elab_Position >
607 UNR.Table (Corresponding_Spec (U2)).Elab_Position;
608 begin
609 if Debug_Flag_B then
610 if Result then
611 Write_Line (" True: based on waiting body elab positions");
612 else
613 Write_Line (" False: based on waiting body elab positions");
614 end if;
615 end if;
617 return Result;
618 end;
619 end if;
621 -- Remaining choice rules are disabled by Debug flag -do
623 if not Debug_Flag_Older then
625 -- The following deal with the case of specs that have been marked
626 -- as Elaborate_Body_Desirable. We generally want to delay these
627 -- specs as long as possible, so that the bodies have a better chance
628 -- of being elaborated closer to the specs.
630 -- If we have two units, one of which is a spec for which this flag
631 -- is set, and the other is not, we prefer to delay the spec for
632 -- which the flag is set.
634 if not UT1.Elaborate_Body_Desirable
635 and then UT2.Elaborate_Body_Desirable
636 then
637 if Debug_Flag_B then
638 Write_Line (" True: u1 is elab body desirable, u2 is not");
639 end if;
641 return True;
643 elsif not UT2.Elaborate_Body_Desirable
644 and then UT1.Elaborate_Body_Desirable
645 then
646 if Debug_Flag_B then
647 Write_Line (" False: u1 is elab body desirable, u2 is not");
648 end if;
650 return False;
652 -- If we have two specs that are both marked as Elaborate_Body
653 -- desirable, we prefer the one whose body is nearer to being able
654 -- to be elaborated, based on the Num_Pred count. This helps to
655 -- ensure bodies are as close to specs as possible.
657 elsif UT1.Elaborate_Body_Desirable
658 and then UT2.Elaborate_Body_Desirable
659 then
660 declare
661 Result : constant Boolean :=
662 UNR.Table (Corresponding_Body (U1)).Num_Pred <
663 UNR.Table (Corresponding_Body (U2)).Num_Pred;
664 begin
665 if Debug_Flag_B then
666 if Result then
667 Write_Line (" True based on Num_Pred compare");
668 else
669 Write_Line (" False based on Num_Pred compare");
670 end if;
671 end if;
673 return Result;
674 end;
675 end if;
676 end if;
678 -- If we have two specs in the same SCC, choose the one whose body is
679 -- closer to being ready.
681 if Doing_New
682 and then SCC (U1) = SCC (U2)
683 and then Units.Table (U1).Utype = Is_Spec
684 and then Units.Table (U2).Utype = Is_Spec
685 and then UNR.Table (Corresponding_Body (U1)).Num_Pred /=
686 UNR.Table (Corresponding_Body (U2)).Num_Pred
687 then
688 if UNR.Table (Corresponding_Body (U1)).Num_Pred <
689 UNR.Table (Corresponding_Body (U2)).Num_Pred
690 then
691 if Debug_Flag_B then
692 Write_Str (" True: same SCC; ");
693 Write_Int (UNR.Table (Corresponding_Body (U1)).Num_Pred);
694 Write_Str (" < ");
695 Write_Int (UNR.Table (Corresponding_Body (U2)).Num_Pred);
696 Write_Eol;
697 end if;
699 return True;
700 else
701 if Debug_Flag_B then
702 Write_Str (" False: same SCC; ");
703 Write_Int (UNR.Table (Corresponding_Body (U1)).Num_Pred);
704 Write_Str (" > ");
705 Write_Int (UNR.Table (Corresponding_Body (U2)).Num_Pred);
706 Write_Eol;
707 end if;
709 return False;
710 end if;
711 end if;
713 -- If we fall through, it means that no preference rule applies, so we
714 -- use alphabetical order to at least give a deterministic result.
716 if Debug_Flag_B then
717 Write_Line (" choose on alpha order");
718 end if;
720 return Uname_Less (UT1.Uname, UT2.Uname);
721 end Better_Choice_Optimistic;
723 -------------------------------
724 -- Better_Choice_Pessimistic --
725 -------------------------------
727 function Better_Choice_Pessimistic
728 (U1 : Unit_Id;
729 U2 : Unit_Id) return Boolean
731 UT1 : Unit_Record renames Units.Table (U1);
732 UT2 : Unit_Record renames Units.Table (U2);
734 begin
735 if Debug_Flag_B then
736 Write_Str ("Better_Choice_Pessimistic (");
737 Write_Unit_Name (UT1.Uname);
738 Write_Str (", ");
739 Write_Unit_Name (UT2.Uname);
740 Write_Line (")");
741 end if;
743 -- Note: the checks here are applied in sequence, and the ordering is
744 -- significant (i.e. the more important criteria are applied first).
746 -- If either unit is predefined or internal, then we use the normal
747 -- Better_Choice_Optimistic rule, since we don't want to disturb the
748 -- elaboration rules of the language with -p; same treatment for
749 -- Pure/Preelab.
751 -- Prefer a predefined unit to a non-predefined unit
753 if UT1.Predefined and then not UT2.Predefined then
754 if Debug_Flag_B then
755 Write_Line (" True: u1 is predefined, u2 is not");
756 end if;
758 return True;
760 elsif UT2.Predefined and then not UT1.Predefined then
761 if Debug_Flag_B then
762 Write_Line (" False: u2 is predefined, u1 is not");
763 end if;
765 return False;
767 -- Prefer an internal unit to a non-internal unit
769 elsif UT1.Internal and then not UT2.Internal then
770 if Debug_Flag_B then
771 Write_Line (" True: u1 is internal, u2 is not");
772 end if;
774 return True;
776 elsif UT2.Internal and then not UT1.Internal then
777 if Debug_Flag_B then
778 Write_Line (" False: u2 is internal, u1 is not");
779 end if;
781 return False;
783 -- Prefer a pure or preelaborated unit to one that is not
785 elsif Is_Pure_Or_Preelab_Unit (U1)
786 and then not
787 Is_Pure_Or_Preelab_Unit (U2)
788 then
789 if Debug_Flag_B then
790 Write_Line (" True: u1 is pure/preelab, u2 is not");
791 end if;
793 return True;
795 elsif Is_Pure_Or_Preelab_Unit (U2)
796 and then not
797 Is_Pure_Or_Preelab_Unit (U1)
798 then
799 if Debug_Flag_B then
800 Write_Line (" False: u2 is pure/preelab, u1 is not");
801 end if;
803 return False;
805 -- Prefer anything else to a waiting body. We want to make bodies wait
806 -- as long as possible, till we are forced to choose them.
808 elsif Is_Waiting_Body (U1) and then not Is_Waiting_Body (U2) then
809 if Debug_Flag_B then
810 Write_Line (" False: u1 is waiting body, u2 is not");
811 end if;
813 return False;
815 elsif Is_Waiting_Body (U2) and then not Is_Waiting_Body (U1) then
816 if Debug_Flag_B then
817 Write_Line (" True: u2 is waiting body, u1 is not");
818 end if;
820 return True;
822 -- Prefer a spec to a body (this is mandatory)
824 elsif Is_Body_Unit (U1) and then not Is_Body_Unit (U2) then
825 if Debug_Flag_B then
826 Write_Line (" False: u1 is body, u2 is not");
827 end if;
829 return False;
831 elsif Is_Body_Unit (U2) and then not Is_Body_Unit (U1) then
832 if Debug_Flag_B then
833 Write_Line (" True: u2 is body, u1 is not");
834 end if;
836 return True;
838 -- If both are waiting bodies, then prefer the one whose spec is less
839 -- recently elaborated. Consider the following:
841 -- spec of A
842 -- spec of B
843 -- body of A or B?
845 -- The normal waiting body preference would have placed the body of A
846 -- before the spec of B if it could. Since it could not, then it must be
847 -- the case that A depends on B. It is therefore a good idea to put the
848 -- body of B last so that if there is an elaboration order problem, we
849 -- will find it (that's what pessimistic order is about).
851 elsif Is_Waiting_Body (U1) and then Is_Waiting_Body (U2) then
852 declare
853 Result : constant Boolean :=
854 UNR.Table (Corresponding_Spec (U1)).Elab_Position <
855 UNR.Table (Corresponding_Spec (U2)).Elab_Position;
856 begin
857 if Debug_Flag_B then
858 if Result then
859 Write_Line (" True: based on waiting body elab positions");
860 else
861 Write_Line (" False: based on waiting body elab positions");
862 end if;
863 end if;
865 return Result;
866 end;
867 end if;
869 -- Remaining choice rules are disabled by Debug flag -do
871 if not Debug_Flag_Older then
873 -- The following deal with the case of specs that have been marked as
874 -- Elaborate_Body_Desirable. In the normal case, we generally want to
875 -- delay the elaboration of these specs as long as possible, so that
876 -- bodies have better chance of being elaborated closer to the specs.
877 -- Better_Choice_Pessimistic as usual wants to do the opposite and
878 -- elaborate such specs as early as possible.
880 -- If we have two units, one of which is a spec for which this flag
881 -- is set, and the other is not, we normally prefer to delay the spec
882 -- for which the flag is set, so again Better_Choice_Pessimistic does
883 -- the opposite.
885 if not UT1.Elaborate_Body_Desirable
886 and then UT2.Elaborate_Body_Desirable
887 then
888 if Debug_Flag_B then
889 Write_Line (" False: u1 is elab body desirable, u2 is not");
890 end if;
892 return False;
894 elsif not UT2.Elaborate_Body_Desirable
895 and then UT1.Elaborate_Body_Desirable
896 then
897 if Debug_Flag_B then
898 Write_Line (" True: u1 is elab body desirable, u2 is not");
899 end if;
901 return True;
903 -- If we have two specs that are both marked as Elaborate_Body
904 -- desirable, we normally prefer the one whose body is nearer to
905 -- being able to be elaborated, based on the Num_Pred count. This
906 -- helps to ensure bodies are as close to specs as possible. As
907 -- usual, Better_Choice_Pessimistic does the opposite.
909 elsif UT1.Elaborate_Body_Desirable
910 and then UT2.Elaborate_Body_Desirable
911 then
912 declare
913 Result : constant Boolean :=
914 UNR.Table (Corresponding_Body (U1)).Num_Pred >=
915 UNR.Table (Corresponding_Body (U2)).Num_Pred;
916 begin
917 if Debug_Flag_B then
918 if Result then
919 Write_Line (" True based on Num_Pred compare");
920 else
921 Write_Line (" False based on Num_Pred compare");
922 end if;
923 end if;
925 return Result;
926 end;
927 end if;
928 end if;
930 -- If we fall through, it means that no preference rule applies, so we
931 -- use alphabetical order to at least give a deterministic result. Since
932 -- Better_Choice_Pessimistic is in the business of stirring up the
933 -- order, we will use reverse alphabetical ordering.
935 if Debug_Flag_B then
936 Write_Line (" choose on reverse alpha order");
937 end if;
939 return Uname_Less (UT2.Uname, UT1.Uname);
940 end Better_Choice_Pessimistic;
942 ----------------
943 -- Build_Link --
944 ----------------
946 procedure Build_Link
947 (Before : Unit_Id;
948 After : Unit_Id;
949 R : Succ_Reason;
950 Ea_Id : Elab_All_Id := No_Elab_All_Link)
952 Cspec : Unit_Id;
954 begin
955 Succ.Append
956 ((Before => Before,
957 After => No_Unit_Id, -- filled in below
958 Next => UNR.Table (Before).Successors,
959 Reason => R,
960 Elab_Body => False, -- set correctly below
961 Reason_Unit => Cur_Unit,
962 Elab_All_Link => Ea_Id));
963 UNR.Table (Before).Successors := Succ.Last;
965 -- Deal with special Elab_Body case. If the After of this link is
966 -- a body whose spec has Elaborate_All set, and this is not the link
967 -- directly from the body to the spec, then we make the After of the
968 -- link reference its spec instead, marking the link appropriately.
970 if Units.Table (After).Utype = Is_Body then
971 Cspec := Corresponding_Spec (After);
973 if Units.Table (Cspec).Elaborate_Body
974 and then Cspec /= Before
975 then
976 Succ.Table (Succ.Last).After := Cspec;
977 Succ.Table (Succ.Last).Elab_Body := True;
978 UNR.Table (Cspec).Num_Pred := UNR.Table (Cspec).Num_Pred + 1;
979 return;
980 end if;
981 end if;
983 -- Fall through on normal case
985 Succ.Table (Succ.Last).After := After;
986 Succ.Table (Succ.Last).Elab_Body := False;
987 UNR.Table (After).Num_Pred := UNR.Table (After).Num_Pred + 1;
988 end Build_Link;
990 ------------
991 -- Choose --
992 ------------
994 procedure Choose
995 (Elab_Order : in out Unit_Id_Table;
996 Chosen : Unit_Id;
997 Msg : String)
999 pragma Assert (Chosen /= No_Unit_Id);
1000 S : Successor_Id;
1001 U : Unit_Id;
1003 begin
1004 if Debug_Flag_C then
1005 Write_Str ("Choosing Unit ");
1006 Write_Unit_Name (Units.Table (Chosen).Uname);
1007 Write_Str (Msg);
1008 end if;
1010 -- We shouldn't be choosing something with unelaborated predecessors,
1011 -- and we shouldn't call this twice on the same unit. But that's not
1012 -- true when this is called from Diagnose_Elaboration_Problem.
1014 if Errors_Detected = 0 then
1015 pragma Assert (UNR.Table (Chosen).Num_Pred = 0);
1016 pragma Assert (UNR.Table (Chosen).Elab_Position = 0);
1017 pragma Assert (not Doing_New or else SCC_Num_Pred (Chosen) = 0);
1018 null;
1019 end if;
1021 -- Add to elaboration order. Note that units having no elaboration code
1022 -- are not treated specially yet. The special casing of this is in
1023 -- Bindgen, where Gen_Elab_Calls skips over them. Meanwhile we need them
1024 -- here, because the object file list is also driven by the contents of
1025 -- the Elab_Order table.
1027 Append (Elab_Order, Chosen);
1029 -- Remove from No_Pred list. This is a little inefficient and may be we
1030 -- should doubly link the list, but it will do for now.
1032 if No_Pred = Chosen then
1033 No_Pred := UNR.Table (Chosen).Nextnp;
1034 else
1035 U := No_Pred;
1036 while U /= No_Unit_Id loop
1037 if UNR.Table (U).Nextnp = Chosen then
1038 UNR.Table (U).Nextnp := UNR.Table (Chosen).Nextnp;
1039 goto Done_Removal;
1040 end if;
1042 U := UNR.Table (U).Nextnp;
1043 end loop;
1045 -- Here if we didn't find it on the No_Pred list. This can happen
1046 -- only in calls from the Diagnose_Elaboration_Problem routine,
1047 -- where cycles are being removed arbitrarily from the graph.
1049 pragma Assert (Errors_Detected > 0);
1050 <<Done_Removal>> null;
1051 end if;
1053 -- For all successors, decrement the number of predecessors, and if it
1054 -- becomes zero, then add to no-predecessor list.
1056 S := UNR.Table (Chosen).Successors;
1057 while S /= No_Successor loop
1058 U := Succ.Table (S).After;
1059 UNR.Table (U).Num_Pred := UNR.Table (U).Num_Pred - 1;
1061 if Debug_Flag_N then
1062 Write_Str (" decrementing Num_Pred for unit ");
1063 Write_Unit_Name (Units.Table (U).Uname);
1064 Write_Str (" new value = ");
1065 Write_Int (UNR.Table (U).Num_Pred);
1066 Write_Eol;
1067 end if;
1069 if UNR.Table (U).Num_Pred = 0 then
1070 UNR.Table (U).Nextnp := No_Pred;
1071 No_Pred := U;
1072 end if;
1074 if Doing_New and then SCC (U) /= SCC (Chosen) then
1075 UNR.Table (SCC (U)).SCC_Num_Pred :=
1076 UNR.Table (SCC (U)).SCC_Num_Pred - 1;
1078 if Debug_Flag_N then
1079 Write_Str (" decrementing SCC_Num_Pred for unit ");
1080 Write_Unit_Name (Units.Table (U).Uname);
1081 Write_Str (" new value = ");
1082 Write_Int (SCC_Num_Pred (U));
1083 Write_Eol;
1084 end if;
1085 end if;
1087 S := Succ.Table (S).Next;
1088 end loop;
1090 -- All done, adjust number of units left count and set elaboration pos
1092 Num_Left := Num_Left - 1;
1093 Num_Chosen := Num_Chosen + 1;
1095 pragma Assert
1096 (Errors_Detected > 0 or else Num_Chosen = Last (Elab_Order));
1097 pragma Assert (Units.Last = UNR.Last);
1098 pragma Assert (Num_Chosen + Num_Left = Int (UNR.Last));
1100 if Debug_Flag_C then
1101 Write_Str (" ");
1102 Write_Int (Int (Num_Chosen));
1103 Write_Str ("+");
1104 Write_Int (Num_Left);
1105 Write_Str ("=");
1106 Write_Int (Int (UNR.Last));
1107 Write_Eol;
1108 end if;
1110 UNR.Table (Chosen).Elab_Position := Num_Chosen;
1112 -- If we just chose a spec with Elaborate_Body set, then we must
1113 -- immediately elaborate the body, before any other units.
1115 if Units.Table (Chosen).Elaborate_Body then
1117 -- If the unit is a spec only, then there is no body. This is a bit
1118 -- odd given that Elaborate_Body is here, but it is valid in an RCI
1119 -- unit, where we only have the interface in the stub bind.
1121 if Units.Table (Chosen).Utype = Is_Spec_Only
1122 and then Units.Table (Chosen).RCI
1123 then
1124 null;
1125 else
1126 Choose
1127 (Elab_Order => Elab_Order,
1128 Chosen => Corresponding_Body (Chosen),
1129 Msg => " [Elaborate_Body]");
1130 end if;
1131 end if;
1132 end Choose;
1134 ------------------------
1135 -- Corresponding_Body --
1136 ------------------------
1138 -- Currently if the body and spec are separate, then they appear as two
1139 -- separate units in the same ALI file, with the body appearing first and
1140 -- the spec appearing second.
1142 function Corresponding_Body (U : Unit_Id) return Unit_Id is
1143 begin
1144 pragma Assert (Units.Table (U).Utype = Is_Spec);
1145 return U - 1;
1146 end Corresponding_Body;
1148 ------------------------
1149 -- Corresponding_Spec --
1150 ------------------------
1152 -- Currently if the body and spec are separate, then they appear as two
1153 -- separate units in the same ALI file, with the body appearing first and
1154 -- the spec appearing second.
1156 function Corresponding_Spec (U : Unit_Id) return Unit_Id is
1157 begin
1158 pragma Assert (Units.Table (U).Utype = Is_Body);
1159 return U + 1;
1160 end Corresponding_Spec;
1162 --------------------
1163 -- Debug_Flag_Old --
1164 --------------------
1166 function Debug_Flag_Old return Boolean is
1167 begin
1168 -- If the user specified both flags, we want to use the older algorithm,
1169 -- rather than some confusing mix of the two.
1171 return Debug_Flag_P and not Debug_Flag_O;
1172 end Debug_Flag_Old;
1174 ----------------------
1175 -- Debug_Flag_Older --
1176 ----------------------
1178 function Debug_Flag_Older return Boolean is
1179 begin
1180 return Debug_Flag_O;
1181 end Debug_Flag_Older;
1183 ----------------------------------
1184 -- Diagnose_Elaboration_Problem --
1185 ----------------------------------
1187 procedure Diagnose_Elaboration_Problem
1188 (Elab_Order : in out Unit_Id_Table)
1190 function Find_Path
1191 (Ufrom : Unit_Id;
1192 Uto : Unit_Id;
1193 ML : Nat) return Boolean;
1194 -- Recursive routine used to find a path from node Ufrom to node Uto.
1195 -- If a path exists, returns True and outputs an appropriate set of
1196 -- error messages giving the path. Also calls Choose for each of the
1197 -- nodes so that they get removed from the remaining set. There are
1198 -- two cases of calls, either Ufrom = Uto for an attempt to find a
1199 -- cycle, or Ufrom is a spec and Uto the corresponding body for the
1200 -- case of an unsatisfiable Elaborate_Body pragma. ML is the minimum
1201 -- acceptable length for a path.
1203 ---------------
1204 -- Find_Path --
1205 ---------------
1207 function Find_Path
1208 (Ufrom : Unit_Id;
1209 Uto : Unit_Id;
1210 ML : Nat) return Boolean
1212 function Find_Link (U : Unit_Id; PL : Nat) return Boolean;
1213 -- This is the inner recursive routine, it determines if a path
1214 -- exists from U to Uto, and if so returns True and outputs the
1215 -- appropriate set of error messages. PL is the path length
1217 ---------------
1218 -- Find_Link --
1219 ---------------
1221 function Find_Link (U : Unit_Id; PL : Nat) return Boolean is
1222 S : Successor_Id;
1224 begin
1225 -- Recursion ends if we are at terminating node and the path is
1226 -- sufficiently long, generate error message and return True.
1228 if U = Uto and then PL >= ML then
1229 Choose (Elab_Order, U, " [Find_Link: base]");
1230 return True;
1232 -- All done if already visited
1234 elsif UNR.Table (U).Visited then
1235 return False;
1237 -- Otherwise mark as visited and look at all successors
1239 else
1240 UNR.Table (U).Visited := True;
1242 S := UNR.Table (U).Successors;
1243 while S /= No_Successor loop
1244 if Find_Link (Succ.Table (S).After, PL + 1) then
1245 Elab_Error_Msg (S);
1246 Choose (Elab_Order, U, " [Find_Link: recursive]");
1247 return True;
1248 end if;
1250 S := Succ.Table (S).Next;
1251 end loop;
1253 -- Falling through means this does not lead to a path
1255 return False;
1256 end if;
1257 end Find_Link;
1259 -- Start of processing for Find_Path
1261 begin
1262 -- Initialize all non-chosen nodes to not visited yet
1264 for U in Units.First .. Units.Last loop
1265 UNR.Table (U).Visited := UNR.Table (U).Elab_Position /= 0;
1266 end loop;
1268 -- Now try to find the path
1270 return Find_Link (Ufrom, 0);
1271 end Find_Path;
1273 -- Start of processing for Diagnose_Elaboration_Problem
1275 begin
1276 Diagnose_Elaboration_Problem_Called := True;
1277 Set_Standard_Error;
1279 -- Output state of things if debug flag N set
1281 if Debug_Flag_N then
1282 declare
1283 NP : Int;
1285 begin
1286 Write_Eol;
1287 Write_Eol;
1288 Write_Line ("Diagnose_Elaboration_Problem called");
1289 Write_Line ("List of remaining unchosen units and predecessors");
1291 for U in Units.First .. Units.Last loop
1292 if UNR.Table (U).Elab_Position = 0 then
1293 NP := UNR.Table (U).Num_Pred;
1294 Write_Eol;
1295 Write_Str (" Unchosen unit: #");
1296 Write_Int (Int (U));
1297 Write_Str (" ");
1298 Write_Unit_Name (Units.Table (U).Uname);
1299 Write_Str (" (Num_Pred = ");
1300 Write_Int (NP);
1301 Write_Line (")");
1303 if NP = 0 then
1304 if Units.Table (U).Elaborate_Body then
1305 Write_Line
1306 (" (not chosen because of Elaborate_Body)");
1307 else
1308 Write_Line (" ****************** why not chosen?");
1309 end if;
1310 end if;
1312 -- Search links list to find unchosen predecessors
1314 for S in Succ.First .. Succ.Last loop
1315 declare
1316 SL : Successor_Link renames Succ.Table (S);
1318 begin
1319 if SL.After = U
1320 and then UNR.Table (SL.Before).Elab_Position = 0
1321 then
1322 Write_Str (" unchosen predecessor: #");
1323 Write_Int (Int (SL.Before));
1324 Write_Str (" ");
1325 Write_Unit_Name (Units.Table (SL.Before).Uname);
1326 Write_Eol;
1327 NP := NP - 1;
1328 end if;
1329 end;
1330 end loop;
1332 if NP /= 0 then
1333 Write_Line (" **************** Num_Pred value wrong!");
1334 end if;
1335 end if;
1336 end loop;
1337 end;
1338 end if;
1340 -- Output the header for the error, and manually increment the error
1341 -- count. We are using Error_Msg_Output rather than Error_Msg here for
1342 -- two reasons:
1344 -- This is really only one error, not one for each line
1345 -- We want this output on standard output since it is voluminous
1347 -- But we do need to deal with the error count manually in this case
1349 Errors_Detected := Errors_Detected + 1;
1350 Error_Msg_Output ("elaboration circularity detected", Info => False);
1352 -- Try to find cycles starting with any of the remaining nodes that have
1353 -- not yet been chosen. There must be at least one (there is some reason
1354 -- we are being called).
1356 for U in Units.First .. Units.Last loop
1357 if UNR.Table (U).Elab_Position = 0 then
1358 if Find_Path (U, U, 1) then
1359 raise Unrecoverable_Error;
1360 end if;
1361 end if;
1362 end loop;
1364 -- We should never get here, since we were called for some reason, and
1365 -- we should have found and eliminated at least one bad path.
1367 raise Program_Error;
1368 end Diagnose_Elaboration_Problem;
1370 --------------------
1371 -- Elab_All_Links --
1372 --------------------
1374 procedure Elab_All_Links
1375 (Before : Unit_Id;
1376 After : Unit_Id;
1377 Reason : Succ_Reason;
1378 Link : Elab_All_Id)
1380 begin
1381 if UNR.Table (Before).Visited then
1382 return;
1383 end if;
1385 -- Build the direct link for Before
1387 UNR.Table (Before).Visited := True;
1388 Build_Link (Before, After, Reason, Link);
1390 -- Process all units with'ed by Before recursively
1392 for W in Units.Table (Before).First_With ..
1393 Units.Table (Before).Last_With
1394 loop
1395 -- Skip if this with is an interface to a stand-alone library. Skip
1396 -- also if no ALI file for this WITH, happens for language defined
1397 -- generics while bootstrapping the compiler (see body of routine
1398 -- Lib.Writ.Write_With_Lines). Finally, skip if it is a limited with
1399 -- clause, which does not impose an elaboration link.
1401 if not Withs.Table (W).SAL_Interface
1402 and then Withs.Table (W).Afile /= No_File
1403 and then not Withs.Table (W).Limited_With
1404 then
1405 declare
1406 Info : constant Int :=
1407 Get_Name_Table_Int (Withs.Table (W).Uname);
1409 begin
1410 -- If the unit is unknown, for some unknown reason, fail
1411 -- graciously explaining that the unit is unknown. Without
1412 -- this check, gnatbind will crash in Unit_Id_Of.
1414 if Info = 0 or else Unit_Id (Info) = No_Unit_Id then
1415 declare
1416 Withed : String :=
1417 Get_Name_String (Withs.Table (W).Uname);
1418 Last_Withed : Natural := Withed'Last;
1419 Withing : String :=
1420 Get_Name_String
1421 (Units.Table (Before).Uname);
1422 Last_Withing : Natural := Withing'Last;
1423 Spec_Body : String := " (Spec)";
1425 begin
1426 To_Mixed (Withed);
1427 To_Mixed (Withing);
1429 if Last_Withed > 2
1430 and then Withed (Last_Withed - 1) = '%'
1431 then
1432 Last_Withed := Last_Withed - 2;
1433 end if;
1435 if Last_Withing > 2
1436 and then Withing (Last_Withing - 1) = '%'
1437 then
1438 Last_Withing := Last_Withing - 2;
1439 end if;
1441 if Units.Table (Before).Utype = Is_Body
1442 or else Units.Table (Before).Utype = Is_Body_Only
1443 then
1444 Spec_Body := " (Body)";
1445 end if;
1447 Osint.Fail
1448 ("could not find unit "
1449 & Withed (Withed'First .. Last_Withed) & " needed by "
1450 & Withing (Withing'First .. Last_Withing) & Spec_Body);
1451 end;
1452 end if;
1454 Elab_All_Links
1455 (Unit_Id_Of (Withs.Table (W).Uname),
1456 After,
1457 Reason,
1458 Make_Elab_All_Entry (Withs.Table (W).Uname, Link));
1459 end;
1460 end if;
1461 end loop;
1463 -- Process corresponding body, if there is one
1465 if Units.Table (Before).Utype = Is_Spec then
1466 Elab_All_Links
1467 (Corresponding_Body (Before),
1468 After, Reason,
1469 Make_Elab_All_Entry
1470 (Units.Table (Corresponding_Body (Before)).Uname, Link));
1471 end if;
1472 end Elab_All_Links;
1474 --------------------
1475 -- Elab_Error_Msg --
1476 --------------------
1478 procedure Elab_Error_Msg (S : Successor_Id) is
1479 SL : Successor_Link renames Succ.Table (S);
1481 begin
1482 -- Nothing to do if internal unit involved and no -da flag
1484 if not Debug_Flag_A
1485 and then
1486 (Is_Internal_File_Name (Units.Table (SL.Before).Sfile)
1487 or else
1488 Is_Internal_File_Name (Units.Table (SL.After).Sfile))
1489 then
1490 return;
1491 end if;
1493 -- Here we want to generate output
1495 Error_Msg_Unit_1 := Units.Table (SL.Before).Uname;
1497 if SL.Elab_Body then
1498 Error_Msg_Unit_2 := Units.Table (Corresponding_Body (SL.After)).Uname;
1499 else
1500 Error_Msg_Unit_2 := Units.Table (SL.After).Uname;
1501 end if;
1503 Error_Msg_Output (" $ must be elaborated before $", Info => True);
1505 Error_Msg_Unit_1 := Units.Table (SL.Reason_Unit).Uname;
1507 case SL.Reason is
1508 when Withed =>
1509 Error_Msg_Output
1510 (" reason: with clause",
1511 Info => True);
1513 when Forced =>
1514 Error_Msg_Output
1515 (" reason: forced by -f switch",
1516 Info => True);
1518 when Elab =>
1519 Error_Msg_Output
1520 (" reason: pragma Elaborate in unit $",
1521 Info => True);
1523 when Elab_All =>
1524 Error_Msg_Output
1525 (" reason: pragma Elaborate_All in unit $",
1526 Info => True);
1528 when Elab_All_Desirable =>
1529 Error_Msg_Output
1530 (" reason: implicit Elaborate_All in unit $",
1531 Info => True);
1533 Error_Msg_Output
1534 (" recompile $ with -gnatel for full details",
1535 Info => True);
1537 when Elab_Desirable =>
1538 Error_Msg_Output
1539 (" reason: implicit Elaborate in unit $",
1540 Info => True);
1542 Error_Msg_Output
1543 (" recompile $ with -gnatel for full details",
1544 Info => True);
1546 when Spec_First =>
1547 Error_Msg_Output
1548 (" reason: spec always elaborated before body",
1549 Info => True);
1550 end case;
1552 Write_Elab_All_Chain (S);
1554 if SL.Elab_Body then
1555 Error_Msg_Unit_1 := Units.Table (SL.Before).Uname;
1556 Error_Msg_Unit_2 := Units.Table (SL.After).Uname;
1557 Error_Msg_Output
1558 (" $ must therefore be elaborated before $", True);
1560 Error_Msg_Unit_1 := Units.Table (SL.After).Uname;
1561 Error_Msg_Output
1562 (" (because $ has a pragma Elaborate_Body)", True);
1563 end if;
1565 if not Zero_Formatting then
1566 Write_Eol;
1567 end if;
1568 end Elab_Error_Msg;
1570 ---------------------
1571 -- Find_Elab_Order --
1572 ---------------------
1574 procedure Find_Elab_Order
1575 (Elab_Order : out Unit_Id_Table;
1576 First_Main_Lib_File : File_Name_Type)
1578 function Num_Spec_Body_Pairs (Order : Unit_Id_Array) return Nat;
1579 -- Number of cases where the body of a unit immediately follows the
1580 -- corresponding spec. Such cases are good, because calls to that unit
1581 -- from outside can't get ABE.
1583 -------------------------
1584 -- Num_Spec_Body_Pairs --
1585 -------------------------
1587 function Num_Spec_Body_Pairs (Order : Unit_Id_Array) return Nat is
1588 Result : Nat := 0;
1590 begin
1591 for J in Order'First + 1 .. Order'Last loop
1592 if Units.Table (Order (J - 1)).Utype = Is_Spec
1593 and then Units.Table (Order (J)).Utype = Is_Body
1594 and then Corresponding_Spec (Order (J)) = Order (J - 1)
1595 then
1596 Result := Result + 1;
1597 end if;
1598 end loop;
1600 return Result;
1601 end Num_Spec_Body_Pairs;
1603 -- Local variables
1605 Old_Elab_Order : Unit_Id_Table;
1607 -- Start of processing for Find_Elab_Order
1609 begin
1610 -- Output warning if -p used with no -gnatE units
1612 if Pessimistic_Elab_Order
1613 and not Dynamic_Elaboration_Checks_Specified
1614 then
1615 Error_Msg ("?use of -p switch questionable");
1616 Error_Msg ("?since all units compiled with static elaboration model");
1617 end if;
1619 if Do_New and not Debug_Flag_Old and not Debug_Flag_Older then
1620 if Debug_Flag_V then
1621 Write_Line ("Doing new...");
1622 end if;
1624 Doing_New := True;
1625 Init;
1626 Elab_New.Find_Elab_Order (Elab_Order);
1627 end if;
1629 -- Elab_New does not support the pessimistic order, so if that was
1630 -- requested, use the old results. Use Elab_Old if -dp or -do was
1631 -- selected. Elab_New does not yet give proper error messages for
1632 -- illegal Elaborate_Alls, so if there is one, run Elab_Old.
1634 if Do_Old
1635 or Pessimistic_Elab_Order
1636 or Debug_Flag_Old
1637 or Debug_Flag_Older
1638 or Elab_Cycle_Found
1639 then
1640 if Debug_Flag_V then
1641 Write_Line ("Doing old...");
1642 end if;
1644 Doing_New := False;
1645 Init;
1646 Elab_Old.Find_Elab_Order (Old_Elab_Order);
1647 end if;
1649 pragma Assert (Elab_Cycle_Found <= -- implies
1650 Diagnose_Elaboration_Problem_Called);
1652 declare
1653 Old_Order : Unit_Id_Array renames
1654 Old_Elab_Order.Table (1 .. Last (Old_Elab_Order));
1655 begin
1656 if Do_Old and Do_New then
1657 declare
1658 New_Order : Unit_Id_Array renames
1659 Elab_Order.Table (1 .. Last (Elab_Order));
1660 Old_Pairs : constant Nat := Num_Spec_Body_Pairs (Old_Order);
1661 New_Pairs : constant Nat := Num_Spec_Body_Pairs (New_Order);
1663 begin
1664 Write_Line (Get_Name_String (First_Main_Lib_File));
1666 pragma Assert (Old_Order'Length = New_Order'Length);
1667 pragma Debug (Validate (Old_Order, Doing_New => False));
1668 pragma Debug (Validate (New_Order, Doing_New => True));
1670 -- Misc debug printouts that can be used for experimentation by
1671 -- changing the 'if's below.
1673 if True then
1674 if New_Order = Old_Order then
1675 Write_Line ("Elab_New: same order.");
1676 else
1677 Write_Line ("Elab_New: diff order.");
1678 end if;
1679 end if;
1681 if New_Order /= Old_Order and then False then
1682 Write_Line ("Elaboration orders differ:");
1683 Write_Elab_Order
1684 (Old_Order, Title => "OLD ELABORATION ORDER");
1685 Write_Elab_Order
1686 (New_Order, Title => "NEW ELABORATION ORDER");
1687 end if;
1689 if True then
1690 Write_Str ("Pairs: ");
1691 Write_Int (Old_Pairs);
1693 if Old_Pairs = New_Pairs then
1694 Write_Str (" = ");
1695 elsif Old_Pairs < New_Pairs then
1696 Write_Str (" < ");
1697 else
1698 Write_Str (" > ");
1699 end if;
1701 Write_Int (New_Pairs);
1702 Write_Eol;
1703 end if;
1705 if Old_Pairs /= New_Pairs and then False then
1706 Write_Str ("Pairs: ");
1707 Write_Int (Old_Pairs);
1709 if Old_Pairs < New_Pairs then
1710 Write_Str (" < ");
1711 else
1712 Write_Str (" > ");
1713 end if;
1715 Write_Int (New_Pairs);
1716 Write_Eol;
1718 if Old_Pairs /= New_Pairs and then Debug_Flag_V then
1719 Write_Elab_Order
1720 (Old_Order, Title => "OLD ELABORATION ORDER");
1721 Write_Elab_Order
1722 (New_Order, Title => "NEW ELABORATION ORDER");
1723 pragma Assert (New_Pairs >= Old_Pairs);
1724 end if;
1725 end if;
1726 end;
1727 end if;
1729 -- The Elab_New algorithm doesn't implement the -p switch, so if that
1730 -- was used, use the results from the old algorithm. Likewise if the
1731 -- user has requested the old algorithm.
1733 if Pessimistic_Elab_Order or Debug_Flag_Old or Debug_Flag_Older then
1734 pragma Assert
1735 (Last (Elab_Order) = 0
1736 or else Last (Elab_Order) = Old_Order'Last);
1738 Init (Elab_Order);
1739 Append_All (Elab_Order, Old_Order);
1740 end if;
1742 -- Now set the Elab_Positions in the Units table. It is important to
1743 -- do this late, in case we're running both Elab_New and Elab_Old.
1745 declare
1746 New_Order : Unit_Id_Array renames
1747 Elab_Order.Table (1 .. Last (Elab_Order));
1748 Units_Array : Units.Table_Type renames
1749 Units.Table (Units.First .. Units.Last);
1750 begin
1751 for J in New_Order'Range loop
1752 pragma Assert
1753 (UNR.Table (New_Order (J)).Elab_Position = J);
1754 Units_Array (New_Order (J)).Elab_Position := J;
1755 end loop;
1757 if Errors_Detected = 0 then
1759 -- Display elaboration order if -l was specified
1761 if Elab_Order_Output then
1762 if Zero_Formatting then
1763 Write_Elab_Order (New_Order, Title => "");
1764 else
1765 Write_Elab_Order
1766 (New_Order, Title => "ELABORATION ORDER");
1767 end if;
1768 end if;
1770 -- Display list of sources in the closure (except predefined
1771 -- sources) if -R was used. Include predefined sources if -Ra
1772 -- was used.
1774 if List_Closure then
1775 Write_Closure (New_Order);
1776 end if;
1777 end if;
1778 end;
1779 end;
1780 end Find_Elab_Order;
1782 ----------------------
1783 -- Force_Elab_Order --
1784 ----------------------
1786 procedure Force_Elab_Order is
1787 use System.OS_Lib;
1788 -- There is a lot of fiddly string manipulation below, because we don't
1789 -- want to depend on misc utility packages like Ada.Characters.Handling.
1791 function Get_Line return String;
1792 -- Read the next line from the file content read by Read_File. Strip
1793 -- all leading and trailing blanks. Convert "(spec)" or "(body)" to
1794 -- "%s"/"%b". Remove comments (Ada style; "--" to end of line).
1796 function Read_File (Name : String) return String_Ptr;
1797 -- Read the entire contents of the named file
1799 ---------------
1800 -- Read_File --
1801 ---------------
1803 function Read_File (Name : String) return String_Ptr is
1805 -- All of the following calls should succeed, because we checked the
1806 -- file in Switch.B, but we double check and raise Program_Error on
1807 -- failure, just in case.
1809 F : constant File_Descriptor := Open_Read (Name, Binary);
1811 begin
1812 if F = Invalid_FD then
1813 raise Program_Error;
1814 end if;
1816 declare
1817 Len : constant Natural := Natural (File_Length (F));
1818 Result : constant String_Ptr := new String (1 .. Len);
1819 Len_Read : constant Natural :=
1820 Read (F, Result (1)'Address, Len);
1822 Status : Boolean;
1824 begin
1825 if Len_Read /= Len then
1826 raise Program_Error;
1827 end if;
1829 Close (F, Status);
1831 if not Status then
1832 raise Program_Error;
1833 end if;
1835 return Result;
1836 end;
1837 end Read_File;
1839 Cur : Positive := 1;
1840 S : String_Ptr := Read_File (Force_Elab_Order_File.all);
1842 --------------
1843 -- Get_Line --
1844 --------------
1846 function Get_Line return String is
1847 First : Positive := Cur;
1848 Last : Natural;
1850 begin
1851 -- Skip to end of line
1853 while Cur <= S'Last
1854 and then S (Cur) /= ASCII.LF
1855 and then S (Cur) /= ASCII.CR
1856 loop
1857 Cur := Cur + 1;
1858 end loop;
1860 -- Strip leading blanks
1862 while First <= S'Last and then S (First) = ' ' loop
1863 First := First + 1;
1864 end loop;
1866 -- Strip trailing blanks and comment
1868 Last := Cur - 1;
1870 for J in First .. Last - 1 loop
1871 if S (J .. J + 1) = "--" then
1872 Last := J - 1;
1873 exit;
1874 end if;
1875 end loop;
1877 while Last >= First and then S (Last) = ' ' loop
1878 Last := Last - 1;
1879 end loop;
1881 -- Convert "(spec)" or "(body)" to "%s"/"%b", strip trailing blanks
1882 -- again.
1884 declare
1885 Body_String : constant String := "(body)";
1886 BL : constant Positive := Body_String'Length;
1887 Spec_String : constant String := "(spec)";
1888 SL : constant Positive := Spec_String'Length;
1890 Line : String renames S (First .. Last);
1892 Is_Body : Boolean := False;
1893 Is_Spec : Boolean := False;
1895 begin
1896 if Line'Length >= SL
1897 and then Line (Last - SL + 1 .. Last) = Spec_String
1898 then
1899 Is_Spec := True;
1900 Last := Last - SL;
1901 elsif Line'Length >= BL
1902 and then Line (Last - BL + 1 .. Last) = Body_String
1903 then
1904 Is_Body := True;
1905 Last := Last - BL;
1906 end if;
1908 while Last >= First and then S (Last) = ' ' loop
1909 Last := Last - 1;
1910 end loop;
1912 -- Skip past LF or CR/LF
1914 if Cur <= S'Last and then S (Cur) = ASCII.CR then
1915 Cur := Cur + 1;
1916 end if;
1918 if Cur <= S'Last and then S (Cur) = ASCII.LF then
1919 Cur := Cur + 1;
1920 end if;
1922 if Is_Spec then
1923 return Line (First .. Last) & "%s";
1924 elsif Is_Body then
1925 return Line (First .. Last) & "%b";
1926 else
1927 return Line;
1928 end if;
1929 end;
1930 end Get_Line;
1932 -- Local variables
1934 Empty_Name : constant Unit_Name_Type := Name_Find ("");
1935 Prev_Unit : Unit_Id := No_Unit_Id;
1937 -- Start of processing for Force_Elab_Order
1939 begin
1940 -- Loop through the file content, and build a dependency link for each
1941 -- pair of lines. Ignore lines that should be ignored.
1943 while Cur <= S'Last loop
1944 declare
1945 Uname : constant Unit_Name_Type := Name_Find (Get_Line);
1947 begin
1948 if Uname = Empty_Name then
1949 null; -- silently skip blank lines
1951 elsif Get_Name_Table_Int (Uname) = 0
1952 or else Unit_Id (Get_Name_Table_Int (Uname)) = No_Unit_Id
1953 then
1954 if Doing_New then
1955 Write_Line
1956 ("""" & Get_Name_String (Uname)
1957 & """: not present; ignored");
1958 end if;
1960 else
1961 declare
1962 Cur_Unit : constant Unit_Id := Unit_Id_Of (Uname);
1964 begin
1965 if Is_Internal_File_Name (Units.Table (Cur_Unit).Sfile) then
1966 if Doing_New then
1967 Write_Line
1968 ("""" & Get_Name_String (Uname) &
1969 """: predefined unit ignored");
1970 end if;
1972 else
1973 if Prev_Unit /= No_Unit_Id then
1974 if Doing_New then
1975 Write_Unit_Name (Units.Table (Prev_Unit).Uname);
1976 Write_Str (" <-- ");
1977 Write_Unit_Name (Units.Table (Cur_Unit).Uname);
1978 Write_Eol;
1979 end if;
1981 Build_Link
1982 (Before => Prev_Unit,
1983 After => Cur_Unit,
1984 R => Forced);
1985 end if;
1987 Prev_Unit := Cur_Unit;
1988 end if;
1989 end;
1990 end if;
1991 end;
1992 end loop;
1994 Free (S);
1995 end Force_Elab_Order;
1997 -------------------------
1998 -- Gather_Dependencies --
1999 -------------------------
2001 procedure Gather_Dependencies is
2002 Withed_Unit : Unit_Id;
2004 begin
2005 -- Loop through all units
2007 for U in Units.First .. Units.Last loop
2008 Cur_Unit := U;
2010 -- If this is not an interface to a stand-alone library and there is
2011 -- a body and a spec, then spec must be elaborated first. Note that
2012 -- the corresponding spec immediately follows the body.
2014 if not Units.Table (U).SAL_Interface
2015 and then Units.Table (U).Utype = Is_Body
2016 then
2017 Build_Link (Corresponding_Spec (U), U, Spec_First);
2018 end if;
2020 -- If this unit is not an interface to a stand-alone library, process
2021 -- WITH references for this unit ignoring interfaces to stand-alone
2022 -- libraries.
2024 if not Units.Table (U).SAL_Interface then
2025 for W in Units.Table (U).First_With ..
2026 Units.Table (U).Last_With
2027 loop
2028 if Withs.Table (W).Sfile /= No_File
2029 and then (not Withs.Table (W).SAL_Interface)
2030 then
2031 -- Check for special case of withing a unit that does not
2032 -- exist any more. If the unit was completely missing we
2033 -- would already have detected this, but a nasty case arises
2034 -- when we have a subprogram body with no spec, and some
2035 -- obsolete unit with's a previous (now disappeared) spec.
2037 if Get_Name_Table_Int (Withs.Table (W).Uname) = 0 then
2038 if Doing_New then
2039 Error_Msg_File_1 := Units.Table (U).Sfile;
2040 Error_Msg_Unit_1 := Withs.Table (W).Uname;
2041 Error_Msg ("{ depends on $ which no longer exists");
2042 end if;
2044 goto Next_With;
2045 end if;
2047 Withed_Unit := Unit_Id_Of (Withs.Table (W).Uname);
2049 -- Pragma Elaborate_All case, for this we use the recursive
2050 -- Elab_All_Links procedure to establish the links.
2052 -- Elab_New ignores Elaborate_All and Elab_All_Desirable,
2053 -- except for error messages.
2055 if Withs.Table (W).Elaborate_All and then not Doing_New then
2057 -- Reset flags used to stop multiple visits to a given
2058 -- node.
2060 for Uref in UNR.First .. UNR.Last loop
2061 UNR.Table (Uref).Visited := False;
2062 end loop;
2064 -- Now establish all the links we need
2066 Elab_All_Links
2067 (Withed_Unit, U, Elab_All,
2068 Make_Elab_All_Entry
2069 (Withs.Table (W).Uname, No_Elab_All_Link));
2071 -- Elaborate_All_Desirable case, for this we establish the
2072 -- same links as above, but with a different reason.
2074 elsif Withs.Table (W).Elab_All_Desirable
2075 and then not Doing_New
2076 then
2077 -- Reset flags used to stop multiple visits to a given
2078 -- node.
2080 for Uref in UNR.First .. UNR.Last loop
2081 UNR.Table (Uref).Visited := False;
2082 end loop;
2084 -- Now establish all the links we need
2086 Elab_All_Links
2087 (Withed_Unit, U, Elab_All_Desirable,
2088 Make_Elab_All_Entry
2089 (Withs.Table (W).Uname, No_Elab_All_Link));
2091 -- Pragma Elaborate case. We must build a link for the
2092 -- withed unit itself, and also the corresponding body if
2093 -- there is one.
2095 -- However, skip this processing if there is no ALI file for
2096 -- the WITH entry, because this means it is a generic (even
2097 -- when we fix the generics so that an ALI file is present,
2098 -- we probably still will have no ALI file for unchecked and
2099 -- other special cases).
2101 elsif Withs.Table (W).Elaborate
2102 and then Withs.Table (W).Afile /= No_File
2103 then
2104 Build_Link (Withed_Unit, U, Withed);
2106 if Units.Table (Withed_Unit).Utype = Is_Spec then
2107 Build_Link
2108 (Corresponding_Body (Withed_Unit), U, Elab);
2109 end if;
2111 -- Elaborate_Desirable case, for this we establish the same
2112 -- links as above, but with a different reason.
2114 elsif Withs.Table (W).Elab_Desirable then
2115 Build_Link (Withed_Unit, U, Withed);
2117 if Units.Table (Withed_Unit).Utype = Is_Spec then
2118 Build_Link
2119 (Corresponding_Body (Withed_Unit),
2120 U, Elab_Desirable);
2121 end if;
2123 -- A limited_with does not establish an elaboration
2124 -- dependence (that's the whole point).
2126 elsif Withs.Table (W).Limited_With then
2127 null;
2129 -- Case of normal WITH with no elaboration pragmas, just
2130 -- build the single link to the directly referenced unit
2132 else
2133 Build_Link (Withed_Unit, U, Withed);
2134 end if;
2135 end if;
2137 <<Next_With>>
2138 null;
2139 end loop;
2140 end if;
2141 end loop;
2143 -- If -f<elab_order> switch was given, take into account dependences
2144 -- specified in the file <elab_order>.
2146 if Force_Elab_Order_File /= null then
2147 Force_Elab_Order;
2148 end if;
2150 -- Output elaboration dependencies if option is set
2152 if Elab_Dependency_Output or Debug_Flag_E then
2153 if Doing_New then
2154 Write_Dependencies;
2155 end if;
2156 end if;
2157 end Gather_Dependencies;
2159 ----------
2160 -- Init --
2161 ----------
2163 procedure Init is
2164 begin
2165 Num_Chosen := 0;
2166 Num_Left := Int (Units.Last - Units.First + 1);
2167 Succ.Init;
2168 Elab_All_Entries.Init;
2169 UNR.Init;
2171 -- Initialize unit table for elaboration control
2173 for U in Units.First .. Units.Last loop
2174 UNR.Append
2175 ((Successors => No_Successor,
2176 Num_Pred => 0,
2177 Nextnp => No_Unit_Id,
2178 Visited => False,
2179 Elab_Position => 0,
2180 SCC_Root => No_Unit_Id,
2181 Nodes => null,
2182 SCC_Num_Pred => 0,
2183 Validate_Seen => False));
2184 end loop;
2185 end Init;
2187 ------------------
2188 -- Is_Body_Unit --
2189 ------------------
2191 function Is_Body_Unit (U : Unit_Id) return Boolean is
2192 begin
2193 return
2194 Units.Table (U).Utype = Is_Body
2195 or else Units.Table (U).Utype = Is_Body_Only;
2196 end Is_Body_Unit;
2198 -----------------------------
2199 -- Is_Pure_Or_Preelab_Unit --
2200 -----------------------------
2202 function Is_Pure_Or_Preelab_Unit (U : Unit_Id) return Boolean is
2203 begin
2204 -- If we have a body with separate spec, test flags on the spec
2206 if Units.Table (U).Utype = Is_Body then
2207 return
2208 Units.Table (Corresponding_Spec (U)).Preelab
2209 or else Units.Table (Corresponding_Spec (U)).Pure;
2211 -- Otherwise we have a spec or body acting as spec, test flags on unit
2213 else
2214 return Units.Table (U).Preelab or else Units.Table (U).Pure;
2215 end if;
2216 end Is_Pure_Or_Preelab_Unit;
2218 ---------------------
2219 -- Is_Waiting_Body --
2220 ---------------------
2222 function Is_Waiting_Body (U : Unit_Id) return Boolean is
2223 begin
2224 return
2225 Units.Table (U).Utype = Is_Body
2226 and then UNR.Table (Corresponding_Spec (U)).Elab_Position /= 0;
2227 end Is_Waiting_Body;
2229 -------------------------
2230 -- Make_Elab_All_Entry --
2231 -------------------------
2233 function Make_Elab_All_Entry
2234 (Unam : Unit_Name_Type;
2235 Link : Elab_All_Id) return Elab_All_Id
2237 begin
2238 Elab_All_Entries.Append ((Needed_By => Unam, Next_Elab => Link));
2239 return Elab_All_Entries.Last;
2240 end Make_Elab_All_Entry;
2242 ----------------
2243 -- Unit_Id_Of --
2244 ----------------
2246 function Unit_Id_Of (Uname : Unit_Name_Type) return Unit_Id is
2247 Info : constant Int := Get_Name_Table_Int (Uname);
2249 begin
2250 pragma Assert (Info /= 0 and then Unit_Id (Info) /= No_Unit_Id);
2251 return Unit_Id (Info);
2252 end Unit_Id_Of;
2254 --------------
2255 -- Validate --
2256 --------------
2258 procedure Validate (Order : Unit_Id_Array; Doing_New : Boolean) is
2259 Cur_SCC : Unit_Id := No_Unit_Id;
2260 OK : Boolean := True;
2261 Msg : String := "Old: ";
2263 begin
2264 if Doing_New then
2265 Msg := "New: ";
2266 end if;
2268 -- For each unit, assert that its successors are elaborated after it
2270 for J in Order'Range loop
2271 declare
2272 U : constant Unit_Id := Order (J);
2273 S : Successor_Id := UNR.Table (U).Successors;
2275 begin
2276 while S /= No_Successor loop
2277 if UNR.Table (Succ.Table (S).After).Elab_Position <=
2278 UNR.Table (U).Elab_Position
2279 then
2280 OK := False;
2281 Write_Line (Msg & " elab order failed");
2282 end if;
2284 S := Succ.Table (S).Next;
2285 end loop;
2286 end;
2287 end loop;
2289 -- An SCC of size 2 units necessarily consists of a spec and the
2290 -- corresponding body. Assert that the body is elaborated immediately
2291 -- after the spec, with nothing in between. (We only have SCCs in the
2292 -- new algorithm.)
2294 if Doing_New then
2295 for J in Order'Range loop
2296 declare
2297 U : constant Unit_Id := Order (J);
2299 begin
2300 if Nodes (U)'Length = 2 then
2301 if Units.Table (U).Utype = Is_Spec then
2302 if Order (J + 1) /= Corresponding_Body (U) then
2303 OK := False;
2304 Write_Line (Msg & "Bad spec with SCC of size 2:");
2305 Write_SCC (SCC (U));
2306 end if;
2307 end if;
2309 if Units.Table (U).Utype = Is_Body then
2310 if Order (J - 1) /= Corresponding_Spec (U) then
2311 OK := False;
2312 Write_Line (Msg & "Bad body with SCC of size 2:");
2313 Write_SCC (SCC (U));
2314 end if;
2315 end if;
2316 end if;
2317 end;
2318 end loop;
2320 -- Assert that all units of an SCC are elaborated together, with no
2321 -- units from other SCCs in between. The above spec/body case is a
2322 -- special case of this general rule.
2324 for J in Order'Range loop
2325 declare
2326 U : constant Unit_Id := Order (J);
2328 begin
2329 if SCC (U) /= Cur_SCC then
2330 Cur_SCC := SCC (U);
2331 if UNR.Table (Cur_SCC).Validate_Seen then
2332 OK := False;
2333 Write_Line (Msg & "SCC not elaborated together:");
2334 Write_SCC (Cur_SCC);
2335 end if;
2337 UNR.Table (Cur_SCC).Validate_Seen := True;
2338 end if;
2339 end;
2340 end loop;
2341 end if;
2343 pragma Assert (OK);
2344 end Validate;
2346 -------------------
2347 -- Write_Closure --
2348 -------------------
2350 procedure Write_Closure (Order : Unit_Id_Array) is
2351 package Closure_Sources is new Table.Table
2352 (Table_Component_Type => File_Name_Type,
2353 Table_Index_Type => Natural,
2354 Table_Low_Bound => 1,
2355 Table_Initial => 10,
2356 Table_Increment => 100,
2357 Table_Name => "Gnatbind.Closure_Sources");
2358 -- Table to record the sources in the closure, to avoid duplications
2360 function Put_In_Sources (S : File_Name_Type) return Boolean;
2361 -- Check if S is already in table Sources and put in Sources if it is
2362 -- not. Return False if the source is already in Sources, and True if
2363 -- it is added.
2365 --------------------
2366 -- Put_In_Sources --
2367 --------------------
2369 function Put_In_Sources (S : File_Name_Type) return Boolean is
2370 begin
2371 for J in 1 .. Closure_Sources.Last loop
2372 if Closure_Sources.Table (J) = S then
2373 return False;
2374 end if;
2375 end loop;
2377 Closure_Sources.Append (S);
2378 return True;
2379 end Put_In_Sources;
2381 -- Local variables
2383 Source : File_Name_Type;
2385 -- Start of processing for Write_Closure
2387 begin
2388 Closure_Sources.Init;
2390 if not Zero_Formatting then
2391 Write_Eol;
2392 Write_Line ("REFERENCED SOURCES");
2393 end if;
2395 for J in reverse Order'Range loop
2396 Source := Units.Table (Order (J)).Sfile;
2398 -- Do not include same source more than once
2400 if Put_In_Sources (Source)
2402 -- Do not include run-time units unless -Ra switch set
2404 and then (List_Closure_All
2405 or else not Is_Internal_File_Name (Source))
2406 then
2407 if not Zero_Formatting then
2408 Write_Str (" ");
2409 end if;
2411 Write_Line (Get_Name_String (Source));
2412 end if;
2413 end loop;
2415 -- Subunits do not appear in the elaboration table because they are
2416 -- subsumed by their parent units, but we need to list them for other
2417 -- tools. For now they are listed after other files, rather than right
2418 -- after their parent, since there is no easy link between the
2419 -- elaboration table and the ALIs table ??? As subunits may appear
2420 -- repeatedly in the list, if the parent unit appears in the context of
2421 -- several units in the closure, duplicates are suppressed.
2423 for J in Sdep.First .. Sdep.Last loop
2424 Source := Sdep.Table (J).Sfile;
2426 if Sdep.Table (J).Subunit_Name /= No_Name
2427 and then Put_In_Sources (Source)
2428 and then not Is_Internal_File_Name (Source)
2429 then
2430 if not Zero_Formatting then
2431 Write_Str (" ");
2432 end if;
2434 Write_Line (Get_Name_String (Source));
2435 end if;
2436 end loop;
2438 if not Zero_Formatting then
2439 Write_Eol;
2440 end if;
2441 end Write_Closure;
2443 ------------------------
2444 -- Write_Dependencies --
2445 ------------------------
2447 procedure Write_Dependencies is
2448 begin
2449 if not Zero_Formatting then
2450 Write_Eol;
2451 Write_Line (" ELABORATION ORDER DEPENDENCIES");
2452 Write_Eol;
2453 end if;
2455 Info_Prefix_Suppress := True;
2457 for S in Succ_First .. Succ.Last loop
2458 Elab_Error_Msg (S);
2459 end loop;
2461 Info_Prefix_Suppress := False;
2463 if not Zero_Formatting then
2464 Write_Eol;
2465 end if;
2466 end Write_Dependencies;
2468 --------------------------
2469 -- Write_Elab_All_Chain --
2470 --------------------------
2472 procedure Write_Elab_All_Chain (S : Successor_Id) is
2473 ST : constant Successor_Link := Succ.Table (S);
2474 After : constant Unit_Name_Type := Units.Table (ST.After).Uname;
2476 L : Elab_All_Id;
2477 Nam : Unit_Name_Type;
2479 First_Name : Boolean := True;
2481 begin
2482 if ST.Reason in Elab_All .. Elab_All_Desirable then
2483 L := ST.Elab_All_Link;
2484 while L /= No_Elab_All_Link loop
2485 Nam := Elab_All_Entries.Table (L).Needed_By;
2486 Error_Msg_Unit_1 := Nam;
2487 Error_Msg_Output (" $", Info => True);
2489 Get_Name_String (Nam);
2491 if Name_Buffer (Name_Len) = 'b' then
2492 if First_Name then
2493 Error_Msg_Output
2494 (" must be elaborated along with its spec:",
2495 Info => True);
2497 else
2498 Error_Msg_Output
2499 (" which must be elaborated along with its "
2500 & "spec:",
2501 Info => True);
2502 end if;
2504 else
2505 if First_Name then
2506 Error_Msg_Output
2507 (" is withed by:",
2508 Info => True);
2510 else
2511 Error_Msg_Output
2512 (" which is withed by:",
2513 Info => True);
2514 end if;
2515 end if;
2517 First_Name := False;
2519 L := Elab_All_Entries.Table (L).Next_Elab;
2520 end loop;
2522 Error_Msg_Unit_1 := After;
2523 Error_Msg_Output (" $", Info => True);
2524 end if;
2525 end Write_Elab_All_Chain;
2527 ----------------------
2528 -- Write_Elab_Order --
2529 ----------------------
2531 procedure Write_Elab_Order
2532 (Order : Unit_Id_Array; Title : String)
2534 begin
2535 if Title /= "" then
2536 Write_Eol;
2537 Write_Line (Title);
2538 end if;
2540 for J in Order'Range loop
2541 if not Units.Table (Order (J)).SAL_Interface then
2542 if not Zero_Formatting then
2543 Write_Str (" ");
2544 end if;
2546 Write_Unit_Name (Units.Table (Order (J)).Uname);
2547 Write_Eol;
2548 end if;
2549 end loop;
2551 if Title /= "" then
2552 Write_Eol;
2553 end if;
2554 end Write_Elab_Order;
2556 --------------
2557 -- Elab_New --
2558 --------------
2560 package body Elab_New is
2562 generic
2563 type Node is (<>);
2564 First_Node : Node;
2565 Last_Node : Node;
2566 type Node_Array is array (Pos range <>) of Node;
2567 with function Successors (N : Node) return Node_Array;
2568 with procedure Create_SCC (Root : Node; Nodes : Node_Array);
2570 procedure Compute_Strongly_Connected_Components;
2571 -- Compute SCCs for a directed graph. The nodes in the graph are all
2572 -- values of type Node in the range First_Node .. Last_Node.
2573 -- Successors(N) returns the nodes pointed to by the edges emanating
2574 -- from N. Create_SCC is a callback that is called once for each SCC,
2575 -- passing in the Root node for that SCC (which is an arbitrary node in
2576 -- the SCC used as a representative of that SCC), and the set of Nodes
2577 -- in that SCC.
2579 -- This is generic, in case we want to use it elsewhere; then we could
2580 -- move this into a separate library unit. Unfortunately, it's not as
2581 -- generic as one might like. Ideally, we would have "type Node is
2582 -- private;", and pass in iterators to iterate over all nodes, and over
2583 -- the successors of a given node. However, that leads to using advanced
2584 -- features of Ada that are not allowed in the compiler and binder for
2585 -- bootstrapping reasons. It also leads to trampolines, which are not
2586 -- allowed in the compiler and binder. Restricting Node to be discrete
2587 -- allows us to iterate over all nodes with a 'for' loop, and allows us
2588 -- to attach temporary information to nodes by having an array indexed
2589 -- by Node.
2591 procedure Compute_Unit_SCCs;
2592 -- Use the above generic procedure to compute the SCCs for the graph of
2593 -- units. Store in each Unit_Node_Record the SCC_Root and Nodes
2594 -- components. Also initialize the SCC_Num_Pred components.
2596 procedure Find_Elab_All_Errors;
2597 -- Generate an error for illegal Elaborate_All pragmas (explicit or
2598 -- implicit). A pragma Elaborate_All (Y) on unit X is legal if and only
2599 -- if X and Y are in different SCCs.
2601 -------------------------------------------
2602 -- Compute_Strongly_Connected_Components --
2603 -------------------------------------------
2605 procedure Compute_Strongly_Connected_Components is
2607 -- This uses Tarjan's algorithm for finding SCCs. Comments here are
2608 -- intended to tell what it does, but if you want to know how it
2609 -- works, you have to look it up. Please do not modify this code
2610 -- without reading up on Tarjan's algorithm.
2612 subtype Node_Index is Nat;
2613 No_Index : constant Node_Index := 0;
2615 Num_Nodes : constant Nat :=
2616 Node'Pos (Last_Node) - Node'Pos (First_Node) + 1;
2617 Stack : Node_Array (1 .. Num_Nodes);
2618 Top : Node_Index := 0;
2619 -- Stack of nodes, pushed when first visited. All nodes of an SCC are
2620 -- popped at once when the SCC is found.
2622 subtype Valid_Node is Node range First_Node .. Last_Node;
2623 Node_Indices : array (Valid_Node) of Node_Index :=
2624 (others => No_Index);
2625 -- Each node has an "index", which is the sequential number in the
2626 -- order in which they are visited in the recursive walk. No_Index
2627 -- means "not yet visited"; we want to avoid walking any node more
2628 -- than once.
2630 Index : Node_Index := 1;
2631 -- Next value to be assigned to a node index
2633 Low_Links : array (Valid_Node) of Node_Index;
2634 -- Low_Links (N) is the smallest index of nodes reachable from N
2636 On_Stack : array (Valid_Node) of Boolean := (others => False);
2637 -- True if the node is currently on the stack
2639 procedure Walk (N : Valid_Node);
2640 -- Recursive depth-first graph walk, with the node index used to
2641 -- avoid visiting a node more than once.
2643 ----------
2644 -- Walk --
2645 ----------
2647 procedure Walk (N : Valid_Node) is
2648 Stack_Position_Of_N : constant Pos := Top + 1;
2649 S : constant Node_Array := Successors (N);
2651 begin
2652 -- Assign the index and low link, increment Index for next call to
2653 -- Walk.
2655 Node_Indices (N) := Index;
2656 Low_Links (N) := Index;
2657 Index := Index + 1;
2659 -- Push it on the stack:
2661 Top := Stack_Position_Of_N;
2662 Stack (Top) := N;
2663 On_Stack (N) := True;
2665 -- Walk not-yet-visited subnodes, and update low link for visited
2666 -- ones as appropriate.
2668 for J in S'Range loop
2669 if Node_Indices (S (J)) = No_Index then
2670 Walk (S (J));
2671 Low_Links (N) :=
2672 Node_Index'Min (Low_Links (N), Low_Links (S (J)));
2673 elsif On_Stack (S (J)) then
2674 Low_Links (N) :=
2675 Node_Index'Min (Low_Links (N), Node_Indices (S (J)));
2676 end if;
2677 end loop;
2679 -- If the index is (still) equal to the low link, we've found an
2680 -- SCC. Pop the whole SCC off the stack, and call Create_SCC.
2682 if Low_Links (N) = Node_Indices (N) then
2683 declare
2684 SCC : Node_Array renames
2685 Stack (Stack_Position_Of_N .. Top);
2686 pragma Assert (SCC'Length >= 1);
2687 pragma Assert (SCC (SCC'First) = N);
2689 begin
2690 for J in SCC'Range loop
2691 On_Stack (SCC (J)) := False;
2692 end loop;
2694 Create_SCC (Root => N, Nodes => SCC);
2695 pragma Assert (Top - SCC'Length = Stack_Position_Of_N - 1);
2696 Top := Stack_Position_Of_N - 1; -- pop all
2697 end;
2698 end if;
2699 end Walk;
2701 -- Start of processing for Compute_Strongly_Connected_Components
2703 begin
2704 -- Walk all the nodes that have not yet been walked
2706 for N in Valid_Node loop
2707 if Node_Indices (N) = No_Index then
2708 Walk (N);
2709 end if;
2710 end loop;
2711 end Compute_Strongly_Connected_Components;
2713 -----------------------
2714 -- Compute_Unit_SCCs --
2715 -----------------------
2717 procedure Compute_Unit_SCCs is
2718 function Successors (U : Unit_Id) return Unit_Id_Array;
2719 -- Return all the units that must be elaborated after U. In addition,
2720 -- if U is a body, include the corresponding spec; this ensures that
2721 -- a spec/body pair are always in the same SCC.
2723 procedure Create_SCC (Root : Unit_Id; Nodes : Unit_Id_Array);
2724 -- Set Nodes of the Root, and set SCC_Root of all the Nodes
2726 procedure Init_SCC_Num_Pred (U : Unit_Id);
2727 -- Initialize the SCC_Num_Pred fields, so that the root of each SCC
2728 -- has a count of the number of successors of all the units in the
2729 -- SCC, but only for successors outside the SCC.
2731 procedure Compute_SCCs is new Compute_Strongly_Connected_Components
2732 (Node => Unit_Id,
2733 First_Node => Units.First,
2734 Last_Node => Units.Last,
2735 Node_Array => Unit_Id_Array,
2736 Successors => Successors,
2737 Create_SCC => Create_SCC);
2739 ----------------
2740 -- Create_SCC --
2741 ----------------
2743 procedure Create_SCC (Root : Unit_Id; Nodes : Unit_Id_Array) is
2744 begin
2745 if Debug_Flag_V then
2746 Write_Str ("Root = ");
2747 Write_Int (Int (Root));
2748 Write_Str (" ");
2749 Write_Unit_Name (Units.Table (Root).Uname);
2750 Write_Str (" -- ");
2751 Write_Int (Nodes'Length);
2752 Write_Line (" units:");
2754 for J in Nodes'Range loop
2755 Write_Str (" ");
2756 Write_Int (Int (Nodes (J)));
2757 Write_Str (" ");
2758 Write_Unit_Name (Units.Table (Nodes (J)).Uname);
2759 Write_Eol;
2760 end loop;
2761 end if;
2763 pragma Assert (Nodes (Nodes'First) = Root);
2764 pragma Assert (UNR.Table (Root).Nodes = null);
2765 UNR.Table (Root).Nodes := new Unit_Id_Array'(Nodes);
2767 for J in Nodes'Range loop
2768 pragma Assert (SCC (Nodes (J)) = No_Unit_Id);
2769 UNR.Table (Nodes (J)).SCC_Root := Root;
2770 end loop;
2771 end Create_SCC;
2773 ----------------
2774 -- Successors --
2775 ----------------
2777 function Successors (U : Unit_Id) return Unit_Id_Array is
2778 S : Successor_Id := UNR.Table (U).Successors;
2779 Tab : Unit_Id_Table;
2781 begin
2782 -- Pretend that a spec is a successor of its body (even though it
2783 -- isn't), just so both get included.
2785 if Units.Table (U).Utype = Is_Body then
2786 Append (Tab, Corresponding_Spec (U));
2787 end if;
2789 -- Now include the real successors
2791 while S /= No_Successor loop
2792 pragma Assert (Succ.Table (S).Before = U);
2793 Append (Tab, Succ.Table (S).After);
2794 S := Succ.Table (S).Next;
2795 end loop;
2797 declare
2798 Result : constant Unit_Id_Array := Tab.Table (1 .. Last (Tab));
2800 begin
2801 Free (Tab);
2802 return Result;
2803 end;
2804 end Successors;
2806 -----------------------
2807 -- Init_SCC_Num_Pred --
2808 -----------------------
2810 procedure Init_SCC_Num_Pred (U : Unit_Id) is
2811 begin
2812 if UNR.Table (U).Visited then
2813 return;
2814 end if;
2816 UNR.Table (U).Visited := True;
2818 declare
2819 S : Successor_Id := UNR.Table (U).Successors;
2821 begin
2822 while S /= No_Successor loop
2823 pragma Assert (Succ.Table (S).Before = U);
2824 Init_SCC_Num_Pred (Succ.Table (S).After);
2826 if SCC (U) /= SCC (Succ.Table (S).After) then
2827 UNR.Table (SCC (Succ.Table (S).After)).SCC_Num_Pred :=
2828 UNR.Table (SCC (Succ.Table (S).After)).SCC_Num_Pred + 1;
2829 end if;
2831 S := Succ.Table (S).Next;
2832 end loop;
2833 end;
2834 end Init_SCC_Num_Pred;
2836 -- Start of processing for Compute_Unit_SCCs
2838 begin
2839 Compute_SCCs;
2841 for Uref in UNR.First .. UNR.Last loop
2842 pragma Assert (not UNR.Table (Uref).Visited);
2843 null;
2844 end loop;
2846 for Uref in UNR.First .. UNR.Last loop
2847 Init_SCC_Num_Pred (Uref);
2848 end loop;
2850 -- Assert that SCC_Root of all units has been set to a valid unit,
2851 -- and that SCC_Num_Pred has not been modified in non-root units.
2853 for Uref in UNR.First .. UNR.Last loop
2854 pragma Assert (UNR.Table (Uref).SCC_Root /= No_Unit_Id);
2855 pragma Assert (UNR.Table (Uref).SCC_Root in UNR.First .. UNR.Last);
2857 if SCC (Uref) /= Uref then
2858 pragma Assert (UNR.Table (Uref).SCC_Num_Pred = 0);
2859 null;
2860 end if;
2861 end loop;
2862 end Compute_Unit_SCCs;
2864 --------------------------
2865 -- Find_Elab_All_Errors --
2866 --------------------------
2868 procedure Find_Elab_All_Errors is
2869 Withed_Unit : Unit_Id;
2871 begin
2872 for U in Units.First .. Units.Last loop
2874 -- If this unit is not an interface to a stand-alone library,
2875 -- process WITH references for this unit ignoring interfaces to
2876 -- stand-alone libraries.
2878 if not Units.Table (U).SAL_Interface then
2879 for W in Units.Table (U).First_With ..
2880 Units.Table (U).Last_With
2881 loop
2882 if Withs.Table (W).Sfile /= No_File
2883 and then (not Withs.Table (W).SAL_Interface)
2884 then
2885 -- Check for special case of withing a unit that does not
2886 -- exist any more.
2888 if Get_Name_Table_Int (Withs.Table (W).Uname) = 0 then
2889 goto Next_With;
2890 end if;
2892 Withed_Unit := Unit_Id_Of (Withs.Table (W).Uname);
2894 -- If it's Elaborate_All or Elab_All_Desirable, check
2895 -- that the withER and withEE are not in the same SCC.
2897 if Withs.Table (W).Elaborate_All
2898 or else Withs.Table (W).Elab_All_Desirable
2899 then
2900 if SCC (U) = SCC (Withed_Unit) then
2901 Elab_Cycle_Found := True; -- ???
2903 -- We could probably give better error messages
2904 -- than Elab_Old here, but for now, to avoid
2905 -- disruption, we don't give any error here.
2906 -- Instead, we set the Elab_Cycle_Found flag above,
2907 -- and then run the Elab_Old algorithm to issue the
2908 -- error message. Ideally, we would like to print
2909 -- multiple errors rather than stopping after the
2910 -- first cycle.
2912 if False then
2913 Error_Msg_Output
2914 ("illegal pragma Elaborate_All",
2915 Info => False);
2916 end if;
2917 end if;
2918 end if;
2919 end if;
2921 <<Next_With>>
2922 null;
2923 end loop;
2924 end if;
2925 end loop;
2926 end Find_Elab_All_Errors;
2928 ---------------------
2929 -- Find_Elab_Order --
2930 ---------------------
2932 procedure Find_Elab_Order (Elab_Order : out Unit_Id_Table) is
2933 Best_So_Far : Unit_Id;
2934 U : Unit_Id;
2936 begin
2937 -- Gather dependencies and output them if option set
2939 Gather_Dependencies;
2941 Compute_Unit_SCCs;
2943 -- Initialize the no-predecessor list
2945 No_Pred := No_Unit_Id;
2946 for U in UNR.First .. UNR.Last loop
2947 if UNR.Table (U).Num_Pred = 0 then
2948 UNR.Table (U).Nextnp := No_Pred;
2949 No_Pred := U;
2950 end if;
2951 end loop;
2953 -- OK, now we determine the elaboration order proper. All we do is to
2954 -- select the best choice from the no-predecessor list until all the
2955 -- nodes have been chosen.
2957 Outer : loop
2958 if Debug_Flag_N then
2959 Write_Line ("Outer loop");
2960 end if;
2962 -- If there are no nodes with predecessors, then either we are
2963 -- done, as indicated by Num_Left being set to zero, or we have
2964 -- a circularity. In the latter case, diagnose the circularity,
2965 -- removing it from the graph and continue.
2966 -- ????But Diagnose_Elaboration_Problem always raises an
2967 -- exception, so the loop never goes around more than once.
2969 Get_No_Pred : while No_Pred = No_Unit_Id loop
2970 exit Outer when Num_Left < 1;
2971 Diagnose_Elaboration_Problem (Elab_Order);
2972 end loop Get_No_Pred;
2974 U := No_Pred;
2975 Best_So_Far := No_Unit_Id;
2977 -- Loop to choose best entry in No_Pred list
2979 No_Pred_Search : loop
2980 if Debug_Flag_N then
2981 Write_Str (" considering choice of ");
2982 Write_Unit_Name (Units.Table (U).Uname);
2983 Write_Eol;
2985 if Units.Table (U).Elaborate_Body then
2986 Write_Str
2987 (" Elaborate_Body = True, Num_Pred for body = ");
2988 Write_Int
2989 (UNR.Table (Corresponding_Body (U)).Num_Pred);
2990 else
2991 Write_Str
2992 (" Elaborate_Body = False");
2993 end if;
2995 Write_Eol;
2996 end if;
2998 -- Don't even consider units whose SCC is not ready. This
2999 -- ensures that all units of an SCC will be elaborated
3000 -- together, with no other units in between.
3002 if SCC_Num_Pred (U) = 0
3003 and then Better_Choice (U, Best_So_Far)
3004 then
3005 if Debug_Flag_N then
3006 Write_Line (" tentatively chosen (best so far)");
3007 end if;
3009 Best_So_Far := U;
3010 else
3011 if Debug_Flag_N then
3012 Write_Line (" SCC not ready");
3013 end if;
3014 end if;
3016 U := UNR.Table (U).Nextnp;
3017 exit No_Pred_Search when U = No_Unit_Id;
3018 end loop No_Pred_Search;
3020 -- If there are no units on the No_Pred list whose SCC is ready,
3021 -- there must be a cycle. Defer to Elab_Old to print an error
3022 -- message.
3024 if Best_So_Far = No_Unit_Id then
3025 Elab_Cycle_Found := True;
3026 return;
3027 end if;
3029 -- Choose the best candidate found
3031 Choose (Elab_Order, Best_So_Far, " [Best_So_Far]");
3033 -- If it's a spec with a body, and the body is not yet chosen,
3034 -- choose the body if possible. The case where the body is
3035 -- already chosen is Elaborate_Body; the above call to Choose
3036 -- the spec will also Choose the body.
3038 if Units.Table (Best_So_Far).Utype = Is_Spec
3039 and then UNR.Table
3040 (Corresponding_Body (Best_So_Far)).Elab_Position = 0
3041 then
3042 declare
3043 Choose_The_Body : constant Boolean :=
3044 UNR.Table (Corresponding_Body
3045 (Best_So_Far)).Num_Pred = 0;
3047 begin
3048 if Debug_Flag_B then
3049 Write_Str ("Can we choose the body?... ");
3051 if Choose_The_Body then
3052 Write_Line ("Yes!");
3053 else
3054 Write_Line ("No.");
3055 end if;
3056 end if;
3058 if Choose_The_Body then
3059 Choose
3060 (Elab_Order => Elab_Order,
3061 Chosen => Corresponding_Body (Best_So_Far),
3062 Msg => " [body]");
3063 end if;
3064 end;
3065 end if;
3067 -- Finally, choose all the rest of the units in the same SCC as
3068 -- Best_So_Far. If it hasn't been chosen (Elab_Position = 0), and
3069 -- it's ready to be chosen (Num_Pred = 0), then we can choose it.
3071 loop
3072 declare
3073 Chose_One_Or_More : Boolean := False;
3074 SCC : Unit_Id_Array renames Nodes (Best_So_Far).all;
3076 begin
3077 for J in SCC'Range loop
3078 if UNR.Table (SCC (J)).Elab_Position = 0
3079 and then UNR.Table (SCC (J)).Num_Pred = 0
3080 then
3081 Chose_One_Or_More := True;
3082 Choose (Elab_Order, SCC (J), " [same SCC]");
3083 end if;
3084 end loop;
3086 exit when not Chose_One_Or_More;
3087 end;
3088 end loop;
3089 end loop Outer;
3091 Find_Elab_All_Errors;
3092 end Find_Elab_Order;
3094 -----------
3095 -- Nodes --
3096 -----------
3098 function Nodes (U : Unit_Id) return Unit_Id_Array_Ptr is
3099 begin
3100 return UNR.Table (SCC (U)).Nodes;
3101 end Nodes;
3103 ---------
3104 -- SCC --
3105 ---------
3107 function SCC (U : Unit_Id) return Unit_Id is
3108 begin
3109 return UNR.Table (U).SCC_Root;
3110 end SCC;
3112 ------------------
3113 -- SCC_Num_Pred --
3114 ------------------
3116 function SCC_Num_Pred (U : Unit_Id) return Int is
3117 begin
3118 return UNR.Table (SCC (U)).SCC_Num_Pred;
3119 end SCC_Num_Pred;
3121 ---------------
3122 -- Write_SCC --
3123 ---------------
3125 procedure Write_SCC (U : Unit_Id) is
3126 pragma Assert (SCC (U) = U);
3127 begin
3128 for J in Nodes (U)'Range loop
3129 Write_Int (UNR.Table (Nodes (U) (J)).Elab_Position);
3130 Write_Str (". ");
3131 Write_Unit_Name (Units.Table (Nodes (U) (J)).Uname);
3132 Write_Eol;
3133 end loop;
3135 Write_Eol;
3136 end Write_SCC;
3138 end Elab_New;
3140 --------------
3141 -- Elab_Old --
3142 --------------
3144 package body Elab_Old is
3146 ---------------------
3147 -- Find_Elab_Order --
3148 ---------------------
3150 procedure Find_Elab_Order (Elab_Order : out Unit_Id_Table) is
3151 Best_So_Far : Unit_Id;
3152 U : Unit_Id;
3154 begin
3155 -- Gather dependencies and output them if option set
3157 Gather_Dependencies;
3159 -- Initialize the no-predecessor list
3161 No_Pred := No_Unit_Id;
3162 for U in UNR.First .. UNR.Last loop
3163 if UNR.Table (U).Num_Pred = 0 then
3164 UNR.Table (U).Nextnp := No_Pred;
3165 No_Pred := U;
3166 end if;
3167 end loop;
3169 -- OK, now we determine the elaboration order proper. All we do is to
3170 -- select the best choice from the no-predecessor list until all the
3171 -- nodes have been chosen.
3173 Outer : loop
3175 -- If there are no nodes with predecessors, then either we are
3176 -- done, as indicated by Num_Left being set to zero, or we have
3177 -- a circularity. In the latter case, diagnose the circularity,
3178 -- removing it from the graph and continue.
3179 -- ????But Diagnose_Elaboration_Problem always raises an
3180 -- exception, so the loop never goes around more than once.
3182 Get_No_Pred : while No_Pred = No_Unit_Id loop
3183 exit Outer when Num_Left < 1;
3184 Diagnose_Elaboration_Problem (Elab_Order);
3185 end loop Get_No_Pred;
3187 U := No_Pred;
3188 Best_So_Far := No_Unit_Id;
3190 -- Loop to choose best entry in No_Pred list
3192 No_Pred_Search : loop
3193 if Debug_Flag_N then
3194 Write_Str (" considering choice of ");
3195 Write_Unit_Name (Units.Table (U).Uname);
3196 Write_Eol;
3198 if Units.Table (U).Elaborate_Body then
3199 Write_Str
3200 (" Elaborate_Body = True, Num_Pred for body = ");
3201 Write_Int
3202 (UNR.Table (Corresponding_Body (U)).Num_Pred);
3203 else
3204 Write_Str
3205 (" Elaborate_Body = False");
3206 end if;
3208 Write_Eol;
3209 end if;
3211 -- This is a candididate to be considered for choice
3213 if Better_Choice (U, Best_So_Far) then
3214 if Debug_Flag_N then
3215 Write_Line (" tentatively chosen (best so far)");
3216 end if;
3218 Best_So_Far := U;
3219 end if;
3221 U := UNR.Table (U).Nextnp;
3222 exit No_Pred_Search when U = No_Unit_Id;
3223 end loop No_Pred_Search;
3225 -- Choose the best candidate found
3227 Choose (Elab_Order, Best_So_Far, " [Elab_Old Best_So_Far]");
3228 end loop Outer;
3229 end Find_Elab_Order;
3231 end Elab_Old;
3233 end Binde;