Mercurial > hg > CbC > CbC_gcc
comparison gcc/ada/inline.adb @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 ------------------------------------------------------------------------------ | |
2 -- -- | |
3 -- GNAT COMPILER COMPONENTS -- | |
4 -- -- | |
5 -- I N L I N 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 ------------------------------------------------------------------------------ | |
25 | |
26 with Aspects; use Aspects; | |
27 with Atree; use Atree; | |
28 with Debug; use Debug; | |
29 with Einfo; use Einfo; | |
30 with Elists; use Elists; | |
31 with Errout; use Errout; | |
32 with Expander; use Expander; | |
33 with Exp_Ch6; use Exp_Ch6; | |
34 with Exp_Ch7; use Exp_Ch7; | |
35 with Exp_Tss; use Exp_Tss; | |
36 with Exp_Util; use Exp_Util; | |
37 with Fname; use Fname; | |
38 with Fname.UF; use Fname.UF; | |
39 with Lib; use Lib; | |
40 with Namet; use Namet; | |
41 with Nmake; use Nmake; | |
42 with Nlists; use Nlists; | |
43 with Output; use Output; | |
44 with Sem_Aux; use Sem_Aux; | |
45 with Sem_Ch8; use Sem_Ch8; | |
46 with Sem_Ch10; use Sem_Ch10; | |
47 with Sem_Ch12; use Sem_Ch12; | |
48 with Sem_Prag; use Sem_Prag; | |
49 with Sem_Util; use Sem_Util; | |
50 with Sinfo; use Sinfo; | |
51 with Sinput; use Sinput; | |
52 with Snames; use Snames; | |
53 with Stand; use Stand; | |
54 with Uname; use Uname; | |
55 with Tbuild; use Tbuild; | |
56 | |
57 package body Inline is | |
58 | |
59 Check_Inlining_Restrictions : constant Boolean := True; | |
60 -- In the following cases the frontend rejects inlining because they | |
61 -- are not handled well by the backend. This variable facilitates | |
62 -- disabling these restrictions to evaluate future versions of the | |
63 -- GCC backend in which some of the restrictions may be supported. | |
64 -- | |
65 -- - subprograms that have: | |
66 -- - nested subprograms | |
67 -- - instantiations | |
68 -- - package declarations | |
69 -- - task or protected object declarations | |
70 -- - some of the following statements: | |
71 -- - abort | |
72 -- - asynchronous-select | |
73 -- - conditional-entry-call | |
74 -- - delay-relative | |
75 -- - delay-until | |
76 -- - selective-accept | |
77 -- - timed-entry-call | |
78 | |
79 Inlined_Calls : Elist_Id; | |
80 -- List of frontend inlined calls | |
81 | |
82 Backend_Calls : Elist_Id; | |
83 -- List of inline calls passed to the backend | |
84 | |
85 Backend_Inlined_Subps : Elist_Id; | |
86 -- List of subprograms inlined by the backend | |
87 | |
88 Backend_Not_Inlined_Subps : Elist_Id; | |
89 -- List of subprograms that cannot be inlined by the backend | |
90 | |
91 -------------------- | |
92 -- Inlined Bodies -- | |
93 -------------------- | |
94 | |
95 -- Inlined functions are actually placed in line by the backend if the | |
96 -- corresponding bodies are available (i.e. compiled). Whenever we find | |
97 -- a call to an inlined subprogram, we add the name of the enclosing | |
98 -- compilation unit to a worklist. After all compilation, and after | |
99 -- expansion of generic bodies, we traverse the list of pending bodies | |
100 -- and compile them as well. | |
101 | |
102 package Inlined_Bodies is new Table.Table ( | |
103 Table_Component_Type => Entity_Id, | |
104 Table_Index_Type => Int, | |
105 Table_Low_Bound => 0, | |
106 Table_Initial => Alloc.Inlined_Bodies_Initial, | |
107 Table_Increment => Alloc.Inlined_Bodies_Increment, | |
108 Table_Name => "Inlined_Bodies"); | |
109 | |
110 ----------------------- | |
111 -- Inline Processing -- | |
112 ----------------------- | |
113 | |
114 -- For each call to an inlined subprogram, we make entries in a table | |
115 -- that stores caller and callee, and indicates the call direction from | |
116 -- one to the other. We also record the compilation unit that contains | |
117 -- the callee. After analyzing the bodies of all such compilation units, | |
118 -- we compute the transitive closure of inlined subprograms called from | |
119 -- the main compilation unit and make it available to the code generator | |
120 -- in no particular order, thus allowing cycles in the call graph. | |
121 | |
122 Last_Inlined : Entity_Id := Empty; | |
123 | |
124 -- For each entry in the table we keep a list of successors in topological | |
125 -- order, i.e. callers of the current subprogram. | |
126 | |
127 type Subp_Index is new Nat; | |
128 No_Subp : constant Subp_Index := 0; | |
129 | |
130 -- The subprogram entities are hashed into the Inlined table | |
131 | |
132 Num_Hash_Headers : constant := 512; | |
133 | |
134 Hash_Headers : array (Subp_Index range 0 .. Num_Hash_Headers - 1) | |
135 of Subp_Index; | |
136 | |
137 type Succ_Index is new Nat; | |
138 No_Succ : constant Succ_Index := 0; | |
139 | |
140 type Succ_Info is record | |
141 Subp : Subp_Index; | |
142 Next : Succ_Index; | |
143 end record; | |
144 | |
145 -- The following table stores list elements for the successor lists. These | |
146 -- lists cannot be chained directly through entries in the Inlined table, | |
147 -- because a given subprogram can appear in several such lists. | |
148 | |
149 package Successors is new Table.Table ( | |
150 Table_Component_Type => Succ_Info, | |
151 Table_Index_Type => Succ_Index, | |
152 Table_Low_Bound => 1, | |
153 Table_Initial => Alloc.Successors_Initial, | |
154 Table_Increment => Alloc.Successors_Increment, | |
155 Table_Name => "Successors"); | |
156 | |
157 type Subp_Info is record | |
158 Name : Entity_Id := Empty; | |
159 Next : Subp_Index := No_Subp; | |
160 First_Succ : Succ_Index := No_Succ; | |
161 Main_Call : Boolean := False; | |
162 Processed : Boolean := False; | |
163 end record; | |
164 | |
165 package Inlined is new Table.Table ( | |
166 Table_Component_Type => Subp_Info, | |
167 Table_Index_Type => Subp_Index, | |
168 Table_Low_Bound => 1, | |
169 Table_Initial => Alloc.Inlined_Initial, | |
170 Table_Increment => Alloc.Inlined_Increment, | |
171 Table_Name => "Inlined"); | |
172 | |
173 ----------------------- | |
174 -- Local Subprograms -- | |
175 ----------------------- | |
176 | |
177 procedure Add_Call (Called : Entity_Id; Caller : Entity_Id := Empty); | |
178 -- Make two entries in Inlined table, for an inlined subprogram being | |
179 -- called, and for the inlined subprogram that contains the call. If | |
180 -- the call is in the main compilation unit, Caller is Empty. | |
181 | |
182 procedure Add_Inlined_Subprogram (E : Entity_Id); | |
183 -- Add subprogram E to the list of inlined subprogram for the unit | |
184 | |
185 function Add_Subp (E : Entity_Id) return Subp_Index; | |
186 -- Make entry in Inlined table for subprogram E, or return table index | |
187 -- that already holds E. | |
188 | |
189 function Get_Code_Unit_Entity (E : Entity_Id) return Entity_Id; | |
190 pragma Inline (Get_Code_Unit_Entity); | |
191 -- Return the entity node for the unit containing E. Always return the spec | |
192 -- for a package. | |
193 | |
194 function Has_Initialized_Type (E : Entity_Id) return Boolean; | |
195 -- If a candidate for inlining contains type declarations for types with | |
196 -- nontrivial initialization procedures, they are not worth inlining. | |
197 | |
198 function Has_Single_Return (N : Node_Id) return Boolean; | |
199 -- In general we cannot inline functions that return unconstrained type. | |
200 -- However, we can handle such functions if all return statements return a | |
201 -- local variable that is the only declaration in the body of the function. | |
202 -- In that case the call can be replaced by that local variable as is done | |
203 -- for other inlined calls. | |
204 | |
205 function In_Main_Unit_Or_Subunit (E : Entity_Id) return Boolean; | |
206 -- Return True if E is in the main unit or its spec or in a subunit | |
207 | |
208 function Is_Nested (E : Entity_Id) return Boolean; | |
209 -- If the function is nested inside some other function, it will always | |
210 -- be compiled if that function is, so don't add it to the inline list. | |
211 -- We cannot compile a nested function outside the scope of the containing | |
212 -- function anyway. This is also the case if the function is defined in a | |
213 -- task body or within an entry (for example, an initialization procedure). | |
214 | |
215 procedure Remove_Aspects_And_Pragmas (Body_Decl : Node_Id); | |
216 -- Remove all aspects and/or pragmas that have no meaning in inlined body | |
217 -- Body_Decl. The analysis of these items is performed on the non-inlined | |
218 -- body. The items currently removed are: | |
219 -- Contract_Cases | |
220 -- Global | |
221 -- Depends | |
222 -- Postcondition | |
223 -- Precondition | |
224 -- Refined_Global | |
225 -- Refined_Depends | |
226 -- Refined_Post | |
227 -- Test_Case | |
228 -- Unmodified | |
229 -- Unreferenced | |
230 | |
231 ------------------------------ | |
232 -- Deferred Cleanup Actions -- | |
233 ------------------------------ | |
234 | |
235 -- The cleanup actions for scopes that contain instantiations is delayed | |
236 -- until after expansion of those instantiations, because they may contain | |
237 -- finalizable objects or tasks that affect the cleanup code. A scope | |
238 -- that contains instantiations only needs to be finalized once, even | |
239 -- if it contains more than one instance. We keep a list of scopes | |
240 -- that must still be finalized, and call cleanup_actions after all | |
241 -- the instantiations have been completed. | |
242 | |
243 To_Clean : Elist_Id; | |
244 | |
245 procedure Add_Scope_To_Clean (Inst : Entity_Id); | |
246 -- Build set of scopes on which cleanup actions must be performed | |
247 | |
248 procedure Cleanup_Scopes; | |
249 -- Complete cleanup actions on scopes that need it | |
250 | |
251 -------------- | |
252 -- Add_Call -- | |
253 -------------- | |
254 | |
255 procedure Add_Call (Called : Entity_Id; Caller : Entity_Id := Empty) is | |
256 P1 : constant Subp_Index := Add_Subp (Called); | |
257 P2 : Subp_Index; | |
258 J : Succ_Index; | |
259 | |
260 begin | |
261 if Present (Caller) then | |
262 P2 := Add_Subp (Caller); | |
263 | |
264 -- Add P1 to the list of successors of P2, if not already there. | |
265 -- Note that P2 may contain more than one call to P1, and only | |
266 -- one needs to be recorded. | |
267 | |
268 J := Inlined.Table (P2).First_Succ; | |
269 while J /= No_Succ loop | |
270 if Successors.Table (J).Subp = P1 then | |
271 return; | |
272 end if; | |
273 | |
274 J := Successors.Table (J).Next; | |
275 end loop; | |
276 | |
277 -- On exit, make a successor entry for P1 | |
278 | |
279 Successors.Increment_Last; | |
280 Successors.Table (Successors.Last).Subp := P1; | |
281 Successors.Table (Successors.Last).Next := | |
282 Inlined.Table (P2).First_Succ; | |
283 Inlined.Table (P2).First_Succ := Successors.Last; | |
284 else | |
285 Inlined.Table (P1).Main_Call := True; | |
286 end if; | |
287 end Add_Call; | |
288 | |
289 ---------------------- | |
290 -- Add_Inlined_Body -- | |
291 ---------------------- | |
292 | |
293 procedure Add_Inlined_Body (E : Entity_Id; N : Node_Id) is | |
294 | |
295 type Inline_Level_Type is (Dont_Inline, Inline_Call, Inline_Package); | |
296 -- Level of inlining for the call: Dont_Inline means no inlining, | |
297 -- Inline_Call means that only the call is considered for inlining, | |
298 -- Inline_Package means that the call is considered for inlining and | |
299 -- its package compiled and scanned for more inlining opportunities. | |
300 | |
301 function Must_Inline return Inline_Level_Type; | |
302 -- Inlining is only done if the call statement N is in the main unit, | |
303 -- or within the body of another inlined subprogram. | |
304 | |
305 ----------------- | |
306 -- Must_Inline -- | |
307 ----------------- | |
308 | |
309 function Must_Inline return Inline_Level_Type is | |
310 Scop : Entity_Id; | |
311 Comp : Node_Id; | |
312 | |
313 begin | |
314 -- Check if call is in main unit | |
315 | |
316 Scop := Current_Scope; | |
317 | |
318 -- Do not try to inline if scope is standard. This could happen, for | |
319 -- example, for a call to Add_Global_Declaration, and it causes | |
320 -- trouble to try to inline at this level. | |
321 | |
322 if Scop = Standard_Standard then | |
323 return Dont_Inline; | |
324 end if; | |
325 | |
326 -- Otherwise lookup scope stack to outer scope | |
327 | |
328 while Scope (Scop) /= Standard_Standard | |
329 and then not Is_Child_Unit (Scop) | |
330 loop | |
331 Scop := Scope (Scop); | |
332 end loop; | |
333 | |
334 Comp := Parent (Scop); | |
335 while Nkind (Comp) /= N_Compilation_Unit loop | |
336 Comp := Parent (Comp); | |
337 end loop; | |
338 | |
339 -- If the call is in the main unit, inline the call and compile the | |
340 -- package of the subprogram to find more calls to be inlined. | |
341 | |
342 if Comp = Cunit (Main_Unit) | |
343 or else Comp = Library_Unit (Cunit (Main_Unit)) | |
344 then | |
345 Add_Call (E); | |
346 return Inline_Package; | |
347 end if; | |
348 | |
349 -- The call is not in the main unit. See if it is in some subprogram | |
350 -- that can be inlined outside its unit. If so, inline the call and, | |
351 -- if the inlining level is set to 1, stop there; otherwise also | |
352 -- compile the package as above. | |
353 | |
354 Scop := Current_Scope; | |
355 while Scope (Scop) /= Standard_Standard | |
356 and then not Is_Child_Unit (Scop) | |
357 loop | |
358 if Is_Overloadable (Scop) | |
359 and then Is_Inlined (Scop) | |
360 and then not Is_Nested (Scop) | |
361 then | |
362 Add_Call (E, Scop); | |
363 | |
364 if Inline_Level = 1 then | |
365 return Inline_Call; | |
366 else | |
367 return Inline_Package; | |
368 end if; | |
369 end if; | |
370 | |
371 Scop := Scope (Scop); | |
372 end loop; | |
373 | |
374 return Dont_Inline; | |
375 end Must_Inline; | |
376 | |
377 Level : Inline_Level_Type; | |
378 | |
379 -- Start of processing for Add_Inlined_Body | |
380 | |
381 begin | |
382 Append_New_Elmt (N, To => Backend_Calls); | |
383 | |
384 -- Skip subprograms that cannot be inlined outside their unit | |
385 | |
386 if Is_Abstract_Subprogram (E) | |
387 or else Convention (E) = Convention_Protected | |
388 or else Is_Nested (E) | |
389 then | |
390 return; | |
391 end if; | |
392 | |
393 -- Find out whether the call must be inlined. Unless the result is | |
394 -- Dont_Inline, Must_Inline also creates an edge for the call in the | |
395 -- callgraph; however, it will not be activated until after Is_Called | |
396 -- is set on the subprogram. | |
397 | |
398 Level := Must_Inline; | |
399 | |
400 if Level = Dont_Inline then | |
401 return; | |
402 end if; | |
403 | |
404 -- If the call was generated by the compiler and is to a subprogram in | |
405 -- a run-time unit, we need to suppress debugging information for it, | |
406 -- so that the code that is eventually inlined will not affect the | |
407 -- debugging of the program. We do not do it if the call comes from | |
408 -- source because, even if the call is inlined, the user may expect it | |
409 -- to be present in the debugging information. | |
410 | |
411 if not Comes_From_Source (N) | |
412 and then In_Extended_Main_Source_Unit (N) | |
413 and then Is_Predefined_Unit (Get_Source_Unit (E)) | |
414 then | |
415 Set_Needs_Debug_Info (E, False); | |
416 end if; | |
417 | |
418 -- If the subprogram is an expression function, then there is no need to | |
419 -- load any package body since the body of the function is in the spec. | |
420 | |
421 if Is_Expression_Function (E) then | |
422 Set_Is_Called (E); | |
423 return; | |
424 end if; | |
425 | |
426 -- Find unit containing E, and add to list of inlined bodies if needed. | |
427 -- If the body is already present, no need to load any other unit. This | |
428 -- is the case for an initialization procedure, which appears in the | |
429 -- package declaration that contains the type. It is also the case if | |
430 -- the body has already been analyzed. Finally, if the unit enclosing | |
431 -- E is an instance, the instance body will be analyzed in any case, | |
432 -- and there is no need to add the enclosing unit (whose body might not | |
433 -- be available). | |
434 | |
435 -- Library-level functions must be handled specially, because there is | |
436 -- no enclosing package to retrieve. In this case, it is the body of | |
437 -- the function that will have to be loaded. | |
438 | |
439 declare | |
440 Pack : constant Entity_Id := Get_Code_Unit_Entity (E); | |
441 | |
442 begin | |
443 if Pack = E then | |
444 Set_Is_Called (E); | |
445 Inlined_Bodies.Increment_Last; | |
446 Inlined_Bodies.Table (Inlined_Bodies.Last) := E; | |
447 | |
448 elsif Ekind (Pack) = E_Package then | |
449 Set_Is_Called (E); | |
450 | |
451 if Is_Generic_Instance (Pack) then | |
452 null; | |
453 | |
454 -- Do not inline the package if the subprogram is an init proc | |
455 -- or other internally generated subprogram, because in that | |
456 -- case the subprogram body appears in the same unit that | |
457 -- declares the type, and that body is visible to the back end. | |
458 -- Do not inline it either if it is in the main unit. | |
459 -- Extend the -gnatn2 processing to -gnatn1 for Inline_Always | |
460 -- calls if the back-end takes care of inlining the call. | |
461 -- Note that Level in Inline_Package | Inline_Call here. | |
462 | |
463 elsif ((Level = Inline_Call | |
464 and then Has_Pragma_Inline_Always (E) | |
465 and then Back_End_Inlining) | |
466 or else Level = Inline_Package) | |
467 and then not Is_Inlined (Pack) | |
468 and then not Is_Internal (E) | |
469 and then not In_Main_Unit_Or_Subunit (Pack) | |
470 then | |
471 Set_Is_Inlined (Pack); | |
472 Inlined_Bodies.Increment_Last; | |
473 Inlined_Bodies.Table (Inlined_Bodies.Last) := Pack; | |
474 end if; | |
475 end if; | |
476 | |
477 -- Ensure that Analyze_Inlined_Bodies will be invoked after | |
478 -- completing the analysis of the current unit. | |
479 | |
480 Inline_Processing_Required := True; | |
481 end; | |
482 end Add_Inlined_Body; | |
483 | |
484 ---------------------------- | |
485 -- Add_Inlined_Subprogram -- | |
486 ---------------------------- | |
487 | |
488 procedure Add_Inlined_Subprogram (E : Entity_Id) is | |
489 Decl : constant Node_Id := Parent (Declaration_Node (E)); | |
490 Pack : constant Entity_Id := Get_Code_Unit_Entity (E); | |
491 | |
492 procedure Register_Backend_Inlined_Subprogram (Subp : Entity_Id); | |
493 -- Append Subp to the list of subprograms inlined by the backend | |
494 | |
495 procedure Register_Backend_Not_Inlined_Subprogram (Subp : Entity_Id); | |
496 -- Append Subp to the list of subprograms that cannot be inlined by | |
497 -- the backend. | |
498 | |
499 ----------------------------------------- | |
500 -- Register_Backend_Inlined_Subprogram -- | |
501 ----------------------------------------- | |
502 | |
503 procedure Register_Backend_Inlined_Subprogram (Subp : Entity_Id) is | |
504 begin | |
505 Append_New_Elmt (Subp, To => Backend_Inlined_Subps); | |
506 end Register_Backend_Inlined_Subprogram; | |
507 | |
508 --------------------------------------------- | |
509 -- Register_Backend_Not_Inlined_Subprogram -- | |
510 --------------------------------------------- | |
511 | |
512 procedure Register_Backend_Not_Inlined_Subprogram (Subp : Entity_Id) is | |
513 begin | |
514 Append_New_Elmt (Subp, To => Backend_Not_Inlined_Subps); | |
515 end Register_Backend_Not_Inlined_Subprogram; | |
516 | |
517 -- Start of processing for Add_Inlined_Subprogram | |
518 | |
519 begin | |
520 -- If the subprogram is to be inlined, and if its unit is known to be | |
521 -- inlined or is an instance whose body will be analyzed anyway or the | |
522 -- subprogram was generated as a body by the compiler (for example an | |
523 -- initialization procedure) or its declaration was provided along with | |
524 -- the body (for example an expression function), and if it is declared | |
525 -- at the library level not in the main unit, and if it can be inlined | |
526 -- by the back-end, then insert it in the list of inlined subprograms. | |
527 | |
528 if Is_Inlined (E) | |
529 and then (Is_Inlined (Pack) | |
530 or else Is_Generic_Instance (Pack) | |
531 or else Nkind (Decl) = N_Subprogram_Body | |
532 or else Present (Corresponding_Body (Decl))) | |
533 and then not In_Main_Unit_Or_Subunit (E) | |
534 and then not Is_Nested (E) | |
535 and then not Has_Initialized_Type (E) | |
536 then | |
537 Register_Backend_Inlined_Subprogram (E); | |
538 | |
539 if No (Last_Inlined) then | |
540 Set_First_Inlined_Subprogram (Cunit (Main_Unit), E); | |
541 else | |
542 Set_Next_Inlined_Subprogram (Last_Inlined, E); | |
543 end if; | |
544 | |
545 Last_Inlined := E; | |
546 | |
547 else | |
548 Register_Backend_Not_Inlined_Subprogram (E); | |
549 end if; | |
550 end Add_Inlined_Subprogram; | |
551 | |
552 ------------------------ | |
553 -- Add_Scope_To_Clean -- | |
554 ------------------------ | |
555 | |
556 procedure Add_Scope_To_Clean (Inst : Entity_Id) is | |
557 Scop : constant Entity_Id := Enclosing_Dynamic_Scope (Inst); | |
558 Elmt : Elmt_Id; | |
559 | |
560 begin | |
561 -- If the instance appears in a library-level package declaration, | |
562 -- all finalization is global, and nothing needs doing here. | |
563 | |
564 if Scop = Standard_Standard then | |
565 return; | |
566 end if; | |
567 | |
568 -- If the instance is within a generic unit, no finalization code | |
569 -- can be generated. Note that at this point all bodies have been | |
570 -- analyzed, and the scope stack itself is not present, and the flag | |
571 -- Inside_A_Generic is not set. | |
572 | |
573 declare | |
574 S : Entity_Id; | |
575 | |
576 begin | |
577 S := Scope (Inst); | |
578 while Present (S) and then S /= Standard_Standard loop | |
579 if Is_Generic_Unit (S) then | |
580 return; | |
581 end if; | |
582 | |
583 S := Scope (S); | |
584 end loop; | |
585 end; | |
586 | |
587 Elmt := First_Elmt (To_Clean); | |
588 while Present (Elmt) loop | |
589 if Node (Elmt) = Scop then | |
590 return; | |
591 end if; | |
592 | |
593 Elmt := Next_Elmt (Elmt); | |
594 end loop; | |
595 | |
596 Append_Elmt (Scop, To_Clean); | |
597 end Add_Scope_To_Clean; | |
598 | |
599 -------------- | |
600 -- Add_Subp -- | |
601 -------------- | |
602 | |
603 function Add_Subp (E : Entity_Id) return Subp_Index is | |
604 Index : Subp_Index := Subp_Index (E) mod Num_Hash_Headers; | |
605 J : Subp_Index; | |
606 | |
607 procedure New_Entry; | |
608 -- Initialize entry in Inlined table | |
609 | |
610 procedure New_Entry is | |
611 begin | |
612 Inlined.Increment_Last; | |
613 Inlined.Table (Inlined.Last).Name := E; | |
614 Inlined.Table (Inlined.Last).Next := No_Subp; | |
615 Inlined.Table (Inlined.Last).First_Succ := No_Succ; | |
616 Inlined.Table (Inlined.Last).Main_Call := False; | |
617 Inlined.Table (Inlined.Last).Processed := False; | |
618 end New_Entry; | |
619 | |
620 -- Start of processing for Add_Subp | |
621 | |
622 begin | |
623 if Hash_Headers (Index) = No_Subp then | |
624 New_Entry; | |
625 Hash_Headers (Index) := Inlined.Last; | |
626 return Inlined.Last; | |
627 | |
628 else | |
629 J := Hash_Headers (Index); | |
630 while J /= No_Subp loop | |
631 if Inlined.Table (J).Name = E then | |
632 return J; | |
633 else | |
634 Index := J; | |
635 J := Inlined.Table (J).Next; | |
636 end if; | |
637 end loop; | |
638 | |
639 -- On exit, subprogram was not found. Enter in table. Index is | |
640 -- the current last entry on the hash chain. | |
641 | |
642 New_Entry; | |
643 Inlined.Table (Index).Next := Inlined.Last; | |
644 return Inlined.Last; | |
645 end if; | |
646 end Add_Subp; | |
647 | |
648 ---------------------------- | |
649 -- Analyze_Inlined_Bodies -- | |
650 ---------------------------- | |
651 | |
652 procedure Analyze_Inlined_Bodies is | |
653 Comp_Unit : Node_Id; | |
654 J : Int; | |
655 Pack : Entity_Id; | |
656 Subp : Subp_Index; | |
657 S : Succ_Index; | |
658 | |
659 type Pending_Index is new Nat; | |
660 | |
661 package Pending_Inlined is new Table.Table ( | |
662 Table_Component_Type => Subp_Index, | |
663 Table_Index_Type => Pending_Index, | |
664 Table_Low_Bound => 1, | |
665 Table_Initial => Alloc.Inlined_Initial, | |
666 Table_Increment => Alloc.Inlined_Increment, | |
667 Table_Name => "Pending_Inlined"); | |
668 -- The workpile used to compute the transitive closure | |
669 | |
670 -- Start of processing for Analyze_Inlined_Bodies | |
671 | |
672 begin | |
673 if Serious_Errors_Detected = 0 then | |
674 Push_Scope (Standard_Standard); | |
675 | |
676 J := 0; | |
677 while J <= Inlined_Bodies.Last | |
678 and then Serious_Errors_Detected = 0 | |
679 loop | |
680 Pack := Inlined_Bodies.Table (J); | |
681 while Present (Pack) | |
682 and then Scope (Pack) /= Standard_Standard | |
683 and then not Is_Child_Unit (Pack) | |
684 loop | |
685 Pack := Scope (Pack); | |
686 end loop; | |
687 | |
688 Comp_Unit := Parent (Pack); | |
689 while Present (Comp_Unit) | |
690 and then Nkind (Comp_Unit) /= N_Compilation_Unit | |
691 loop | |
692 Comp_Unit := Parent (Comp_Unit); | |
693 end loop; | |
694 | |
695 -- Load the body if it exists and contains inlineable entities, | |
696 -- unless it is the main unit, or is an instance whose body has | |
697 -- already been analyzed. | |
698 | |
699 if Present (Comp_Unit) | |
700 and then Comp_Unit /= Cunit (Main_Unit) | |
701 and then Body_Required (Comp_Unit) | |
702 and then | |
703 (Nkind (Unit (Comp_Unit)) /= N_Package_Declaration | |
704 or else | |
705 (No (Corresponding_Body (Unit (Comp_Unit))) | |
706 and then Body_Needed_For_Inlining | |
707 (Defining_Entity (Unit (Comp_Unit))))) | |
708 then | |
709 declare | |
710 Bname : constant Unit_Name_Type := | |
711 Get_Body_Name (Get_Unit_Name (Unit (Comp_Unit))); | |
712 | |
713 OK : Boolean; | |
714 | |
715 begin | |
716 if not Is_Loaded (Bname) then | |
717 Style_Check := False; | |
718 Load_Needed_Body (Comp_Unit, OK); | |
719 | |
720 if not OK then | |
721 | |
722 -- Warn that a body was not available for inlining | |
723 -- by the back-end. | |
724 | |
725 Error_Msg_Unit_1 := Bname; | |
726 Error_Msg_N | |
727 ("one or more inlined subprograms accessed in $!??", | |
728 Comp_Unit); | |
729 Error_Msg_File_1 := | |
730 Get_File_Name (Bname, Subunit => False); | |
731 Error_Msg_N ("\but file{ was not found!??", Comp_Unit); | |
732 end if; | |
733 end if; | |
734 end; | |
735 end if; | |
736 | |
737 J := J + 1; | |
738 | |
739 if J > Inlined_Bodies.Last then | |
740 | |
741 -- The analysis of required bodies may have produced additional | |
742 -- generic instantiations. To obtain further inlining, we need | |
743 -- to perform another round of generic body instantiations. | |
744 | |
745 Instantiate_Bodies; | |
746 | |
747 -- Symmetrically, the instantiation of required generic bodies | |
748 -- may have caused additional bodies to be inlined. To obtain | |
749 -- further inlining, we keep looping over the inlined bodies. | |
750 end if; | |
751 end loop; | |
752 | |
753 -- The list of inlined subprograms is an overestimate, because it | |
754 -- includes inlined functions called from functions that are compiled | |
755 -- as part of an inlined package, but are not themselves called. An | |
756 -- accurate computation of just those subprograms that are needed | |
757 -- requires that we perform a transitive closure over the call graph, | |
758 -- starting from calls in the main compilation unit. | |
759 | |
760 for Index in Inlined.First .. Inlined.Last loop | |
761 if not Is_Called (Inlined.Table (Index).Name) then | |
762 | |
763 -- This means that Add_Inlined_Body added the subprogram to the | |
764 -- table but wasn't able to handle its code unit. Do nothing. | |
765 | |
766 Inlined.Table (Index).Processed := True; | |
767 | |
768 elsif Inlined.Table (Index).Main_Call then | |
769 Pending_Inlined.Increment_Last; | |
770 Pending_Inlined.Table (Pending_Inlined.Last) := Index; | |
771 Inlined.Table (Index).Processed := True; | |
772 | |
773 else | |
774 Set_Is_Called (Inlined.Table (Index).Name, False); | |
775 end if; | |
776 end loop; | |
777 | |
778 -- Iterate over the workpile until it is emptied, propagating the | |
779 -- Is_Called flag to the successors of the processed subprogram. | |
780 | |
781 while Pending_Inlined.Last >= Pending_Inlined.First loop | |
782 Subp := Pending_Inlined.Table (Pending_Inlined.Last); | |
783 Pending_Inlined.Decrement_Last; | |
784 | |
785 S := Inlined.Table (Subp).First_Succ; | |
786 | |
787 while S /= No_Succ loop | |
788 Subp := Successors.Table (S).Subp; | |
789 | |
790 if not Inlined.Table (Subp).Processed then | |
791 Set_Is_Called (Inlined.Table (Subp).Name); | |
792 Pending_Inlined.Increment_Last; | |
793 Pending_Inlined.Table (Pending_Inlined.Last) := Subp; | |
794 Inlined.Table (Subp).Processed := True; | |
795 end if; | |
796 | |
797 S := Successors.Table (S).Next; | |
798 end loop; | |
799 end loop; | |
800 | |
801 -- Finally add the called subprograms to the list of inlined | |
802 -- subprograms for the unit. | |
803 | |
804 for Index in Inlined.First .. Inlined.Last loop | |
805 if Is_Called (Inlined.Table (Index).Name) then | |
806 Add_Inlined_Subprogram (Inlined.Table (Index).Name); | |
807 end if; | |
808 end loop; | |
809 | |
810 Pop_Scope; | |
811 end if; | |
812 end Analyze_Inlined_Bodies; | |
813 | |
814 -------------------------- | |
815 -- Build_Body_To_Inline -- | |
816 -------------------------- | |
817 | |
818 procedure Build_Body_To_Inline (N : Node_Id; Spec_Id : Entity_Id) is | |
819 Decl : constant Node_Id := Unit_Declaration_Node (Spec_Id); | |
820 Analysis_Status : constant Boolean := Full_Analysis; | |
821 Original_Body : Node_Id; | |
822 Body_To_Analyze : Node_Id; | |
823 Max_Size : constant := 10; | |
824 | |
825 function Has_Pending_Instantiation return Boolean; | |
826 -- If some enclosing body contains instantiations that appear before | |
827 -- the corresponding generic body, the enclosing body has a freeze node | |
828 -- so that it can be elaborated after the generic itself. This might | |
829 -- conflict with subsequent inlinings, so that it is unsafe to try to | |
830 -- inline in such a case. | |
831 | |
832 function Has_Single_Return_In_GNATprove_Mode return Boolean; | |
833 -- This function is called only in GNATprove mode, and it returns | |
834 -- True if the subprogram has no return statement or a single return | |
835 -- statement as last statement. It returns False for subprogram with | |
836 -- a single return as last statement inside one or more blocks, as | |
837 -- inlining would generate gotos in that case as well (although the | |
838 -- goto is useless in that case). | |
839 | |
840 function Uses_Secondary_Stack (Bod : Node_Id) return Boolean; | |
841 -- If the body of the subprogram includes a call that returns an | |
842 -- unconstrained type, the secondary stack is involved, and it | |
843 -- is not worth inlining. | |
844 | |
845 ------------------------------- | |
846 -- Has_Pending_Instantiation -- | |
847 ------------------------------- | |
848 | |
849 function Has_Pending_Instantiation return Boolean is | |
850 S : Entity_Id; | |
851 | |
852 begin | |
853 S := Current_Scope; | |
854 while Present (S) loop | |
855 if Is_Compilation_Unit (S) | |
856 or else Is_Child_Unit (S) | |
857 then | |
858 return False; | |
859 | |
860 elsif Ekind (S) = E_Package | |
861 and then Has_Forward_Instantiation (S) | |
862 then | |
863 return True; | |
864 end if; | |
865 | |
866 S := Scope (S); | |
867 end loop; | |
868 | |
869 return False; | |
870 end Has_Pending_Instantiation; | |
871 | |
872 ----------------------------------------- | |
873 -- Has_Single_Return_In_GNATprove_Mode -- | |
874 ----------------------------------------- | |
875 | |
876 function Has_Single_Return_In_GNATprove_Mode return Boolean is | |
877 Body_To_Inline : constant Node_Id := N; | |
878 Last_Statement : Node_Id := Empty; | |
879 | |
880 function Check_Return (N : Node_Id) return Traverse_Result; | |
881 -- Returns OK on node N if this is not a return statement different | |
882 -- from the last statement in the subprogram. | |
883 | |
884 ------------------ | |
885 -- Check_Return -- | |
886 ------------------ | |
887 | |
888 function Check_Return (N : Node_Id) return Traverse_Result is | |
889 begin | |
890 case Nkind (N) is | |
891 when N_Extended_Return_Statement | |
892 | N_Simple_Return_Statement | |
893 => | |
894 if N = Last_Statement then | |
895 return OK; | |
896 else | |
897 return Abandon; | |
898 end if; | |
899 | |
900 -- Skip locally declared subprogram bodies inside the body to | |
901 -- inline, as the return statements inside those do not count. | |
902 | |
903 when N_Subprogram_Body => | |
904 if N = Body_To_Inline then | |
905 return OK; | |
906 else | |
907 return Skip; | |
908 end if; | |
909 | |
910 when others => | |
911 return OK; | |
912 end case; | |
913 end Check_Return; | |
914 | |
915 function Check_All_Returns is new Traverse_Func (Check_Return); | |
916 | |
917 -- Start of processing for Has_Single_Return_In_GNATprove_Mode | |
918 | |
919 begin | |
920 -- Retrieve the last statement | |
921 | |
922 Last_Statement := Last (Statements (Handled_Statement_Sequence (N))); | |
923 | |
924 -- Check that the last statement is the only possible return | |
925 -- statement in the subprogram. | |
926 | |
927 return Check_All_Returns (N) = OK; | |
928 end Has_Single_Return_In_GNATprove_Mode; | |
929 | |
930 -------------------------- | |
931 -- Uses_Secondary_Stack -- | |
932 -------------------------- | |
933 | |
934 function Uses_Secondary_Stack (Bod : Node_Id) return Boolean is | |
935 function Check_Call (N : Node_Id) return Traverse_Result; | |
936 -- Look for function calls that return an unconstrained type | |
937 | |
938 ---------------- | |
939 -- Check_Call -- | |
940 ---------------- | |
941 | |
942 function Check_Call (N : Node_Id) return Traverse_Result is | |
943 begin | |
944 if Nkind (N) = N_Function_Call | |
945 and then Is_Entity_Name (Name (N)) | |
946 and then Is_Composite_Type (Etype (Entity (Name (N)))) | |
947 and then not Is_Constrained (Etype (Entity (Name (N)))) | |
948 then | |
949 Cannot_Inline | |
950 ("cannot inline & (call returns unconstrained type)?", | |
951 N, Spec_Id); | |
952 return Abandon; | |
953 else | |
954 return OK; | |
955 end if; | |
956 end Check_Call; | |
957 | |
958 function Check_Calls is new Traverse_Func (Check_Call); | |
959 | |
960 begin | |
961 return Check_Calls (Bod) = Abandon; | |
962 end Uses_Secondary_Stack; | |
963 | |
964 -- Start of processing for Build_Body_To_Inline | |
965 | |
966 begin | |
967 -- Return immediately if done already | |
968 | |
969 if Nkind (Decl) = N_Subprogram_Declaration | |
970 and then Present (Body_To_Inline (Decl)) | |
971 then | |
972 return; | |
973 | |
974 -- Subprograms that have return statements in the middle of the body are | |
975 -- inlined with gotos. GNATprove does not currently support gotos, so | |
976 -- we prevent such inlining. | |
977 | |
978 elsif GNATprove_Mode | |
979 and then not Has_Single_Return_In_GNATprove_Mode | |
980 then | |
981 Cannot_Inline ("cannot inline & (multiple returns)?", N, Spec_Id); | |
982 return; | |
983 | |
984 -- Functions that return unconstrained composite types require | |
985 -- secondary stack handling, and cannot currently be inlined, unless | |
986 -- all return statements return a local variable that is the first | |
987 -- local declaration in the body. | |
988 | |
989 elsif Ekind (Spec_Id) = E_Function | |
990 and then not Is_Scalar_Type (Etype (Spec_Id)) | |
991 and then not Is_Access_Type (Etype (Spec_Id)) | |
992 and then not Is_Constrained (Etype (Spec_Id)) | |
993 then | |
994 if not Has_Single_Return (N) then | |
995 Cannot_Inline | |
996 ("cannot inline & (unconstrained return type)?", N, Spec_Id); | |
997 return; | |
998 end if; | |
999 | |
1000 -- Ditto for functions that return controlled types, where controlled | |
1001 -- actions interfere in complex ways with inlining. | |
1002 | |
1003 elsif Ekind (Spec_Id) = E_Function | |
1004 and then Needs_Finalization (Etype (Spec_Id)) | |
1005 then | |
1006 Cannot_Inline | |
1007 ("cannot inline & (controlled return type)?", N, Spec_Id); | |
1008 return; | |
1009 end if; | |
1010 | |
1011 if Present (Declarations (N)) | |
1012 and then Has_Excluded_Declaration (Spec_Id, Declarations (N)) | |
1013 then | |
1014 return; | |
1015 end if; | |
1016 | |
1017 if Present (Handled_Statement_Sequence (N)) then | |
1018 if Present (Exception_Handlers (Handled_Statement_Sequence (N))) then | |
1019 Cannot_Inline | |
1020 ("cannot inline& (exception handler)?", | |
1021 First (Exception_Handlers (Handled_Statement_Sequence (N))), | |
1022 Spec_Id); | |
1023 return; | |
1024 | |
1025 elsif Has_Excluded_Statement | |
1026 (Spec_Id, Statements (Handled_Statement_Sequence (N))) | |
1027 then | |
1028 return; | |
1029 end if; | |
1030 end if; | |
1031 | |
1032 -- We do not inline a subprogram that is too large, unless it is marked | |
1033 -- Inline_Always or we are in GNATprove mode. This pragma does not | |
1034 -- suppress the other checks on inlining (forbidden declarations, | |
1035 -- handlers, etc). | |
1036 | |
1037 if not (Has_Pragma_Inline_Always (Spec_Id) or else GNATprove_Mode) | |
1038 and then List_Length | |
1039 (Statements (Handled_Statement_Sequence (N))) > Max_Size | |
1040 then | |
1041 Cannot_Inline ("cannot inline& (body too large)?", N, Spec_Id); | |
1042 return; | |
1043 end if; | |
1044 | |
1045 if Has_Pending_Instantiation then | |
1046 Cannot_Inline | |
1047 ("cannot inline& (forward instance within enclosing body)?", | |
1048 N, Spec_Id); | |
1049 return; | |
1050 end if; | |
1051 | |
1052 -- Within an instance, the body to inline must be treated as a nested | |
1053 -- generic, so that the proper global references are preserved. | |
1054 | |
1055 -- Note that we do not do this at the library level, because it is not | |
1056 -- needed, and furthermore this causes trouble if front-end inlining | |
1057 -- is activated (-gnatN). | |
1058 | |
1059 if In_Instance and then Scope (Current_Scope) /= Standard_Standard then | |
1060 Save_Env (Scope (Current_Scope), Scope (Current_Scope)); | |
1061 Original_Body := Copy_Generic_Node (N, Empty, Instantiating => True); | |
1062 else | |
1063 Original_Body := Copy_Separate_Tree (N); | |
1064 end if; | |
1065 | |
1066 -- We need to capture references to the formals in order to substitute | |
1067 -- the actuals at the point of inlining, i.e. instantiation. To treat | |
1068 -- the formals as globals to the body to inline, we nest it within a | |
1069 -- dummy parameterless subprogram, declared within the real one. To | |
1070 -- avoid generating an internal name (which is never public, and which | |
1071 -- affects serial numbers of other generated names), we use an internal | |
1072 -- symbol that cannot conflict with user declarations. | |
1073 | |
1074 Set_Parameter_Specifications (Specification (Original_Body), No_List); | |
1075 Set_Defining_Unit_Name | |
1076 (Specification (Original_Body), | |
1077 Make_Defining_Identifier (Sloc (N), Name_uParent)); | |
1078 Set_Corresponding_Spec (Original_Body, Empty); | |
1079 | |
1080 -- Remove all aspects/pragmas that have no meaning in an inlined body | |
1081 | |
1082 Remove_Aspects_And_Pragmas (Original_Body); | |
1083 | |
1084 Body_To_Analyze := | |
1085 Copy_Generic_Node (Original_Body, Empty, Instantiating => False); | |
1086 | |
1087 -- Set return type of function, which is also global and does not need | |
1088 -- to be resolved. | |
1089 | |
1090 if Ekind (Spec_Id) = E_Function then | |
1091 Set_Result_Definition | |
1092 (Specification (Body_To_Analyze), | |
1093 New_Occurrence_Of (Etype (Spec_Id), Sloc (N))); | |
1094 end if; | |
1095 | |
1096 if No (Declarations (N)) then | |
1097 Set_Declarations (N, New_List (Body_To_Analyze)); | |
1098 else | |
1099 Append (Body_To_Analyze, Declarations (N)); | |
1100 end if; | |
1101 | |
1102 -- The body to inline is pre-analyzed. In GNATprove mode we must disable | |
1103 -- full analysis as well so that light expansion does not take place | |
1104 -- either, and name resolution is unaffected. | |
1105 | |
1106 Expander_Mode_Save_And_Set (False); | |
1107 Full_Analysis := False; | |
1108 | |
1109 Analyze (Body_To_Analyze); | |
1110 Push_Scope (Defining_Entity (Body_To_Analyze)); | |
1111 Save_Global_References (Original_Body); | |
1112 End_Scope; | |
1113 Remove (Body_To_Analyze); | |
1114 | |
1115 Expander_Mode_Restore; | |
1116 Full_Analysis := Analysis_Status; | |
1117 | |
1118 -- Restore environment if previously saved | |
1119 | |
1120 if In_Instance and then Scope (Current_Scope) /= Standard_Standard then | |
1121 Restore_Env; | |
1122 end if; | |
1123 | |
1124 -- If secondary stack is used, there is no point in inlining. We have | |
1125 -- already issued the warning in this case, so nothing to do. | |
1126 | |
1127 if Uses_Secondary_Stack (Body_To_Analyze) then | |
1128 return; | |
1129 end if; | |
1130 | |
1131 Set_Body_To_Inline (Decl, Original_Body); | |
1132 Set_Ekind (Defining_Entity (Original_Body), Ekind (Spec_Id)); | |
1133 Set_Is_Inlined (Spec_Id); | |
1134 end Build_Body_To_Inline; | |
1135 | |
1136 ------------------------------------------- | |
1137 -- Call_Can_Be_Inlined_In_GNATprove_Mode -- | |
1138 ------------------------------------------- | |
1139 | |
1140 function Call_Can_Be_Inlined_In_GNATprove_Mode | |
1141 (N : Node_Id; | |
1142 Subp : Entity_Id) return Boolean | |
1143 is | |
1144 F : Entity_Id; | |
1145 A : Node_Id; | |
1146 | |
1147 begin | |
1148 F := First_Formal (Subp); | |
1149 A := First_Actual (N); | |
1150 while Present (F) loop | |
1151 if Ekind (F) /= E_Out_Parameter | |
1152 and then not Same_Type (Etype (F), Etype (A)) | |
1153 and then | |
1154 (Is_By_Reference_Type (Etype (A)) | |
1155 or else Is_Limited_Type (Etype (A))) | |
1156 then | |
1157 return False; | |
1158 end if; | |
1159 | |
1160 Next_Formal (F); | |
1161 Next_Actual (A); | |
1162 end loop; | |
1163 | |
1164 return True; | |
1165 end Call_Can_Be_Inlined_In_GNATprove_Mode; | |
1166 | |
1167 -------------------------------------- | |
1168 -- Can_Be_Inlined_In_GNATprove_Mode -- | |
1169 -------------------------------------- | |
1170 | |
1171 function Can_Be_Inlined_In_GNATprove_Mode | |
1172 (Spec_Id : Entity_Id; | |
1173 Body_Id : Entity_Id) return Boolean | |
1174 is | |
1175 function Has_Formal_With_Discriminant_Dependent_Fields | |
1176 (Id : Entity_Id) return Boolean; | |
1177 -- Returns true if the subprogram has at least one formal parameter of | |
1178 -- an unconstrained record type with per-object constraints on component | |
1179 -- types. | |
1180 | |
1181 function Has_Some_Contract (Id : Entity_Id) return Boolean; | |
1182 -- Return True if subprogram Id has any contract. The presence of | |
1183 -- Extensions_Visible or Volatile_Function is also considered as a | |
1184 -- contract here. | |
1185 | |
1186 function Is_Unit_Subprogram (Id : Entity_Id) return Boolean; | |
1187 -- Return True if subprogram Id defines a compilation unit | |
1188 -- Shouldn't this be in Sem_Aux??? | |
1189 | |
1190 function In_Package_Spec (Id : Entity_Id) return Boolean; | |
1191 -- Return True if subprogram Id is defined in the package specification, | |
1192 -- either its visible or private part. | |
1193 | |
1194 --------------------------------------------------- | |
1195 -- Has_Formal_With_Discriminant_Dependent_Fields -- | |
1196 --------------------------------------------------- | |
1197 | |
1198 function Has_Formal_With_Discriminant_Dependent_Fields | |
1199 (Id : Entity_Id) return Boolean | |
1200 is | |
1201 function Has_Discriminant_Dependent_Component | |
1202 (Typ : Entity_Id) return Boolean; | |
1203 -- Determine whether unconstrained record type Typ has at least one | |
1204 -- component that depends on a discriminant. | |
1205 | |
1206 ------------------------------------------ | |
1207 -- Has_Discriminant_Dependent_Component -- | |
1208 ------------------------------------------ | |
1209 | |
1210 function Has_Discriminant_Dependent_Component | |
1211 (Typ : Entity_Id) return Boolean | |
1212 is | |
1213 Comp : Entity_Id; | |
1214 | |
1215 begin | |
1216 -- Inspect all components of the record type looking for one that | |
1217 -- depends on a discriminant. | |
1218 | |
1219 Comp := First_Component (Typ); | |
1220 while Present (Comp) loop | |
1221 if Has_Discriminant_Dependent_Constraint (Comp) then | |
1222 return True; | |
1223 end if; | |
1224 | |
1225 Next_Component (Comp); | |
1226 end loop; | |
1227 | |
1228 return False; | |
1229 end Has_Discriminant_Dependent_Component; | |
1230 | |
1231 -- Local variables | |
1232 | |
1233 Subp_Id : constant Entity_Id := Ultimate_Alias (Id); | |
1234 Formal : Entity_Id; | |
1235 Formal_Typ : Entity_Id; | |
1236 | |
1237 -- Start of processing for | |
1238 -- Has_Formal_With_Discriminant_Dependent_Fields | |
1239 | |
1240 begin | |
1241 -- Inspect all parameters of the subprogram looking for a formal | |
1242 -- of an unconstrained record type with at least one discriminant | |
1243 -- dependent component. | |
1244 | |
1245 Formal := First_Formal (Subp_Id); | |
1246 while Present (Formal) loop | |
1247 Formal_Typ := Etype (Formal); | |
1248 | |
1249 if Is_Record_Type (Formal_Typ) | |
1250 and then not Is_Constrained (Formal_Typ) | |
1251 and then Has_Discriminant_Dependent_Component (Formal_Typ) | |
1252 then | |
1253 return True; | |
1254 end if; | |
1255 | |
1256 Next_Formal (Formal); | |
1257 end loop; | |
1258 | |
1259 return False; | |
1260 end Has_Formal_With_Discriminant_Dependent_Fields; | |
1261 | |
1262 ----------------------- | |
1263 -- Has_Some_Contract -- | |
1264 ----------------------- | |
1265 | |
1266 function Has_Some_Contract (Id : Entity_Id) return Boolean is | |
1267 Items : Node_Id; | |
1268 | |
1269 begin | |
1270 -- A call to an expression function may precede the actual body which | |
1271 -- is inserted at the end of the enclosing declarations. Ensure that | |
1272 -- the related entity is decorated before inspecting the contract. | |
1273 | |
1274 if Is_Subprogram_Or_Generic_Subprogram (Id) then | |
1275 Items := Contract (Id); | |
1276 | |
1277 -- Note that Classifications is not Empty when Extensions_Visible | |
1278 -- or Volatile_Function is present, which causes such subprograms | |
1279 -- to be considered to have a contract here. This is fine as we | |
1280 -- want to avoid inlining these too. | |
1281 | |
1282 return Present (Items) | |
1283 and then (Present (Pre_Post_Conditions (Items)) or else | |
1284 Present (Contract_Test_Cases (Items)) or else | |
1285 Present (Classifications (Items))); | |
1286 end if; | |
1287 | |
1288 return False; | |
1289 end Has_Some_Contract; | |
1290 | |
1291 --------------------- | |
1292 -- In_Package_Spec -- | |
1293 --------------------- | |
1294 | |
1295 function In_Package_Spec (Id : Entity_Id) return Boolean is | |
1296 P : constant Node_Id := Parent (Subprogram_Spec (Id)); | |
1297 -- Parent of the subprogram's declaration | |
1298 | |
1299 begin | |
1300 return Nkind (Enclosing_Declaration (P)) = N_Package_Declaration; | |
1301 end In_Package_Spec; | |
1302 | |
1303 ------------------------ | |
1304 -- Is_Unit_Subprogram -- | |
1305 ------------------------ | |
1306 | |
1307 function Is_Unit_Subprogram (Id : Entity_Id) return Boolean is | |
1308 Decl : Node_Id := Parent (Parent (Id)); | |
1309 begin | |
1310 if Nkind (Parent (Id)) = N_Defining_Program_Unit_Name then | |
1311 Decl := Parent (Decl); | |
1312 end if; | |
1313 | |
1314 return Nkind (Parent (Decl)) = N_Compilation_Unit; | |
1315 end Is_Unit_Subprogram; | |
1316 | |
1317 -- Local declarations | |
1318 | |
1319 Id : Entity_Id; | |
1320 -- Procedure or function entity for the subprogram | |
1321 | |
1322 -- Start of processing for Can_Be_Inlined_In_GNATprove_Mode | |
1323 | |
1324 begin | |
1325 pragma Assert (Present (Spec_Id) or else Present (Body_Id)); | |
1326 | |
1327 if Present (Spec_Id) then | |
1328 Id := Spec_Id; | |
1329 else | |
1330 Id := Body_Id; | |
1331 end if; | |
1332 | |
1333 -- Only local subprograms without contracts are inlined in GNATprove | |
1334 -- mode, as these are the subprograms which a user is not interested in | |
1335 -- analyzing in isolation, but rather in the context of their call. This | |
1336 -- is a convenient convention, that could be changed for an explicit | |
1337 -- pragma/aspect one day. | |
1338 | |
1339 -- In a number of special cases, inlining is not desirable or not | |
1340 -- possible, see below. | |
1341 | |
1342 -- Do not inline unit-level subprograms | |
1343 | |
1344 if Is_Unit_Subprogram (Id) then | |
1345 return False; | |
1346 | |
1347 -- Do not inline subprograms declared in package specs, because they are | |
1348 -- not local, i.e. can be called either from anywhere (if declared in | |
1349 -- visible part) or from the child units (if declared in private part). | |
1350 | |
1351 elsif In_Package_Spec (Id) then | |
1352 return False; | |
1353 | |
1354 -- Do not inline subprograms declared in other units. This is important | |
1355 -- in particular for subprograms defined in the private part of a | |
1356 -- package spec, when analyzing one of its child packages, as otherwise | |
1357 -- we issue spurious messages about the impossibility to inline such | |
1358 -- calls. | |
1359 | |
1360 elsif not In_Extended_Main_Code_Unit (Id) then | |
1361 return False; | |
1362 | |
1363 -- Do not inline subprograms marked No_Return, possibly used for | |
1364 -- signaling errors, which GNATprove handles specially. | |
1365 | |
1366 elsif No_Return (Id) then | |
1367 return False; | |
1368 | |
1369 -- Do not inline subprograms that have a contract on the spec or the | |
1370 -- body. Use the contract(s) instead in GNATprove. This also prevents | |
1371 -- inlining of subprograms with Extensions_Visible or Volatile_Function. | |
1372 | |
1373 elsif (Present (Spec_Id) and then Has_Some_Contract (Spec_Id)) | |
1374 or else | |
1375 (Present (Body_Id) and then Has_Some_Contract (Body_Id)) | |
1376 then | |
1377 return False; | |
1378 | |
1379 -- Do not inline expression functions, which are directly inlined at the | |
1380 -- prover level. | |
1381 | |
1382 elsif (Present (Spec_Id) and then Is_Expression_Function (Spec_Id)) | |
1383 or else | |
1384 (Present (Body_Id) and then Is_Expression_Function (Body_Id)) | |
1385 then | |
1386 return False; | |
1387 | |
1388 -- Do not inline generic subprogram instances. The visibility rules of | |
1389 -- generic instances plays badly with inlining. | |
1390 | |
1391 elsif Is_Generic_Instance (Spec_Id) then | |
1392 return False; | |
1393 | |
1394 -- Only inline subprograms whose spec is marked SPARK_Mode On. For | |
1395 -- the subprogram body, a similar check is performed after the body | |
1396 -- is analyzed, as this is where a pragma SPARK_Mode might be inserted. | |
1397 | |
1398 elsif Present (Spec_Id) | |
1399 and then | |
1400 (No (SPARK_Pragma (Spec_Id)) | |
1401 or else | |
1402 Get_SPARK_Mode_From_Annotation (SPARK_Pragma (Spec_Id)) /= On) | |
1403 then | |
1404 return False; | |
1405 | |
1406 -- Subprograms in generic instances are currently not inlined, to avoid | |
1407 -- problems with inlining of standard library subprograms. | |
1408 | |
1409 elsif Instantiation_Location (Sloc (Id)) /= No_Location then | |
1410 return False; | |
1411 | |
1412 -- Do not inline subprograms and entries defined inside protected types, | |
1413 -- which typically are not helper subprograms, which also avoids getting | |
1414 -- spurious messages on calls that cannot be inlined. | |
1415 | |
1416 elsif Within_Protected_Type (Id) then | |
1417 return False; | |
1418 | |
1419 -- Do not inline predicate functions (treated specially by GNATprove) | |
1420 | |
1421 elsif Is_Predicate_Function (Id) then | |
1422 return False; | |
1423 | |
1424 -- Do not inline subprograms with a parameter of an unconstrained | |
1425 -- record type if it has discrimiant dependent fields. Indeed, with | |
1426 -- such parameters, the frontend cannot always ensure type compliance | |
1427 -- in record component accesses (in particular with records containing | |
1428 -- packed arrays). | |
1429 | |
1430 elsif Has_Formal_With_Discriminant_Dependent_Fields (Id) then | |
1431 return False; | |
1432 | |
1433 -- Otherwise, this is a subprogram declared inside the private part of a | |
1434 -- package, or inside a package body, or locally in a subprogram, and it | |
1435 -- does not have any contract. Inline it. | |
1436 | |
1437 else | |
1438 return True; | |
1439 end if; | |
1440 end Can_Be_Inlined_In_GNATprove_Mode; | |
1441 | |
1442 ------------------- | |
1443 -- Cannot_Inline -- | |
1444 ------------------- | |
1445 | |
1446 procedure Cannot_Inline | |
1447 (Msg : String; | |
1448 N : Node_Id; | |
1449 Subp : Entity_Id; | |
1450 Is_Serious : Boolean := False) | |
1451 is | |
1452 begin | |
1453 -- In GNATprove mode, inlining is the technical means by which the | |
1454 -- higher-level goal of contextual analysis is reached, so issue | |
1455 -- messages about failure to apply contextual analysis to a | |
1456 -- subprogram, rather than failure to inline it. | |
1457 | |
1458 if GNATprove_Mode | |
1459 and then Msg (Msg'First .. Msg'First + 12) = "cannot inline" | |
1460 then | |
1461 declare | |
1462 Len1 : constant Positive := | |
1463 String (String'("cannot inline"))'Length; | |
1464 Len2 : constant Positive := | |
1465 String (String'("info: no contextual analysis of"))'Length; | |
1466 | |
1467 New_Msg : String (1 .. Msg'Length + Len2 - Len1); | |
1468 | |
1469 begin | |
1470 New_Msg (1 .. Len2) := "info: no contextual analysis of"; | |
1471 New_Msg (Len2 + 1 .. Msg'Length + Len2 - Len1) := | |
1472 Msg (Msg'First + Len1 .. Msg'Last); | |
1473 Cannot_Inline (New_Msg, N, Subp, Is_Serious); | |
1474 return; | |
1475 end; | |
1476 end if; | |
1477 | |
1478 pragma Assert (Msg (Msg'Last) = '?'); | |
1479 | |
1480 -- Legacy front-end inlining model | |
1481 | |
1482 if not Back_End_Inlining then | |
1483 | |
1484 -- Do not emit warning if this is a predefined unit which is not | |
1485 -- the main unit. With validity checks enabled, some predefined | |
1486 -- subprograms may contain nested subprograms and become ineligible | |
1487 -- for inlining. | |
1488 | |
1489 if Is_Predefined_Unit (Get_Source_Unit (Subp)) | |
1490 and then not In_Extended_Main_Source_Unit (Subp) | |
1491 then | |
1492 null; | |
1493 | |
1494 -- In GNATprove mode, issue a warning, and indicate that the | |
1495 -- subprogram is not always inlined by setting flag Is_Inlined_Always | |
1496 -- to False. | |
1497 | |
1498 elsif GNATprove_Mode then | |
1499 Set_Is_Inlined_Always (Subp, False); | |
1500 Error_Msg_NE (Msg & "p?", N, Subp); | |
1501 | |
1502 elsif Has_Pragma_Inline_Always (Subp) then | |
1503 | |
1504 -- Remove last character (question mark) to make this into an | |
1505 -- error, because the Inline_Always pragma cannot be obeyed. | |
1506 | |
1507 Error_Msg_NE (Msg (Msg'First .. Msg'Last - 1), N, Subp); | |
1508 | |
1509 elsif Ineffective_Inline_Warnings then | |
1510 Error_Msg_NE (Msg & "p?", N, Subp); | |
1511 end if; | |
1512 | |
1513 -- New semantics relying on back-end inlining | |
1514 | |
1515 elsif Is_Serious then | |
1516 | |
1517 -- Remove last character (question mark) to make this into an error. | |
1518 | |
1519 Error_Msg_NE (Msg (Msg'First .. Msg'Last - 1), N, Subp); | |
1520 | |
1521 -- In GNATprove mode, issue a warning, and indicate that the subprogram | |
1522 -- is not always inlined by setting flag Is_Inlined_Always to False. | |
1523 | |
1524 elsif GNATprove_Mode then | |
1525 Set_Is_Inlined_Always (Subp, False); | |
1526 Error_Msg_NE (Msg & "p?", N, Subp); | |
1527 | |
1528 else | |
1529 | |
1530 -- Do not emit warning if this is a predefined unit which is not | |
1531 -- the main unit. This behavior is currently provided for backward | |
1532 -- compatibility but it will be removed when we enforce the | |
1533 -- strictness of the new rules. | |
1534 | |
1535 if Is_Predefined_Unit (Get_Source_Unit (Subp)) | |
1536 and then not In_Extended_Main_Source_Unit (Subp) | |
1537 then | |
1538 null; | |
1539 | |
1540 elsif Has_Pragma_Inline_Always (Subp) then | |
1541 | |
1542 -- Emit a warning if this is a call to a runtime subprogram | |
1543 -- which is located inside a generic. Previously this call | |
1544 -- was silently skipped. | |
1545 | |
1546 if Is_Generic_Instance (Subp) then | |
1547 declare | |
1548 Gen_P : constant Entity_Id := Generic_Parent (Parent (Subp)); | |
1549 begin | |
1550 if Is_Predefined_Unit (Get_Source_Unit (Gen_P)) then | |
1551 Set_Is_Inlined (Subp, False); | |
1552 Error_Msg_NE (Msg & "p?", N, Subp); | |
1553 return; | |
1554 end if; | |
1555 end; | |
1556 end if; | |
1557 | |
1558 -- Remove last character (question mark) to make this into an | |
1559 -- error, because the Inline_Always pragma cannot be obeyed. | |
1560 | |
1561 Error_Msg_NE (Msg (Msg'First .. Msg'Last - 1), N, Subp); | |
1562 | |
1563 else | |
1564 Set_Is_Inlined (Subp, False); | |
1565 | |
1566 if Ineffective_Inline_Warnings then | |
1567 Error_Msg_NE (Msg & "p?", N, Subp); | |
1568 end if; | |
1569 end if; | |
1570 end if; | |
1571 end Cannot_Inline; | |
1572 | |
1573 -------------------------------------------- | |
1574 -- Check_And_Split_Unconstrained_Function -- | |
1575 -------------------------------------------- | |
1576 | |
1577 procedure Check_And_Split_Unconstrained_Function | |
1578 (N : Node_Id; | |
1579 Spec_Id : Entity_Id; | |
1580 Body_Id : Entity_Id) | |
1581 is | |
1582 procedure Build_Body_To_Inline (N : Node_Id; Spec_Id : Entity_Id); | |
1583 -- Use generic machinery to build an unexpanded body for the subprogram. | |
1584 -- This body is subsequently used for inline expansions at call sites. | |
1585 | |
1586 function Can_Split_Unconstrained_Function (N : Node_Id) return Boolean; | |
1587 -- Return true if we generate code for the function body N, the function | |
1588 -- body N has no local declarations and its unique statement is a single | |
1589 -- extended return statement with a handled statements sequence. | |
1590 | |
1591 procedure Split_Unconstrained_Function | |
1592 (N : Node_Id; | |
1593 Spec_Id : Entity_Id); | |
1594 -- N is an inlined function body that returns an unconstrained type and | |
1595 -- has a single extended return statement. Split N in two subprograms: | |
1596 -- a procedure P' and a function F'. The formals of P' duplicate the | |
1597 -- formals of N plus an extra formal which is used to return a value; | |
1598 -- its body is composed by the declarations and list of statements | |
1599 -- of the extended return statement of N. | |
1600 | |
1601 -------------------------- | |
1602 -- Build_Body_To_Inline -- | |
1603 -------------------------- | |
1604 | |
1605 procedure Build_Body_To_Inline (N : Node_Id; Spec_Id : Entity_Id) is | |
1606 procedure Generate_Subprogram_Body | |
1607 (N : Node_Id; | |
1608 Body_To_Inline : out Node_Id); | |
1609 -- Generate a parameterless duplicate of subprogram body N. Note that | |
1610 -- occurrences of pragmas referencing the formals are removed since | |
1611 -- they have no meaning when the body is inlined and the formals are | |
1612 -- rewritten (the analysis of the non-inlined body will handle these | |
1613 -- pragmas). A new internal name is associated with Body_To_Inline. | |
1614 | |
1615 ----------------------------- | |
1616 -- Generate_Body_To_Inline -- | |
1617 ----------------------------- | |
1618 | |
1619 procedure Generate_Subprogram_Body | |
1620 (N : Node_Id; | |
1621 Body_To_Inline : out Node_Id) | |
1622 is | |
1623 begin | |
1624 -- Within an instance, the body to inline must be treated as a | |
1625 -- nested generic so that proper global references are preserved. | |
1626 | |
1627 -- Note that we do not do this at the library level, because it | |
1628 -- is not needed, and furthermore this causes trouble if front | |
1629 -- end inlining is activated (-gnatN). | |
1630 | |
1631 if In_Instance | |
1632 and then Scope (Current_Scope) /= Standard_Standard | |
1633 then | |
1634 Body_To_Inline := | |
1635 Copy_Generic_Node (N, Empty, Instantiating => True); | |
1636 else | |
1637 Body_To_Inline := Copy_Separate_Tree (N); | |
1638 end if; | |
1639 | |
1640 -- Remove aspects/pragmas that have no meaning in an inlined body | |
1641 | |
1642 Remove_Aspects_And_Pragmas (Body_To_Inline); | |
1643 | |
1644 -- We need to capture references to the formals in order | |
1645 -- to substitute the actuals at the point of inlining, i.e. | |
1646 -- instantiation. To treat the formals as globals to the body to | |
1647 -- inline, we nest it within a dummy parameterless subprogram, | |
1648 -- declared within the real one. | |
1649 | |
1650 Set_Parameter_Specifications | |
1651 (Specification (Body_To_Inline), No_List); | |
1652 | |
1653 -- A new internal name is associated with Body_To_Inline to avoid | |
1654 -- conflicts when the non-inlined body N is analyzed. | |
1655 | |
1656 Set_Defining_Unit_Name (Specification (Body_To_Inline), | |
1657 Make_Defining_Identifier (Sloc (N), New_Internal_Name ('P'))); | |
1658 Set_Corresponding_Spec (Body_To_Inline, Empty); | |
1659 end Generate_Subprogram_Body; | |
1660 | |
1661 -- Local variables | |
1662 | |
1663 Decl : constant Node_Id := Unit_Declaration_Node (Spec_Id); | |
1664 Original_Body : Node_Id; | |
1665 Body_To_Analyze : Node_Id; | |
1666 | |
1667 begin | |
1668 pragma Assert (Current_Scope = Spec_Id); | |
1669 | |
1670 -- Within an instance, the body to inline must be treated as a nested | |
1671 -- generic, so that the proper global references are preserved. We | |
1672 -- do not do this at the library level, because it is not needed, and | |
1673 -- furthermore this causes trouble if front-end inlining is activated | |
1674 -- (-gnatN). | |
1675 | |
1676 if In_Instance | |
1677 and then Scope (Current_Scope) /= Standard_Standard | |
1678 then | |
1679 Save_Env (Scope (Current_Scope), Scope (Current_Scope)); | |
1680 end if; | |
1681 | |
1682 -- Capture references to formals in order to substitute the actuals | |
1683 -- at the point of inlining or instantiation. To treat the formals | |
1684 -- as globals to the body to inline, nest the body within a dummy | |
1685 -- parameterless subprogram, declared within the real one. | |
1686 | |
1687 Generate_Subprogram_Body (N, Original_Body); | |
1688 Body_To_Analyze := | |
1689 Copy_Generic_Node (Original_Body, Empty, Instantiating => False); | |
1690 | |
1691 -- Set return type of function, which is also global and does not | |
1692 -- need to be resolved. | |
1693 | |
1694 if Ekind (Spec_Id) = E_Function then | |
1695 Set_Result_Definition (Specification (Body_To_Analyze), | |
1696 New_Occurrence_Of (Etype (Spec_Id), Sloc (N))); | |
1697 end if; | |
1698 | |
1699 if No (Declarations (N)) then | |
1700 Set_Declarations (N, New_List (Body_To_Analyze)); | |
1701 else | |
1702 Append_To (Declarations (N), Body_To_Analyze); | |
1703 end if; | |
1704 | |
1705 Preanalyze (Body_To_Analyze); | |
1706 | |
1707 Push_Scope (Defining_Entity (Body_To_Analyze)); | |
1708 Save_Global_References (Original_Body); | |
1709 End_Scope; | |
1710 Remove (Body_To_Analyze); | |
1711 | |
1712 -- Restore environment if previously saved | |
1713 | |
1714 if In_Instance | |
1715 and then Scope (Current_Scope) /= Standard_Standard | |
1716 then | |
1717 Restore_Env; | |
1718 end if; | |
1719 | |
1720 pragma Assert (No (Body_To_Inline (Decl))); | |
1721 Set_Body_To_Inline (Decl, Original_Body); | |
1722 Set_Ekind (Defining_Entity (Original_Body), Ekind (Spec_Id)); | |
1723 end Build_Body_To_Inline; | |
1724 | |
1725 -------------------------------------- | |
1726 -- Can_Split_Unconstrained_Function -- | |
1727 -------------------------------------- | |
1728 | |
1729 function Can_Split_Unconstrained_Function (N : Node_Id) return Boolean is | |
1730 Ret_Node : constant Node_Id := | |
1731 First (Statements (Handled_Statement_Sequence (N))); | |
1732 D : Node_Id; | |
1733 | |
1734 begin | |
1735 -- No user defined declarations allowed in the function except inside | |
1736 -- the unique return statement; implicit labels are the only allowed | |
1737 -- declarations. | |
1738 | |
1739 if not Is_Empty_List (Declarations (N)) then | |
1740 D := First (Declarations (N)); | |
1741 while Present (D) loop | |
1742 if Nkind (D) /= N_Implicit_Label_Declaration then | |
1743 return False; | |
1744 end if; | |
1745 | |
1746 Next (D); | |
1747 end loop; | |
1748 end if; | |
1749 | |
1750 -- We only split the inlined function when we are generating the code | |
1751 -- of its body; otherwise we leave duplicated split subprograms in | |
1752 -- the tree which (if referenced) generate wrong references at link | |
1753 -- time. | |
1754 | |
1755 return In_Extended_Main_Code_Unit (N) | |
1756 and then Present (Ret_Node) | |
1757 and then Nkind (Ret_Node) = N_Extended_Return_Statement | |
1758 and then No (Next (Ret_Node)) | |
1759 and then Present (Handled_Statement_Sequence (Ret_Node)); | |
1760 end Can_Split_Unconstrained_Function; | |
1761 | |
1762 ---------------------------------- | |
1763 -- Split_Unconstrained_Function -- | |
1764 ---------------------------------- | |
1765 | |
1766 procedure Split_Unconstrained_Function | |
1767 (N : Node_Id; | |
1768 Spec_Id : Entity_Id) | |
1769 is | |
1770 Loc : constant Source_Ptr := Sloc (N); | |
1771 Ret_Node : constant Node_Id := | |
1772 First (Statements (Handled_Statement_Sequence (N))); | |
1773 Ret_Obj : constant Node_Id := | |
1774 First (Return_Object_Declarations (Ret_Node)); | |
1775 | |
1776 procedure Build_Procedure | |
1777 (Proc_Id : out Entity_Id; | |
1778 Decl_List : out List_Id); | |
1779 -- Build a procedure containing the statements found in the extended | |
1780 -- return statement of the unconstrained function body N. | |
1781 | |
1782 --------------------- | |
1783 -- Build_Procedure -- | |
1784 --------------------- | |
1785 | |
1786 procedure Build_Procedure | |
1787 (Proc_Id : out Entity_Id; | |
1788 Decl_List : out List_Id) | |
1789 is | |
1790 Formal : Entity_Id; | |
1791 Formal_List : constant List_Id := New_List; | |
1792 Proc_Spec : Node_Id; | |
1793 Proc_Body : Node_Id; | |
1794 Subp_Name : constant Name_Id := New_Internal_Name ('F'); | |
1795 Body_Decl_List : List_Id := No_List; | |
1796 Param_Type : Node_Id; | |
1797 | |
1798 begin | |
1799 if Nkind (Object_Definition (Ret_Obj)) = N_Identifier then | |
1800 Param_Type := | |
1801 New_Copy (Object_Definition (Ret_Obj)); | |
1802 else | |
1803 Param_Type := | |
1804 New_Copy (Subtype_Mark (Object_Definition (Ret_Obj))); | |
1805 end if; | |
1806 | |
1807 Append_To (Formal_List, | |
1808 Make_Parameter_Specification (Loc, | |
1809 Defining_Identifier => | |
1810 Make_Defining_Identifier (Loc, | |
1811 Chars => Chars (Defining_Identifier (Ret_Obj))), | |
1812 In_Present => False, | |
1813 Out_Present => True, | |
1814 Null_Exclusion_Present => False, | |
1815 Parameter_Type => Param_Type)); | |
1816 | |
1817 Formal := First_Formal (Spec_Id); | |
1818 | |
1819 -- Note that we copy the parameter type rather than creating | |
1820 -- a reference to it, because it may be a class-wide entity | |
1821 -- that will not be retrieved by name. | |
1822 | |
1823 while Present (Formal) loop | |
1824 Append_To (Formal_List, | |
1825 Make_Parameter_Specification (Loc, | |
1826 Defining_Identifier => | |
1827 Make_Defining_Identifier (Sloc (Formal), | |
1828 Chars => Chars (Formal)), | |
1829 In_Present => In_Present (Parent (Formal)), | |
1830 Out_Present => Out_Present (Parent (Formal)), | |
1831 Null_Exclusion_Present => | |
1832 Null_Exclusion_Present (Parent (Formal)), | |
1833 Parameter_Type => | |
1834 New_Copy_Tree (Parameter_Type (Parent (Formal))), | |
1835 Expression => | |
1836 Copy_Separate_Tree (Expression (Parent (Formal))))); | |
1837 | |
1838 Next_Formal (Formal); | |
1839 end loop; | |
1840 | |
1841 Proc_Id := Make_Defining_Identifier (Loc, Chars => Subp_Name); | |
1842 | |
1843 Proc_Spec := | |
1844 Make_Procedure_Specification (Loc, | |
1845 Defining_Unit_Name => Proc_Id, | |
1846 Parameter_Specifications => Formal_List); | |
1847 | |
1848 Decl_List := New_List; | |
1849 | |
1850 Append_To (Decl_List, | |
1851 Make_Subprogram_Declaration (Loc, Proc_Spec)); | |
1852 | |
1853 -- Can_Convert_Unconstrained_Function checked that the function | |
1854 -- has no local declarations except implicit label declarations. | |
1855 -- Copy these declarations to the built procedure. | |
1856 | |
1857 if Present (Declarations (N)) then | |
1858 Body_Decl_List := New_List; | |
1859 | |
1860 declare | |
1861 D : Node_Id; | |
1862 New_D : Node_Id; | |
1863 | |
1864 begin | |
1865 D := First (Declarations (N)); | |
1866 while Present (D) loop | |
1867 pragma Assert (Nkind (D) = N_Implicit_Label_Declaration); | |
1868 | |
1869 New_D := | |
1870 Make_Implicit_Label_Declaration (Loc, | |
1871 Make_Defining_Identifier (Loc, | |
1872 Chars => Chars (Defining_Identifier (D))), | |
1873 Label_Construct => Empty); | |
1874 Append_To (Body_Decl_List, New_D); | |
1875 | |
1876 Next (D); | |
1877 end loop; | |
1878 end; | |
1879 end if; | |
1880 | |
1881 pragma Assert (Present (Handled_Statement_Sequence (Ret_Node))); | |
1882 | |
1883 Proc_Body := | |
1884 Make_Subprogram_Body (Loc, | |
1885 Specification => Copy_Separate_Tree (Proc_Spec), | |
1886 Declarations => Body_Decl_List, | |
1887 Handled_Statement_Sequence => | |
1888 Copy_Separate_Tree (Handled_Statement_Sequence (Ret_Node))); | |
1889 | |
1890 Set_Defining_Unit_Name (Specification (Proc_Body), | |
1891 Make_Defining_Identifier (Loc, Subp_Name)); | |
1892 | |
1893 Append_To (Decl_List, Proc_Body); | |
1894 end Build_Procedure; | |
1895 | |
1896 -- Local variables | |
1897 | |
1898 New_Obj : constant Node_Id := Copy_Separate_Tree (Ret_Obj); | |
1899 Blk_Stmt : Node_Id; | |
1900 Proc_Id : Entity_Id; | |
1901 Proc_Call : Node_Id; | |
1902 | |
1903 -- Start of processing for Split_Unconstrained_Function | |
1904 | |
1905 begin | |
1906 -- Build the associated procedure, analyze it and insert it before | |
1907 -- the function body N. | |
1908 | |
1909 declare | |
1910 Scope : constant Entity_Id := Current_Scope; | |
1911 Decl_List : List_Id; | |
1912 begin | |
1913 Pop_Scope; | |
1914 Build_Procedure (Proc_Id, Decl_List); | |
1915 Insert_Actions (N, Decl_List); | |
1916 Set_Is_Inlined (Proc_Id); | |
1917 Push_Scope (Scope); | |
1918 end; | |
1919 | |
1920 -- Build the call to the generated procedure | |
1921 | |
1922 declare | |
1923 Actual_List : constant List_Id := New_List; | |
1924 Formal : Entity_Id; | |
1925 | |
1926 begin | |
1927 Append_To (Actual_List, | |
1928 New_Occurrence_Of (Defining_Identifier (New_Obj), Loc)); | |
1929 | |
1930 Formal := First_Formal (Spec_Id); | |
1931 while Present (Formal) loop | |
1932 Append_To (Actual_List, New_Occurrence_Of (Formal, Loc)); | |
1933 | |
1934 -- Avoid spurious warning on unreferenced formals | |
1935 | |
1936 Set_Referenced (Formal); | |
1937 Next_Formal (Formal); | |
1938 end loop; | |
1939 | |
1940 Proc_Call := | |
1941 Make_Procedure_Call_Statement (Loc, | |
1942 Name => New_Occurrence_Of (Proc_Id, Loc), | |
1943 Parameter_Associations => Actual_List); | |
1944 end; | |
1945 | |
1946 -- Generate: | |
1947 | |
1948 -- declare | |
1949 -- New_Obj : ... | |
1950 -- begin | |
1951 -- Proc (New_Obj, ...); | |
1952 -- return New_Obj; | |
1953 -- end; | |
1954 | |
1955 Blk_Stmt := | |
1956 Make_Block_Statement (Loc, | |
1957 Declarations => New_List (New_Obj), | |
1958 Handled_Statement_Sequence => | |
1959 Make_Handled_Sequence_Of_Statements (Loc, | |
1960 Statements => New_List ( | |
1961 | |
1962 Proc_Call, | |
1963 | |
1964 Make_Simple_Return_Statement (Loc, | |
1965 Expression => | |
1966 New_Occurrence_Of | |
1967 (Defining_Identifier (New_Obj), Loc))))); | |
1968 | |
1969 Rewrite (Ret_Node, Blk_Stmt); | |
1970 end Split_Unconstrained_Function; | |
1971 | |
1972 -- Local variables | |
1973 | |
1974 Decl : constant Node_Id := Unit_Declaration_Node (Spec_Id); | |
1975 | |
1976 -- Start of processing for Check_And_Split_Unconstrained_Function | |
1977 | |
1978 begin | |
1979 pragma Assert (Back_End_Inlining | |
1980 and then Ekind (Spec_Id) = E_Function | |
1981 and then Returns_Unconstrained_Type (Spec_Id) | |
1982 and then Comes_From_Source (Body_Id) | |
1983 and then (Has_Pragma_Inline_Always (Spec_Id) | |
1984 or else Optimization_Level > 0)); | |
1985 | |
1986 -- This routine must not be used in GNATprove mode since GNATprove | |
1987 -- relies on frontend inlining | |
1988 | |
1989 pragma Assert (not GNATprove_Mode); | |
1990 | |
1991 -- No need to split the function if we cannot generate the code | |
1992 | |
1993 if Serious_Errors_Detected /= 0 then | |
1994 return; | |
1995 end if; | |
1996 | |
1997 -- No action needed in stubs since the attribute Body_To_Inline | |
1998 -- is not available | |
1999 | |
2000 if Nkind (Decl) = N_Subprogram_Body_Stub then | |
2001 return; | |
2002 | |
2003 -- Cannot build the body to inline if the attribute is already set. | |
2004 -- This attribute may have been set if this is a subprogram renaming | |
2005 -- declarations (see Freeze.Build_Renamed_Body). | |
2006 | |
2007 elsif Present (Body_To_Inline (Decl)) then | |
2008 return; | |
2009 | |
2010 -- Check excluded declarations | |
2011 | |
2012 elsif Present (Declarations (N)) | |
2013 and then Has_Excluded_Declaration (Spec_Id, Declarations (N)) | |
2014 then | |
2015 return; | |
2016 | |
2017 -- Check excluded statements. There is no need to protect us against | |
2018 -- exception handlers since they are supported by the GCC backend. | |
2019 | |
2020 elsif Present (Handled_Statement_Sequence (N)) | |
2021 and then Has_Excluded_Statement | |
2022 (Spec_Id, Statements (Handled_Statement_Sequence (N))) | |
2023 then | |
2024 return; | |
2025 end if; | |
2026 | |
2027 -- Build the body to inline only if really needed | |
2028 | |
2029 if Can_Split_Unconstrained_Function (N) then | |
2030 Split_Unconstrained_Function (N, Spec_Id); | |
2031 Build_Body_To_Inline (N, Spec_Id); | |
2032 Set_Is_Inlined (Spec_Id); | |
2033 end if; | |
2034 end Check_And_Split_Unconstrained_Function; | |
2035 | |
2036 ------------------------------------- | |
2037 -- Check_Package_Body_For_Inlining -- | |
2038 ------------------------------------- | |
2039 | |
2040 procedure Check_Package_Body_For_Inlining (N : Node_Id; P : Entity_Id) is | |
2041 Bname : Unit_Name_Type; | |
2042 E : Entity_Id; | |
2043 OK : Boolean; | |
2044 | |
2045 begin | |
2046 -- Legacy implementation (relying on frontend inlining) | |
2047 | |
2048 if not Back_End_Inlining | |
2049 and then Is_Compilation_Unit (P) | |
2050 and then not Is_Generic_Instance (P) | |
2051 then | |
2052 Bname := Get_Body_Name (Get_Unit_Name (Unit (N))); | |
2053 | |
2054 E := First_Entity (P); | |
2055 while Present (E) loop | |
2056 if Has_Pragma_Inline_Always (E) | |
2057 or else (Has_Pragma_Inline (E) and Front_End_Inlining) | |
2058 then | |
2059 if not Is_Loaded (Bname) then | |
2060 Load_Needed_Body (N, OK); | |
2061 | |
2062 if OK then | |
2063 | |
2064 -- Check we are not trying to inline a parent whose body | |
2065 -- depends on a child, when we are compiling the body of | |
2066 -- the child. Otherwise we have a potential elaboration | |
2067 -- circularity with inlined subprograms and with | |
2068 -- Taft-Amendment types. | |
2069 | |
2070 declare | |
2071 Comp : Node_Id; -- Body just compiled | |
2072 Child_Spec : Entity_Id; -- Spec of main unit | |
2073 Ent : Entity_Id; -- For iteration | |
2074 With_Clause : Node_Id; -- Context of body. | |
2075 | |
2076 begin | |
2077 if Nkind (Unit (Cunit (Main_Unit))) = N_Package_Body | |
2078 and then Present (Body_Entity (P)) | |
2079 then | |
2080 Child_Spec := | |
2081 Defining_Entity | |
2082 ((Unit (Library_Unit (Cunit (Main_Unit))))); | |
2083 | |
2084 Comp := | |
2085 Parent (Unit_Declaration_Node (Body_Entity (P))); | |
2086 | |
2087 -- Check whether the context of the body just | |
2088 -- compiled includes a child of itself, and that | |
2089 -- child is the spec of the main compilation. | |
2090 | |
2091 With_Clause := First (Context_Items (Comp)); | |
2092 while Present (With_Clause) loop | |
2093 if Nkind (With_Clause) = N_With_Clause | |
2094 and then | |
2095 Scope (Entity (Name (With_Clause))) = P | |
2096 and then | |
2097 Entity (Name (With_Clause)) = Child_Spec | |
2098 then | |
2099 Error_Msg_Node_2 := Child_Spec; | |
2100 Error_Msg_NE | |
2101 ("body of & depends on child unit&??", | |
2102 With_Clause, P); | |
2103 Error_Msg_N | |
2104 ("\subprograms in body cannot be inlined??", | |
2105 With_Clause); | |
2106 | |
2107 -- Disable further inlining from this unit, | |
2108 -- and keep Taft-amendment types incomplete. | |
2109 | |
2110 Ent := First_Entity (P); | |
2111 while Present (Ent) loop | |
2112 if Is_Type (Ent) | |
2113 and then Has_Completion_In_Body (Ent) | |
2114 then | |
2115 Set_Full_View (Ent, Empty); | |
2116 | |
2117 elsif Is_Subprogram (Ent) then | |
2118 Set_Is_Inlined (Ent, False); | |
2119 end if; | |
2120 | |
2121 Next_Entity (Ent); | |
2122 end loop; | |
2123 | |
2124 return; | |
2125 end if; | |
2126 | |
2127 Next (With_Clause); | |
2128 end loop; | |
2129 end if; | |
2130 end; | |
2131 | |
2132 elsif Ineffective_Inline_Warnings then | |
2133 Error_Msg_Unit_1 := Bname; | |
2134 Error_Msg_N | |
2135 ("unable to inline subprograms defined in $??", P); | |
2136 Error_Msg_N ("\body not found??", P); | |
2137 return; | |
2138 end if; | |
2139 end if; | |
2140 | |
2141 return; | |
2142 end if; | |
2143 | |
2144 Next_Entity (E); | |
2145 end loop; | |
2146 end if; | |
2147 end Check_Package_Body_For_Inlining; | |
2148 | |
2149 -------------------- | |
2150 -- Cleanup_Scopes -- | |
2151 -------------------- | |
2152 | |
2153 procedure Cleanup_Scopes is | |
2154 Elmt : Elmt_Id; | |
2155 Decl : Node_Id; | |
2156 Scop : Entity_Id; | |
2157 | |
2158 begin | |
2159 Elmt := First_Elmt (To_Clean); | |
2160 while Present (Elmt) loop | |
2161 Scop := Node (Elmt); | |
2162 | |
2163 if Ekind (Scop) = E_Entry then | |
2164 Scop := Protected_Body_Subprogram (Scop); | |
2165 | |
2166 elsif Is_Subprogram (Scop) | |
2167 and then Is_Protected_Type (Scope (Scop)) | |
2168 and then Present (Protected_Body_Subprogram (Scop)) | |
2169 then | |
2170 -- If a protected operation contains an instance, its cleanup | |
2171 -- operations have been delayed, and the subprogram has been | |
2172 -- rewritten in the expansion of the enclosing protected body. It | |
2173 -- is the corresponding subprogram that may require the cleanup | |
2174 -- operations, so propagate the information that triggers cleanup | |
2175 -- activity. | |
2176 | |
2177 Set_Uses_Sec_Stack | |
2178 (Protected_Body_Subprogram (Scop), | |
2179 Uses_Sec_Stack (Scop)); | |
2180 | |
2181 Scop := Protected_Body_Subprogram (Scop); | |
2182 end if; | |
2183 | |
2184 if Ekind (Scop) = E_Block then | |
2185 Decl := Parent (Block_Node (Scop)); | |
2186 | |
2187 else | |
2188 Decl := Unit_Declaration_Node (Scop); | |
2189 | |
2190 if Nkind_In (Decl, N_Subprogram_Declaration, | |
2191 N_Task_Type_Declaration, | |
2192 N_Subprogram_Body_Stub) | |
2193 then | |
2194 Decl := Unit_Declaration_Node (Corresponding_Body (Decl)); | |
2195 end if; | |
2196 end if; | |
2197 | |
2198 Push_Scope (Scop); | |
2199 Expand_Cleanup_Actions (Decl); | |
2200 End_Scope; | |
2201 | |
2202 Elmt := Next_Elmt (Elmt); | |
2203 end loop; | |
2204 end Cleanup_Scopes; | |
2205 | |
2206 ------------------------- | |
2207 -- Expand_Inlined_Call -- | |
2208 ------------------------- | |
2209 | |
2210 procedure Expand_Inlined_Call | |
2211 (N : Node_Id; | |
2212 Subp : Entity_Id; | |
2213 Orig_Subp : Entity_Id) | |
2214 is | |
2215 Loc : constant Source_Ptr := Sloc (N); | |
2216 Is_Predef : constant Boolean := | |
2217 Is_Predefined_Unit (Get_Source_Unit (Subp)); | |
2218 Orig_Bod : constant Node_Id := | |
2219 Body_To_Inline (Unit_Declaration_Node (Subp)); | |
2220 | |
2221 Blk : Node_Id; | |
2222 Decl : Node_Id; | |
2223 Decls : constant List_Id := New_List; | |
2224 Exit_Lab : Entity_Id := Empty; | |
2225 F : Entity_Id; | |
2226 A : Node_Id; | |
2227 Lab_Decl : Node_Id; | |
2228 Lab_Id : Node_Id; | |
2229 New_A : Node_Id; | |
2230 Num_Ret : Nat := 0; | |
2231 Ret_Type : Entity_Id; | |
2232 | |
2233 Targ : Node_Id; | |
2234 -- The target of the call. If context is an assignment statement then | |
2235 -- this is the left-hand side of the assignment, else it is a temporary | |
2236 -- to which the return value is assigned prior to rewriting the call. | |
2237 | |
2238 Targ1 : Node_Id := Empty; | |
2239 -- A separate target used when the return type is unconstrained | |
2240 | |
2241 Temp : Entity_Id; | |
2242 Temp_Typ : Entity_Id; | |
2243 | |
2244 Return_Object : Entity_Id := Empty; | |
2245 -- Entity in declaration in an extended_return_statement | |
2246 | |
2247 Is_Unc : Boolean; | |
2248 Is_Unc_Decl : Boolean; | |
2249 -- If the type returned by the function is unconstrained and the call | |
2250 -- can be inlined, special processing is required. | |
2251 | |
2252 procedure Declare_Postconditions_Result; | |
2253 -- When generating C code, declare _Result, which may be used in the | |
2254 -- inlined _Postconditions procedure to verify the return value. | |
2255 | |
2256 procedure Make_Exit_Label; | |
2257 -- Build declaration for exit label to be used in Return statements, | |
2258 -- sets Exit_Lab (the label node) and Lab_Decl (corresponding implicit | |
2259 -- declaration). Does nothing if Exit_Lab already set. | |
2260 | |
2261 function Process_Formals (N : Node_Id) return Traverse_Result; | |
2262 -- Replace occurrence of a formal with the corresponding actual, or the | |
2263 -- thunk generated for it. Replace a return statement with an assignment | |
2264 -- to the target of the call, with appropriate conversions if needed. | |
2265 | |
2266 function Process_Sloc (Nod : Node_Id) return Traverse_Result; | |
2267 -- If the call being expanded is that of an internal subprogram, set the | |
2268 -- sloc of the generated block to that of the call itself, so that the | |
2269 -- expansion is skipped by the "next" command in gdb. Same processing | |
2270 -- for a subprogram in a predefined file, e.g. Ada.Tags. If | |
2271 -- Debug_Generated_Code is true, suppress this change to simplify our | |
2272 -- own development. Same in GNATprove mode, to ensure that warnings and | |
2273 -- diagnostics point to the proper location. | |
2274 | |
2275 procedure Reset_Dispatching_Calls (N : Node_Id); | |
2276 -- In subtree N search for occurrences of dispatching calls that use the | |
2277 -- Ada 2005 Object.Operation notation and the object is a formal of the | |
2278 -- inlined subprogram. Reset the entity associated with Operation in all | |
2279 -- the found occurrences. | |
2280 | |
2281 procedure Rewrite_Function_Call (N : Node_Id; Blk : Node_Id); | |
2282 -- If the function body is a single expression, replace call with | |
2283 -- expression, else insert block appropriately. | |
2284 | |
2285 procedure Rewrite_Procedure_Call (N : Node_Id; Blk : Node_Id); | |
2286 -- If procedure body has no local variables, inline body without | |
2287 -- creating block, otherwise rewrite call with block. | |
2288 | |
2289 function Formal_Is_Used_Once (Formal : Entity_Id) return Boolean; | |
2290 -- Determine whether a formal parameter is used only once in Orig_Bod | |
2291 | |
2292 ----------------------------------- | |
2293 -- Declare_Postconditions_Result -- | |
2294 ----------------------------------- | |
2295 | |
2296 procedure Declare_Postconditions_Result is | |
2297 Enclosing_Subp : constant Entity_Id := Scope (Subp); | |
2298 | |
2299 begin | |
2300 pragma Assert | |
2301 (Modify_Tree_For_C | |
2302 and then Is_Subprogram (Enclosing_Subp) | |
2303 and then Present (Postconditions_Proc (Enclosing_Subp))); | |
2304 | |
2305 if Ekind (Enclosing_Subp) = E_Function then | |
2306 if Nkind (First (Parameter_Associations (N))) in | |
2307 N_Numeric_Or_String_Literal | |
2308 then | |
2309 Append_To (Declarations (Blk), | |
2310 Make_Object_Declaration (Loc, | |
2311 Defining_Identifier => | |
2312 Make_Defining_Identifier (Loc, Name_uResult), | |
2313 Constant_Present => True, | |
2314 Object_Definition => | |
2315 New_Occurrence_Of (Etype (Enclosing_Subp), Loc), | |
2316 Expression => | |
2317 New_Copy_Tree (First (Parameter_Associations (N))))); | |
2318 else | |
2319 Append_To (Declarations (Blk), | |
2320 Make_Object_Renaming_Declaration (Loc, | |
2321 Defining_Identifier => | |
2322 Make_Defining_Identifier (Loc, Name_uResult), | |
2323 Subtype_Mark => | |
2324 New_Occurrence_Of (Etype (Enclosing_Subp), Loc), | |
2325 Name => | |
2326 New_Copy_Tree (First (Parameter_Associations (N))))); | |
2327 end if; | |
2328 end if; | |
2329 end Declare_Postconditions_Result; | |
2330 | |
2331 --------------------- | |
2332 -- Make_Exit_Label -- | |
2333 --------------------- | |
2334 | |
2335 procedure Make_Exit_Label is | |
2336 Lab_Ent : Entity_Id; | |
2337 begin | |
2338 if No (Exit_Lab) then | |
2339 Lab_Ent := Make_Temporary (Loc, 'L'); | |
2340 Lab_Id := New_Occurrence_Of (Lab_Ent, Loc); | |
2341 Exit_Lab := Make_Label (Loc, Lab_Id); | |
2342 Lab_Decl := | |
2343 Make_Implicit_Label_Declaration (Loc, | |
2344 Defining_Identifier => Lab_Ent, | |
2345 Label_Construct => Exit_Lab); | |
2346 end if; | |
2347 end Make_Exit_Label; | |
2348 | |
2349 --------------------- | |
2350 -- Process_Formals -- | |
2351 --------------------- | |
2352 | |
2353 function Process_Formals (N : Node_Id) return Traverse_Result is | |
2354 A : Entity_Id; | |
2355 E : Entity_Id; | |
2356 Ret : Node_Id; | |
2357 | |
2358 begin | |
2359 if Is_Entity_Name (N) and then Present (Entity (N)) then | |
2360 E := Entity (N); | |
2361 | |
2362 if Is_Formal (E) and then Scope (E) = Subp then | |
2363 A := Renamed_Object (E); | |
2364 | |
2365 -- Rewrite the occurrence of the formal into an occurrence of | |
2366 -- the actual. Also establish visibility on the proper view of | |
2367 -- the actual's subtype for the body's context (if the actual's | |
2368 -- subtype is private at the call point but its full view is | |
2369 -- visible to the body, then the inlined tree here must be | |
2370 -- analyzed with the full view). | |
2371 | |
2372 if Is_Entity_Name (A) then | |
2373 Rewrite (N, New_Occurrence_Of (Entity (A), Sloc (N))); | |
2374 Check_Private_View (N); | |
2375 | |
2376 elsif Nkind (A) = N_Defining_Identifier then | |
2377 Rewrite (N, New_Occurrence_Of (A, Sloc (N))); | |
2378 Check_Private_View (N); | |
2379 | |
2380 -- Numeric literal | |
2381 | |
2382 else | |
2383 Rewrite (N, New_Copy (A)); | |
2384 end if; | |
2385 end if; | |
2386 | |
2387 return Skip; | |
2388 | |
2389 elsif Is_Entity_Name (N) | |
2390 and then Present (Return_Object) | |
2391 and then Chars (N) = Chars (Return_Object) | |
2392 then | |
2393 -- Occurrence within an extended return statement. The return | |
2394 -- object is local to the body been inlined, and thus the generic | |
2395 -- copy is not analyzed yet, so we match by name, and replace it | |
2396 -- with target of call. | |
2397 | |
2398 if Nkind (Targ) = N_Defining_Identifier then | |
2399 Rewrite (N, New_Occurrence_Of (Targ, Loc)); | |
2400 else | |
2401 Rewrite (N, New_Copy_Tree (Targ)); | |
2402 end if; | |
2403 | |
2404 return Skip; | |
2405 | |
2406 elsif Nkind (N) = N_Simple_Return_Statement then | |
2407 if No (Expression (N)) then | |
2408 Num_Ret := Num_Ret + 1; | |
2409 Make_Exit_Label; | |
2410 Rewrite (N, | |
2411 Make_Goto_Statement (Loc, Name => New_Copy (Lab_Id))); | |
2412 | |
2413 else | |
2414 if Nkind (Parent (N)) = N_Handled_Sequence_Of_Statements | |
2415 and then Nkind (Parent (Parent (N))) = N_Subprogram_Body | |
2416 then | |
2417 -- Function body is a single expression. No need for | |
2418 -- exit label. | |
2419 | |
2420 null; | |
2421 | |
2422 else | |
2423 Num_Ret := Num_Ret + 1; | |
2424 Make_Exit_Label; | |
2425 end if; | |
2426 | |
2427 -- Because of the presence of private types, the views of the | |
2428 -- expression and the context may be different, so place an | |
2429 -- unchecked conversion to the context type to avoid spurious | |
2430 -- errors, e.g. when the expression is a numeric literal and | |
2431 -- the context is private. If the expression is an aggregate, | |
2432 -- use a qualified expression, because an aggregate is not a | |
2433 -- legal argument of a conversion. Ditto for numeric literals | |
2434 -- and attributes that yield a universal type, because those | |
2435 -- must be resolved to a specific type. | |
2436 | |
2437 if Nkind_In (Expression (N), N_Aggregate, N_Null) | |
2438 or else Yields_Universal_Type (Expression (N)) | |
2439 then | |
2440 Ret := | |
2441 Make_Qualified_Expression (Sloc (N), | |
2442 Subtype_Mark => New_Occurrence_Of (Ret_Type, Sloc (N)), | |
2443 Expression => Relocate_Node (Expression (N))); | |
2444 else | |
2445 Ret := | |
2446 Unchecked_Convert_To | |
2447 (Ret_Type, Relocate_Node (Expression (N))); | |
2448 end if; | |
2449 | |
2450 if Nkind (Targ) = N_Defining_Identifier then | |
2451 Rewrite (N, | |
2452 Make_Assignment_Statement (Loc, | |
2453 Name => New_Occurrence_Of (Targ, Loc), | |
2454 Expression => Ret)); | |
2455 else | |
2456 Rewrite (N, | |
2457 Make_Assignment_Statement (Loc, | |
2458 Name => New_Copy (Targ), | |
2459 Expression => Ret)); | |
2460 end if; | |
2461 | |
2462 Set_Assignment_OK (Name (N)); | |
2463 | |
2464 if Present (Exit_Lab) then | |
2465 Insert_After (N, | |
2466 Make_Goto_Statement (Loc, Name => New_Copy (Lab_Id))); | |
2467 end if; | |
2468 end if; | |
2469 | |
2470 return OK; | |
2471 | |
2472 -- An extended return becomes a block whose first statement is the | |
2473 -- assignment of the initial expression of the return object to the | |
2474 -- target of the call itself. | |
2475 | |
2476 elsif Nkind (N) = N_Extended_Return_Statement then | |
2477 declare | |
2478 Return_Decl : constant Entity_Id := | |
2479 First (Return_Object_Declarations (N)); | |
2480 Assign : Node_Id; | |
2481 | |
2482 begin | |
2483 Return_Object := Defining_Identifier (Return_Decl); | |
2484 | |
2485 if Present (Expression (Return_Decl)) then | |
2486 if Nkind (Targ) = N_Defining_Identifier then | |
2487 Assign := | |
2488 Make_Assignment_Statement (Loc, | |
2489 Name => New_Occurrence_Of (Targ, Loc), | |
2490 Expression => Expression (Return_Decl)); | |
2491 else | |
2492 Assign := | |
2493 Make_Assignment_Statement (Loc, | |
2494 Name => New_Copy (Targ), | |
2495 Expression => Expression (Return_Decl)); | |
2496 end if; | |
2497 | |
2498 Set_Assignment_OK (Name (Assign)); | |
2499 | |
2500 if No (Handled_Statement_Sequence (N)) then | |
2501 Set_Handled_Statement_Sequence (N, | |
2502 Make_Handled_Sequence_Of_Statements (Loc, | |
2503 Statements => New_List)); | |
2504 end if; | |
2505 | |
2506 Prepend (Assign, | |
2507 Statements (Handled_Statement_Sequence (N))); | |
2508 end if; | |
2509 | |
2510 Rewrite (N, | |
2511 Make_Block_Statement (Loc, | |
2512 Handled_Statement_Sequence => | |
2513 Handled_Statement_Sequence (N))); | |
2514 | |
2515 return OK; | |
2516 end; | |
2517 | |
2518 -- Remove pragma Unreferenced since it may refer to formals that | |
2519 -- are not visible in the inlined body, and in any case we will | |
2520 -- not be posting warnings on the inlined body so it is unneeded. | |
2521 | |
2522 elsif Nkind (N) = N_Pragma | |
2523 and then Pragma_Name (N) = Name_Unreferenced | |
2524 then | |
2525 Rewrite (N, Make_Null_Statement (Sloc (N))); | |
2526 return OK; | |
2527 | |
2528 else | |
2529 return OK; | |
2530 end if; | |
2531 end Process_Formals; | |
2532 | |
2533 procedure Replace_Formals is new Traverse_Proc (Process_Formals); | |
2534 | |
2535 ------------------ | |
2536 -- Process_Sloc -- | |
2537 ------------------ | |
2538 | |
2539 function Process_Sloc (Nod : Node_Id) return Traverse_Result is | |
2540 begin | |
2541 if not Debug_Generated_Code then | |
2542 Set_Sloc (Nod, Sloc (N)); | |
2543 Set_Comes_From_Source (Nod, False); | |
2544 end if; | |
2545 | |
2546 return OK; | |
2547 end Process_Sloc; | |
2548 | |
2549 procedure Reset_Slocs is new Traverse_Proc (Process_Sloc); | |
2550 | |
2551 ------------------------------ | |
2552 -- Reset_Dispatching_Calls -- | |
2553 ------------------------------ | |
2554 | |
2555 procedure Reset_Dispatching_Calls (N : Node_Id) is | |
2556 | |
2557 function Do_Reset (N : Node_Id) return Traverse_Result; | |
2558 -- Comment required ??? | |
2559 | |
2560 -------------- | |
2561 -- Do_Reset -- | |
2562 -------------- | |
2563 | |
2564 function Do_Reset (N : Node_Id) return Traverse_Result is | |
2565 begin | |
2566 if Nkind (N) = N_Procedure_Call_Statement | |
2567 and then Nkind (Name (N)) = N_Selected_Component | |
2568 and then Nkind (Prefix (Name (N))) = N_Identifier | |
2569 and then Is_Formal (Entity (Prefix (Name (N)))) | |
2570 and then Is_Dispatching_Operation | |
2571 (Entity (Selector_Name (Name (N)))) | |
2572 then | |
2573 Set_Entity (Selector_Name (Name (N)), Empty); | |
2574 end if; | |
2575 | |
2576 return OK; | |
2577 end Do_Reset; | |
2578 | |
2579 function Do_Reset_Calls is new Traverse_Func (Do_Reset); | |
2580 | |
2581 -- Local variables | |
2582 | |
2583 Dummy : constant Traverse_Result := Do_Reset_Calls (N); | |
2584 pragma Unreferenced (Dummy); | |
2585 | |
2586 -- Start of processing for Reset_Dispatching_Calls | |
2587 | |
2588 begin | |
2589 null; | |
2590 end Reset_Dispatching_Calls; | |
2591 | |
2592 --------------------------- | |
2593 -- Rewrite_Function_Call -- | |
2594 --------------------------- | |
2595 | |
2596 procedure Rewrite_Function_Call (N : Node_Id; Blk : Node_Id) is | |
2597 HSS : constant Node_Id := Handled_Statement_Sequence (Blk); | |
2598 Fst : constant Node_Id := First (Statements (HSS)); | |
2599 | |
2600 begin | |
2601 -- Optimize simple case: function body is a single return statement, | |
2602 -- which has been expanded into an assignment. | |
2603 | |
2604 if Is_Empty_List (Declarations (Blk)) | |
2605 and then Nkind (Fst) = N_Assignment_Statement | |
2606 and then No (Next (Fst)) | |
2607 then | |
2608 -- The function call may have been rewritten as the temporary | |
2609 -- that holds the result of the call, in which case remove the | |
2610 -- now useless declaration. | |
2611 | |
2612 if Nkind (N) = N_Identifier | |
2613 and then Nkind (Parent (Entity (N))) = N_Object_Declaration | |
2614 then | |
2615 Rewrite (Parent (Entity (N)), Make_Null_Statement (Loc)); | |
2616 end if; | |
2617 | |
2618 Rewrite (N, Expression (Fst)); | |
2619 | |
2620 elsif Nkind (N) = N_Identifier | |
2621 and then Nkind (Parent (Entity (N))) = N_Object_Declaration | |
2622 then | |
2623 -- The block assigns the result of the call to the temporary | |
2624 | |
2625 Insert_After (Parent (Entity (N)), Blk); | |
2626 | |
2627 -- If the context is an assignment, and the left-hand side is free of | |
2628 -- side-effects, the replacement is also safe. | |
2629 -- Can this be generalized further??? | |
2630 | |
2631 elsif Nkind (Parent (N)) = N_Assignment_Statement | |
2632 and then | |
2633 (Is_Entity_Name (Name (Parent (N))) | |
2634 or else | |
2635 (Nkind (Name (Parent (N))) = N_Explicit_Dereference | |
2636 and then Is_Entity_Name (Prefix (Name (Parent (N))))) | |
2637 | |
2638 or else | |
2639 (Nkind (Name (Parent (N))) = N_Selected_Component | |
2640 and then Is_Entity_Name (Prefix (Name (Parent (N)))))) | |
2641 then | |
2642 -- Replace assignment with the block | |
2643 | |
2644 declare | |
2645 Original_Assignment : constant Node_Id := Parent (N); | |
2646 | |
2647 begin | |
2648 -- Preserve the original assignment node to keep the complete | |
2649 -- assignment subtree consistent enough for Analyze_Assignment | |
2650 -- to proceed (specifically, the original Lhs node must still | |
2651 -- have an assignment statement as its parent). | |
2652 | |
2653 -- We cannot rely on Original_Node to go back from the block | |
2654 -- node to the assignment node, because the assignment might | |
2655 -- already be a rewrite substitution. | |
2656 | |
2657 Discard_Node (Relocate_Node (Original_Assignment)); | |
2658 Rewrite (Original_Assignment, Blk); | |
2659 end; | |
2660 | |
2661 elsif Nkind (Parent (N)) = N_Object_Declaration then | |
2662 | |
2663 -- A call to a function which returns an unconstrained type | |
2664 -- found in the expression initializing an object-declaration is | |
2665 -- expanded into a procedure call which must be added after the | |
2666 -- object declaration. | |
2667 | |
2668 if Is_Unc_Decl and Back_End_Inlining then | |
2669 Insert_Action_After (Parent (N), Blk); | |
2670 else | |
2671 Set_Expression (Parent (N), Empty); | |
2672 Insert_After (Parent (N), Blk); | |
2673 end if; | |
2674 | |
2675 elsif Is_Unc and then not Back_End_Inlining then | |
2676 Insert_Before (Parent (N), Blk); | |
2677 end if; | |
2678 end Rewrite_Function_Call; | |
2679 | |
2680 ---------------------------- | |
2681 -- Rewrite_Procedure_Call -- | |
2682 ---------------------------- | |
2683 | |
2684 procedure Rewrite_Procedure_Call (N : Node_Id; Blk : Node_Id) is | |
2685 HSS : constant Node_Id := Handled_Statement_Sequence (Blk); | |
2686 | |
2687 begin | |
2688 -- If there is a transient scope for N, this will be the scope of the | |
2689 -- actions for N, and the statements in Blk need to be within this | |
2690 -- scope. For example, they need to have visibility on the constant | |
2691 -- declarations created for the formals. | |
2692 | |
2693 -- If N needs no transient scope, and if there are no declarations in | |
2694 -- the inlined body, we can do a little optimization and insert the | |
2695 -- statements for the body directly after N, and rewrite N to a | |
2696 -- null statement, instead of rewriting N into a full-blown block | |
2697 -- statement. | |
2698 | |
2699 if not Scope_Is_Transient | |
2700 and then Is_Empty_List (Declarations (Blk)) | |
2701 then | |
2702 Insert_List_After (N, Statements (HSS)); | |
2703 Rewrite (N, Make_Null_Statement (Loc)); | |
2704 else | |
2705 Rewrite (N, Blk); | |
2706 end if; | |
2707 end Rewrite_Procedure_Call; | |
2708 | |
2709 ------------------------- | |
2710 -- Formal_Is_Used_Once -- | |
2711 ------------------------- | |
2712 | |
2713 function Formal_Is_Used_Once (Formal : Entity_Id) return Boolean is | |
2714 Use_Counter : Int := 0; | |
2715 | |
2716 function Count_Uses (N : Node_Id) return Traverse_Result; | |
2717 -- Traverse the tree and count the uses of the formal parameter. | |
2718 -- In this case, for optimization purposes, we do not need to | |
2719 -- continue the traversal once more than one use is encountered. | |
2720 | |
2721 ---------------- | |
2722 -- Count_Uses -- | |
2723 ---------------- | |
2724 | |
2725 function Count_Uses (N : Node_Id) return Traverse_Result is | |
2726 begin | |
2727 -- The original node is an identifier | |
2728 | |
2729 if Nkind (N) = N_Identifier | |
2730 and then Present (Entity (N)) | |
2731 | |
2732 -- Original node's entity points to the one in the copied body | |
2733 | |
2734 and then Nkind (Entity (N)) = N_Identifier | |
2735 and then Present (Entity (Entity (N))) | |
2736 | |
2737 -- The entity of the copied node is the formal parameter | |
2738 | |
2739 and then Entity (Entity (N)) = Formal | |
2740 then | |
2741 Use_Counter := Use_Counter + 1; | |
2742 | |
2743 if Use_Counter > 1 then | |
2744 | |
2745 -- Denote more than one use and abandon the traversal | |
2746 | |
2747 Use_Counter := 2; | |
2748 return Abandon; | |
2749 | |
2750 end if; | |
2751 end if; | |
2752 | |
2753 return OK; | |
2754 end Count_Uses; | |
2755 | |
2756 procedure Count_Formal_Uses is new Traverse_Proc (Count_Uses); | |
2757 | |
2758 -- Start of processing for Formal_Is_Used_Once | |
2759 | |
2760 begin | |
2761 Count_Formal_Uses (Orig_Bod); | |
2762 return Use_Counter = 1; | |
2763 end Formal_Is_Used_Once; | |
2764 | |
2765 -- Start of processing for Expand_Inlined_Call | |
2766 | |
2767 begin | |
2768 -- Initializations for old/new semantics | |
2769 | |
2770 if not Back_End_Inlining then | |
2771 Is_Unc := Is_Array_Type (Etype (Subp)) | |
2772 and then not Is_Constrained (Etype (Subp)); | |
2773 Is_Unc_Decl := False; | |
2774 else | |
2775 Is_Unc := Returns_Unconstrained_Type (Subp) | |
2776 and then Optimization_Level > 0; | |
2777 Is_Unc_Decl := Nkind (Parent (N)) = N_Object_Declaration | |
2778 and then Is_Unc; | |
2779 end if; | |
2780 | |
2781 -- Check for an illegal attempt to inline a recursive procedure. If the | |
2782 -- subprogram has parameters this is detected when trying to supply a | |
2783 -- binding for parameters that already have one. For parameterless | |
2784 -- subprograms this must be done explicitly. | |
2785 | |
2786 if In_Open_Scopes (Subp) then | |
2787 Cannot_Inline | |
2788 ("cannot inline call to recursive subprogram?", N, Subp); | |
2789 Set_Is_Inlined (Subp, False); | |
2790 return; | |
2791 | |
2792 -- Skip inlining if this is not a true inlining since the attribute | |
2793 -- Body_To_Inline is also set for renamings (see sinfo.ads). For a | |
2794 -- true inlining, Orig_Bod has code rather than being an entity. | |
2795 | |
2796 elsif Nkind (Orig_Bod) in N_Entity then | |
2797 return; | |
2798 | |
2799 -- Skip inlining if the function returns an unconstrained type using | |
2800 -- an extended return statement since this part of the new inlining | |
2801 -- model which is not yet supported by the current implementation. ??? | |
2802 | |
2803 elsif Is_Unc | |
2804 and then | |
2805 Nkind (First (Statements (Handled_Statement_Sequence (Orig_Bod)))) = | |
2806 N_Extended_Return_Statement | |
2807 and then not Back_End_Inlining | |
2808 then | |
2809 return; | |
2810 end if; | |
2811 | |
2812 if Nkind (Orig_Bod) = N_Defining_Identifier | |
2813 or else Nkind (Orig_Bod) = N_Defining_Operator_Symbol | |
2814 then | |
2815 -- Subprogram is renaming_as_body. Calls occurring after the renaming | |
2816 -- can be replaced with calls to the renamed entity directly, because | |
2817 -- the subprograms are subtype conformant. If the renamed subprogram | |
2818 -- is an inherited operation, we must redo the expansion because | |
2819 -- implicit conversions may be needed. Similarly, if the renamed | |
2820 -- entity is inlined, expand the call for further optimizations. | |
2821 | |
2822 Set_Name (N, New_Occurrence_Of (Orig_Bod, Loc)); | |
2823 | |
2824 if Present (Alias (Orig_Bod)) or else Is_Inlined (Orig_Bod) then | |
2825 Expand_Call (N); | |
2826 end if; | |
2827 | |
2828 return; | |
2829 end if; | |
2830 | |
2831 -- Register the call in the list of inlined calls | |
2832 | |
2833 Append_New_Elmt (N, To => Inlined_Calls); | |
2834 | |
2835 -- Use generic machinery to copy body of inlined subprogram, as if it | |
2836 -- were an instantiation, resetting source locations appropriately, so | |
2837 -- that nested inlined calls appear in the main unit. | |
2838 | |
2839 Save_Env (Subp, Empty); | |
2840 Set_Copied_Sloc_For_Inlined_Body (N, Defining_Entity (Orig_Bod)); | |
2841 | |
2842 -- Old semantics | |
2843 | |
2844 if not Back_End_Inlining then | |
2845 declare | |
2846 Bod : Node_Id; | |
2847 | |
2848 begin | |
2849 Bod := Copy_Generic_Node (Orig_Bod, Empty, Instantiating => True); | |
2850 Blk := | |
2851 Make_Block_Statement (Loc, | |
2852 Declarations => Declarations (Bod), | |
2853 Handled_Statement_Sequence => | |
2854 Handled_Statement_Sequence (Bod)); | |
2855 | |
2856 if No (Declarations (Bod)) then | |
2857 Set_Declarations (Blk, New_List); | |
2858 end if; | |
2859 | |
2860 -- When generating C code, declare _Result, which may be used to | |
2861 -- verify the return value. | |
2862 | |
2863 if Modify_Tree_For_C | |
2864 and then Nkind (N) = N_Procedure_Call_Statement | |
2865 and then Chars (Name (N)) = Name_uPostconditions | |
2866 then | |
2867 Declare_Postconditions_Result; | |
2868 end if; | |
2869 | |
2870 -- For the unconstrained case, capture the name of the local | |
2871 -- variable that holds the result. This must be the first | |
2872 -- declaration in the block, because its bounds cannot depend | |
2873 -- on local variables. Otherwise there is no way to declare the | |
2874 -- result outside of the block. Needless to say, in general the | |
2875 -- bounds will depend on the actuals in the call. | |
2876 | |
2877 -- If the context is an assignment statement, as is the case | |
2878 -- for the expansion of an extended return, the left-hand side | |
2879 -- provides bounds even if the return type is unconstrained. | |
2880 | |
2881 if Is_Unc then | |
2882 declare | |
2883 First_Decl : Node_Id; | |
2884 | |
2885 begin | |
2886 First_Decl := First (Declarations (Blk)); | |
2887 | |
2888 if Nkind (First_Decl) /= N_Object_Declaration then | |
2889 return; | |
2890 end if; | |
2891 | |
2892 if Nkind (Parent (N)) /= N_Assignment_Statement then | |
2893 Targ1 := Defining_Identifier (First_Decl); | |
2894 else | |
2895 Targ1 := Name (Parent (N)); | |
2896 end if; | |
2897 end; | |
2898 end if; | |
2899 end; | |
2900 | |
2901 -- New semantics | |
2902 | |
2903 else | |
2904 declare | |
2905 Bod : Node_Id; | |
2906 | |
2907 begin | |
2908 -- General case | |
2909 | |
2910 if not Is_Unc then | |
2911 Bod := | |
2912 Copy_Generic_Node (Orig_Bod, Empty, Instantiating => True); | |
2913 Blk := | |
2914 Make_Block_Statement (Loc, | |
2915 Declarations => Declarations (Bod), | |
2916 Handled_Statement_Sequence => | |
2917 Handled_Statement_Sequence (Bod)); | |
2918 | |
2919 -- Inline a call to a function that returns an unconstrained type. | |
2920 -- The semantic analyzer checked that frontend-inlined functions | |
2921 -- returning unconstrained types have no declarations and have | |
2922 -- a single extended return statement. As part of its processing | |
2923 -- the function was split into two subprograms: a procedure P' and | |
2924 -- a function F' that has a block with a call to procedure P' (see | |
2925 -- Split_Unconstrained_Function). | |
2926 | |
2927 else | |
2928 pragma Assert | |
2929 (Nkind | |
2930 (First | |
2931 (Statements (Handled_Statement_Sequence (Orig_Bod)))) = | |
2932 N_Block_Statement); | |
2933 | |
2934 declare | |
2935 Blk_Stmt : constant Node_Id := | |
2936 First (Statements (Handled_Statement_Sequence (Orig_Bod))); | |
2937 First_Stmt : constant Node_Id := | |
2938 First (Statements (Handled_Statement_Sequence (Blk_Stmt))); | |
2939 Second_Stmt : constant Node_Id := Next (First_Stmt); | |
2940 | |
2941 begin | |
2942 pragma Assert | |
2943 (Nkind (First_Stmt) = N_Procedure_Call_Statement | |
2944 and then Nkind (Second_Stmt) = N_Simple_Return_Statement | |
2945 and then No (Next (Second_Stmt))); | |
2946 | |
2947 Bod := | |
2948 Copy_Generic_Node | |
2949 (First | |
2950 (Statements (Handled_Statement_Sequence (Orig_Bod))), | |
2951 Empty, Instantiating => True); | |
2952 Blk := Bod; | |
2953 | |
2954 -- Capture the name of the local variable that holds the | |
2955 -- result. This must be the first declaration in the block, | |
2956 -- because its bounds cannot depend on local variables. | |
2957 -- Otherwise there is no way to declare the result outside | |
2958 -- of the block. Needless to say, in general the bounds will | |
2959 -- depend on the actuals in the call. | |
2960 | |
2961 if Nkind (Parent (N)) /= N_Assignment_Statement then | |
2962 Targ1 := Defining_Identifier (First (Declarations (Blk))); | |
2963 | |
2964 -- If the context is an assignment statement, as is the case | |
2965 -- for the expansion of an extended return, the left-hand | |
2966 -- side provides bounds even if the return type is | |
2967 -- unconstrained. | |
2968 | |
2969 else | |
2970 Targ1 := Name (Parent (N)); | |
2971 end if; | |
2972 end; | |
2973 end if; | |
2974 | |
2975 if No (Declarations (Bod)) then | |
2976 Set_Declarations (Blk, New_List); | |
2977 end if; | |
2978 end; | |
2979 end if; | |
2980 | |
2981 -- If this is a derived function, establish the proper return type | |
2982 | |
2983 if Present (Orig_Subp) and then Orig_Subp /= Subp then | |
2984 Ret_Type := Etype (Orig_Subp); | |
2985 else | |
2986 Ret_Type := Etype (Subp); | |
2987 end if; | |
2988 | |
2989 -- Create temporaries for the actuals that are expressions, or that are | |
2990 -- scalars and require copying to preserve semantics. | |
2991 | |
2992 F := First_Formal (Subp); | |
2993 A := First_Actual (N); | |
2994 while Present (F) loop | |
2995 if Present (Renamed_Object (F)) then | |
2996 | |
2997 -- If expander is active, it is an error to try to inline a | |
2998 -- recursive program. In GNATprove mode, just indicate that the | |
2999 -- inlining will not happen, and mark the subprogram as not always | |
3000 -- inlined. | |
3001 | |
3002 if GNATprove_Mode then | |
3003 Cannot_Inline | |
3004 ("cannot inline call to recursive subprogram?", N, Subp); | |
3005 Set_Is_Inlined_Always (Subp, False); | |
3006 else | |
3007 Error_Msg_N | |
3008 ("cannot inline call to recursive subprogram", N); | |
3009 end if; | |
3010 | |
3011 return; | |
3012 end if; | |
3013 | |
3014 -- Reset Last_Assignment for any parameters of mode out or in out, to | |
3015 -- prevent spurious warnings about overwriting for assignments to the | |
3016 -- formal in the inlined code. | |
3017 | |
3018 if Is_Entity_Name (A) and then Ekind (F) /= E_In_Parameter then | |
3019 Set_Last_Assignment (Entity (A), Empty); | |
3020 end if; | |
3021 | |
3022 -- If the argument may be a controlling argument in a call within | |
3023 -- the inlined body, we must preserve its classwide nature to insure | |
3024 -- that dynamic dispatching take place subsequently. If the formal | |
3025 -- has a constraint it must be preserved to retain the semantics of | |
3026 -- the body. | |
3027 | |
3028 if Is_Class_Wide_Type (Etype (F)) | |
3029 or else (Is_Access_Type (Etype (F)) | |
3030 and then Is_Class_Wide_Type (Designated_Type (Etype (F)))) | |
3031 then | |
3032 Temp_Typ := Etype (F); | |
3033 | |
3034 elsif Base_Type (Etype (F)) = Base_Type (Etype (A)) | |
3035 and then Etype (F) /= Base_Type (Etype (F)) | |
3036 and then Is_Constrained (Etype (F)) | |
3037 then | |
3038 Temp_Typ := Etype (F); | |
3039 | |
3040 else | |
3041 Temp_Typ := Etype (A); | |
3042 end if; | |
3043 | |
3044 -- If the actual is a simple name or a literal, no need to | |
3045 -- create a temporary, object can be used directly. | |
3046 | |
3047 -- If the actual is a literal and the formal has its address taken, | |
3048 -- we cannot pass the literal itself as an argument, so its value | |
3049 -- must be captured in a temporary. Skip this optimization in | |
3050 -- GNATprove mode, to make sure any check on a type conversion | |
3051 -- will be issued. | |
3052 | |
3053 if (Is_Entity_Name (A) | |
3054 and then | |
3055 (not Is_Scalar_Type (Etype (A)) | |
3056 or else Ekind (Entity (A)) = E_Enumeration_Literal) | |
3057 and then not GNATprove_Mode) | |
3058 | |
3059 -- When the actual is an identifier and the corresponding formal is | |
3060 -- used only once in the original body, the formal can be substituted | |
3061 -- directly with the actual parameter. Skip this optimization in | |
3062 -- GNATprove mode, to make sure any check on a type conversion | |
3063 -- will be issued. | |
3064 | |
3065 or else | |
3066 (Nkind (A) = N_Identifier | |
3067 and then Formal_Is_Used_Once (F) | |
3068 and then not GNATprove_Mode) | |
3069 | |
3070 or else | |
3071 (Nkind_In (A, N_Real_Literal, | |
3072 N_Integer_Literal, | |
3073 N_Character_Literal) | |
3074 and then not Address_Taken (F)) | |
3075 then | |
3076 if Etype (F) /= Etype (A) then | |
3077 Set_Renamed_Object | |
3078 (F, Unchecked_Convert_To (Etype (F), Relocate_Node (A))); | |
3079 else | |
3080 Set_Renamed_Object (F, A); | |
3081 end if; | |
3082 | |
3083 else | |
3084 Temp := Make_Temporary (Loc, 'C'); | |
3085 | |
3086 -- If the actual for an in/in-out parameter is a view conversion, | |
3087 -- make it into an unchecked conversion, given that an untagged | |
3088 -- type conversion is not a proper object for a renaming. | |
3089 | |
3090 -- In-out conversions that involve real conversions have already | |
3091 -- been transformed in Expand_Actuals. | |
3092 | |
3093 if Nkind (A) = N_Type_Conversion | |
3094 and then Ekind (F) /= E_In_Parameter | |
3095 then | |
3096 New_A := | |
3097 Make_Unchecked_Type_Conversion (Loc, | |
3098 Subtype_Mark => New_Occurrence_Of (Etype (F), Loc), | |
3099 Expression => Relocate_Node (Expression (A))); | |
3100 | |
3101 -- In GNATprove mode, keep the most precise type of the actual for | |
3102 -- the temporary variable, when the formal type is unconstrained. | |
3103 -- Otherwise, the AST may contain unexpected assignment statements | |
3104 -- to a temporary variable of unconstrained type renaming a local | |
3105 -- variable of constrained type, which is not expected by | |
3106 -- GNATprove. | |
3107 | |
3108 elsif Etype (F) /= Etype (A) | |
3109 and then (not GNATprove_Mode or else Is_Constrained (Etype (F))) | |
3110 then | |
3111 New_A := Unchecked_Convert_To (Etype (F), Relocate_Node (A)); | |
3112 Temp_Typ := Etype (F); | |
3113 | |
3114 else | |
3115 New_A := Relocate_Node (A); | |
3116 end if; | |
3117 | |
3118 Set_Sloc (New_A, Sloc (N)); | |
3119 | |
3120 -- If the actual has a by-reference type, it cannot be copied, | |
3121 -- so its value is captured in a renaming declaration. Otherwise | |
3122 -- declare a local constant initialized with the actual. | |
3123 | |
3124 -- We also use a renaming declaration for expressions of an array | |
3125 -- type that is not bit-packed, both for efficiency reasons and to | |
3126 -- respect the semantics of the call: in most cases the original | |
3127 -- call will pass the parameter by reference, and thus the inlined | |
3128 -- code will have the same semantics. | |
3129 | |
3130 -- Finally, we need a renaming declaration in the case of limited | |
3131 -- types for which initialization cannot be by copy either. | |
3132 | |
3133 if Ekind (F) = E_In_Parameter | |
3134 and then not Is_By_Reference_Type (Etype (A)) | |
3135 and then not Is_Limited_Type (Etype (A)) | |
3136 and then | |
3137 (not Is_Array_Type (Etype (A)) | |
3138 or else not Is_Object_Reference (A) | |
3139 or else Is_Bit_Packed_Array (Etype (A))) | |
3140 then | |
3141 Decl := | |
3142 Make_Object_Declaration (Loc, | |
3143 Defining_Identifier => Temp, | |
3144 Constant_Present => True, | |
3145 Object_Definition => New_Occurrence_Of (Temp_Typ, Loc), | |
3146 Expression => New_A); | |
3147 | |
3148 else | |
3149 -- In GNATprove mode, make an explicit copy of input | |
3150 -- parameters when formal and actual types differ, to make | |
3151 -- sure any check on the type conversion will be issued. | |
3152 -- The legality of the copy is ensured by calling first | |
3153 -- Call_Can_Be_Inlined_In_GNATprove_Mode. | |
3154 | |
3155 if GNATprove_Mode | |
3156 and then Ekind (F) /= E_Out_Parameter | |
3157 and then not Same_Type (Etype (F), Etype (A)) | |
3158 then | |
3159 pragma Assert (not (Is_By_Reference_Type (Etype (A)))); | |
3160 pragma Assert (not (Is_Limited_Type (Etype (A)))); | |
3161 | |
3162 Append_To (Decls, | |
3163 Make_Object_Declaration (Loc, | |
3164 Defining_Identifier => Make_Temporary (Loc, 'C'), | |
3165 Constant_Present => True, | |
3166 Object_Definition => New_Occurrence_Of (Temp_Typ, Loc), | |
3167 Expression => New_Copy_Tree (New_A))); | |
3168 end if; | |
3169 | |
3170 Decl := | |
3171 Make_Object_Renaming_Declaration (Loc, | |
3172 Defining_Identifier => Temp, | |
3173 Subtype_Mark => New_Occurrence_Of (Temp_Typ, Loc), | |
3174 Name => New_A); | |
3175 end if; | |
3176 | |
3177 Append (Decl, Decls); | |
3178 Set_Renamed_Object (F, Temp); | |
3179 end if; | |
3180 | |
3181 Next_Formal (F); | |
3182 Next_Actual (A); | |
3183 end loop; | |
3184 | |
3185 -- Establish target of function call. If context is not assignment or | |
3186 -- declaration, create a temporary as a target. The declaration for the | |
3187 -- temporary may be subsequently optimized away if the body is a single | |
3188 -- expression, or if the left-hand side of the assignment is simple | |
3189 -- enough, i.e. an entity or an explicit dereference of one. | |
3190 | |
3191 if Ekind (Subp) = E_Function then | |
3192 if Nkind (Parent (N)) = N_Assignment_Statement | |
3193 and then Is_Entity_Name (Name (Parent (N))) | |
3194 then | |
3195 Targ := Name (Parent (N)); | |
3196 | |
3197 elsif Nkind (Parent (N)) = N_Assignment_Statement | |
3198 and then Nkind (Name (Parent (N))) = N_Explicit_Dereference | |
3199 and then Is_Entity_Name (Prefix (Name (Parent (N)))) | |
3200 then | |
3201 Targ := Name (Parent (N)); | |
3202 | |
3203 elsif Nkind (Parent (N)) = N_Assignment_Statement | |
3204 and then Nkind (Name (Parent (N))) = N_Selected_Component | |
3205 and then Is_Entity_Name (Prefix (Name (Parent (N)))) | |
3206 then | |
3207 Targ := New_Copy_Tree (Name (Parent (N))); | |
3208 | |
3209 elsif Nkind (Parent (N)) = N_Object_Declaration | |
3210 and then Is_Limited_Type (Etype (Subp)) | |
3211 then | |
3212 Targ := Defining_Identifier (Parent (N)); | |
3213 | |
3214 -- New semantics: In an object declaration avoid an extra copy | |
3215 -- of the result of a call to an inlined function that returns | |
3216 -- an unconstrained type | |
3217 | |
3218 elsif Back_End_Inlining | |
3219 and then Nkind (Parent (N)) = N_Object_Declaration | |
3220 and then Is_Unc | |
3221 then | |
3222 Targ := Defining_Identifier (Parent (N)); | |
3223 | |
3224 else | |
3225 -- Replace call with temporary and create its declaration | |
3226 | |
3227 Temp := Make_Temporary (Loc, 'C'); | |
3228 Set_Is_Internal (Temp); | |
3229 | |
3230 -- For the unconstrained case, the generated temporary has the | |
3231 -- same constrained declaration as the result variable. It may | |
3232 -- eventually be possible to remove that temporary and use the | |
3233 -- result variable directly. | |
3234 | |
3235 if Is_Unc and then Nkind (Parent (N)) /= N_Assignment_Statement | |
3236 then | |
3237 Decl := | |
3238 Make_Object_Declaration (Loc, | |
3239 Defining_Identifier => Temp, | |
3240 Object_Definition => | |
3241 New_Copy_Tree (Object_Definition (Parent (Targ1)))); | |
3242 | |
3243 Replace_Formals (Decl); | |
3244 | |
3245 else | |
3246 Decl := | |
3247 Make_Object_Declaration (Loc, | |
3248 Defining_Identifier => Temp, | |
3249 Object_Definition => New_Occurrence_Of (Ret_Type, Loc)); | |
3250 | |
3251 Set_Etype (Temp, Ret_Type); | |
3252 end if; | |
3253 | |
3254 Set_No_Initialization (Decl); | |
3255 Append (Decl, Decls); | |
3256 Rewrite (N, New_Occurrence_Of (Temp, Loc)); | |
3257 Targ := Temp; | |
3258 end if; | |
3259 end if; | |
3260 | |
3261 Insert_Actions (N, Decls); | |
3262 | |
3263 if Is_Unc_Decl then | |
3264 | |
3265 -- Special management for inlining a call to a function that returns | |
3266 -- an unconstrained type and initializes an object declaration: we | |
3267 -- avoid generating undesired extra calls and goto statements. | |
3268 | |
3269 -- Given: | |
3270 -- function Func (...) return String is | |
3271 -- begin | |
3272 -- declare | |
3273 -- Result : String (1 .. 4); | |
3274 -- begin | |
3275 -- Proc (Result, ...); | |
3276 -- return Result; | |
3277 -- end; | |
3278 -- end Func; | |
3279 | |
3280 -- Result : String := Func (...); | |
3281 | |
3282 -- Replace this object declaration by: | |
3283 | |
3284 -- Result : String (1 .. 4); | |
3285 -- Proc (Result, ...); | |
3286 | |
3287 Remove_Homonym (Targ); | |
3288 | |
3289 Decl := | |
3290 Make_Object_Declaration | |
3291 (Loc, | |
3292 Defining_Identifier => Targ, | |
3293 Object_Definition => | |
3294 New_Copy_Tree (Object_Definition (Parent (Targ1)))); | |
3295 Replace_Formals (Decl); | |
3296 Rewrite (Parent (N), Decl); | |
3297 Analyze (Parent (N)); | |
3298 | |
3299 -- Avoid spurious warnings since we know that this declaration is | |
3300 -- referenced by the procedure call. | |
3301 | |
3302 Set_Never_Set_In_Source (Targ, False); | |
3303 | |
3304 -- Remove the local declaration of the extended return stmt from the | |
3305 -- inlined code | |
3306 | |
3307 Remove (Parent (Targ1)); | |
3308 | |
3309 -- Update the reference to the result (since we have rewriten the | |
3310 -- object declaration) | |
3311 | |
3312 declare | |
3313 Blk_Call_Stmt : Node_Id; | |
3314 | |
3315 begin | |
3316 -- Capture the call to the procedure | |
3317 | |
3318 Blk_Call_Stmt := | |
3319 First (Statements (Handled_Statement_Sequence (Blk))); | |
3320 pragma Assert | |
3321 (Nkind (Blk_Call_Stmt) = N_Procedure_Call_Statement); | |
3322 | |
3323 Remove (First (Parameter_Associations (Blk_Call_Stmt))); | |
3324 Prepend_To (Parameter_Associations (Blk_Call_Stmt), | |
3325 New_Occurrence_Of (Targ, Loc)); | |
3326 end; | |
3327 | |
3328 -- Remove the return statement | |
3329 | |
3330 pragma Assert | |
3331 (Nkind (Last (Statements (Handled_Statement_Sequence (Blk)))) = | |
3332 N_Simple_Return_Statement); | |
3333 | |
3334 Remove (Last (Statements (Handled_Statement_Sequence (Blk)))); | |
3335 end if; | |
3336 | |
3337 -- Traverse the tree and replace formals with actuals or their thunks. | |
3338 -- Attach block to tree before analysis and rewriting. | |
3339 | |
3340 Replace_Formals (Blk); | |
3341 Set_Parent (Blk, N); | |
3342 | |
3343 if GNATprove_Mode then | |
3344 null; | |
3345 | |
3346 elsif not Comes_From_Source (Subp) or else Is_Predef then | |
3347 Reset_Slocs (Blk); | |
3348 end if; | |
3349 | |
3350 if Is_Unc_Decl then | |
3351 | |
3352 -- No action needed since return statement has been already removed | |
3353 | |
3354 null; | |
3355 | |
3356 elsif Present (Exit_Lab) then | |
3357 | |
3358 -- If there's a single return statement at the end of the subprogram, | |
3359 -- the corresponding goto statement and the corresponding label are | |
3360 -- useless. | |
3361 | |
3362 if Num_Ret = 1 | |
3363 and then | |
3364 Nkind (Last (Statements (Handled_Statement_Sequence (Blk)))) = | |
3365 N_Goto_Statement | |
3366 then | |
3367 Remove (Last (Statements (Handled_Statement_Sequence (Blk)))); | |
3368 else | |
3369 Append (Lab_Decl, (Declarations (Blk))); | |
3370 Append (Exit_Lab, Statements (Handled_Statement_Sequence (Blk))); | |
3371 end if; | |
3372 end if; | |
3373 | |
3374 -- Analyze Blk with In_Inlined_Body set, to avoid spurious errors | |
3375 -- on conflicting private views that Gigi would ignore. If this is a | |
3376 -- predefined unit, analyze with checks off, as is done in the non- | |
3377 -- inlined run-time units. | |
3378 | |
3379 declare | |
3380 I_Flag : constant Boolean := In_Inlined_Body; | |
3381 | |
3382 begin | |
3383 In_Inlined_Body := True; | |
3384 | |
3385 if Is_Predef then | |
3386 declare | |
3387 Style : constant Boolean := Style_Check; | |
3388 | |
3389 begin | |
3390 Style_Check := False; | |
3391 | |
3392 -- Search for dispatching calls that use the Object.Operation | |
3393 -- notation using an Object that is a parameter of the inlined | |
3394 -- function. We reset the decoration of Operation to force | |
3395 -- the reanalysis of the inlined dispatching call because | |
3396 -- the actual object has been inlined. | |
3397 | |
3398 Reset_Dispatching_Calls (Blk); | |
3399 | |
3400 Analyze (Blk, Suppress => All_Checks); | |
3401 Style_Check := Style; | |
3402 end; | |
3403 | |
3404 else | |
3405 Analyze (Blk); | |
3406 end if; | |
3407 | |
3408 In_Inlined_Body := I_Flag; | |
3409 end; | |
3410 | |
3411 if Ekind (Subp) = E_Procedure then | |
3412 Rewrite_Procedure_Call (N, Blk); | |
3413 | |
3414 else | |
3415 Rewrite_Function_Call (N, Blk); | |
3416 | |
3417 if Is_Unc_Decl then | |
3418 null; | |
3419 | |
3420 -- For the unconstrained case, the replacement of the call has been | |
3421 -- made prior to the complete analysis of the generated declarations. | |
3422 -- Propagate the proper type now. | |
3423 | |
3424 elsif Is_Unc then | |
3425 if Nkind (N) = N_Identifier then | |
3426 Set_Etype (N, Etype (Entity (N))); | |
3427 else | |
3428 Set_Etype (N, Etype (Targ1)); | |
3429 end if; | |
3430 end if; | |
3431 end if; | |
3432 | |
3433 Restore_Env; | |
3434 | |
3435 -- Cleanup mapping between formals and actuals for other expansions | |
3436 | |
3437 F := First_Formal (Subp); | |
3438 while Present (F) loop | |
3439 Set_Renamed_Object (F, Empty); | |
3440 Next_Formal (F); | |
3441 end loop; | |
3442 end Expand_Inlined_Call; | |
3443 | |
3444 -------------------------- | |
3445 -- Get_Code_Unit_Entity -- | |
3446 -------------------------- | |
3447 | |
3448 function Get_Code_Unit_Entity (E : Entity_Id) return Entity_Id is | |
3449 Unit : Entity_Id := Cunit_Entity (Get_Code_Unit (E)); | |
3450 | |
3451 begin | |
3452 if Ekind (Unit) = E_Package_Body then | |
3453 Unit := Spec_Entity (Unit); | |
3454 end if; | |
3455 | |
3456 return Unit; | |
3457 end Get_Code_Unit_Entity; | |
3458 | |
3459 ------------------------------ | |
3460 -- Has_Excluded_Declaration -- | |
3461 ------------------------------ | |
3462 | |
3463 function Has_Excluded_Declaration | |
3464 (Subp : Entity_Id; | |
3465 Decls : List_Id) return Boolean | |
3466 is | |
3467 D : Node_Id; | |
3468 | |
3469 function Is_Unchecked_Conversion (D : Node_Id) return Boolean; | |
3470 -- Nested subprograms make a given body ineligible for inlining, but | |
3471 -- we make an exception for instantiations of unchecked conversion. | |
3472 -- The body has not been analyzed yet, so check the name, and verify | |
3473 -- that the visible entity with that name is the predefined unit. | |
3474 | |
3475 ----------------------------- | |
3476 -- Is_Unchecked_Conversion -- | |
3477 ----------------------------- | |
3478 | |
3479 function Is_Unchecked_Conversion (D : Node_Id) return Boolean is | |
3480 Id : constant Node_Id := Name (D); | |
3481 Conv : Entity_Id; | |
3482 | |
3483 begin | |
3484 if Nkind (Id) = N_Identifier | |
3485 and then Chars (Id) = Name_Unchecked_Conversion | |
3486 then | |
3487 Conv := Current_Entity (Id); | |
3488 | |
3489 elsif Nkind_In (Id, N_Selected_Component, N_Expanded_Name) | |
3490 and then Chars (Selector_Name (Id)) = Name_Unchecked_Conversion | |
3491 then | |
3492 Conv := Current_Entity (Selector_Name (Id)); | |
3493 else | |
3494 return False; | |
3495 end if; | |
3496 | |
3497 return Present (Conv) | |
3498 and then Is_Predefined_Unit (Get_Source_Unit (Conv)) | |
3499 and then Is_Intrinsic_Subprogram (Conv); | |
3500 end Is_Unchecked_Conversion; | |
3501 | |
3502 -- Start of processing for Has_Excluded_Declaration | |
3503 | |
3504 begin | |
3505 -- No action needed if the check is not needed | |
3506 | |
3507 if not Check_Inlining_Restrictions then | |
3508 return False; | |
3509 end if; | |
3510 | |
3511 D := First (Decls); | |
3512 while Present (D) loop | |
3513 | |
3514 -- First declarations universally excluded | |
3515 | |
3516 if Nkind (D) = N_Package_Declaration then | |
3517 Cannot_Inline | |
3518 ("cannot inline & (nested package declaration)?", D, Subp); | |
3519 return True; | |
3520 | |
3521 elsif Nkind (D) = N_Package_Instantiation then | |
3522 Cannot_Inline | |
3523 ("cannot inline & (nested package instantiation)?", D, Subp); | |
3524 return True; | |
3525 end if; | |
3526 | |
3527 -- Then declarations excluded only for front-end inlining | |
3528 | |
3529 if Back_End_Inlining then | |
3530 null; | |
3531 | |
3532 elsif Nkind (D) = N_Task_Type_Declaration | |
3533 or else Nkind (D) = N_Single_Task_Declaration | |
3534 then | |
3535 Cannot_Inline | |
3536 ("cannot inline & (nested task type declaration)?", D, Subp); | |
3537 return True; | |
3538 | |
3539 elsif Nkind (D) = N_Protected_Type_Declaration | |
3540 or else Nkind (D) = N_Single_Protected_Declaration | |
3541 then | |
3542 Cannot_Inline | |
3543 ("cannot inline & (nested protected type declaration)?", | |
3544 D, Subp); | |
3545 return True; | |
3546 | |
3547 elsif Nkind (D) = N_Subprogram_Body then | |
3548 Cannot_Inline | |
3549 ("cannot inline & (nested subprogram)?", D, Subp); | |
3550 return True; | |
3551 | |
3552 elsif Nkind (D) = N_Function_Instantiation | |
3553 and then not Is_Unchecked_Conversion (D) | |
3554 then | |
3555 Cannot_Inline | |
3556 ("cannot inline & (nested function instantiation)?", D, Subp); | |
3557 return True; | |
3558 | |
3559 elsif Nkind (D) = N_Procedure_Instantiation then | |
3560 Cannot_Inline | |
3561 ("cannot inline & (nested procedure instantiation)?", D, Subp); | |
3562 return True; | |
3563 | |
3564 -- Subtype declarations with predicates will generate predicate | |
3565 -- functions, i.e. nested subprogram bodies, so inlining is not | |
3566 -- possible. | |
3567 | |
3568 elsif Nkind (D) = N_Subtype_Declaration | |
3569 and then Present (Aspect_Specifications (D)) | |
3570 then | |
3571 declare | |
3572 A : Node_Id; | |
3573 A_Id : Aspect_Id; | |
3574 | |
3575 begin | |
3576 A := First (Aspect_Specifications (D)); | |
3577 while Present (A) loop | |
3578 A_Id := Get_Aspect_Id (Chars (Identifier (A))); | |
3579 | |
3580 if A_Id = Aspect_Predicate | |
3581 or else A_Id = Aspect_Static_Predicate | |
3582 or else A_Id = Aspect_Dynamic_Predicate | |
3583 then | |
3584 Cannot_Inline | |
3585 ("cannot inline & (subtype declaration with " | |
3586 & "predicate)?", D, Subp); | |
3587 return True; | |
3588 end if; | |
3589 | |
3590 Next (A); | |
3591 end loop; | |
3592 end; | |
3593 end if; | |
3594 | |
3595 Next (D); | |
3596 end loop; | |
3597 | |
3598 return False; | |
3599 end Has_Excluded_Declaration; | |
3600 | |
3601 ---------------------------- | |
3602 -- Has_Excluded_Statement -- | |
3603 ---------------------------- | |
3604 | |
3605 function Has_Excluded_Statement | |
3606 (Subp : Entity_Id; | |
3607 Stats : List_Id) return Boolean | |
3608 is | |
3609 S : Node_Id; | |
3610 E : Node_Id; | |
3611 | |
3612 begin | |
3613 -- No action needed if the check is not needed | |
3614 | |
3615 if not Check_Inlining_Restrictions then | |
3616 return False; | |
3617 end if; | |
3618 | |
3619 S := First (Stats); | |
3620 while Present (S) loop | |
3621 if Nkind_In (S, N_Abort_Statement, | |
3622 N_Asynchronous_Select, | |
3623 N_Conditional_Entry_Call, | |
3624 N_Delay_Relative_Statement, | |
3625 N_Delay_Until_Statement, | |
3626 N_Selective_Accept, | |
3627 N_Timed_Entry_Call) | |
3628 then | |
3629 Cannot_Inline | |
3630 ("cannot inline & (non-allowed statement)?", S, Subp); | |
3631 return True; | |
3632 | |
3633 elsif Nkind (S) = N_Block_Statement then | |
3634 if Present (Declarations (S)) | |
3635 and then Has_Excluded_Declaration (Subp, Declarations (S)) | |
3636 then | |
3637 return True; | |
3638 | |
3639 elsif Present (Handled_Statement_Sequence (S)) then | |
3640 if not Back_End_Inlining | |
3641 and then | |
3642 Present | |
3643 (Exception_Handlers (Handled_Statement_Sequence (S))) | |
3644 then | |
3645 Cannot_Inline | |
3646 ("cannot inline& (exception handler)?", | |
3647 First (Exception_Handlers | |
3648 (Handled_Statement_Sequence (S))), | |
3649 Subp); | |
3650 return True; | |
3651 | |
3652 elsif Has_Excluded_Statement | |
3653 (Subp, Statements (Handled_Statement_Sequence (S))) | |
3654 then | |
3655 return True; | |
3656 end if; | |
3657 end if; | |
3658 | |
3659 elsif Nkind (S) = N_Case_Statement then | |
3660 E := First (Alternatives (S)); | |
3661 while Present (E) loop | |
3662 if Has_Excluded_Statement (Subp, Statements (E)) then | |
3663 return True; | |
3664 end if; | |
3665 | |
3666 Next (E); | |
3667 end loop; | |
3668 | |
3669 elsif Nkind (S) = N_If_Statement then | |
3670 if Has_Excluded_Statement (Subp, Then_Statements (S)) then | |
3671 return True; | |
3672 end if; | |
3673 | |
3674 if Present (Elsif_Parts (S)) then | |
3675 E := First (Elsif_Parts (S)); | |
3676 while Present (E) loop | |
3677 if Has_Excluded_Statement (Subp, Then_Statements (E)) then | |
3678 return True; | |
3679 end if; | |
3680 | |
3681 Next (E); | |
3682 end loop; | |
3683 end if; | |
3684 | |
3685 if Present (Else_Statements (S)) | |
3686 and then Has_Excluded_Statement (Subp, Else_Statements (S)) | |
3687 then | |
3688 return True; | |
3689 end if; | |
3690 | |
3691 elsif Nkind (S) = N_Loop_Statement | |
3692 and then Has_Excluded_Statement (Subp, Statements (S)) | |
3693 then | |
3694 return True; | |
3695 | |
3696 elsif Nkind (S) = N_Extended_Return_Statement then | |
3697 if Present (Handled_Statement_Sequence (S)) | |
3698 and then | |
3699 Has_Excluded_Statement | |
3700 (Subp, Statements (Handled_Statement_Sequence (S))) | |
3701 then | |
3702 return True; | |
3703 | |
3704 elsif not Back_End_Inlining | |
3705 and then Present (Handled_Statement_Sequence (S)) | |
3706 and then | |
3707 Present (Exception_Handlers | |
3708 (Handled_Statement_Sequence (S))) | |
3709 then | |
3710 Cannot_Inline | |
3711 ("cannot inline& (exception handler)?", | |
3712 First (Exception_Handlers (Handled_Statement_Sequence (S))), | |
3713 Subp); | |
3714 return True; | |
3715 end if; | |
3716 end if; | |
3717 | |
3718 Next (S); | |
3719 end loop; | |
3720 | |
3721 return False; | |
3722 end Has_Excluded_Statement; | |
3723 | |
3724 -------------------------- | |
3725 -- Has_Initialized_Type -- | |
3726 -------------------------- | |
3727 | |
3728 function Has_Initialized_Type (E : Entity_Id) return Boolean is | |
3729 E_Body : constant Node_Id := Subprogram_Body (E); | |
3730 Decl : Node_Id; | |
3731 | |
3732 begin | |
3733 if No (E_Body) then -- imported subprogram | |
3734 return False; | |
3735 | |
3736 else | |
3737 Decl := First (Declarations (E_Body)); | |
3738 while Present (Decl) loop | |
3739 if Nkind (Decl) = N_Full_Type_Declaration | |
3740 and then Present (Init_Proc (Defining_Identifier (Decl))) | |
3741 then | |
3742 return True; | |
3743 end if; | |
3744 | |
3745 Next (Decl); | |
3746 end loop; | |
3747 end if; | |
3748 | |
3749 return False; | |
3750 end Has_Initialized_Type; | |
3751 | |
3752 ----------------------- | |
3753 -- Has_Single_Return -- | |
3754 ----------------------- | |
3755 | |
3756 function Has_Single_Return (N : Node_Id) return Boolean is | |
3757 Return_Statement : Node_Id := Empty; | |
3758 | |
3759 function Check_Return (N : Node_Id) return Traverse_Result; | |
3760 | |
3761 ------------------ | |
3762 -- Check_Return -- | |
3763 ------------------ | |
3764 | |
3765 function Check_Return (N : Node_Id) return Traverse_Result is | |
3766 begin | |
3767 if Nkind (N) = N_Simple_Return_Statement then | |
3768 if Present (Expression (N)) | |
3769 and then Is_Entity_Name (Expression (N)) | |
3770 then | |
3771 if No (Return_Statement) then | |
3772 Return_Statement := N; | |
3773 return OK; | |
3774 | |
3775 elsif Chars (Expression (N)) = | |
3776 Chars (Expression (Return_Statement)) | |
3777 then | |
3778 return OK; | |
3779 | |
3780 else | |
3781 return Abandon; | |
3782 end if; | |
3783 | |
3784 -- A return statement within an extended return is a noop | |
3785 -- after inlining. | |
3786 | |
3787 elsif No (Expression (N)) | |
3788 and then | |
3789 Nkind (Parent (Parent (N))) = N_Extended_Return_Statement | |
3790 then | |
3791 return OK; | |
3792 | |
3793 else | |
3794 -- Expression has wrong form | |
3795 | |
3796 return Abandon; | |
3797 end if; | |
3798 | |
3799 -- We can only inline a build-in-place function if it has a single | |
3800 -- extended return. | |
3801 | |
3802 elsif Nkind (N) = N_Extended_Return_Statement then | |
3803 if No (Return_Statement) then | |
3804 Return_Statement := N; | |
3805 return OK; | |
3806 | |
3807 else | |
3808 return Abandon; | |
3809 end if; | |
3810 | |
3811 else | |
3812 return OK; | |
3813 end if; | |
3814 end Check_Return; | |
3815 | |
3816 function Check_All_Returns is new Traverse_Func (Check_Return); | |
3817 | |
3818 -- Start of processing for Has_Single_Return | |
3819 | |
3820 begin | |
3821 if Check_All_Returns (N) /= OK then | |
3822 return False; | |
3823 | |
3824 elsif Nkind (Return_Statement) = N_Extended_Return_Statement then | |
3825 return True; | |
3826 | |
3827 else | |
3828 return Present (Declarations (N)) | |
3829 and then Present (First (Declarations (N))) | |
3830 and then Chars (Expression (Return_Statement)) = | |
3831 Chars (Defining_Identifier (First (Declarations (N)))); | |
3832 end if; | |
3833 end Has_Single_Return; | |
3834 | |
3835 ----------------------------- | |
3836 -- In_Main_Unit_Or_Subunit -- | |
3837 ----------------------------- | |
3838 | |
3839 function In_Main_Unit_Or_Subunit (E : Entity_Id) return Boolean is | |
3840 Comp : Node_Id := Cunit (Get_Code_Unit (E)); | |
3841 | |
3842 begin | |
3843 -- Check whether the subprogram or package to inline is within the main | |
3844 -- unit or its spec or within a subunit. In either case there are no | |
3845 -- additional bodies to process. If the subprogram appears in a parent | |
3846 -- of the current unit, the check on whether inlining is possible is | |
3847 -- done in Analyze_Inlined_Bodies. | |
3848 | |
3849 while Nkind (Unit (Comp)) = N_Subunit loop | |
3850 Comp := Library_Unit (Comp); | |
3851 end loop; | |
3852 | |
3853 return Comp = Cunit (Main_Unit) | |
3854 or else Comp = Library_Unit (Cunit (Main_Unit)); | |
3855 end In_Main_Unit_Or_Subunit; | |
3856 | |
3857 ---------------- | |
3858 -- Initialize -- | |
3859 ---------------- | |
3860 | |
3861 procedure Initialize is | |
3862 begin | |
3863 Pending_Descriptor.Init; | |
3864 Pending_Instantiations.Init; | |
3865 Inlined_Bodies.Init; | |
3866 Successors.Init; | |
3867 Inlined.Init; | |
3868 | |
3869 for J in Hash_Headers'Range loop | |
3870 Hash_Headers (J) := No_Subp; | |
3871 end loop; | |
3872 | |
3873 Inlined_Calls := No_Elist; | |
3874 Backend_Calls := No_Elist; | |
3875 Backend_Inlined_Subps := No_Elist; | |
3876 Backend_Not_Inlined_Subps := No_Elist; | |
3877 end Initialize; | |
3878 | |
3879 ------------------------ | |
3880 -- Instantiate_Bodies -- | |
3881 ------------------------ | |
3882 | |
3883 -- Generic bodies contain all the non-local references, so an | |
3884 -- instantiation does not need any more context than Standard | |
3885 -- itself, even if the instantiation appears in an inner scope. | |
3886 -- Generic associations have verified that the contract model is | |
3887 -- satisfied, so that any error that may occur in the analysis of | |
3888 -- the body is an internal error. | |
3889 | |
3890 procedure Instantiate_Bodies is | |
3891 J : Nat; | |
3892 Info : Pending_Body_Info; | |
3893 | |
3894 begin | |
3895 if Serious_Errors_Detected = 0 then | |
3896 Expander_Active := (Operating_Mode = Opt.Generate_Code); | |
3897 Push_Scope (Standard_Standard); | |
3898 To_Clean := New_Elmt_List; | |
3899 | |
3900 if Is_Generic_Unit (Cunit_Entity (Main_Unit)) then | |
3901 Start_Generic; | |
3902 end if; | |
3903 | |
3904 -- A body instantiation may generate additional instantiations, so | |
3905 -- the following loop must scan to the end of a possibly expanding | |
3906 -- set (that's why we can't simply use a FOR loop here). | |
3907 | |
3908 J := 0; | |
3909 while J <= Pending_Instantiations.Last | |
3910 and then Serious_Errors_Detected = 0 | |
3911 loop | |
3912 Info := Pending_Instantiations.Table (J); | |
3913 | |
3914 -- If the instantiation node is absent, it has been removed | |
3915 -- as part of unreachable code. | |
3916 | |
3917 if No (Info.Inst_Node) then | |
3918 null; | |
3919 | |
3920 elsif Nkind (Info.Act_Decl) = N_Package_Declaration then | |
3921 Instantiate_Package_Body (Info); | |
3922 Add_Scope_To_Clean (Defining_Entity (Info.Act_Decl)); | |
3923 | |
3924 else | |
3925 Instantiate_Subprogram_Body (Info); | |
3926 end if; | |
3927 | |
3928 J := J + 1; | |
3929 end loop; | |
3930 | |
3931 -- Reset the table of instantiations. Additional instantiations | |
3932 -- may be added through inlining, when additional bodies are | |
3933 -- analyzed. | |
3934 | |
3935 Pending_Instantiations.Init; | |
3936 | |
3937 -- We can now complete the cleanup actions of scopes that contain | |
3938 -- pending instantiations (skipped for generic units, since we | |
3939 -- never need any cleanups in generic units). | |
3940 | |
3941 if Expander_Active | |
3942 and then not Is_Generic_Unit (Main_Unit_Entity) | |
3943 then | |
3944 Cleanup_Scopes; | |
3945 elsif Is_Generic_Unit (Cunit_Entity (Main_Unit)) then | |
3946 End_Generic; | |
3947 end if; | |
3948 | |
3949 Pop_Scope; | |
3950 end if; | |
3951 end Instantiate_Bodies; | |
3952 | |
3953 --------------- | |
3954 -- Is_Nested -- | |
3955 --------------- | |
3956 | |
3957 function Is_Nested (E : Entity_Id) return Boolean is | |
3958 Scop : Entity_Id; | |
3959 | |
3960 begin | |
3961 Scop := Scope (E); | |
3962 while Scop /= Standard_Standard loop | |
3963 if Ekind (Scop) in Subprogram_Kind then | |
3964 return True; | |
3965 | |
3966 elsif Ekind (Scop) = E_Task_Type | |
3967 or else Ekind (Scop) = E_Entry | |
3968 or else Ekind (Scop) = E_Entry_Family | |
3969 then | |
3970 return True; | |
3971 end if; | |
3972 | |
3973 Scop := Scope (Scop); | |
3974 end loop; | |
3975 | |
3976 return False; | |
3977 end Is_Nested; | |
3978 | |
3979 ------------------------ | |
3980 -- List_Inlining_Info -- | |
3981 ------------------------ | |
3982 | |
3983 procedure List_Inlining_Info is | |
3984 Elmt : Elmt_Id; | |
3985 Nod : Node_Id; | |
3986 Count : Nat; | |
3987 | |
3988 begin | |
3989 if not Debug_Flag_Dot_J then | |
3990 return; | |
3991 end if; | |
3992 | |
3993 -- Generate listing of calls inlined by the frontend | |
3994 | |
3995 if Present (Inlined_Calls) then | |
3996 Count := 0; | |
3997 Elmt := First_Elmt (Inlined_Calls); | |
3998 while Present (Elmt) loop | |
3999 Nod := Node (Elmt); | |
4000 | |
4001 if In_Extended_Main_Code_Unit (Nod) then | |
4002 Count := Count + 1; | |
4003 | |
4004 if Count = 1 then | |
4005 Write_Str ("List of calls inlined by the frontend"); | |
4006 Write_Eol; | |
4007 end if; | |
4008 | |
4009 Write_Str (" "); | |
4010 Write_Int (Count); | |
4011 Write_Str (":"); | |
4012 Write_Location (Sloc (Nod)); | |
4013 Write_Str (":"); | |
4014 Output.Write_Eol; | |
4015 end if; | |
4016 | |
4017 Next_Elmt (Elmt); | |
4018 end loop; | |
4019 end if; | |
4020 | |
4021 -- Generate listing of calls passed to the backend | |
4022 | |
4023 if Present (Backend_Calls) then | |
4024 Count := 0; | |
4025 | |
4026 Elmt := First_Elmt (Backend_Calls); | |
4027 while Present (Elmt) loop | |
4028 Nod := Node (Elmt); | |
4029 | |
4030 if In_Extended_Main_Code_Unit (Nod) then | |
4031 Count := Count + 1; | |
4032 | |
4033 if Count = 1 then | |
4034 Write_Str ("List of inlined calls passed to the backend"); | |
4035 Write_Eol; | |
4036 end if; | |
4037 | |
4038 Write_Str (" "); | |
4039 Write_Int (Count); | |
4040 Write_Str (":"); | |
4041 Write_Location (Sloc (Nod)); | |
4042 Output.Write_Eol; | |
4043 end if; | |
4044 | |
4045 Next_Elmt (Elmt); | |
4046 end loop; | |
4047 end if; | |
4048 | |
4049 -- Generate listing of subprograms passed to the backend | |
4050 | |
4051 if Present (Backend_Inlined_Subps) and then Back_End_Inlining then | |
4052 Count := 0; | |
4053 | |
4054 Elmt := First_Elmt (Backend_Inlined_Subps); | |
4055 while Present (Elmt) loop | |
4056 Nod := Node (Elmt); | |
4057 | |
4058 Count := Count + 1; | |
4059 | |
4060 if Count = 1 then | |
4061 Write_Str | |
4062 ("List of inlined subprograms passed to the backend"); | |
4063 Write_Eol; | |
4064 end if; | |
4065 | |
4066 Write_Str (" "); | |
4067 Write_Int (Count); | |
4068 Write_Str (":"); | |
4069 Write_Name (Chars (Nod)); | |
4070 Write_Str (" ("); | |
4071 Write_Location (Sloc (Nod)); | |
4072 Write_Str (")"); | |
4073 Output.Write_Eol; | |
4074 | |
4075 Next_Elmt (Elmt); | |
4076 end loop; | |
4077 end if; | |
4078 | |
4079 -- Generate listing of subprograms that cannot be inlined by the backend | |
4080 | |
4081 if Present (Backend_Not_Inlined_Subps) and then Back_End_Inlining then | |
4082 Count := 0; | |
4083 | |
4084 Elmt := First_Elmt (Backend_Not_Inlined_Subps); | |
4085 while Present (Elmt) loop | |
4086 Nod := Node (Elmt); | |
4087 | |
4088 Count := Count + 1; | |
4089 | |
4090 if Count = 1 then | |
4091 Write_Str | |
4092 ("List of subprograms that cannot be inlined by the backend"); | |
4093 Write_Eol; | |
4094 end if; | |
4095 | |
4096 Write_Str (" "); | |
4097 Write_Int (Count); | |
4098 Write_Str (":"); | |
4099 Write_Name (Chars (Nod)); | |
4100 Write_Str (" ("); | |
4101 Write_Location (Sloc (Nod)); | |
4102 Write_Str (")"); | |
4103 Output.Write_Eol; | |
4104 | |
4105 Next_Elmt (Elmt); | |
4106 end loop; | |
4107 end if; | |
4108 end List_Inlining_Info; | |
4109 | |
4110 ---------- | |
4111 -- Lock -- | |
4112 ---------- | |
4113 | |
4114 procedure Lock is | |
4115 begin | |
4116 Pending_Instantiations.Release; | |
4117 Pending_Instantiations.Locked := True; | |
4118 Inlined_Bodies.Release; | |
4119 Inlined_Bodies.Locked := True; | |
4120 Successors.Release; | |
4121 Successors.Locked := True; | |
4122 Inlined.Release; | |
4123 Inlined.Locked := True; | |
4124 end Lock; | |
4125 | |
4126 -------------------------------- | |
4127 -- Remove_Aspects_And_Pragmas -- | |
4128 -------------------------------- | |
4129 | |
4130 procedure Remove_Aspects_And_Pragmas (Body_Decl : Node_Id) is | |
4131 procedure Remove_Items (List : List_Id); | |
4132 -- Remove all useless aspects/pragmas from a particular list | |
4133 | |
4134 ------------------ | |
4135 -- Remove_Items -- | |
4136 ------------------ | |
4137 | |
4138 procedure Remove_Items (List : List_Id) is | |
4139 Item : Node_Id; | |
4140 Item_Id : Node_Id; | |
4141 Next_Item : Node_Id; | |
4142 | |
4143 begin | |
4144 -- Traverse the list looking for an aspect specification or a pragma | |
4145 | |
4146 Item := First (List); | |
4147 while Present (Item) loop | |
4148 Next_Item := Next (Item); | |
4149 | |
4150 if Nkind (Item) = N_Aspect_Specification then | |
4151 Item_Id := Identifier (Item); | |
4152 elsif Nkind (Item) = N_Pragma then | |
4153 Item_Id := Pragma_Identifier (Item); | |
4154 else | |
4155 Item_Id := Empty; | |
4156 end if; | |
4157 | |
4158 if Present (Item_Id) | |
4159 and then Nam_In (Chars (Item_Id), Name_Contract_Cases, | |
4160 Name_Global, | |
4161 Name_Depends, | |
4162 Name_Postcondition, | |
4163 Name_Precondition, | |
4164 Name_Refined_Global, | |
4165 Name_Refined_Depends, | |
4166 Name_Refined_Post, | |
4167 Name_Test_Case, | |
4168 Name_Unmodified, | |
4169 Name_Unreferenced, | |
4170 Name_Unused) | |
4171 then | |
4172 Remove (Item); | |
4173 end if; | |
4174 | |
4175 Item := Next_Item; | |
4176 end loop; | |
4177 end Remove_Items; | |
4178 | |
4179 -- Start of processing for Remove_Aspects_And_Pragmas | |
4180 | |
4181 begin | |
4182 Remove_Items (Aspect_Specifications (Body_Decl)); | |
4183 Remove_Items (Declarations (Body_Decl)); | |
4184 | |
4185 -- Pragmas Unmodified, Unreferenced, and Unused may additionally appear | |
4186 -- in the body of the subprogram. | |
4187 | |
4188 Remove_Items (Statements (Handled_Statement_Sequence (Body_Decl))); | |
4189 end Remove_Aspects_And_Pragmas; | |
4190 | |
4191 -------------------------- | |
4192 -- Remove_Dead_Instance -- | |
4193 -------------------------- | |
4194 | |
4195 procedure Remove_Dead_Instance (N : Node_Id) is | |
4196 J : Int; | |
4197 | |
4198 begin | |
4199 J := 0; | |
4200 while J <= Pending_Instantiations.Last loop | |
4201 if Pending_Instantiations.Table (J).Inst_Node = N then | |
4202 Pending_Instantiations.Table (J).Inst_Node := Empty; | |
4203 return; | |
4204 end if; | |
4205 | |
4206 J := J + 1; | |
4207 end loop; | |
4208 end Remove_Dead_Instance; | |
4209 | |
4210 end Inline; |