1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1997-2001 Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, 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 COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Atree; use Atree;
28 with Einfo; use Einfo;
29 with Errout; use Errout;
30 with Namet; use Namet;
31 with Nlists; use Nlists;
32 with Sinfo; use Sinfo;
33 with Snames; use Snames;
34 with Stand; use Stand;
35 with Stringt; use Stringt;
36 with Uintp; use Uintp;
38 with GNAT.HTable; use GNAT.HTable;
39 package body Sem_Elim is
41 No_Elimination : Boolean;
42 -- Set True if no Eliminate pragmas active
48 -- A single pragma Eliminate is represented by the following record
51 type Access_Elim_Data is access Elim_Data;
53 type Names is array (Nat range <>) of Name_Id;
54 -- Type used to represent set of names. Used for names in Unit_Name
55 -- and also the set of names in Argument_Types.
57 type Access_Names is access Names;
59 type Elim_Data is record
61 Unit_Name : Access_Names;
62 -- Unit name, broken down into a set of names (e.g. A.B.C is
63 -- represented as Name_Id values for A, B, C in sequence).
65 Entity_Name : Name_Id;
66 -- Entity name if Entity parameter if present. If no Entity parameter
67 -- was supplied, then Entity_Node is set to Empty, and the Entity_Name
68 -- field contains the last identifier name in the Unit_Name.
70 Entity_Scope : Access_Names;
71 -- Static scope of the entity within the compilation unit represented by
74 Entity_Node : Node_Id;
75 -- Save node of entity argument, for posting error messages. Set
76 -- to Empty if there is no entity argument.
78 Parameter_Types : Access_Names;
79 -- Set to set of names given for parameter types. If no parameter
80 -- types argument is present, this argument is set to null.
82 Result_Type : Name_Id;
83 -- Result type name if Result_Types parameter present, No_Name if not
85 Homonym_Number : Uint;
86 -- Homonyn number if Homonym_Number parameter present, No_Uint if not.
88 Hash_Link : Access_Elim_Data;
89 -- Link for hash table use
91 Homonym : Access_Elim_Data;
92 -- Pointer to next entry with same key
100 -- Setup hash table using the Entity_Name field as the hash key
102 subtype Element is Elim_Data;
103 subtype Elmt_Ptr is Access_Elim_Data;
105 subtype Key is Name_Id;
107 type Header_Num is range 0 .. 1023;
109 Null_Ptr : constant Elmt_Ptr := null;
111 ----------------------
112 -- Hash_Subprograms --
113 ----------------------
115 package Hash_Subprograms is
117 function Equal (F1, F2 : Key) return Boolean;
118 pragma Inline (Equal);
120 function Get_Key (E : Elmt_Ptr) return Key;
121 pragma Inline (Get_Key);
123 function Hash (F : Key) return Header_Num;
124 pragma Inline (Hash);
126 function Next (E : Elmt_Ptr) return Elmt_Ptr;
127 pragma Inline (Next);
129 procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr);
130 pragma Inline (Set_Next);
132 end Hash_Subprograms;
134 package body Hash_Subprograms is
140 function Equal (F1, F2 : Key) return Boolean is
149 function Get_Key (E : Elmt_Ptr) return Key is
151 return E.Entity_Name;
158 function Hash (F : Key) return Header_Num is
160 return Header_Num (Int (F) mod 1024);
167 function Next (E : Elmt_Ptr) return Elmt_Ptr is
176 procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr) is
180 end Hash_Subprograms;
182 package Elim_Hash_Table is new Static_HTable (
183 Header_Num => Header_Num,
185 Elmt_Ptr => Elmt_Ptr,
186 Null_Ptr => Null_Ptr,
187 Set_Next => Hash_Subprograms.Set_Next,
188 Next => Hash_Subprograms.Next,
190 Get_Key => Hash_Subprograms.Get_Key,
191 Hash => Hash_Subprograms.Hash,
192 Equal => Hash_Subprograms.Equal);
194 ----------------------
195 -- Check_Eliminated --
196 ----------------------
198 procedure Check_Eliminated (E : Entity_Id) is
199 Elmt : Access_Elim_Data;
206 if No_Elimination then
209 -- Elimination of objects and types is not implemented yet.
211 elsif Ekind (E) not in Subprogram_Kind then
215 Elmt := Elim_Hash_Table.Get (Chars (E));
217 -- Loop through homonyms for this key
219 while Elmt /= null loop
221 -- First we check that the name of the entity matches
223 if Elmt.Entity_Name /= Chars (E) then
227 -- Then we need to see if the static scope matches within the
231 if Elmt.Entity_Scope /= null then
232 for J in reverse Elmt.Entity_Scope'Range loop
233 if Elmt.Entity_Scope (J) /= Chars (Scop) then
237 Scop := Scope (Scop);
239 if not Is_Compilation_Unit (Scop) and then J = 1 then
245 -- Now see if compilation unit matches
247 for J in reverse Elmt.Unit_Name'Range loop
248 if Elmt.Unit_Name (J) /= Chars (Scop) then
252 Scop := Scope (Scop);
254 if Scop /= Standard_Standard and then J = 1 then
259 if Scop /= Standard_Standard then
263 -- Check for case of given entity is a library level subprogram
264 -- and we have the single parameter Eliminate case, a match!
266 if Is_Compilation_Unit (E)
267 and then Is_Subprogram (E)
268 and then No (Elmt.Entity_Node)
270 Set_Is_Eliminated (E);
273 -- Check for case of type or object with two parameter case
275 elsif (Is_Type (E) or else Is_Object (E))
276 and then Elmt.Result_Type = No_Name
277 and then Elmt.Parameter_Types = null
279 Set_Is_Eliminated (E);
282 -- Check for case of subprogram
284 elsif Ekind (E) = E_Function
285 or else Ekind (E) = E_Procedure
287 -- If Homonym_Number present, then see if it matches
289 if Elmt.Homonym_Number /= No_Uint then
293 while Present (Homonym (Ent))
294 and then Scope (Ent) = Scope (Homonym (Ent))
297 Ent := Homonym (Ent);
300 if Ctr /= Elmt.Homonym_Number then
305 -- If we have a Result_Type, then we must have a function
306 -- with the proper result type
308 if Elmt.Result_Type /= No_Name then
309 if Ekind (E) /= E_Function
310 or else Chars (Etype (E)) /= Elmt.Result_Type
316 -- If we have Parameter_Types, they must match
318 if Elmt.Parameter_Types /= null then
319 Form := First_Formal (E);
321 if No (Form) and then Elmt.Parameter_Types = null then
324 elsif Elmt.Parameter_Types = null then
328 for J in Elmt.Parameter_Types'Range loop
330 or else Chars (Etype (Form)) /= Elmt.Parameter_Types (J)
338 if Present (Form) then
344 -- If we fall through, this is match
346 Set_Is_Eliminated (E);
350 <<Continue>> Elmt := Elmt.Homonym;
354 end Check_Eliminated;
360 procedure Initialize is
362 Elim_Hash_Table.Reset;
363 No_Elimination := True;
366 ------------------------------
367 -- Process_Eliminate_Pragma --
368 ------------------------------
370 procedure Process_Eliminate_Pragma
371 (Arg_Unit_Name : Node_Id;
372 Arg_Entity : Node_Id;
373 Arg_Parameter_Types : Node_Id;
374 Arg_Result_Type : Node_Id;
375 Arg_Homonym_Number : Node_Id)
377 Data : constant Access_Elim_Data := new Elim_Data;
378 -- Build result data here
380 Elmt : Access_Elim_Data;
382 Num_Names : Nat := 0;
383 -- Number of names in unit name
389 function OK_Selected_Component (N : Node_Id) return Boolean;
390 -- Test if N is a selected component with all identifiers, or a
391 -- selected component whose selector is an operator symbol. As a
392 -- side effect if result is True, sets Num_Names to the number
393 -- of names present (identifiers and operator if any).
395 ---------------------------
396 -- OK_Selected_Component --
397 ---------------------------
399 function OK_Selected_Component (N : Node_Id) return Boolean is
401 if Nkind (N) = N_Identifier
402 or else Nkind (N) = N_Operator_Symbol
404 Num_Names := Num_Names + 1;
407 elsif Nkind (N) = N_Selected_Component then
408 return OK_Selected_Component (Prefix (N))
409 and then OK_Selected_Component (Selector_Name (N));
414 end OK_Selected_Component;
416 -- Start of processing for Process_Eliminate_Pragma
419 Error_Msg_Name_1 := Name_Eliminate;
421 -- Process Unit_Name argument
423 if Nkind (Arg_Unit_Name) = N_Identifier then
424 Data.Unit_Name := new Names'(1 => Chars (Arg_Unit_Name));
427 elsif OK_Selected_Component (Arg_Unit_Name) then
428 Data.Unit_Name := new Names (1 .. Num_Names);
430 Arg_Uname := Arg_Unit_Name;
431 for J in reverse 2 .. Num_Names loop
432 Data.Unit_Name (J) := Chars (Selector_Name (Arg_Uname));
433 Arg_Uname := Prefix (Arg_Uname);
436 Data.Unit_Name (1) := Chars (Arg_Uname);
440 ("wrong form for Unit_Name parameter of pragma%", Arg_Unit_Name);
444 -- Process Entity argument
446 if Present (Arg_Entity) then
449 if Nkind (Arg_Entity) = N_Identifier
450 or else Nkind (Arg_Entity) = N_Operator_Symbol
452 Data.Entity_Name := Chars (Arg_Entity);
453 Data.Entity_Node := Arg_Entity;
454 Data.Entity_Scope := null;
456 elsif OK_Selected_Component (Arg_Entity) then
457 Data.Entity_Scope := new Names (1 .. Num_Names - 1);
458 Data.Entity_Name := Chars (Selector_Name (Arg_Entity));
459 Data.Entity_Node := Arg_Entity;
461 Arg_Ent := Prefix (Arg_Entity);
462 for J in reverse 2 .. Num_Names - 1 loop
463 Data.Entity_Scope (J) := Chars (Selector_Name (Arg_Ent));
464 Arg_Ent := Prefix (Arg_Ent);
467 Data.Entity_Scope (1) := Chars (Arg_Ent);
469 elsif Nkind (Arg_Entity) = N_String_Literal then
470 String_To_Name_Buffer (Strval (Arg_Entity));
471 Data.Entity_Name := Name_Find;
472 Data.Entity_Node := Arg_Entity;
476 ("wrong form for Entity_Argument parameter of pragma%",
481 Data.Entity_Node := Empty;
482 Data.Entity_Name := Data.Unit_Name (Num_Names);
485 -- Process Parameter_Types argument
487 if Present (Arg_Parameter_Types) then
489 -- Case of one name, which looks like a parenthesized literal
490 -- rather than an aggregate.
492 if Nkind (Arg_Parameter_Types) = N_String_Literal
493 and then Paren_Count (Arg_Parameter_Types) = 1
495 String_To_Name_Buffer (Strval (Arg_Parameter_Types));
496 Data.Parameter_Types := new Names'(1 => Name_Find);
498 -- Otherwise must be an aggregate
500 elsif Nkind (Arg_Parameter_Types) /= N_Aggregate
501 or else Present (Component_Associations (Arg_Parameter_Types))
502 or else No (Expressions (Arg_Parameter_Types))
505 ("Parameter_Types for pragma% must be list of string literals",
506 Arg_Parameter_Types);
509 -- Here for aggregate case
512 Data.Parameter_Types :=
514 (1 .. List_Length (Expressions (Arg_Parameter_Types)));
516 Lit := First (Expressions (Arg_Parameter_Types));
517 for J in Data.Parameter_Types'Range loop
518 if Nkind (Lit) /= N_String_Literal then
520 ("parameter types for pragma% must be string literals",
525 String_To_Name_Buffer (Strval (Lit));
526 Data.Parameter_Types (J) := Name_Find;
532 -- Process Result_Types argument
534 if Present (Arg_Result_Type) then
536 if Nkind (Arg_Result_Type) /= N_String_Literal then
538 ("Result_Type argument for pragma% must be string literal",
543 String_To_Name_Buffer (Strval (Arg_Result_Type));
544 Data.Result_Type := Name_Find;
547 Data.Result_Type := No_Name;
550 -- Process Homonym_Number argument
552 if Present (Arg_Homonym_Number) then
554 if Nkind (Arg_Homonym_Number) /= N_Integer_Literal then
556 ("Homonym_Number argument for pragma% must be integer literal",
561 Data.Homonym_Number := Intval (Arg_Homonym_Number);
564 Data.Homonym_Number := No_Uint;
567 -- Now link this new entry into the hash table
569 Elmt := Elim_Hash_Table.Get (Hash_Subprograms.Get_Key (Data));
571 -- If we already have an entry with this same key, then link
572 -- it into the chain of entries for this key.
575 Data.Homonym := Elmt.Homonym;
576 Elmt.Homonym := Data;
578 -- Otherwise create a new entry
581 Elim_Hash_Table.Set (Data);
584 No_Elimination := False;
585 end Process_Eliminate_Pragma;