2015-03-04 Robert Dewar <dewar@adacore.com>
[official-gcc.git] / gcc / ada / exp_unst.adb
bloba850e7816fa0b0f152bb43cc959f8f2260ae6197
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E X P _ U N S T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2014-2015, 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 Atree; use Atree;
27 with Einfo; use Einfo;
28 with Elists; use Elists;
29 with Exp_Util; use Exp_Util;
30 with Lib; use Lib;
31 with Namet; use Namet;
32 with Nlists; use Nlists;
33 with Nmake; use Nmake;
34 with Opt; use Opt;
35 with Rtsfind; use Rtsfind;
36 with Sinput; use Sinput;
37 with Sem; use Sem;
38 with Sem_Ch8; use Sem_Ch8;
39 with Sem_Mech; use Sem_Mech;
40 with Sem_Res; use Sem_Res;
41 with Sem_Util; use Sem_Util;
42 with Sinfo; use Sinfo;
43 with Snames; use Snames;
44 with Table;
45 with Tbuild; use Tbuild;
46 with Uintp; use Uintp;
48 package body Exp_Unst is
50 -- Tables used by Unnest_Subprogram
52 type Subp_Entry is record
53 Ent : Entity_Id;
54 -- Entity of the subprogram
56 Bod : Node_Id;
57 -- Subprogram_Body node for this subprogram
59 Lev : Nat;
60 -- Subprogram level (1 = outer subprogram (Subp argument), 2 = nested
61 -- immediately within this outer subprogram etc.)
63 Urefs : Elist_Id;
64 -- This is a copy of the Uplevel_References field from the entity for
65 -- the subprogram. Copy this to reuse the field for Subps_Index.
67 ARECnF : Entity_Id;
68 -- This entity is defined for all subprograms with uplevel references
69 -- except for the top-level subprogram (Subp itself). It is the entity
70 -- for the formal which is added to the parameter list to pass the
71 -- pointer to the activation record. Note that for this entity, n is
72 -- one less than the current level.
74 ARECn : Entity_Id;
75 ARECnT : Entity_Id;
76 ARECnPT : Entity_Id;
77 ARECnP : Entity_Id;
78 -- These AREC entities are defined only for subprograms for which we
79 -- generate an activation record declaration, i.e. for subprograms
80 -- with at least one nested subprogram that have uplevel referennces.
81 -- They are set to Empty for all other cases.
83 ARECnU : Entity_Id;
84 -- This AREC entity is the uplink component. It is other than Empty only
85 -- for nested subprograms that themselves have nested subprograms and
86 -- have uplevel references. Note that the n here is one less than the
87 -- level of the subprogram defining the activation record.
89 end record;
91 subtype SI_Type is Nat;
93 package Subps is new Table.Table (
94 Table_Component_Type => Subp_Entry,
95 Table_Index_Type => SI_Type,
96 Table_Low_Bound => 1,
97 Table_Initial => 100,
98 Table_Increment => 200,
99 Table_Name => "Unnest_Subps");
100 -- Records the subprograms in the nest whose outer subprogram is Subp
102 type Call_Entry is record
103 N : Node_Id;
104 -- The actual call
106 From : Entity_Id;
107 -- Entity of the subprogram containing the call
109 To : Entity_Id;
110 -- Entity of the subprogram called
111 end record;
113 package Calls is new Table.Table (
114 Table_Component_Type => Call_Entry,
115 Table_Index_Type => Nat,
116 Table_Low_Bound => 1,
117 Table_Initial => 100,
118 Table_Increment => 200,
119 Table_Name => "Unnest_Calls");
120 -- Records each call within the outer subprogram and all nested subprograms
121 -- that are to other subprograms nested within the outer subprogram. These
122 -- are the calls that may need an additional parameter.
124 -------------------------------------
125 -- Check_Uplevel_Reference_To_Type --
126 -------------------------------------
128 procedure Check_Uplevel_Reference_To_Type (Typ : Entity_Id) is
129 function Check_Dynamic_Type (T : Entity_Id) return Boolean;
130 -- This is an internal recursive routine that checks if T or any of
131 -- its subsdidiary types are dynamic. If so, then the original Typ is
132 -- marked as having an uplevel reference, as is the subsidiary type in
133 -- question, and any referenced dynamic bounds are also marked as having
134 -- an uplevel reference, and True is returned. If the type is a static
135 -- type, then False is returned;
137 ------------------------
138 -- Check_Dynamic_Type --
139 ------------------------
141 function Check_Dynamic_Type (T : Entity_Id) return Boolean is
142 DT : Boolean := False;
144 begin
145 -- If it's a static type, nothing to do
147 if Is_Static_Type (T) then
148 return False;
150 -- If the type is uplevel referenced, then it must be dynamic
152 elsif Has_Uplevel_Reference (T) then
153 Set_Has_Uplevel_Reference (Typ);
154 return True;
156 -- Otherwise we need to figure out what the story is with this type
158 else
159 DT := False;
161 -- For a scalar type, check bounds
163 if Is_Scalar_Type (T) then
165 -- If both bounds static, then this is a static type
167 declare
168 LB : constant Node_Id := Type_Low_Bound (T);
169 UB : constant Node_Id := Type_High_Bound (T);
171 begin
172 if not Is_Static_Expression (LB) then
173 Set_Has_Uplevel_Reference (Entity (LB));
174 DT := True;
175 end if;
177 if not Is_Static_Expression (UB) then
178 Set_Has_Uplevel_Reference (Entity (UB));
179 DT := True;
180 end if;
181 end;
183 -- For record type, check all components
185 elsif Is_Record_Type (T) then
186 declare
187 C : Entity_Id;
189 begin
190 C := First_Component_Or_Discriminant (T);
191 while Present (C) loop
192 if Check_Dynamic_Type (Etype (C)) then
193 DT := True;
194 end if;
196 Next_Component_Or_Discriminant (C);
197 end loop;
198 end;
200 -- For array type, check index types and component type
202 elsif Is_Array_Type (T) then
203 declare
204 IX : Node_Id;
206 begin
207 if Check_Dynamic_Type (Component_Type (T)) then
208 DT := True;
209 end if;
211 IX := First_Index (T);
212 while Present (IX) loop
213 if Check_Dynamic_Type (Etype (IX)) then
214 DT := True;
215 end if;
217 Next_Index (IX);
218 end loop;
219 end;
221 -- For now, ignore other types
223 else
224 return False;
225 end if;
227 -- See if we marked that type as dynamic
229 if DT then
230 Set_Has_Uplevel_Reference (T);
231 Set_Has_Uplevel_Reference (Typ);
232 return True;
234 -- If not mark it as static
236 else
237 Set_Is_Static_Type (T);
238 return False;
239 end if;
240 end if;
241 end Check_Dynamic_Type;
243 -- Start of processing for Check_Uplevel_Reference_To_Type
245 begin
246 -- Nothing to do if we know this is a static type
248 if Is_Static_Type (Typ) then
249 return;
251 -- Nothing to do if already marked as uplevel referenced
253 elsif Has_Uplevel_Reference (Typ) then
254 return;
256 -- Otherwise check if we have a dynamic type
258 else
259 if Check_Dynamic_Type (Typ) then
260 Set_Has_Uplevel_Reference (Typ);
261 end if;
262 end if;
264 null;
265 end Check_Uplevel_Reference_To_Type;
267 ----------------------------
268 -- Note_Uplevel_Reference --
269 ----------------------------
271 procedure Note_Uplevel_Reference (N : Node_Id; Subp : Entity_Id) is
272 begin
273 -- Nothing to do if reference has no entity field
275 if Nkind (N) not in N_Entity then
276 return;
277 end if;
279 -- Establish list if first call for Uplevel_References
281 if No (Uplevel_References (Subp)) then
282 Set_Uplevel_References (Subp, New_Elmt_List);
283 end if;
285 -- Add new entry to Uplevel_References. Each entry is two elements of
286 -- the list. The first is the actual reference, the second is the
287 -- enclosing subprogram at the point of reference
289 Append_Elmt (N, Uplevel_References (Subp));
291 if Is_Subprogram (Current_Scope) then
292 Append_Elmt (Current_Scope, Uplevel_References (Subp));
293 else
294 Append_Elmt
295 (Enclosing_Subprogram (Current_Scope), Uplevel_References (Subp));
296 end if;
298 Set_Has_Uplevel_Reference (Entity (N));
299 Set_Has_Uplevel_Reference (Subp);
300 end Note_Uplevel_Reference;
302 -----------------------
303 -- Unnest_Subprogram --
304 -----------------------
306 procedure Unnest_Subprogram (Subp : Entity_Id; Subp_Body : Node_Id) is
307 function AREC_String (Lev : Pos) return String;
308 -- Given a level value, 1, 2, ... returns the string AREC, AREC2, ...
310 function Enclosing_Subp (Subp : SI_Type) return SI_Type;
311 -- Subp is the index of a subprogram which has a Lev greater than 1.
312 -- This function returns the index of the enclosing subprogram which
313 -- will have a Lev value one less than this.
315 function Get_Level (Sub : Entity_Id) return Nat;
316 -- Sub is either Subp itself, or a subprogram nested within Subp. This
317 -- function returns the level of nesting (Subp = 1, subprograms that
318 -- are immediately nested within Subp = 2, etc).
320 function Subp_Index (Sub : Entity_Id) return SI_Type;
321 -- Given the entity for a subprogram, return corresponding Subps index
323 -----------------
324 -- AREC_String --
325 -----------------
327 function AREC_String (Lev : Pos) return String is
328 begin
329 if Lev > 9 then
330 return
331 AREC_String (Lev / 10) & Character'Val (Lev mod 10 + 48);
332 else
333 return
334 "AREC" & Character'Val (Lev + 48);
335 end if;
336 end AREC_String;
338 --------------------
339 -- Enclosing_Subp --
340 --------------------
342 function Enclosing_Subp (Subp : SI_Type) return SI_Type is
343 STJ : Subp_Entry renames Subps.Table (Subp);
344 Ret : constant SI_Type := Subp_Index (Enclosing_Subprogram (STJ.Ent));
345 begin
346 pragma Assert (STJ.Lev > 1);
347 pragma Assert (Subps.Table (Ret).Lev = STJ.Lev - 1);
348 return Ret;
349 end Enclosing_Subp;
351 ---------------
352 -- Get_Level --
353 ---------------
355 function Get_Level (Sub : Entity_Id) return Nat is
356 Lev : Nat;
357 S : Entity_Id;
359 begin
360 Lev := 1;
361 S := Sub;
362 loop
363 if S = Subp then
364 return Lev;
365 else
366 S := Enclosing_Subprogram (S);
367 Lev := Lev + 1;
368 end if;
369 end loop;
370 end Get_Level;
372 ----------------
373 -- Subp_Index --
374 ----------------
376 function Subp_Index (Sub : Entity_Id) return SI_Type is
377 begin
378 pragma Assert (Is_Subprogram (Sub));
379 return SI_Type (UI_To_Int (Subps_Index (Sub)));
380 end Subp_Index;
382 -- Start of processing for Unnest_Subprogram
384 begin
385 -- At least for now, do not unnest anything but main source unit
387 if not In_Extended_Main_Source_Unit (Subp_Body) then
388 return;
389 end if;
391 -- First step, we must mark all nested subprograms that require a static
392 -- link (activation record) because either they contain explicit uplevel
393 -- references (as indicated by Has_Uplevel_Reference being set at this
394 -- point), or they make calls to other subprograms in the same nest that
395 -- require a static link (in which case we set this flag).
397 -- This is a recursive definition, and to implement this, we have to
398 -- build a call graph for the set of nested subprograms, and then go
399 -- over this graph to implement recursively the invariant that if a
400 -- subprogram has a call to a subprogram requiring a static link, then
401 -- the calling subprogram requires a static link.
403 -- First populate the above tables
405 Subps.Init;
406 Calls.Init;
408 Build_Tables : declare
409 function Visit_Node (N : Node_Id) return Traverse_Result;
410 -- Visit a single node in Subp
412 ----------------
413 -- Visit_Node --
414 ----------------
416 function Visit_Node (N : Node_Id) return Traverse_Result is
417 Ent : Entity_Id;
418 Csub : Entity_Id;
420 function Find_Current_Subprogram return Entity_Id;
421 -- Finds the current subprogram containing the call N
423 -----------------------------
424 -- Find_Current_Subprogram --
425 -----------------------------
427 function Find_Current_Subprogram return Entity_Id is
428 Nod : Node_Id;
430 begin
431 Nod := N;
432 loop
433 Nod := Parent (Nod);
435 if Nkind (Nod) = N_Subprogram_Body then
436 if Acts_As_Spec (Nod) then
437 return Defining_Unit_Name (Specification (Nod));
438 else
439 return Corresponding_Spec (Nod);
440 end if;
441 end if;
442 end loop;
443 end Find_Current_Subprogram;
445 -- Start of processing for Visit_Node
447 begin
448 -- Record a call
450 if Nkind_In (N, N_Procedure_Call_Statement, N_Function_Call)
452 -- We are only interested in direct calls, not indirect calls
453 -- (where Name (N) is an explicit dereference) at least for now!
455 and then Nkind (Name (N)) in N_Has_Entity
456 then
457 Ent := Entity (Name (N));
459 -- We are only interested in calls to subprograms nested
460 -- within Subp. Calls to Subp itself or to subprograms that
461 -- are outside the nested structure do not affect us.
463 if Scope_Within (Ent, Subp) then
465 -- For now, ignore calls to generic instances. Seems to be
466 -- some problem there which we will investigate later ???
468 if Original_Location (Sloc (Ent)) /= Sloc (Ent)
469 or else Is_Generic_Instance (Ent)
470 then
471 null;
473 -- Here we have a call to keep and analyze
475 else
476 Csub := Find_Current_Subprogram;
478 -- Both caller and callee must be subprograms (we ignore
479 -- generic subprograms).
481 if Is_Subprogram (Csub) and then Is_Subprogram (Ent) then
482 Calls.Append ((N, Find_Current_Subprogram, Ent));
483 end if;
484 end if;
485 end if;
487 -- Record a subprogram. We record a subprogram body that acts as
488 -- a spec. Otherwise we record a subprogram declaration, providing
489 -- that it has a corresponding body we can get hold of. The case
490 -- of no corresponding body being available is ignored for now.
492 elsif (Nkind (N) = N_Subprogram_Body and then Acts_As_Spec (N))
493 or else (Nkind (N) = N_Subprogram_Declaration
494 and then Present (Corresponding_Body (N)))
495 then
496 Subps.Increment_Last;
498 declare
499 STJ : Subp_Entry renames Subps.Table (Subps.Last);
501 begin
502 -- Set fields of Subp_Entry for new subprogram
504 STJ.Ent := Defining_Unit_Name (Specification (N));
505 STJ.Lev := Get_Level (STJ.Ent);
507 if Nkind (N) = N_Subprogram_Body then
508 STJ.Bod := N;
509 else
510 STJ.Bod := Parent (Parent (Corresponding_Body (N)));
512 pragma Assert (Nkind (STJ.Bod) = N_Subprogram_Body);
513 end if;
515 -- Capture Uplevel_References, and then set (uses the same
516 -- field), the Subps_Index value for this subprogram.
518 STJ.Urefs := Uplevel_References (STJ.Ent);
519 Set_Subps_Index (STJ.Ent, UI_From_Int (Int (Subps.Last)));
520 end;
521 end if;
523 return OK;
524 end Visit_Node;
526 -----------
527 -- Visit --
528 -----------
530 procedure Visit is new Traverse_Proc (Visit_Node);
531 -- Used to traverse the body of Subp, populating the tables
533 -- Start of processing for Build_Tables
535 begin
536 -- A special case, if the outer level subprogram has a separate spec
537 -- then we won't catch it in the traversal of the body. But we do
538 -- want to visit the declaration in this case!
540 if not Acts_As_Spec (Subp_Body) then
541 declare
542 Dummy : Traverse_Result;
543 Decl : constant Node_Id :=
544 Parent (Declaration_Node (Corresponding_Spec (Subp_Body)));
545 pragma Assert (Nkind (Decl) = N_Subprogram_Declaration);
546 begin
547 Dummy := Visit_Node (Decl);
548 end;
549 end if;
551 -- Traverse the body to get the rest of the subprograms and calls
553 Visit (Subp_Body);
554 end Build_Tables;
556 -- Second step is to do the transitive closure, if any subprogram has
557 -- a call to a subprogram for which Has_Uplevel_Reference is set, then
558 -- we set Has_Uplevel_Reference for the calling routine.
560 Closure : declare
561 Modified : Boolean;
563 begin
564 -- We use a simple minded algorithm as follows (obviously this can
565 -- be done more efficiently, using one of the standard algorithms
566 -- for efficient transitive closure computation, but this is simple
567 -- and most likely fast enough that its speed does not matter).
569 -- Repeatedly scan the list of calls. Any time we find a call from
570 -- A to B, where A does not have Has_Uplevel_Reference, and B does
571 -- have this flag set, then set the flag for A, and note that we
572 -- have made a change by setting Modified True. We repeat this until
573 -- we make a pass with no modifications.
575 Outer : loop
576 Modified := False;
577 Inner : for J in Calls.First .. Calls.Last loop
578 if not Has_Uplevel_Reference (Calls.Table (J).From)
579 and then Has_Uplevel_Reference (Calls.Table (J).To)
580 then
581 Set_Has_Uplevel_Reference (Calls.Table (J).From);
582 Modified := True;
583 end if;
584 end loop Inner;
586 exit Outer when not Modified;
587 end loop Outer;
588 end Closure;
590 -- Next step, create the entities for code we will insert. We do this
591 -- at the start so that all the entities are defined, regardless of the
592 -- order in which we do the code insertions.
594 Create_Entities : for J in Subps.First .. Subps.Last loop
595 declare
596 STJ : Subp_Entry renames Subps.Table (J);
597 Loc : constant Source_Ptr := Sloc (STJ.Bod);
598 ARS : constant String := AREC_String (STJ.Lev);
600 begin
601 -- First we create the ARECnF entity for the additional formal
602 -- for all subprograms requiring that an activation record pointer
603 -- be passed. This is true of all subprograms that have uplevel
604 -- references, and whose enclosing subprogram also has uplevel
605 -- references.
607 if Has_Uplevel_Reference (STJ.Ent)
608 and then STJ.Ent /= Subp
609 and then Has_Uplevel_Reference (Enclosing_Subprogram (STJ.Ent))
610 then
611 STJ.ARECnF :=
612 Make_Defining_Identifier (Loc,
613 Chars => Name_Find_Str (AREC_String (STJ.Lev - 1) & "F"));
614 Set_Is_ARECnF_Entity (STJ.ARECnF, True);
615 else
616 STJ.ARECnF := Empty;
617 end if;
619 -- Now define the AREC entities for the activation record. This
620 -- is needed for any subprogram that has nested subprograms and
621 -- has uplevel references.
623 if Has_Nested_Subprogram (STJ.Ent)
624 and then Has_Uplevel_Reference (STJ.Ent)
625 then
626 STJ.ARECn :=
627 Make_Defining_Identifier (Loc, Name_Find_Str (ARS));
628 STJ.ARECnT :=
629 Make_Defining_Identifier (Loc, Name_Find_Str (ARS & "T"));
630 STJ.ARECnPT :=
631 Make_Defining_Identifier (Loc, Name_Find_Str (ARS & "PT"));
632 STJ.ARECnP :=
633 Make_Defining_Identifier (Loc, Name_Find_Str (ARS & "P"));
635 else
636 STJ.ARECn := Empty;
637 STJ.ARECnT := Empty;
638 STJ.ARECnPT := Empty;
639 STJ.ARECnP := Empty;
640 STJ.ARECnU := Empty;
641 end if;
643 -- Define uplink component entity if inner nesting case
645 if Has_Uplevel_Reference (STJ.Ent) and then STJ.Lev > 1 then
646 declare
647 ARS1 : constant String := AREC_String (STJ.Lev - 1);
648 begin
649 STJ.ARECnU :=
650 Make_Defining_Identifier (Loc,
651 Chars => Name_Find_Str (ARS1 & "U"));
652 end;
654 else
655 STJ.ARECnU := Empty;
656 end if;
657 end;
658 end loop Create_Entities;
660 -- Loop through subprograms
662 Subp_Loop : declare
663 Addr : constant Entity_Id := RTE (RE_Address);
665 begin
666 for J in Subps.First .. Subps.Last loop
667 declare
668 STJ : Subp_Entry renames Subps.Table (J);
670 begin
671 -- First add the extra formal if needed. This applies to all
672 -- nested subprograms that require an activation record to be
673 -- passed, as indicated by ARECnF being defined.
675 if Present (STJ.ARECnF) then
677 -- Here we need the extra formal. We do the expansion and
678 -- analysis of this manually, since it is fairly simple,
679 -- and it is not obvious how we can get what we want if we
680 -- try to use the normal Analyze circuit.
682 Extra_Formal : declare
683 Encl : constant SI_Type := Enclosing_Subp (J);
684 STJE : Subp_Entry renames Subps.Table (Encl);
685 -- Index and Subp_Entry for enclosing routine
687 Form : constant Entity_Id := STJ.ARECnF;
688 -- The formal to be added. Note that n here is one less
689 -- than the level of the subprogram itself (STJ.Ent).
691 Formb : Entity_Id;
692 -- If needed, this is the formal added to the body
694 procedure Add_Form_To_Spec (F : Entity_Id; S : Node_Id);
695 -- S is an N_Function/Procedure_Specification node, and F
696 -- is the new entity to add to this subprogramn spec.
698 ----------------------
699 -- Add_Form_To_Spec --
700 ----------------------
702 procedure Add_Form_To_Spec (F : Entity_Id; S : Node_Id) is
703 Sub : constant Entity_Id := Defining_Unit_Name (S);
705 begin
706 if No (First_Entity (Sub)) then
707 Set_First_Entity (Sub, F);
708 Set_Last_Entity (Sub, F);
710 else
711 declare
712 LastF : constant Entity_Id := Last_Formal (Sub);
713 begin
714 if No (LastF) then
715 Set_Next_Entity (F, First_Entity (Sub));
716 Set_First_Entity (Sub, F);
718 else
719 Set_Next_Entity (F, Next_Entity (LastF));
720 Set_Next_Entity (LastF, F);
722 if Last_Entity (Sub) = LastF then
723 Set_Last_Entity (Sub, F);
724 end if;
725 end if;
726 end;
727 end if;
729 if No (Parameter_Specifications (S)) then
730 Set_Parameter_Specifications (S, Empty_List);
731 end if;
733 Append_To (Parameter_Specifications (S),
734 Make_Parameter_Specification (Sloc (F),
735 Defining_Identifier => F,
736 Parameter_Type =>
737 New_Occurrence_Of (STJE.ARECnPT, Sloc (F))));
738 end Add_Form_To_Spec;
740 -- Start of processing for Extra_Formal
742 begin
743 -- Decorate the new formal entity
745 Set_Scope (Form, STJ.Ent);
746 Set_Ekind (Form, E_In_Parameter);
747 Set_Etype (Form, STJE.ARECnPT);
748 Set_Mechanism (Form, By_Copy);
749 Set_Never_Set_In_Source (Form, True);
750 Set_Analyzed (Form, True);
751 Set_Comes_From_Source (Form, False);
753 -- Case of only body present
755 if Acts_As_Spec (STJ.Bod) then
756 Add_Form_To_Spec (Form, Specification (STJ.Bod));
758 -- Case of separate spec
760 else
761 Formb := New_Entity (Nkind (Form), Sloc (Form));
762 Copy_Node (Form, Formb);
763 Add_Form_To_Spec (Form, Parent (STJ.Ent));
764 Add_Form_To_Spec (Formb, Specification (STJ.Bod));
765 end if;
766 end Extra_Formal;
767 end if;
769 -- Processing for subprograms that have at least one nested
770 -- subprogram, and have uplevel references.
772 if Has_Nested_Subprogram (STJ.Ent)
773 and then Has_Uplevel_Reference (STJ.Ent)
774 then
775 -- Local declarations for one such subprogram
777 declare
778 Loc : constant Source_Ptr := Sloc (STJ.Bod);
779 Elmt : Elmt_Id;
780 Ent : Entity_Id;
781 Clist : List_Id;
782 Comp : Entity_Id;
784 Decl_ARECnT : Node_Id;
785 Decl_ARECn : Node_Id;
786 Decl_ARECnPT : Node_Id;
787 Decl_ARECnP : Node_Id;
788 -- Declaration nodes for the AREC entities we build
790 Uplevel_Entities :
791 array (1 .. List_Length (STJ.Urefs)) of Entity_Id;
792 Num_Uplevel_Entities : Nat;
793 -- Uplevel_Entities (1 .. Num_Uplevel_Entities) contains
794 -- a list (with no duplicates) of the entities for this
795 -- subprogram that are referenced uplevel. The maximum
796 -- number of entries cannot exceed the total number of
797 -- uplevel references.
799 begin
800 -- Populate the Uplevel_Entities array, using the flag
801 -- Uplevel_Reference_Noted to avoid duplicates.
803 Num_Uplevel_Entities := 0;
805 if Present (STJ.Urefs) then
806 Elmt := First_Elmt (STJ.Urefs);
807 while Present (Elmt) loop
808 Ent := Entity (Node (Elmt));
810 if not Uplevel_Reference_Noted (Ent) then
811 Set_Uplevel_Reference_Noted (Ent, True);
812 Num_Uplevel_Entities := Num_Uplevel_Entities + 1;
813 Uplevel_Entities (Num_Uplevel_Entities) := Ent;
814 end if;
816 Next_Elmt (Elmt);
817 Next_Elmt (Elmt);
818 end loop;
819 end if;
821 -- Build list of component declarations for ARECnT
823 Clist := Empty_List;
825 -- If we are in a subprogram that has a static link that
826 -- ias passed in (as indicated by ARECnF being deinfed),
827 -- then include ARECnU : ARECnPT := ARECnF where n is
828 -- one less than the current level and the entity ARECnPT
829 -- comes from the enclosing subprogram.
831 if Present (STJ.ARECnF) then
832 declare
833 STJE : Subp_Entry
834 renames Subps.Table (Enclosing_Subp (J));
836 begin
837 Append_To (Clist,
838 Make_Component_Declaration (Loc,
839 Defining_Identifier => STJ.ARECnU,
840 Component_Definition =>
841 Make_Component_Definition (Loc,
842 Subtype_Indication =>
843 New_Occurrence_Of (STJE.ARECnPT, Loc)),
844 Expression =>
845 New_Occurrence_Of (STJ.ARECnF, Loc)));
846 end;
847 end if;
849 -- Add components for uplevel referenced entities
851 for J in 1 .. Num_Uplevel_Entities loop
852 Comp :=
853 Make_Defining_Identifier (Loc,
854 Chars => Chars (Uplevel_Entities (J)));
856 Set_Activation_Record_Component
857 (Uplevel_Entities (J), Comp);
859 Append_To (Clist,
860 Make_Component_Declaration (Loc,
861 Defining_Identifier => Comp,
862 Component_Definition =>
863 Make_Component_Definition (Loc,
864 Subtype_Indication =>
865 New_Occurrence_Of (Addr, Loc))));
866 end loop;
868 -- Now we can insert the AREC declarations into the body
870 -- type ARECnT is record .. end record;
872 Decl_ARECnT :=
873 Make_Full_Type_Declaration (Loc,
874 Defining_Identifier => STJ.ARECnT,
875 Type_Definition =>
876 Make_Record_Definition (Loc,
877 Component_List =>
878 Make_Component_List (Loc,
879 Component_Items => Clist)));
881 -- ARECn : aliased ARECnT;
883 Decl_ARECn :=
884 Make_Object_Declaration (Loc,
885 Defining_Identifier => STJ.ARECn,
886 Aliased_Present => True,
887 Object_Definition =>
888 New_Occurrence_Of (STJ.ARECnT, Loc));
890 -- type ARECnPT is access all ARECnT;
892 Decl_ARECnPT :=
893 Make_Full_Type_Declaration (Loc,
894 Defining_Identifier => STJ.ARECnPT,
895 Type_Definition =>
896 Make_Access_To_Object_Definition (Loc,
897 All_Present => True,
898 Subtype_Indication =>
899 New_Occurrence_Of (STJ.ARECnT, Loc)));
901 -- ARECnP : constant ARECnPT := ARECn'Access;
903 Decl_ARECnP :=
904 Make_Object_Declaration (Loc,
905 Defining_Identifier => STJ.ARECnP,
906 Constant_Present => True,
907 Object_Definition =>
908 New_Occurrence_Of (STJ.ARECnPT, Loc),
909 Expression =>
910 Make_Attribute_Reference (Loc,
911 Prefix =>
912 New_Occurrence_Of (STJ.ARECn, Loc),
913 Attribute_Name => Name_Access));
915 Prepend_List_To (Declarations (STJ.Bod),
916 New_List
917 (Decl_ARECnT, Decl_ARECn, Decl_ARECnPT, Decl_ARECnP));
919 -- Analyze the newly inserted declarations. Note that we
920 -- do not need to establish the whole scope stack, since
921 -- we have already set all entity fields (so there will
922 -- be no searching of upper scopes to resolve names). But
923 -- we do set the scope of the current subprogram, so that
924 -- newly created entities go in the right entity chain.
926 -- We analyze with all checks suppressed (since we do
927 -- not expect any exceptions, and also we temporarily
928 -- turn off Unested_Subprogram_Mode to avoid trying to
929 -- mark uplevel references (not needed at this stage,
930 -- and in fact causes a bit of recursive chaos).
932 Push_Scope (STJ.Ent);
933 Opt.Unnest_Subprogram_Mode := False;
934 Analyze (Decl_ARECnT, Suppress => All_Checks);
935 Analyze (Decl_ARECn, Suppress => All_Checks);
936 Analyze (Decl_ARECnPT, Suppress => All_Checks);
937 Analyze (Decl_ARECnP, Suppress => All_Checks);
938 Opt.Unnest_Subprogram_Mode := True;
939 Pop_Scope;
941 -- Next step, for each uplevel referenced entity, add
942 -- assignment operations to set the comoponent in the
943 -- activation record.
945 for J in 1 .. Num_Uplevel_Entities loop
946 declare
947 Ent : constant Entity_Id := Uplevel_Entities (J);
948 Loc : constant Source_Ptr := Sloc (Ent);
949 Dec : constant Node_Id := Declaration_Node (Ent);
950 Ins : Node_Id;
951 Asn : Node_Id;
953 begin
954 -- For parameters, we insert the assignment right
955 -- after the declaration of ARECnP. For all other
956 -- entities, we insert the assignment immediately
957 -- after the declaration of the entity.
959 -- Note: we don't need to mark the entity as being
960 -- aliased, because the address attribute will mark
961 -- it as Address_Taken, and that is good enough.
963 if Is_Formal (Ent) then
964 Ins := Decl_ARECnP;
965 else
966 Ins := Dec;
967 end if;
969 -- Build and insert the assignment:
970 -- ARECn.nam := nam
972 Asn :=
973 Make_Assignment_Statement (Loc,
974 Name =>
975 Make_Selected_Component (Loc,
976 Prefix =>
977 New_Occurrence_Of (STJ.ARECn, Loc),
978 Selector_Name =>
979 Make_Identifier (Loc, Chars (Ent))),
981 Expression =>
982 Make_Attribute_Reference (Loc,
983 Prefix =>
984 New_Occurrence_Of (Ent, Loc),
985 Attribute_Name => Name_Address));
987 Insert_After (Ins, Asn);
989 -- Analyze the assignment statement. We do not need
990 -- to establish the relevant scope stack entries
991 -- here, because we have already set the correct
992 -- entity references, so no name resolution is
993 -- required, and no new entities are created, so
994 -- we don't even need to set the current scope.
996 -- We analyze with all checks suppressed (since
997 -- we do not expect any exceptions, and also we
998 -- temporarily turn off Unested_Subprogram_Mode
999 -- to avoid trying to mark uplevel references (not
1000 -- needed at this stage, and in fact causes a bit
1001 -- of recursive chaos).
1003 Opt.Unnest_Subprogram_Mode := False;
1004 Analyze (Asn, Suppress => All_Checks);
1005 Opt.Unnest_Subprogram_Mode := True;
1006 end;
1007 end loop;
1008 end;
1009 end if;
1010 end;
1011 end loop;
1012 end Subp_Loop;
1014 -- Next step, process uplevel references. This has to be done in a
1015 -- separate pass, after completing the processing in Sub_Loop because we
1016 -- need all the AREC declarations generated, inserted, and analyzed so
1017 -- that the uplevel references can be successfully analyzed.
1019 Uplev_Refs : for J in Subps.First .. Subps.Last loop
1020 declare
1021 STJ : Subp_Entry renames Subps.Table (J);
1023 begin
1024 -- We are only interested in entries which have uplevel references
1025 -- to deal with, as indicated by the Urefs list being present
1027 if Present (STJ.Urefs) then
1029 -- Process uplevel references for one subprogram
1031 declare
1032 Elmt : Elmt_Id;
1034 begin
1035 -- Loop through uplevel references
1037 Elmt := First_Elmt (STJ.Urefs);
1038 while Present (Elmt) loop
1040 -- Skip if we have an explicit dereference. This means
1041 -- that we already did the expansion. There can be
1042 -- duplicates in ths STJ.Urefs list.
1044 if Nkind (Node (Elmt)) = N_Explicit_Dereference then
1045 goto Continue;
1046 end if;
1048 -- Otherwise, rewrite this reference
1050 declare
1051 Ref : constant Node_Id := Node (Elmt);
1052 -- The uplevel reference itself
1054 Loc : constant Source_Ptr := Sloc (Ref);
1055 -- Source location for the reference
1057 Ent : constant Entity_Id := Entity (Ref);
1058 -- The referenced entity
1060 Typ : constant Entity_Id := Etype (Ent);
1061 -- The type of the referenced entity
1063 Rsub : constant Entity_Id :=
1064 Node (Next_Elmt (Elmt));
1065 -- The enclosing subprogram for the reference
1067 RSX : constant SI_Type := Subp_Index (Rsub);
1068 -- Subp_Index for enclosing subprogram for ref
1070 STJR : Subp_Entry renames Subps.Table (RSX);
1071 -- Subp_Entry for enclosing subprogram for ref
1073 Tnn : constant Entity_Id :=
1074 Make_Temporary
1075 (Loc, 'T', Related_Node => Ref);
1076 -- Local pointer type for reference
1078 Pfx : Node_Id;
1079 Comp : Entity_Id;
1080 SI : SI_Type;
1082 begin
1083 -- Push the current scope, so that the pointer type
1084 -- Tnn, and any subsidiary entities resulting from
1085 -- the analysis of the rewritten reference, go in the
1086 -- right entity chain.
1088 Push_Scope (STJR.Ent);
1090 -- First insert declaration for pointer type
1092 -- type Tnn is access all typ;
1094 Insert_Action (Ref,
1095 Make_Full_Type_Declaration (Loc,
1096 Defining_Identifier => Tnn,
1097 Type_Definition =>
1098 Make_Access_To_Object_Definition (Loc,
1099 All_Present => True,
1100 Subtype_Indication =>
1101 New_Occurrence_Of (Typ, Loc))));
1103 -- Now we need to rewrite the reference. We have a
1104 -- reference is from level STJE.Lev to level STJ.Lev.
1105 -- The general form of the rewritten reference for
1106 -- entity X is:
1108 -- Tnn!(ARECaF.ARECbU.ARECcU.ARECdU....ARECm.X).all
1110 -- where a,b,c,d .. m =
1111 -- STJR.Lev - 1, STJ.Lev - 2, .. STJ.Lev
1113 pragma Assert (STJR.Lev > STJ.Lev);
1115 -- Compute the prefix of X. Here are examples to make
1116 -- things clear (with parens to show groupings, the
1117 -- prefix is everything except the .X at the end).
1119 -- level 2 to level 1
1121 -- AREC1F.X
1123 -- level 3 to level 1
1125 -- (AREC2F.AREC1U).X
1127 -- level 4 to level 1
1129 -- ((AREC3F.AREC2U).AREC1U).X
1131 -- level 6 to level 2
1133 -- (((AREC5F.AREC4U).AREC3U).AREC2U).X
1135 Pfx := New_Occurrence_Of (STJR.ARECnF, Loc);
1136 SI := RSX;
1137 for L in STJ.Lev .. STJR.Lev - 2 loop
1138 SI := Enclosing_Subp (SI);
1139 Pfx :=
1140 Make_Selected_Component (Loc,
1141 Prefix => Pfx,
1142 Selector_Name =>
1143 New_Occurrence_Of
1144 (Subps.Table (SI).ARECnU, Loc));
1145 end loop;
1147 -- Get activation record component (must exist)
1149 Comp := Activation_Record_Component (Ent);
1150 pragma Assert (Present (Comp));
1152 -- Do the replacement
1154 Rewrite (Ref,
1155 Make_Explicit_Dereference (Loc,
1156 Prefix =>
1157 Unchecked_Convert_To (Tnn,
1158 Make_Selected_Component (Loc,
1159 Prefix => Pfx,
1160 Selector_Name =>
1161 New_Occurrence_Of (Comp, Loc)))));
1163 -- Analyze and resolve the new expression. We do not
1164 -- need to establish the relevant scope stack entries
1165 -- here, because we have already set all the correct
1166 -- entity references, so no name resolution is needed.
1167 -- We have already set the current scope, so that any
1168 -- new entities created will be in the right scope.
1170 -- We analyze with all checks suppressed (since we do
1171 -- not expect any exceptions, and also we temporarily
1172 -- turn off Unested_Subprogram_Mode to avoid trying to
1173 -- mark uplevel references (not needed at this stage,
1174 -- and in fact causes a bit of recursive chaos).
1176 Opt.Unnest_Subprogram_Mode := False;
1177 Analyze_And_Resolve (Ref, Typ, Suppress => All_Checks);
1178 Opt.Unnest_Subprogram_Mode := True;
1179 Pop_Scope;
1180 end;
1182 <<Continue>>
1183 Next_Elmt (Elmt);
1184 Next_Elmt (Elmt);
1185 end loop;
1186 end;
1187 end if;
1188 end;
1189 end loop Uplev_Refs;
1191 -- Finally, loop through all calls adding extra actual for the
1192 -- activation record where it is required.
1194 Adjust_Calls : for J in Calls.First .. Calls.Last loop
1196 -- Process a single call, we are only interested in a call to a
1197 -- subprogram that actually needs a pointer to an activation record,
1198 -- as indicated by the ARECnF entity being set. This excludes the
1199 -- top level subprogram, and any subprogram not having uplevel refs.
1201 Adjust_One_Call : declare
1202 CTJ : Call_Entry renames Calls.Table (J);
1203 STF : Subp_Entry renames Subps.Table (Subp_Index (CTJ.From));
1204 STT : Subp_Entry renames Subps.Table (Subp_Index (CTJ.To));
1206 Loc : constant Source_Ptr := Sloc (CTJ.N);
1208 Extra : Node_Id;
1209 ExtraP : Node_Id;
1210 SubX : SI_Type;
1211 Act : Node_Id;
1213 begin
1214 if Present (STT.ARECnF) then
1216 -- CTJ.N is a call to a subprogram which may require
1217 -- a pointer to an activation record. The subprogram
1218 -- containing the call is CTJ.From and the subprogram being
1219 -- called is CTJ.To, so we have a call from level STF.Lev to
1220 -- level STT.Lev.
1222 -- There are three possibilities:
1224 -- For a call to the same level, we just pass the activation
1225 -- record passed to the calling subprogram.
1227 if STF.Lev = STT.Lev then
1228 Extra := New_Occurrence_Of (STF.ARECnF, Loc);
1230 -- For a call that goes down a level, we pass a pointer
1231 -- to the activation record constructed wtihin the caller
1232 -- (which may be the outer level subprogram, but also may
1233 -- be a more deeply nested caller).
1235 elsif STT.Lev = STF.Lev + 1 then
1236 Extra := New_Occurrence_Of (STF.ARECnP, Loc);
1238 -- Otherwise we must have an upcall (STT.Lev < STF.LEV),
1239 -- since it is not possible to do a downcall of more than
1240 -- one level.
1242 -- For a call from level STF.Lev to level STT.Lev, we
1243 -- have to find the activation record needed by the
1244 -- callee. This is as follows:
1246 -- ARECaF.ARECbU.ARECcU....ARECm
1248 -- where a,b,c .. m =
1249 -- STF.Lev - 1, STF.Lev - 2, STF.Lev - 3 .. STT.Lev
1251 else
1252 pragma Assert (STT.Lev < STF.Lev);
1254 Extra := New_Occurrence_Of (STF.ARECnF, Loc);
1255 SubX := Subp_Index (CTJ.From);
1256 for K in reverse STT.Lev .. STF.Lev - 1 loop
1257 SubX := Enclosing_Subp (SubX);
1258 Extra :=
1259 Make_Selected_Component (Loc,
1260 Prefix => Extra,
1261 Selector_Name =>
1262 New_Occurrence_Of
1263 (Subps.Table (SubX).ARECnU, Loc));
1264 end loop;
1265 end if;
1267 -- Extra is the additional parameter to be added. Build a
1268 -- parameter association that we can append to the actuals.
1270 ExtraP :=
1271 Make_Parameter_Association (Loc,
1272 Selector_Name =>
1273 New_Occurrence_Of (STT.ARECnF, Loc),
1274 Explicit_Actual_Parameter => Extra);
1276 if No (Parameter_Associations (CTJ.N)) then
1277 Set_Parameter_Associations (CTJ.N, Empty_List);
1278 end if;
1280 Append (ExtraP, Parameter_Associations (CTJ.N));
1282 -- We need to deal with the actual parameter chain as well.
1283 -- The newly added parameter is always the last actual.
1285 Act := First_Named_Actual (CTJ.N);
1287 if No (Act) then
1288 Set_First_Named_Actual (CTJ.N, Extra);
1290 -- Here we must follow the chain and append the new entry
1292 else
1293 loop
1294 declare
1295 PAN : Node_Id;
1296 NNA : Node_Id;
1298 begin
1299 PAN := Parent (Act);
1300 pragma Assert (Nkind (PAN) = N_Parameter_Association);
1301 NNA := Next_Named_Actual (PAN);
1303 if No (NNA) then
1304 Set_Next_Named_Actual (PAN, Extra);
1305 exit;
1306 end if;
1308 Act := NNA;
1309 end;
1310 end loop;
1311 end if;
1313 -- Analyze and resolve the new actual. We do not need to
1314 -- establish the relevant scope stack entries here, because
1315 -- we have already set all the correct entity references, so
1316 -- no name resolution is needed.
1318 -- We analyze with all checks suppressed (since we do not
1319 -- expect any exceptions, and also we temporarily turn off
1320 -- Unested_Subprogram_Mode to avoid trying to mark uplevel
1321 -- references (not needed at this stage, and in fact causes
1322 -- a bit of recursive chaos).
1324 Opt.Unnest_Subprogram_Mode := False;
1325 Analyze_And_Resolve
1326 (Extra, Etype (STT.ARECnF), Suppress => All_Checks);
1327 Opt.Unnest_Subprogram_Mode := True;
1328 end if;
1329 end Adjust_One_Call;
1330 end loop Adjust_Calls;
1332 return;
1333 end Unnest_Subprogram;
1335 end Exp_Unst;