Merged trunk at revision 161680 into branch.
[official-gcc.git] / gcc / ada / sem_elim.adb
blobc160c8e419aa96e1710a4d60174ec51957a939de
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S E M _ E L I M --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1997-2010, 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 Errout; use Errout;
29 with Lib; use Lib;
30 with Namet; use Namet;
31 with Nlists; use Nlists;
32 with Opt; use Opt;
33 with Sem; use Sem;
34 with Sem_Aux; use Sem_Aux;
35 with Sem_Prag; use Sem_Prag;
36 with Sem_Util; use Sem_Util;
37 with Sinput; use Sinput;
38 with Sinfo; use Sinfo;
39 with Snames; use Snames;
40 with Stand; use Stand;
41 with Stringt; use Stringt;
42 with Table;
44 with GNAT.HTable; use GNAT.HTable;
46 package body Sem_Elim is
48 No_Elimination : Boolean;
49 -- Set True if no Eliminate pragmas active
51 ---------------------
52 -- Data Structures --
53 ---------------------
55 -- A single pragma Eliminate is represented by the following record
57 type Elim_Data;
58 type Access_Elim_Data is access Elim_Data;
60 type Names is array (Nat range <>) of Name_Id;
61 -- Type used to represent set of names. Used for names in Unit_Name
62 -- and also the set of names in Argument_Types.
64 type Access_Names is access Names;
66 type Elim_Data is record
68 Unit_Name : Access_Names;
69 -- Unit name, broken down into a set of names (e.g. A.B.C is
70 -- represented as Name_Id values for A, B, C in sequence).
72 Entity_Name : Name_Id;
73 -- Entity name if Entity parameter if present. If no Entity parameter
74 -- was supplied, then Entity_Node is set to Empty, and the Entity_Name
75 -- field contains the last identifier name in the Unit_Name.
77 Entity_Scope : Access_Names;
78 -- Static scope of the entity within the compilation unit represented by
79 -- Unit_Name.
81 Entity_Node : Node_Id;
82 -- Save node of entity argument, for posting error messages. Set
83 -- to Empty if there is no entity argument.
85 Parameter_Types : Access_Names;
86 -- Set to set of names given for parameter types. If no parameter
87 -- types argument is present, this argument is set to null.
89 Result_Type : Name_Id;
90 -- Result type name if Result_Types parameter present, No_Name if not
92 Source_Location : Name_Id;
93 -- String describing the source location of subprogram defining name if
94 -- Source_Location parameter present, No_Name if not
96 Hash_Link : Access_Elim_Data;
97 -- Link for hash table use
99 Homonym : Access_Elim_Data;
100 -- Pointer to next entry with same key
102 Prag : Node_Id;
103 -- Node_Id for Eliminate pragma
105 end record;
107 ----------------
108 -- Hash_Table --
109 ----------------
111 -- Setup hash table using the Entity_Name field as the hash key
113 subtype Element is Elim_Data;
114 subtype Elmt_Ptr is Access_Elim_Data;
116 subtype Key is Name_Id;
118 type Header_Num is range 0 .. 1023;
120 Null_Ptr : constant Elmt_Ptr := null;
122 ----------------------
123 -- Hash_Subprograms --
124 ----------------------
126 package Hash_Subprograms is
128 function Equal (F1, F2 : Key) return Boolean;
129 pragma Inline (Equal);
131 function Get_Key (E : Elmt_Ptr) return Key;
132 pragma Inline (Get_Key);
134 function Hash (F : Key) return Header_Num;
135 pragma Inline (Hash);
137 function Next (E : Elmt_Ptr) return Elmt_Ptr;
138 pragma Inline (Next);
140 procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr);
141 pragma Inline (Set_Next);
143 end Hash_Subprograms;
145 package body Hash_Subprograms is
147 -----------
148 -- Equal --
149 -----------
151 function Equal (F1, F2 : Key) return Boolean is
152 begin
153 return F1 = F2;
154 end Equal;
156 -------------
157 -- Get_Key --
158 -------------
160 function Get_Key (E : Elmt_Ptr) return Key is
161 begin
162 return E.Entity_Name;
163 end Get_Key;
165 ----------
166 -- Hash --
167 ----------
169 function Hash (F : Key) return Header_Num is
170 begin
171 return Header_Num (Int (F) mod 1024);
172 end Hash;
174 ----------
175 -- Next --
176 ----------
178 function Next (E : Elmt_Ptr) return Elmt_Ptr is
179 begin
180 return E.Hash_Link;
181 end Next;
183 --------------
184 -- Set_Next --
185 --------------
187 procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr) is
188 begin
189 E.Hash_Link := Next;
190 end Set_Next;
191 end Hash_Subprograms;
193 ------------
194 -- Tables --
195 ------------
197 -- The following table records the data for each pragmas, using the
198 -- entity name as the hash key for retrieval. Entries in this table
199 -- are set by Process_Eliminate_Pragma and read by Check_Eliminated.
201 package Elim_Hash_Table is new Static_HTable (
202 Header_Num => Header_Num,
203 Element => Element,
204 Elmt_Ptr => Elmt_Ptr,
205 Null_Ptr => Null_Ptr,
206 Set_Next => Hash_Subprograms.Set_Next,
207 Next => Hash_Subprograms.Next,
208 Key => Key,
209 Get_Key => Hash_Subprograms.Get_Key,
210 Hash => Hash_Subprograms.Hash,
211 Equal => Hash_Subprograms.Equal);
213 -- The following table records entities for subprograms that are
214 -- eliminated, and corresponding eliminate pragmas that caused the
215 -- elimination. Entries in this table are set by Check_Eliminated
216 -- and read by Eliminate_Error_Msg.
218 type Elim_Entity_Entry is record
219 Prag : Node_Id;
220 Subp : Entity_Id;
221 end record;
223 package Elim_Entities is new Table.Table (
224 Table_Component_Type => Elim_Entity_Entry,
225 Table_Index_Type => Name_Id'Base,
226 Table_Low_Bound => First_Name_Id,
227 Table_Initial => 50,
228 Table_Increment => 200,
229 Table_Name => "Elim_Entries");
231 ----------------------
232 -- Check_Eliminated --
233 ----------------------
235 procedure Check_Eliminated (E : Entity_Id) is
236 Elmt : Access_Elim_Data;
237 Scop : Entity_Id;
238 Form : Entity_Id;
239 Up : Nat;
241 begin
242 if No_Elimination then
243 return;
245 -- Elimination of objects and types is not implemented yet
247 elsif Ekind (E) not in Subprogram_Kind then
248 return;
249 end if;
251 -- Loop through homonyms for this key
253 Elmt := Elim_Hash_Table.Get (Chars (E));
254 while Elmt /= null loop
255 Check_Homonyms : declare
256 procedure Set_Eliminated;
257 -- Set current subprogram entity as eliminated
259 --------------------
260 -- Set_Eliminated --
261 --------------------
263 procedure Set_Eliminated is
264 begin
265 if Is_Dispatching_Operation (E) then
267 -- If an overriding dispatching primitive is eliminated then
268 -- its parent must have been eliminated.
270 if Is_Overriding_Operation (E)
271 and then not Is_Eliminated (Overridden_Operation (E))
272 then
273 Error_Msg_Name_1 := Chars (E);
274 Error_Msg_N ("cannot eliminate subprogram %", E);
275 return;
276 end if;
277 end if;
279 Set_Is_Eliminated (E);
280 Elim_Entities.Append ((Prag => Elmt.Prag, Subp => E));
281 end Set_Eliminated;
283 -- Start of processing for Check_Homonyms
285 begin
286 -- First we check that the name of the entity matches
288 if Elmt.Entity_Name /= Chars (E) then
289 goto Continue;
290 end if;
292 -- Find enclosing unit, and verify that its name and those of its
293 -- parents match.
295 Scop := Cunit_Entity (Current_Sem_Unit);
297 -- Now see if compilation unit matches
299 Up := Elmt.Unit_Name'Last;
301 -- If we are within a subunit, the name in the pragma has been
302 -- parsed as a child unit, but the current compilation unit is in
303 -- fact the parent in which the subunit is embedded. We must skip
304 -- the first name which is that of the subunit to match the pragma
305 -- specification. Body may be that of a package or subprogram.
307 declare
308 Par : Node_Id;
310 begin
311 Par := Parent (E);
312 while Present (Par) loop
313 if Nkind (Par) = N_Subunit then
314 if Chars (Defining_Entity (Proper_Body (Par))) =
315 Elmt.Unit_Name (Up)
316 then
317 Up := Up - 1;
318 exit;
320 else
321 goto Continue;
322 end if;
323 end if;
325 Par := Parent (Par);
326 end loop;
327 end;
329 for J in reverse Elmt.Unit_Name'First .. Up loop
330 if Elmt.Unit_Name (J) /= Chars (Scop) then
331 goto Continue;
332 end if;
334 Scop := Scope (Scop);
336 if Scop /= Standard_Standard and then J = 1 then
337 goto Continue;
338 end if;
339 end loop;
341 if Scop /= Standard_Standard then
342 goto Continue;
343 end if;
345 if Present (Elmt.Entity_Node)
346 and then Elmt.Entity_Scope /= null
347 then
348 -- Check that names of enclosing scopes match. Skip blocks and
349 -- wrapper package of subprogram instances, which do not appear
350 -- in the pragma.
352 Scop := Scope (E);
354 for J in reverse Elmt.Entity_Scope'Range loop
355 while Ekind (Scop) = E_Block
356 or else
357 (Ekind (Scop) = E_Package
358 and then Is_Wrapper_Package (Scop))
359 loop
360 Scop := Scope (Scop);
361 end loop;
363 if Elmt.Entity_Scope (J) /= Chars (Scop) then
364 if Ekind (Scop) /= E_Protected_Type
365 or else Comes_From_Source (Scop)
366 then
367 goto Continue;
369 -- For simple protected declarations, retrieve the source
370 -- name of the object, which appeared in the Eliminate
371 -- pragma.
373 else
374 declare
375 Decl : constant Node_Id :=
376 Original_Node (Parent (Scop));
378 begin
379 if Elmt.Entity_Scope (J) /=
380 Chars (Defining_Identifier (Decl))
381 then
382 if J > 0 then
383 null;
384 end if;
385 goto Continue;
386 end if;
387 end;
388 end if;
390 end if;
392 Scop := Scope (Scop);
393 end loop;
394 end if;
396 -- If given entity is a library level subprogram and pragma had a
397 -- single parameter, a match!
399 if Is_Compilation_Unit (E)
400 and then Is_Subprogram (E)
401 and then No (Elmt.Entity_Node)
402 then
403 Set_Eliminated;
404 return;
406 -- Check for case of type or object with two parameter case
408 elsif (Is_Type (E) or else Is_Object (E))
409 and then Elmt.Result_Type = No_Name
410 and then Elmt.Parameter_Types = null
411 then
412 Set_Eliminated;
413 return;
415 -- Check for case of subprogram
417 elsif Ekind_In (E, E_Function, E_Procedure) then
419 -- If Source_Location present, then see if it matches
421 if Elmt.Source_Location /= No_Name then
422 Get_Name_String (Elmt.Source_Location);
424 declare
425 Sloc_Trace : constant String :=
426 Name_Buffer (1 .. Name_Len);
428 Idx : Natural := Sloc_Trace'First;
429 -- Index in Sloc_Trace, if equals to 0, then we have
430 -- completely traversed Sloc_Trace
432 Last : constant Natural := Sloc_Trace'Last;
434 P : Source_Ptr;
435 Sindex : Source_File_Index;
437 function File_Name_Match return Boolean;
438 -- This function is supposed to be called when Idx points
439 -- to the beginning of the new file name, and Name_Buffer
440 -- is set to contain the name of the proper source file
441 -- from the chain corresponding to the Sloc of E. First
442 -- it checks that these two files have the same name. If
443 -- this check is successful, moves Idx to point to the
444 -- beginning of the column number.
446 function Line_Num_Match return Boolean;
447 -- This function is supposed to be called when Idx points
448 -- to the beginning of the column number, and P is
449 -- set to point to the proper Sloc the chain
450 -- corresponding to the Sloc of E. First it checks that
451 -- the line number Idx points on and the line number
452 -- corresponding to P are the same. If this check is
453 -- successful, moves Idx to point to the beginning of
454 -- the next file name in Sloc_Trace. If there is no file
455 -- name any more, Idx is set to 0.
457 function Different_Trace_Lengths return Boolean;
458 -- From Idx and P, defines if there are in both traces
459 -- more element(s) in the instantiation chains. Returns
460 -- False if one trace contains more element(s), but
461 -- another does not. If both traces contains more
462 -- elements (that is, the function returns False), moves
463 -- P ahead in the chain corresponding to E, recomputes
464 -- Sindex and sets the name of the corresponding file in
465 -- Name_Buffer
467 function Skip_Spaces return Natural;
468 -- If Sloc_Trace (Idx) is not space character, returns
469 -- Idx. Otherwise returns the index of the nearest
470 -- non-space character in Sloc_Trace to the right of Idx.
471 -- Returns 0 if there is no such character.
473 -----------------------------
474 -- Different_Trace_Lengths --
475 -----------------------------
477 function Different_Trace_Lengths return Boolean is
478 begin
479 P := Instantiation (Sindex);
481 if (P = No_Location and then Idx /= 0)
482 or else
483 (P /= No_Location and then Idx = 0)
484 then
485 return True;
487 else
488 if P /= No_Location then
489 Sindex := Get_Source_File_Index (P);
490 Get_Name_String (File_Name (Sindex));
491 end if;
493 return False;
494 end if;
495 end Different_Trace_Lengths;
497 ---------------------
498 -- File_Name_Match --
499 ---------------------
501 function File_Name_Match return Boolean is
502 Tmp_Idx : Natural;
503 End_Idx : Natural;
505 begin
506 if Idx = 0 then
507 return False;
508 end if;
510 -- Find first colon. If no colon, then return False.
511 -- If there is a colon, Tmp_Idx is set to point just
512 -- before the colon.
514 Tmp_Idx := Idx - 1;
515 loop
516 if Tmp_Idx >= Last then
517 return False;
518 elsif Sloc_Trace (Tmp_Idx + 1) = ':' then
519 exit;
520 else
521 Tmp_Idx := Tmp_Idx + 1;
522 end if;
523 end loop;
525 -- Find last non-space before this colon. If there is
526 -- no space character before this colon, then return
527 -- False. Otherwise, End_Idx is set to point to this
528 -- non-space character.
530 End_Idx := Tmp_Idx;
531 loop
532 if End_Idx < Idx then
533 return False;
535 elsif Sloc_Trace (End_Idx) /= ' ' then
536 exit;
538 else
539 End_Idx := End_Idx - 1;
540 end if;
541 end loop;
543 -- Now see if file name matches what is in Name_Buffer
544 -- and if so, step Idx past it and return True. If the
545 -- name does not match, return False.
547 if Sloc_Trace (Idx .. End_Idx) =
548 Name_Buffer (1 .. Name_Len)
549 then
550 Idx := Tmp_Idx + 2;
551 Idx := Skip_Spaces;
552 return True;
553 else
554 return False;
555 end if;
556 end File_Name_Match;
558 --------------------
559 -- Line_Num_Match --
560 --------------------
562 function Line_Num_Match return Boolean is
563 N : Int := 0;
565 begin
566 if Idx = 0 then
567 return False;
568 end if;
570 while Idx <= Last
571 and then Sloc_Trace (Idx) in '0' .. '9'
572 loop
573 N := N * 10 +
574 (Character'Pos (Sloc_Trace (Idx)) -
575 Character'Pos ('0'));
576 Idx := Idx + 1;
577 end loop;
579 if Get_Physical_Line_Number (P) =
580 Physical_Line_Number (N)
581 then
582 while Idx <= Last and then
583 Sloc_Trace (Idx) /= '['
584 loop
585 Idx := Idx + 1;
586 end loop;
588 if Idx <= Last and then
589 Sloc_Trace (Idx) = '['
590 then
591 Idx := Idx + 1;
592 Idx := Skip_Spaces;
593 else
594 Idx := 0;
595 end if;
597 return True;
599 else
600 return False;
601 end if;
602 end Line_Num_Match;
604 -----------------
605 -- Skip_Spaces --
606 -----------------
608 function Skip_Spaces return Natural is
609 Res : Natural;
611 begin
612 Res := Idx;
613 while Sloc_Trace (Res) = ' ' loop
614 Res := Res + 1;
616 if Res > Last then
617 Res := 0;
618 exit;
619 end if;
620 end loop;
622 return Res;
623 end Skip_Spaces;
625 begin
626 P := Sloc (E);
627 Sindex := Get_Source_File_Index (P);
628 Get_Name_String (File_Name (Sindex));
630 Idx := Skip_Spaces;
631 while Idx > 0 loop
632 if not File_Name_Match then
633 goto Continue;
634 elsif not Line_Num_Match then
635 goto Continue;
636 end if;
638 if Different_Trace_Lengths then
639 goto Continue;
640 end if;
641 end loop;
642 end;
643 end if;
645 -- If we have a Result_Type, then we must have a function with
646 -- the proper result type.
648 if Elmt.Result_Type /= No_Name then
649 if Ekind (E) /= E_Function
650 or else Chars (Etype (E)) /= Elmt.Result_Type
651 then
652 goto Continue;
653 end if;
654 end if;
656 -- If we have Parameter_Types, they must match
658 if Elmt.Parameter_Types /= null then
659 Form := First_Formal (E);
661 if No (Form)
662 and then Elmt.Parameter_Types'Length = 1
663 and then Elmt.Parameter_Types (1) = No_Name
664 then
665 -- Parameterless procedure matches
667 null;
669 elsif Elmt.Parameter_Types = null then
670 goto Continue;
672 else
673 for J in Elmt.Parameter_Types'Range loop
674 if No (Form)
675 or else
676 Chars (Etype (Form)) /= Elmt.Parameter_Types (J)
677 then
678 goto Continue;
679 else
680 Next_Formal (Form);
681 end if;
682 end loop;
684 if Present (Form) then
685 goto Continue;
686 end if;
687 end if;
688 end if;
690 -- If we fall through, this is match
692 Set_Eliminated;
693 return;
694 end if;
695 end Check_Homonyms;
697 <<Continue>>
698 Elmt := Elmt.Homonym;
699 end loop;
701 return;
702 end Check_Eliminated;
704 -------------------------------------
705 -- Check_For_Eliminated_Subprogram --
706 -------------------------------------
708 procedure Check_For_Eliminated_Subprogram (N : Node_Id; S : Entity_Id) is
709 Ultimate_Subp : constant Entity_Id := Ultimate_Alias (S);
710 Enclosing_Subp : Entity_Id;
712 begin
713 if Is_Eliminated (Ultimate_Subp)
714 and then not Inside_A_Generic
715 and then not Is_Generic_Unit (Cunit_Entity (Current_Sem_Unit))
716 then
717 Enclosing_Subp := Current_Subprogram;
718 while Present (Enclosing_Subp) loop
719 if Is_Eliminated (Enclosing_Subp) then
720 return;
721 end if;
723 Enclosing_Subp := Enclosing_Subprogram (Enclosing_Subp);
724 end loop;
726 -- Emit error, unless we are within an instance body and the expander
727 -- is disabled, indicating an instance within an enclosing generic.
728 -- In an instance, the ultimate alias is an internal entity, so place
729 -- the message on the original subprogram.
731 if In_Instance_Body and then not Expander_Active then
732 null;
734 elsif Comes_From_Source (Ultimate_Subp) then
735 Eliminate_Error_Msg (N, Ultimate_Subp);
737 else
738 Eliminate_Error_Msg (N, S);
739 end if;
740 end if;
741 end Check_For_Eliminated_Subprogram;
743 -------------------------
744 -- Eliminate_Error_Msg --
745 -------------------------
747 procedure Eliminate_Error_Msg (N : Node_Id; E : Entity_Id) is
748 begin
749 for J in Elim_Entities.First .. Elim_Entities.Last loop
750 if E = Elim_Entities.Table (J).Subp then
751 Error_Msg_Sloc := Sloc (Elim_Entities.Table (J).Prag);
752 Error_Msg_NE ("cannot reference subprogram & eliminated #", N, E);
753 return;
754 end if;
755 end loop;
757 -- If this is an internal operation generated for a protected operation,
758 -- its name does not match the source name, so just report the error.
760 if not Comes_From_Source (E)
761 and then Present (First_Entity (E))
762 and then Is_Concurrent_Record_Type (Etype (First_Entity (E)))
763 then
764 Error_Msg_NE
765 ("cannot reference eliminated protected subprogram", N, E);
767 -- Otherwise should not fall through, entry should be in table
769 else
770 Error_Msg_NE
771 ("subprogram& is called but its alias is eliminated", N, E);
772 -- raise Program_Error;
773 end if;
774 end Eliminate_Error_Msg;
776 ----------------
777 -- Initialize --
778 ----------------
780 procedure Initialize is
781 begin
782 Elim_Hash_Table.Reset;
783 Elim_Entities.Init;
784 No_Elimination := True;
785 end Initialize;
787 ------------------------------
788 -- Process_Eliminate_Pragma --
789 ------------------------------
791 procedure Process_Eliminate_Pragma
792 (Pragma_Node : Node_Id;
793 Arg_Unit_Name : Node_Id;
794 Arg_Entity : Node_Id;
795 Arg_Parameter_Types : Node_Id;
796 Arg_Result_Type : Node_Id;
797 Arg_Source_Location : Node_Id)
799 Data : constant Access_Elim_Data := new Elim_Data;
800 -- Build result data here
802 Elmt : Access_Elim_Data;
804 Num_Names : Nat := 0;
805 -- Number of names in unit name
807 Lit : Node_Id;
808 Arg_Ent : Entity_Id;
809 Arg_Uname : Node_Id;
811 function OK_Selected_Component (N : Node_Id) return Boolean;
812 -- Test if N is a selected component with all identifiers, or a
813 -- selected component whose selector is an operator symbol. As a
814 -- side effect if result is True, sets Num_Names to the number
815 -- of names present (identifiers and operator if any).
817 ---------------------------
818 -- OK_Selected_Component --
819 ---------------------------
821 function OK_Selected_Component (N : Node_Id) return Boolean is
822 begin
823 if Nkind (N) = N_Identifier
824 or else Nkind (N) = N_Operator_Symbol
825 then
826 Num_Names := Num_Names + 1;
827 return True;
829 elsif Nkind (N) = N_Selected_Component then
830 return OK_Selected_Component (Prefix (N))
831 and then OK_Selected_Component (Selector_Name (N));
833 else
834 return False;
835 end if;
836 end OK_Selected_Component;
838 -- Start of processing for Process_Eliminate_Pragma
840 begin
841 Data.Prag := Pragma_Node;
842 Error_Msg_Name_1 := Name_Eliminate;
844 -- Process Unit_Name argument
846 if Nkind (Arg_Unit_Name) = N_Identifier then
847 Data.Unit_Name := new Names'(1 => Chars (Arg_Unit_Name));
848 Num_Names := 1;
850 elsif OK_Selected_Component (Arg_Unit_Name) then
851 Data.Unit_Name := new Names (1 .. Num_Names);
853 Arg_Uname := Arg_Unit_Name;
854 for J in reverse 2 .. Num_Names loop
855 Data.Unit_Name (J) := Chars (Selector_Name (Arg_Uname));
856 Arg_Uname := Prefix (Arg_Uname);
857 end loop;
859 Data.Unit_Name (1) := Chars (Arg_Uname);
861 else
862 Error_Msg_N
863 ("wrong form for Unit_Name parameter of pragma%", Arg_Unit_Name);
864 return;
865 end if;
867 -- Process Entity argument
869 if Present (Arg_Entity) then
870 Num_Names := 0;
872 if Nkind (Arg_Entity) = N_Identifier
873 or else Nkind (Arg_Entity) = N_Operator_Symbol
874 then
875 Data.Entity_Name := Chars (Arg_Entity);
876 Data.Entity_Node := Arg_Entity;
877 Data.Entity_Scope := null;
879 elsif OK_Selected_Component (Arg_Entity) then
880 Data.Entity_Scope := new Names (1 .. Num_Names - 1);
881 Data.Entity_Name := Chars (Selector_Name (Arg_Entity));
882 Data.Entity_Node := Arg_Entity;
884 Arg_Ent := Prefix (Arg_Entity);
885 for J in reverse 2 .. Num_Names - 1 loop
886 Data.Entity_Scope (J) := Chars (Selector_Name (Arg_Ent));
887 Arg_Ent := Prefix (Arg_Ent);
888 end loop;
890 Data.Entity_Scope (1) := Chars (Arg_Ent);
892 elsif Is_Config_Static_String (Arg_Entity) then
893 Data.Entity_Name := Name_Find;
894 Data.Entity_Node := Arg_Entity;
896 else
897 return;
898 end if;
899 else
900 Data.Entity_Node := Empty;
901 Data.Entity_Name := Data.Unit_Name (Num_Names);
902 end if;
904 -- Process Parameter_Types argument
906 if Present (Arg_Parameter_Types) then
908 -- Here for aggregate case
910 if Nkind (Arg_Parameter_Types) = N_Aggregate then
911 Data.Parameter_Types :=
912 new Names
913 (1 .. List_Length (Expressions (Arg_Parameter_Types)));
915 Lit := First (Expressions (Arg_Parameter_Types));
916 for J in Data.Parameter_Types'Range loop
917 if Is_Config_Static_String (Lit) then
918 Data.Parameter_Types (J) := Name_Find;
919 Next (Lit);
920 else
921 return;
922 end if;
923 end loop;
925 -- Otherwise we must have case of one name, which looks like a
926 -- parenthesized literal rather than an aggregate.
928 elsif Paren_Count (Arg_Parameter_Types) /= 1 then
929 Error_Msg_N
930 ("wrong form for argument of pragma Eliminate",
931 Arg_Parameter_Types);
932 return;
934 elsif Is_Config_Static_String (Arg_Parameter_Types) then
935 String_To_Name_Buffer (Strval (Arg_Parameter_Types));
937 if Name_Len = 0 then
939 -- Parameterless procedure
941 Data.Parameter_Types := new Names'(1 => No_Name);
943 else
944 Data.Parameter_Types := new Names'(1 => Name_Find);
945 end if;
947 else
948 return;
949 end if;
950 end if;
952 -- Process Result_Types argument
954 if Present (Arg_Result_Type) then
955 if Is_Config_Static_String (Arg_Result_Type) then
956 Data.Result_Type := Name_Find;
957 else
958 return;
959 end if;
961 -- Here if no Result_Types argument
963 else
964 Data.Result_Type := No_Name;
965 end if;
967 -- Process Source_Location argument
969 if Present (Arg_Source_Location) then
970 if Is_Config_Static_String (Arg_Source_Location) then
971 Data.Source_Location := Name_Find;
972 else
973 return;
974 end if;
975 else
976 Data.Source_Location := No_Name;
977 end if;
979 Elmt := Elim_Hash_Table.Get (Hash_Subprograms.Get_Key (Data));
981 -- If we already have an entry with this same key, then link
982 -- it into the chain of entries for this key.
984 if Elmt /= null then
985 Data.Homonym := Elmt.Homonym;
986 Elmt.Homonym := Data;
988 -- Otherwise create a new entry
990 else
991 Elim_Hash_Table.Set (Data);
992 end if;
994 No_Elimination := False;
995 end Process_Eliminate_Pragma;
997 end Sem_Elim;