OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / sem_elim.adb
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 ------------------------------------------------------------------------------
25
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;
43
44 with GNAT.HTable; use GNAT.HTable;
45
46 package body Sem_Elim is
47
48    No_Elimination : Boolean;
49    --  Set True if no Eliminate pragmas active
50
51    ---------------------
52    -- Data Structures --
53    ---------------------
54
55    --  A single pragma Eliminate is represented by the following record
56
57    type Elim_Data;
58    type Access_Elim_Data is access Elim_Data;
59
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.
63
64    type Access_Names is access Names;
65
66    type Elim_Data is record
67
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).
71
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.
76
77       Entity_Scope : Access_Names;
78       --  Static scope of the entity within the compilation unit represented by
79       --  Unit_Name.
80
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.
84
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.
88
89       Result_Type : Name_Id;
90       --  Result type name if Result_Types parameter present, No_Name if not
91
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
95
96       Hash_Link : Access_Elim_Data;
97       --  Link for hash table use
98
99       Homonym : Access_Elim_Data;
100       --  Pointer to next entry with same key
101
102       Prag : Node_Id;
103       --  Node_Id for Eliminate pragma
104
105    end record;
106
107    ----------------
108    -- Hash_Table --
109    ----------------
110
111    --  Setup hash table using the Entity_Name field as the hash key
112
113    subtype Element is Elim_Data;
114    subtype Elmt_Ptr is Access_Elim_Data;
115
116    subtype Key is Name_Id;
117
118    type Header_Num is range 0 .. 1023;
119
120    Null_Ptr : constant Elmt_Ptr := null;
121
122    ----------------------
123    -- Hash_Subprograms --
124    ----------------------
125
126    package Hash_Subprograms is
127
128       function Equal (F1, F2 : Key) return Boolean;
129       pragma Inline (Equal);
130
131       function Get_Key (E : Elmt_Ptr) return Key;
132       pragma Inline (Get_Key);
133
134       function Hash (F : Key) return Header_Num;
135       pragma Inline (Hash);
136
137       function Next (E : Elmt_Ptr) return Elmt_Ptr;
138       pragma Inline (Next);
139
140       procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr);
141       pragma Inline (Set_Next);
142
143    end Hash_Subprograms;
144
145    package body Hash_Subprograms is
146
147       -----------
148       -- Equal --
149       -----------
150
151       function Equal (F1, F2 : Key) return Boolean is
152       begin
153          return F1 = F2;
154       end Equal;
155
156       -------------
157       -- Get_Key --
158       -------------
159
160       function Get_Key (E : Elmt_Ptr) return Key is
161       begin
162          return E.Entity_Name;
163       end Get_Key;
164
165       ----------
166       -- Hash --
167       ----------
168
169       function Hash (F : Key) return Header_Num is
170       begin
171          return Header_Num (Int (F) mod 1024);
172       end Hash;
173
174       ----------
175       -- Next --
176       ----------
177
178       function Next (E : Elmt_Ptr) return Elmt_Ptr is
179       begin
180          return E.Hash_Link;
181       end Next;
182
183       --------------
184       -- Set_Next --
185       --------------
186
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;
192
193    ------------
194    -- Tables --
195    ------------
196
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.
200
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);
212
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.
217
218    type Elim_Entity_Entry is record
219       Prag : Node_Id;
220       Subp : Entity_Id;
221    end record;
222
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");
230
231    ----------------------
232    -- Check_Eliminated --
233    ----------------------
234
235    procedure Check_Eliminated (E : Entity_Id) is
236       Elmt : Access_Elim_Data;
237       Scop : Entity_Id;
238       Form : Entity_Id;
239       Up   : Nat;
240
241    begin
242       if No_Elimination then
243          return;
244
245       --  Elimination of objects and types is not implemented yet
246
247       elsif Ekind (E) not in Subprogram_Kind then
248          return;
249       end if;
250
251       --  Loop through homonyms for this key
252
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
258
259             --------------------
260             -- Set_Eliminated --
261             --------------------
262
263             procedure Set_Eliminated is
264                Overridden : Entity_Id;
265
266             begin
267                if Is_Dispatching_Operation (E) then
268
269                   --  If an overriding dispatching primitive is eliminated then
270                   --  its parent must have been eliminated. If the parent is an
271                   --  inherited operation, check the operation that it renames,
272                   --  because flag Eliminated is only set on source operations.
273
274                   Overridden := Overridden_Operation (E);
275
276                   if Present (Overridden)
277                     and then not Comes_From_Source (Overridden)
278                     and then Present (Alias (Overridden))
279                   then
280                      Overridden := Alias (Overridden);
281                   end if;
282
283                   if Present (Overridden)
284                     and then not Is_Eliminated (Overridden)
285                     and then not Is_Abstract_Subprogram (Overridden)
286                   then
287                      Error_Msg_Name_1 := Chars (E);
288                      Error_Msg_N ("cannot eliminate subprogram %", E);
289                      return;
290                   end if;
291                end if;
292
293                Set_Is_Eliminated (E);
294                Elim_Entities.Append ((Prag => Elmt.Prag, Subp => E));
295             end Set_Eliminated;
296
297          --  Start of processing for Check_Homonyms
298
299          begin
300             --  First we check that the name of the entity matches
301
302             if Elmt.Entity_Name /= Chars (E) then
303                goto Continue;
304             end if;
305
306             --  Find enclosing unit, and verify that its name and those of its
307             --  parents match.
308
309             Scop := Cunit_Entity (Current_Sem_Unit);
310
311             --  Now see if compilation unit matches
312
313             Up := Elmt.Unit_Name'Last;
314
315             --  If we are within a subunit, the name in the pragma has been
316             --  parsed as a child unit, but the current compilation unit is in
317             --  fact the parent in which the subunit is embedded. We must skip
318             --  the first name which is that of the subunit to match the pragma
319             --  specification. Body may be that of a package or subprogram.
320
321             declare
322                Par : Node_Id;
323
324             begin
325                Par := Parent (E);
326                while Present (Par) loop
327                   if Nkind (Par) = N_Subunit then
328                      if Chars (Defining_Entity (Proper_Body (Par))) =
329                                                          Elmt.Unit_Name (Up)
330                      then
331                         Up := Up - 1;
332                         exit;
333
334                      else
335                         goto Continue;
336                      end if;
337                   end if;
338
339                   Par := Parent (Par);
340                end loop;
341             end;
342
343             for J in reverse Elmt.Unit_Name'First .. Up loop
344                if Elmt.Unit_Name (J) /= Chars (Scop) then
345                   goto Continue;
346                end if;
347
348                Scop := Scope (Scop);
349
350                if Scop /= Standard_Standard and then J = 1 then
351                   goto Continue;
352                end if;
353             end loop;
354
355             if Scop /= Standard_Standard then
356                goto Continue;
357             end if;
358
359             if Present (Elmt.Entity_Node)
360               and then Elmt.Entity_Scope /= null
361             then
362                --  Check that names of enclosing scopes match. Skip blocks and
363                --  wrapper package of subprogram instances, which do not appear
364                --  in the pragma.
365
366                Scop := Scope (E);
367
368                for J in reverse  Elmt.Entity_Scope'Range loop
369                   while Ekind (Scop) = E_Block
370                     or else
371                      (Ekind (Scop) = E_Package
372                        and then Is_Wrapper_Package (Scop))
373                   loop
374                      Scop := Scope (Scop);
375                   end loop;
376
377                   if Elmt.Entity_Scope (J) /= Chars (Scop) then
378                      if Ekind (Scop) /= E_Protected_Type
379                        or else Comes_From_Source (Scop)
380                      then
381                         goto Continue;
382
383                      --  For simple protected declarations, retrieve the source
384                      --  name of the object, which appeared in the Eliminate
385                      --  pragma.
386
387                      else
388                         declare
389                            Decl : constant Node_Id :=
390                              Original_Node (Parent (Scop));
391
392                         begin
393                            if Elmt.Entity_Scope (J) /=
394                              Chars (Defining_Identifier (Decl))
395                            then
396                               if J > 0 then
397                                  null;
398                               end if;
399                               goto Continue;
400                            end if;
401                         end;
402                      end if;
403
404                   end if;
405
406                   Scop := Scope (Scop);
407                end loop;
408             end if;
409
410             --  If given entity is a library level subprogram and pragma had a
411             --  single parameter, a match!
412
413             if Is_Compilation_Unit (E)
414               and then Is_Subprogram (E)
415               and then No (Elmt.Entity_Node)
416             then
417                Set_Eliminated;
418                return;
419
420                --  Check for case of type or object with two parameter case
421
422             elsif (Is_Type (E) or else Is_Object (E))
423               and then Elmt.Result_Type = No_Name
424               and then Elmt.Parameter_Types = null
425             then
426                Set_Eliminated;
427                return;
428
429             --  Check for case of subprogram
430
431             elsif Ekind_In (E, E_Function, E_Procedure) then
432
433                --  If Source_Location present, then see if it matches
434
435                if Elmt.Source_Location /= No_Name then
436                   Get_Name_String (Elmt.Source_Location);
437
438                   declare
439                      Sloc_Trace : constant String :=
440                                     Name_Buffer (1 .. Name_Len);
441
442                      Idx : Natural := Sloc_Trace'First;
443                      --  Index in Sloc_Trace, if equals to 0, then we have
444                      --  completely traversed Sloc_Trace
445
446                      Last : constant Natural := Sloc_Trace'Last;
447
448                      P      : Source_Ptr;
449                      Sindex : Source_File_Index;
450
451                      function File_Name_Match return Boolean;
452                      --  This function is supposed to be called when Idx points
453                      --  to the beginning of the new file name, and Name_Buffer
454                      --  is set to contain the name of the proper source file
455                      --  from the chain corresponding to the Sloc of E. First
456                      --  it checks that these two files have the same name. If
457                      --  this check is successful, moves Idx to point to the
458                      --  beginning of the column number.
459
460                      function Line_Num_Match return Boolean;
461                      --  This function is supposed to be called when Idx points
462                      --  to the beginning of the column number, and P is
463                      --  set to point to the proper Sloc the chain
464                      --  corresponding to the Sloc of E. First it checks that
465                      --  the line number Idx points on and the line number
466                      --  corresponding to P are the same. If this check is
467                      --  successful, moves Idx to point to the beginning of
468                      --  the next file name in Sloc_Trace. If there is no file
469                      --  name any more, Idx is set to 0.
470
471                      function Different_Trace_Lengths return Boolean;
472                      --  From Idx and P, defines if there are in both traces
473                      --  more element(s) in the instantiation chains. Returns
474                      --  False if one trace contains more element(s), but
475                      --  another does not. If both traces contains more
476                      --  elements (that is, the function returns False), moves
477                      --  P ahead in the chain corresponding to E, recomputes
478                      --  Sindex and sets the name of the corresponding file in
479                      --  Name_Buffer
480
481                      function Skip_Spaces return Natural;
482                      --  If Sloc_Trace (Idx) is not space character, returns
483                      --  Idx. Otherwise returns the index of the nearest
484                      --  non-space character in Sloc_Trace to the right of Idx.
485                      --  Returns 0 if there is no such character.
486
487                      -----------------------------
488                      -- Different_Trace_Lengths --
489                      -----------------------------
490
491                      function Different_Trace_Lengths return Boolean is
492                      begin
493                         P := Instantiation (Sindex);
494
495                         if (P = No_Location and then Idx /= 0)
496                           or else
497                            (P /= No_Location and then Idx = 0)
498                         then
499                            return True;
500
501                         else
502                            if P /= No_Location then
503                               Sindex := Get_Source_File_Index (P);
504                               Get_Name_String (File_Name (Sindex));
505                            end if;
506
507                            return False;
508                         end if;
509                      end Different_Trace_Lengths;
510
511                      ---------------------
512                      -- File_Name_Match --
513                      ---------------------
514
515                      function File_Name_Match return Boolean is
516                         Tmp_Idx : Natural;
517                         End_Idx : Natural;
518
519                      begin
520                         if Idx = 0 then
521                            return False;
522                         end if;
523
524                         --  Find first colon. If no colon, then return False.
525                         --  If there is a colon, Tmp_Idx is set to point just
526                         --  before the colon.
527
528                         Tmp_Idx := Idx - 1;
529                         loop
530                            if Tmp_Idx >= Last then
531                               return False;
532                            elsif Sloc_Trace (Tmp_Idx + 1) = ':' then
533                               exit;
534                            else
535                               Tmp_Idx := Tmp_Idx + 1;
536                            end if;
537                         end loop;
538
539                         --  Find last non-space before this colon. If there is
540                         --  no space character before this colon, then return
541                         --  False. Otherwise, End_Idx is set to point to this
542                         --  non-space character.
543
544                         End_Idx := Tmp_Idx;
545                         loop
546                            if End_Idx < Idx then
547                               return False;
548
549                            elsif Sloc_Trace (End_Idx) /= ' ' then
550                               exit;
551
552                            else
553                               End_Idx := End_Idx - 1;
554                            end if;
555                         end loop;
556
557                         --  Now see if file name matches what is in Name_Buffer
558                         --  and if so, step Idx past it and return True. If the
559                         --  name does not match, return False.
560
561                         if Sloc_Trace (Idx .. End_Idx) =
562                            Name_Buffer (1 .. Name_Len)
563                         then
564                            Idx := Tmp_Idx + 2;
565                            Idx := Skip_Spaces;
566                            return True;
567                         else
568                            return False;
569                         end if;
570                      end File_Name_Match;
571
572                      --------------------
573                      -- Line_Num_Match --
574                      --------------------
575
576                      function Line_Num_Match return Boolean is
577                         N : Int := 0;
578
579                      begin
580                         if Idx = 0 then
581                            return False;
582                         end if;
583
584                         while Idx <= Last
585                            and then Sloc_Trace (Idx) in '0' .. '9'
586                         loop
587                            N := N * 10 +
588                             (Character'Pos (Sloc_Trace (Idx)) -
589                              Character'Pos ('0'));
590                            Idx := Idx + 1;
591                         end loop;
592
593                         if Get_Physical_Line_Number (P) =
594                            Physical_Line_Number (N)
595                         then
596                            while Idx <= Last and then
597                               Sloc_Trace (Idx) /= '['
598                            loop
599                               Idx := Idx + 1;
600                            end loop;
601
602                            if Idx <= Last and then
603                              Sloc_Trace (Idx) = '['
604                            then
605                               Idx := Idx + 1;
606                               Idx := Skip_Spaces;
607                            else
608                               Idx := 0;
609                            end if;
610
611                            return True;
612
613                         else
614                            return False;
615                         end if;
616                      end Line_Num_Match;
617
618                      -----------------
619                      -- Skip_Spaces --
620                      -----------------
621
622                      function Skip_Spaces return Natural is
623                         Res : Natural;
624
625                      begin
626                         Res := Idx;
627                         while Sloc_Trace (Res) = ' ' loop
628                            Res := Res + 1;
629
630                            if Res > Last then
631                               Res := 0;
632                               exit;
633                            end if;
634                         end loop;
635
636                         return Res;
637                      end Skip_Spaces;
638
639                   begin
640                      P := Sloc (E);
641                      Sindex := Get_Source_File_Index (P);
642                      Get_Name_String (File_Name (Sindex));
643
644                      Idx := Skip_Spaces;
645                      while Idx > 0 loop
646                         if not File_Name_Match then
647                            goto Continue;
648                         elsif not Line_Num_Match then
649                            goto Continue;
650                         end if;
651
652                         if Different_Trace_Lengths then
653                            goto Continue;
654                         end if;
655                      end loop;
656                   end;
657                end if;
658
659                --  If we have a Result_Type, then we must have a function with
660                --  the proper result type.
661
662                if Elmt.Result_Type /= No_Name then
663                   if Ekind (E) /= E_Function
664                     or else Chars (Etype (E)) /= Elmt.Result_Type
665                   then
666                      goto Continue;
667                   end if;
668                end if;
669
670                --  If we have Parameter_Types, they must match
671
672                if Elmt.Parameter_Types /= null then
673                   Form := First_Formal (E);
674
675                   if No (Form)
676                     and then Elmt.Parameter_Types'Length = 1
677                     and then Elmt.Parameter_Types (1) = No_Name
678                   then
679                      --  Parameterless procedure matches
680
681                      null;
682
683                   elsif Elmt.Parameter_Types = null then
684                      goto Continue;
685
686                   else
687                      for J in Elmt.Parameter_Types'Range loop
688                         if No (Form)
689                           or else
690                             Chars (Etype (Form)) /= Elmt.Parameter_Types (J)
691                         then
692                            goto Continue;
693                         else
694                            Next_Formal (Form);
695                         end if;
696                      end loop;
697
698                      if Present (Form) then
699                         goto Continue;
700                      end if;
701                   end if;
702                end if;
703
704                --  If we fall through, this is match
705
706                Set_Eliminated;
707                return;
708             end if;
709          end Check_Homonyms;
710
711       <<Continue>>
712          Elmt := Elmt.Homonym;
713       end loop;
714
715       return;
716    end Check_Eliminated;
717
718    -------------------------------------
719    -- Check_For_Eliminated_Subprogram --
720    -------------------------------------
721
722    procedure Check_For_Eliminated_Subprogram (N : Node_Id; S : Entity_Id) is
723       Ultimate_Subp  : constant Entity_Id := Ultimate_Alias (S);
724       Enclosing_Subp : Entity_Id;
725
726    begin
727       if Is_Eliminated (Ultimate_Subp)
728         and then not Inside_A_Generic
729         and then not Is_Generic_Unit (Cunit_Entity (Current_Sem_Unit))
730       then
731          Enclosing_Subp := Current_Subprogram;
732          while Present (Enclosing_Subp) loop
733             if Is_Eliminated (Enclosing_Subp) then
734                return;
735             end if;
736
737             Enclosing_Subp := Enclosing_Subprogram (Enclosing_Subp);
738          end loop;
739
740          --  Emit error, unless we are within an instance body and the expander
741          --  is disabled, indicating an instance within an enclosing generic.
742          --  In an instance, the ultimate alias is an internal entity, so place
743          --  the message on the original subprogram.
744
745          if In_Instance_Body and then not Expander_Active then
746             null;
747
748          elsif Comes_From_Source (Ultimate_Subp) then
749             Eliminate_Error_Msg (N, Ultimate_Subp);
750
751          else
752             Eliminate_Error_Msg (N, S);
753          end if;
754       end if;
755    end Check_For_Eliminated_Subprogram;
756
757    -------------------------
758    -- Eliminate_Error_Msg --
759    -------------------------
760
761    procedure Eliminate_Error_Msg (N : Node_Id; E : Entity_Id) is
762    begin
763       for J in Elim_Entities.First .. Elim_Entities.Last loop
764          if E = Elim_Entities.Table (J).Subp then
765             Error_Msg_Sloc := Sloc (Elim_Entities.Table (J).Prag);
766             Error_Msg_NE ("cannot reference subprogram & eliminated #", N, E);
767             return;
768          end if;
769       end loop;
770
771       --  If this is an internal operation generated for a protected operation,
772       --  its name does not match the source name, so just report the error.
773
774       if not Comes_From_Source (E)
775         and then Present (First_Entity (E))
776         and then Is_Concurrent_Record_Type (Etype (First_Entity (E)))
777       then
778          Error_Msg_NE
779            ("cannot reference eliminated protected subprogram", N, E);
780
781       --  Otherwise should not fall through, entry should be in table
782
783       else
784          Error_Msg_NE
785            ("subprogram& is called but its alias is eliminated", N, E);
786          --  raise Program_Error;
787       end if;
788    end Eliminate_Error_Msg;
789
790    ----------------
791    -- Initialize --
792    ----------------
793
794    procedure Initialize is
795    begin
796       Elim_Hash_Table.Reset;
797       Elim_Entities.Init;
798       No_Elimination := True;
799    end Initialize;
800
801    ------------------------------
802    -- Process_Eliminate_Pragma --
803    ------------------------------
804
805    procedure Process_Eliminate_Pragma
806      (Pragma_Node         : Node_Id;
807       Arg_Unit_Name       : Node_Id;
808       Arg_Entity          : Node_Id;
809       Arg_Parameter_Types : Node_Id;
810       Arg_Result_Type     : Node_Id;
811       Arg_Source_Location : Node_Id)
812    is
813       Data : constant Access_Elim_Data := new Elim_Data;
814       --  Build result data here
815
816       Elmt : Access_Elim_Data;
817
818       Num_Names : Nat := 0;
819       --  Number of names in unit name
820
821       Lit       : Node_Id;
822       Arg_Ent   : Entity_Id;
823       Arg_Uname : Node_Id;
824
825       function OK_Selected_Component (N : Node_Id) return Boolean;
826       --  Test if N is a selected component with all identifiers, or a
827       --  selected component whose selector is an operator symbol. As a
828       --  side effect if result is True, sets Num_Names to the number
829       --  of names present (identifiers and operator if any).
830
831       ---------------------------
832       -- OK_Selected_Component --
833       ---------------------------
834
835       function OK_Selected_Component (N : Node_Id) return Boolean is
836       begin
837          if Nkind (N) = N_Identifier
838            or else Nkind (N) = N_Operator_Symbol
839          then
840             Num_Names := Num_Names + 1;
841             return True;
842
843          elsif Nkind (N) = N_Selected_Component then
844             return OK_Selected_Component (Prefix (N))
845               and then OK_Selected_Component (Selector_Name (N));
846
847          else
848             return False;
849          end if;
850       end OK_Selected_Component;
851
852    --  Start of processing for Process_Eliminate_Pragma
853
854    begin
855       Data.Prag := Pragma_Node;
856       Error_Msg_Name_1 := Name_Eliminate;
857
858       --  Process Unit_Name argument
859
860       if Nkind (Arg_Unit_Name) = N_Identifier then
861          Data.Unit_Name := new Names'(1 => Chars (Arg_Unit_Name));
862          Num_Names := 1;
863
864       elsif OK_Selected_Component (Arg_Unit_Name) then
865          Data.Unit_Name := new Names (1 .. Num_Names);
866
867          Arg_Uname := Arg_Unit_Name;
868          for J in reverse 2 .. Num_Names loop
869             Data.Unit_Name (J) := Chars (Selector_Name (Arg_Uname));
870             Arg_Uname := Prefix (Arg_Uname);
871          end loop;
872
873          Data.Unit_Name (1) := Chars (Arg_Uname);
874
875       else
876          Error_Msg_N
877            ("wrong form for Unit_Name parameter of pragma%", Arg_Unit_Name);
878          return;
879       end if;
880
881       --  Process Entity argument
882
883       if Present (Arg_Entity) then
884          Num_Names := 0;
885
886          if Nkind (Arg_Entity) = N_Identifier
887            or else Nkind (Arg_Entity) = N_Operator_Symbol
888          then
889             Data.Entity_Name  := Chars (Arg_Entity);
890             Data.Entity_Node  := Arg_Entity;
891             Data.Entity_Scope := null;
892
893          elsif OK_Selected_Component (Arg_Entity) then
894             Data.Entity_Scope := new Names (1 .. Num_Names - 1);
895             Data.Entity_Name  := Chars (Selector_Name (Arg_Entity));
896             Data.Entity_Node  := Arg_Entity;
897
898             Arg_Ent := Prefix (Arg_Entity);
899             for J in reverse 2 .. Num_Names - 1 loop
900                Data.Entity_Scope (J) := Chars (Selector_Name (Arg_Ent));
901                Arg_Ent := Prefix (Arg_Ent);
902             end loop;
903
904             Data.Entity_Scope (1) := Chars (Arg_Ent);
905
906          elsif Is_Config_Static_String (Arg_Entity) then
907             Data.Entity_Name := Name_Find;
908             Data.Entity_Node := Arg_Entity;
909
910          else
911             return;
912          end if;
913       else
914          Data.Entity_Node := Empty;
915          Data.Entity_Name := Data.Unit_Name (Num_Names);
916       end if;
917
918       --  Process Parameter_Types argument
919
920       if Present (Arg_Parameter_Types) then
921
922          --  Here for aggregate case
923
924          if Nkind (Arg_Parameter_Types) = N_Aggregate then
925             Data.Parameter_Types :=
926               new Names
927                 (1 .. List_Length (Expressions (Arg_Parameter_Types)));
928
929             Lit := First (Expressions (Arg_Parameter_Types));
930             for J in Data.Parameter_Types'Range loop
931                if Is_Config_Static_String (Lit) then
932                   Data.Parameter_Types (J) := Name_Find;
933                   Next (Lit);
934                else
935                   return;
936                end if;
937             end loop;
938
939          --  Otherwise we must have case of one name, which looks like a
940          --  parenthesized literal rather than an aggregate.
941
942          elsif Paren_Count (Arg_Parameter_Types) /= 1 then
943             Error_Msg_N
944               ("wrong form for argument of pragma Eliminate",
945                Arg_Parameter_Types);
946             return;
947
948          elsif Is_Config_Static_String (Arg_Parameter_Types) then
949             String_To_Name_Buffer (Strval (Arg_Parameter_Types));
950
951             if Name_Len = 0 then
952
953                --  Parameterless procedure
954
955                Data.Parameter_Types := new Names'(1 => No_Name);
956
957             else
958                Data.Parameter_Types := new Names'(1 => Name_Find);
959             end if;
960
961          else
962             return;
963          end if;
964       end if;
965
966       --  Process Result_Types argument
967
968       if Present (Arg_Result_Type) then
969          if Is_Config_Static_String (Arg_Result_Type) then
970             Data.Result_Type := Name_Find;
971          else
972             return;
973          end if;
974
975       --  Here if no Result_Types argument
976
977       else
978          Data.Result_Type := No_Name;
979       end if;
980
981       --  Process Source_Location argument
982
983       if Present (Arg_Source_Location) then
984          if Is_Config_Static_String (Arg_Source_Location) then
985             Data.Source_Location := Name_Find;
986          else
987             return;
988          end if;
989       else
990          Data.Source_Location := No_Name;
991       end if;
992
993       Elmt := Elim_Hash_Table.Get (Hash_Subprograms.Get_Key (Data));
994
995       --  If we already have an entry with this same key, then link
996       --  it into the chain of entries for this key.
997
998       if Elmt /= null then
999          Data.Homonym := Elmt.Homonym;
1000          Elmt.Homonym := Data;
1001
1002       --  Otherwise create a new entry
1003
1004       else
1005          Elim_Hash_Table.Set (Data);
1006       end if;
1007
1008       No_Elimination := False;
1009    end Process_Eliminate_Pragma;
1010
1011 end Sem_Elim;