PR testsuite/44195
[official-gcc.git] / gcc / ada / live.adb
blobeaa52020b5f5bef1714de2bcf4ac591488e468cc
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- L I V E --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2000-2007, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Atree; use Atree;
27 with Einfo; use Einfo;
28 with Lib; use Lib;
29 with Nlists; use Nlists;
30 with Sem_Util; use Sem_Util;
31 with Sinfo; use Sinfo;
32 with Types; use Types;
34 package body Live is
36 -- Name_Set
38 -- The Name_Set type is used to store the temporary mark bits
39 -- used by the garbage collection of entities. Using a separate
40 -- array prevents using up any valuable per-node space and possibly
41 -- results in better locality and cache usage.
43 type Name_Set is array (Node_Id range <>) of Boolean;
44 pragma Pack (Name_Set);
46 function Marked (Marks : Name_Set; Name : Node_Id) return Boolean;
47 pragma Inline (Marked);
49 procedure Set_Marked
50 (Marks : in out Name_Set;
51 Name : Node_Id;
52 Mark : Boolean := True);
53 pragma Inline (Set_Marked);
55 -- Algorithm
57 -- The problem of finding live entities is solved in two steps:
59 procedure Mark (Root : Node_Id; Marks : out Name_Set);
60 -- Mark all live entities in Root as Marked
62 procedure Sweep (Root : Node_Id; Marks : Name_Set);
63 -- For all unmarked entities in Root set Is_Eliminated to true
65 -- The Mark phase is split into two phases:
67 procedure Init_Marked (Root : Node_Id; Marks : out Name_Set);
68 -- For all subprograms, reset Is_Public flag if a pragma Eliminate
69 -- applies to the entity, and set the Marked flag to Is_Public
71 procedure Trace_Marked (Root : Node_Id; Marks : in out Name_Set);
72 -- Traverse the tree skipping any unmarked subprogram bodies.
73 -- All visited entities are marked, as well as entities denoted
74 -- by a visited identifier or operator. When an entity is first
75 -- marked it is traced as well.
77 -- Local functions
79 function Body_Of (E : Entity_Id) return Node_Id;
80 -- Returns subprogram body corresponding to entity E
82 function Spec_Of (N : Node_Id) return Entity_Id;
83 -- Given a subprogram body N, return defining identifier of its declaration
85 -- ??? the body of this package contains no comments at all, this
86 -- should be fixed!
88 -------------
89 -- Body_Of --
90 -------------
92 function Body_Of (E : Entity_Id) return Node_Id is
93 Decl : constant Node_Id := Unit_Declaration_Node (E);
94 Kind : constant Node_Kind := Nkind (Decl);
95 Result : Node_Id;
97 begin
98 if Kind = N_Subprogram_Body then
99 Result := Decl;
101 elsif Kind /= N_Subprogram_Declaration
102 and Kind /= N_Subprogram_Body_Stub
103 then
104 Result := Empty;
106 else
107 Result := Corresponding_Body (Decl);
109 if Result /= Empty then
110 Result := Unit_Declaration_Node (Result);
111 end if;
112 end if;
114 return Result;
115 end Body_Of;
117 ------------------------------
118 -- Collect_Garbage_Entities --
119 ------------------------------
121 procedure Collect_Garbage_Entities is
122 Root : constant Node_Id := Cunit (Main_Unit);
123 Marks : Name_Set (0 .. Last_Node_Id);
125 begin
126 Mark (Root, Marks);
127 Sweep (Root, Marks);
128 end Collect_Garbage_Entities;
130 -----------------
131 -- Init_Marked --
132 -----------------
134 procedure Init_Marked (Root : Node_Id; Marks : out Name_Set) is
136 function Process (N : Node_Id) return Traverse_Result;
137 procedure Traverse is new Traverse_Proc (Process);
139 function Process (N : Node_Id) return Traverse_Result is
140 begin
141 case Nkind (N) is
142 when N_Entity'Range =>
143 if Is_Eliminated (N) then
144 Set_Is_Public (N, False);
145 end if;
147 Set_Marked (Marks, N, Is_Public (N));
149 when N_Subprogram_Body =>
150 Traverse (Spec_Of (N));
152 when N_Package_Body_Stub =>
153 if Present (Library_Unit (N)) then
154 Traverse (Proper_Body (Unit (Library_Unit (N))));
155 end if;
157 when N_Package_Body =>
158 declare
159 Elmt : Node_Id := First (Declarations (N));
160 begin
161 while Present (Elmt) loop
162 Traverse (Elmt);
163 Next (Elmt);
164 end loop;
165 end;
167 when others =>
168 null;
169 end case;
171 return OK;
172 end Process;
174 -- Start of processing for Init_Marked
176 begin
177 Marks := (others => False);
178 Traverse (Root);
179 end Init_Marked;
181 ----------
182 -- Mark --
183 ----------
185 procedure Mark (Root : Node_Id; Marks : out Name_Set) is
186 begin
187 Init_Marked (Root, Marks);
188 Trace_Marked (Root, Marks);
189 end Mark;
191 ------------
192 -- Marked --
193 ------------
195 function Marked (Marks : Name_Set; Name : Node_Id) return Boolean is
196 begin
197 return Marks (Name);
198 end Marked;
200 ----------------
201 -- Set_Marked --
202 ----------------
204 procedure Set_Marked
205 (Marks : in out Name_Set;
206 Name : Node_Id;
207 Mark : Boolean := True)
209 begin
210 Marks (Name) := Mark;
211 end Set_Marked;
213 -------------
214 -- Spec_Of --
215 -------------
217 function Spec_Of (N : Node_Id) return Entity_Id is
218 begin
219 if Acts_As_Spec (N) then
220 return Defining_Entity (N);
221 else
222 return Corresponding_Spec (N);
223 end if;
224 end Spec_Of;
226 -----------
227 -- Sweep --
228 -----------
230 procedure Sweep (Root : Node_Id; Marks : Name_Set) is
232 function Process (N : Node_Id) return Traverse_Result;
233 procedure Traverse is new Traverse_Proc (Process);
235 function Process (N : Node_Id) return Traverse_Result is
236 begin
237 case Nkind (N) is
238 when N_Entity'Range =>
239 Set_Is_Eliminated (N, not Marked (Marks, N));
241 when N_Subprogram_Body =>
242 Traverse (Spec_Of (N));
244 when N_Package_Body_Stub =>
245 if Present (Library_Unit (N)) then
246 Traverse (Proper_Body (Unit (Library_Unit (N))));
247 end if;
249 when N_Package_Body =>
250 declare
251 Elmt : Node_Id := First (Declarations (N));
252 begin
253 while Present (Elmt) loop
254 Traverse (Elmt);
255 Next (Elmt);
256 end loop;
257 end;
259 when others =>
260 null;
261 end case;
262 return OK;
263 end Process;
265 begin
266 Traverse (Root);
267 end Sweep;
269 ------------------
270 -- Trace_Marked --
271 ------------------
273 procedure Trace_Marked (Root : Node_Id; Marks : in out Name_Set) is
275 function Process (N : Node_Id) return Traverse_Result;
276 procedure Process (N : Node_Id);
277 procedure Traverse is new Traverse_Proc (Process);
279 procedure Process (N : Node_Id) is
280 Result : Traverse_Result;
281 pragma Warnings (Off, Result);
283 begin
284 Result := Process (N);
285 end Process;
287 function Process (N : Node_Id) return Traverse_Result is
288 Result : Traverse_Result := OK;
289 B : Node_Id;
290 E : Entity_Id;
292 begin
293 case Nkind (N) is
294 when N_Pragma | N_Generic_Declaration'Range |
295 N_Subprogram_Declaration | N_Subprogram_Body_Stub =>
296 Result := Skip;
298 when N_Subprogram_Body =>
299 if not Marked (Marks, Spec_Of (N)) then
300 Result := Skip;
301 end if;
303 when N_Package_Body_Stub =>
304 if Present (Library_Unit (N)) then
305 Traverse (Proper_Body (Unit (Library_Unit (N))));
306 end if;
308 when N_Identifier | N_Operator_Symbol | N_Expanded_Name =>
309 E := Entity (N);
311 if E /= Empty and then not Marked (Marks, E) then
312 Process (E);
314 if Is_Subprogram (E) then
315 B := Body_Of (E);
317 if B /= Empty then
318 Traverse (B);
319 end if;
320 end if;
321 end if;
323 when N_Entity'Range =>
324 if (Ekind (N) = E_Component) and then not Marked (Marks, N) then
325 if Present (Discriminant_Checking_Func (N)) then
326 Process (Discriminant_Checking_Func (N));
327 end if;
328 end if;
330 Set_Marked (Marks, N);
332 when others =>
333 null;
334 end case;
336 return Result;
337 end Process;
339 -- Start of processing for Trace_Marked
341 begin
342 Traverse (Root);
343 end Trace_Marked;
345 end Live;