1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2015, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Atree
; use Atree
;
27 with Einfo
; use Einfo
;
28 with Elists
; use Elists
;
29 with Namet
; use Namet
;
30 with Nlists
; use Nlists
;
31 with Nmake
; use Nmake
;
32 with Rtsfind
; use Rtsfind
;
33 with Sem_Aux
; use Sem_Aux
;
34 with Sem_Util
; use Sem_Util
;
35 with Sinfo
; use Sinfo
;
36 with Snames
; use Snames
;
38 with Tbuild
; use Tbuild
;
40 package body Exp_Unst
is
42 -------------------------------------
43 -- Check_Uplevel_Reference_To_Type --
44 -------------------------------------
46 procedure Check_Uplevel_Reference_To_Type
(Typ
: Entity_Id
) is
47 function Check_Dynamic_Type
(T
: Entity_Id
) return Boolean;
48 -- This is an internal recursive routine that checks if T or any of
49 -- its subsdidiary types are dynamic. If so, then the original Typ is
50 -- marked as having an uplevel reference, as is the subsidiary type in
51 -- question, and any referenced dynamic bounds are also marked as having
52 -- an uplevel reference, and True is returned. If the type is a static
53 -- type, then False is returned;
55 ------------------------
56 -- Check_Dynamic_Type --
57 ------------------------
59 function Check_Dynamic_Type
(T
: Entity_Id
) return Boolean is
60 DT
: Boolean := False;
63 -- If it's a static type, nothing to do
65 if Is_Static_Type
(T
) then
68 -- If the type is uplevel referenced, then it must be dynamic
70 elsif Has_Uplevel_Reference
(T
) then
71 Set_Has_Uplevel_Reference
(Typ
);
74 -- Otherwise we need to figure out what the story is with this type
79 -- For a scalar type, check bounds
81 if Is_Scalar_Type
(T
) then
83 -- If both bounds static, then this is a static type
86 LB
: constant Node_Id
:= Type_Low_Bound
(T
);
87 UB
: constant Node_Id
:= Type_High_Bound
(T
);
90 if not Is_Static_Expression
(LB
) then
91 Set_Has_Uplevel_Reference
(Entity
(LB
));
95 if not Is_Static_Expression
(UB
) then
96 Set_Has_Uplevel_Reference
(Entity
(UB
));
101 -- For record type, check all components
103 elsif Is_Record_Type
(T
) then
108 C
:= First_Component_Or_Discriminant
(T
);
109 while Present
(T
) loop
110 if Check_Dynamic_Type
(C
) then
114 Next_Component_Or_Discriminant
(C
);
118 -- For array type, check index types and component type
120 elsif Is_Array_Type
(T
) then
125 if Check_Dynamic_Type
(Component_Type
(T
)) then
129 IX
:= First_Index
(T
);
130 while Present
(IX
) loop
131 if Check_Dynamic_Type
(Etype
(IX
)) then
139 -- For now, ignore other types
145 -- See if we marked that type as dynamic
148 Set_Has_Uplevel_Reference
(T
);
149 Set_Has_Uplevel_Reference
(Typ
);
152 -- If not mark it as static
155 Set_Is_Static_Type
(T
);
159 end Check_Dynamic_Type
;
161 -- Start of processing for Check_Uplevel_Reference_To_Type
164 -- Nothing to do if we know this is a static type
166 if Is_Static_Type
(Typ
) then
169 -- Nothing to do if already marked as uplevel referenced
171 elsif Has_Uplevel_Reference
(Typ
) then
174 -- Otherwise check if we have a dynamic type
177 if Check_Dynamic_Type
(Typ
) then
178 Set_Has_Uplevel_Reference
(Typ
);
183 end Check_Uplevel_Reference_To_Type
;
185 ----------------------------
186 -- Note_Uplevel_Reference --
187 ----------------------------
189 procedure Note_Uplevel_Reference
(N
: Node_Id
; Subp
: Entity_Id
) is
191 -- Establish list if first call for Uplevel_References
193 if No
(Uplevel_References
(Subp
)) then
194 Set_Uplevel_References
(Subp
, New_Elmt_List
);
197 -- Add new element to Uplevel_References
199 Append_Elmt
(N
, Uplevel_References
(Subp
));
200 Set_Has_Uplevel_Reference
(Entity
(N
));
201 end Note_Uplevel_Reference
;
203 -----------------------
204 -- Unnest_Subprogram --
205 -----------------------
207 -- Tables used by Unnest_Subprogram
209 type Subp_Entry
is record
211 -- Entity of the subprogram
214 -- Subprogram_Body node for this subprogram
217 -- Subprogram level (1 = outer subprogram (Subp argument), 2 = nested
218 -- immediately within this outer subprogram etc.)
221 package Subps
is new Table
.Table
(
222 Table_Component_Type
=> Subp_Entry
,
223 Table_Index_Type
=> Nat
,
224 Table_Low_Bound
=> 1,
225 Table_Initial
=> 100,
226 Table_Increment
=> 200,
227 Table_Name
=> "Subps");
228 -- Records the subprograms in the nest whose outer subprogram is Subp
230 type Call_Entry
is record
235 -- Entity of the subprogram containing the call
238 -- Entity of the subprogram called
241 package Calls
is new Table
.Table
(
242 Table_Component_Type
=> Call_Entry
,
243 Table_Index_Type
=> Nat
,
244 Table_Low_Bound
=> 1,
245 Table_Initial
=> 100,
246 Table_Increment
=> 200,
247 Table_Name
=> "Calls");
248 -- Records each call within the outer subprogram and all nested subprograms
249 -- that are to other subprograms nested within the outer subprogram. These
250 -- are the calls that may need an additional parameter.
252 procedure Unnest_Subprogram
(Subp
: Entity_Id
; Subp_Body
: Node_Id
) is
254 function Get_AREC_String
(Lev
: Pos
) return String;
255 -- Given a level value, 1, 2, ... returns the string AREC, AREC2, ...
257 function Get_Level
(Sub
: Entity_Id
) return Nat
;
258 -- Sub is either Subp itself, or a subprogram nested within Subp. This
259 -- function returns the level of nesting (Subp = 1, subprograms that
260 -- are immediately nested within Subp = 2, etc).
262 ---------------------
263 -- Get_AREC_String --
264 ---------------------
266 function Get_AREC_String
(Lev
: Pos
) return String is
270 Get_AREC_String
(Lev
/ 10) & Character'Val (Lev
mod 10 + 48);
273 "AREC" & Character'Val (Lev
+ 48);
281 function Get_Level
(Sub
: Entity_Id
) return Nat
is
291 S
:= Enclosing_Dynamic_Scope
(S
);
297 -- Start of processing for Unnest_Subprogram
300 -- First step, we must mark all nested subprograms that require a static
301 -- link (activation record) because either they contain explicit uplevel
302 -- references (as indicated by Has_Uplevel_Reference being set at this
303 -- point), or they make calls to other subprograms in the same nest that
304 -- require a static link (in which case we set this flag).
306 -- This is a recursive definition, and to implement this, we have to
307 -- build a call graph for the set of nested subprograms, and then go
308 -- over this graph to implement recursively the invariant that if a
309 -- subprogram has a call to a subprogram requiring a static link, then
310 -- the calling subprogram requires a static link.
312 -- First step, populate the above tables
317 Build_Tables
: declare
318 function Visit_Node
(N
: Node_Id
) return Traverse_Result
;
319 -- Visit a single node in Subp
325 function Visit_Node
(N
: Node_Id
) return Traverse_Result
is
328 function Find_Current_Subprogram
return Entity_Id
;
329 -- Finds the current subprogram containing the call N
331 -----------------------------
332 -- Find_Current_Subprogram --
333 -----------------------------
335 function Find_Current_Subprogram
return Entity_Id
is
343 if Nkind
(Nod
) = N_Subprogram_Body
then
344 if Acts_As_Spec
(Nod
) then
345 return Defining_Unit_Name
(Specification
(Nod
));
347 return Corresponding_Spec
(Nod
);
351 end Find_Current_Subprogram
;
353 -- Start of processing for Visit_Node
356 if Nkind_In
(N
, N_Procedure_Call_Statement
, N_Function_Call
) then
357 Ent
:= Entity
(Name
(N
));
359 if not Is_Library_Level_Entity
(Ent
) then
360 Calls
.Append
((N
, Find_Current_Subprogram
, Ent
));
363 elsif Nkind
(N
) = N_Subprogram_Body
and then Acts_As_Spec
(N
) then
364 Ent
:= Defining_Unit_Name
(Specification
(N
));
368 Lev
=> Get_Level
(Ent
)));
370 elsif Nkind
(N
) = N_Subprogram_Declaration
then
371 Ent
:= Defining_Unit_Name
(Specification
(N
));
374 Bod
=> Corresponding_Body
(N
),
375 Lev
=> Get_Level
(Ent
)));
385 procedure Visit
is new Traverse_Proc
(Visit_Node
);
386 -- Used to traverse the body of Subp, populating the tables
392 -- Second step is to do the transitive closure, if any subprogram has
393 -- a call to a subprogram for which Has_Uplevel_Reference is set, then
394 -- we set Has_Uplevel_Reference for the calling routine.
400 -- We use a simple minded algorithm as follows (obviously this can
401 -- be done more efficiently, using one of the standard algorithms
402 -- for efficient transitive closure computation, but this is simple
403 -- and most likely fast enough that its speed does not matter).
405 -- Repeatedly scan the list of calls. Any time we find a call from
406 -- A to B, where A does not have Has_Uplevel_Reference, and B does
407 -- have this flag set, then set the flag for A, and note that we
408 -- have made a change by setting Modified True. We repeat this until
409 -- we make a pass with no modifications.
413 Inner
: for J
in Calls
.First
.. Calls
.Last
loop
414 if not Has_Uplevel_Reference
(Calls
.Table
(J
).From
)
415 and then Has_Uplevel_Reference
(Calls
.Table
(J
).To
)
417 Set_Has_Uplevel_Reference
(Calls
.Table
(J
).From
);
422 exit Outer
when not Modified
;
426 -- Next step, process each subprogram in turn, inserting necessary
427 -- declarations for ARECxx types and variables for any subprogram
428 -- that has nested subprograms, and is uplevel referenced.
431 Addr
: constant Entity_Id
:= RTE
(RE_Address
);
434 for J
in Subps
.First
.. Subps
.Last
loop
436 STJ
: Subp_Entry
renames Subps
.Table
(J
);
439 -- We add AREC declarations for any subprogram that has at
440 -- least one nested subprogram, and has uplevel references.
442 if Has_Nested_Subprogram
(STJ
.Ent
)
443 and then Has_Uplevel_Reference
(STJ
.Ent
)
445 Add_AREC_Declarations
: declare
446 Loc
: constant Source_Ptr
:= Sloc
(STJ
.Bod
);
447 ARS
: constant String := Get_AREC_String
(STJ
.Lev
);
448 Urefs
: constant Elist_Id
:=
449 Uplevel_References
(STJ
.Ent
);
455 array (1 .. List_Length
(Urefs
)) of Entity_Id
;
456 Num_Uplevel_Entities
: Nat
;
457 -- Uplevel_Entities (1 .. Num_Uplevel_Entities) contains
458 -- a list (with no duplicates) of the entities for this
459 -- subprogram that are referenced uplevel. The maximum
460 -- number of entries cannot exceed the total number of
461 -- uplevel references.
464 -- Populate the Uplevel_Entities array, using the flag
465 -- Uplevel_Reference_Noted to avoid duplicates.
467 Num_Uplevel_Entities
:= 0;
468 Elmt
:= First_Elmt
(Urefs
);
469 while Present
(Elmt
) loop
470 Ent
:= Entity
(Node
(Elmt
));
472 if not Uplevel_Reference_Noted
(Ent
) then
473 Set_Uplevel_Reference_Noted
(Ent
, True);
474 Num_Uplevel_Entities
:= Num_Uplevel_Entities
+ 1;
475 Uplevel_Entities
(Num_Uplevel_Entities
) := Ent
;
481 -- Build list of component declarations for ARECnT
485 -- If not top level, include ARECn : ARECnPT := ARECnP
489 Make_Component_Declaration
(Loc
,
490 Defining_Identifier
=>
491 Make_Defining_Identifier
(Loc
,
492 Chars
=> Name_Find_Str
(ARS
)),
493 Component_Definition
=>
494 Make_Component_Definition
(Loc
,
495 Subtype_Indication
=>
496 Make_Identifier
(Loc
,
497 Chars
=> Name_Find_Str
(ARS
& "PT"))),
499 Make_Identifier
(Loc
,
500 Chars
=> Name_Find_Str
(ARS
& "P"))));
503 -- Add components for uplevel referenced entities
505 for J
in 1 .. Num_Uplevel_Entities
loop
507 Make_Component_Declaration
(Loc
,
508 Defining_Identifier
=>
509 Make_Defining_Identifier
(Loc
,
510 Chars
=> Chars
(Uplevel_Entities
(J
))),
511 Component_Definition
=>
512 Make_Component_Definition
(Loc
,
513 Subtype_Indication
=>
514 New_Occurrence_Of
(Addr
, Loc
))));
517 -- Now we can insert the AREC declarations into the body
519 Prepend_List_To
(Declarations
(STJ
.Bod
),
522 -- type ARECT is record .. end record;
524 Make_Full_Type_Declaration
(Loc
,
525 Defining_Identifier
=>
526 Make_Defining_Identifier
(Loc
,
527 Chars
=> Name_Find_Str
(ARS
& "T")),
529 Make_Record_Definition
(Loc
,
531 Make_Component_List
(Loc
,
532 Component_Items
=> Clist
))),
534 -- type ARECPT is access all ARECT;
536 Make_Full_Type_Declaration
(Loc
,
537 Defining_Identifier
=>
538 Make_Defining_Identifier
(Loc
,
539 Chars
=> Name_Find_Str
(ARS
& "PT")),
541 Make_Access_To_Object_Definition
(Loc
,
543 Subtype_Indication
=>
544 Make_Identifier
(Loc
,
545 Chars
=> Name_Find_Str
(ARS
& "T")))),
547 -- ARECP : constant ARECPT := AREC'Access;
549 Make_Object_Declaration
(Loc
,
550 Defining_Identifier
=>
551 Make_Defining_Identifier
(Loc
,
552 Chars
=> Name_Find_Str
(ARS
& "P")),
553 Constant_Present
=> True,
555 Make_Identifier
(Loc
, Name_Find_Str
(ARS
& "PT")),
557 Make_Attribute_Reference
(Loc
,
559 Make_Identifier
(Loc
, Name_Find_Str
(ARS
)),
560 Attribute_Name
=> Name_Access
))));
561 end Add_AREC_Declarations
;
567 -- Next step, for each uplevel referenced entity, add assignment
568 -- operations to set the corresponding AREC fields, and define
572 end Unnest_Subprogram
;