OSDN Git Service

gcc/fortran/
[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             begin
265                if Is_Dispatching_Operation (E) then
266
267                   --  If an overriding dispatching primitive is eliminated then
268                   --  its parent must have been eliminated.
269
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;
278
279                Set_Is_Eliminated (E);
280                Elim_Entities.Append ((Prag => Elmt.Prag, Subp => E));
281             end Set_Eliminated;
282
283          --  Start of processing for Check_Homonyms
284
285          begin
286             --  First we check that the name of the entity matches
287
288             if Elmt.Entity_Name /= Chars (E) then
289                goto Continue;
290             end if;
291
292             --  Find enclosing unit, and verify that its name and those of its
293             --  parents match.
294
295             Scop := Cunit_Entity (Current_Sem_Unit);
296
297             --  Now see if compilation unit matches
298
299             Up := Elmt.Unit_Name'Last;
300
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.
306
307             declare
308                Par : Node_Id;
309
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;
319
320                      else
321                         goto Continue;
322                      end if;
323                   end if;
324
325                   Par := Parent (Par);
326                end loop;
327             end;
328
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;
333
334                Scop := Scope (Scop);
335
336                if Scop /= Standard_Standard and then J = 1 then
337                   goto Continue;
338                end if;
339             end loop;
340
341             if Scop /= Standard_Standard then
342                goto Continue;
343             end if;
344
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.
351
352                Scop := Scope (E);
353
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;
362
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;
368
369                      --  For simple protected declarations, retrieve the source
370                      --  name of the object, which appeared in the Eliminate
371                      --  pragma.
372
373                      else
374                         declare
375                            Decl : constant Node_Id :=
376                              Original_Node (Parent (Scop));
377
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;
389
390                   end if;
391
392                   Scop := Scope (Scop);
393                end loop;
394             end if;
395
396             --  If given entity is a library level subprogram and pragma had a
397             --  single parameter, a match!
398
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;
405
406                --  Check for case of type or object with two parameter case
407
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;
414
415             --  Check for case of subprogram
416
417             elsif Ekind_In (E, E_Function, E_Procedure) then
418
419                --  If Source_Location present, then see if it matches
420
421                if Elmt.Source_Location /= No_Name then
422                   Get_Name_String (Elmt.Source_Location);
423
424                   declare
425                      Sloc_Trace : constant String :=
426                                     Name_Buffer (1 .. Name_Len);
427
428                      Idx : Natural := Sloc_Trace'First;
429                      --  Index in Sloc_Trace, if equals to 0, then we have
430                      --  completely traversed Sloc_Trace
431
432                      Last : constant Natural := Sloc_Trace'Last;
433
434                      P      : Source_Ptr;
435                      Sindex : Source_File_Index;
436
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.
445
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.
456
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
466
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.
472
473                      -----------------------------
474                      -- Different_Trace_Lengths --
475                      -----------------------------
476
477                      function Different_Trace_Lengths return Boolean is
478                      begin
479                         P := Instantiation (Sindex);
480
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;
486
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;
492
493                            return False;
494                         end if;
495                      end Different_Trace_Lengths;
496
497                      ---------------------
498                      -- File_Name_Match --
499                      ---------------------
500
501                      function File_Name_Match return Boolean is
502                         Tmp_Idx : Natural;
503                         End_Idx : Natural;
504
505                      begin
506                         if Idx = 0 then
507                            return False;
508                         end if;
509
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.
513
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;
524
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.
529
530                         End_Idx := Tmp_Idx;
531                         loop
532                            if End_Idx < Idx then
533                               return False;
534
535                            elsif Sloc_Trace (End_Idx) /= ' ' then
536                               exit;
537
538                            else
539                               End_Idx := End_Idx - 1;
540                            end if;
541                         end loop;
542
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.
546
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;
557
558                      --------------------
559                      -- Line_Num_Match --
560                      --------------------
561
562                      function Line_Num_Match return Boolean is
563                         N : Int := 0;
564
565                      begin
566                         if Idx = 0 then
567                            return False;
568                         end if;
569
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;
578
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;
587
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;
596
597                            return True;
598
599                         else
600                            return False;
601                         end if;
602                      end Line_Num_Match;
603
604                      -----------------
605                      -- Skip_Spaces --
606                      -----------------
607
608                      function Skip_Spaces return Natural is
609                         Res : Natural;
610
611                      begin
612                         Res := Idx;
613                         while Sloc_Trace (Res) = ' ' loop
614                            Res := Res + 1;
615
616                            if Res > Last then
617                               Res := 0;
618                               exit;
619                            end if;
620                         end loop;
621
622                         return Res;
623                      end Skip_Spaces;
624
625                   begin
626                      P := Sloc (E);
627                      Sindex := Get_Source_File_Index (P);
628                      Get_Name_String (File_Name (Sindex));
629
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;
637
638                         if Different_Trace_Lengths then
639                            goto Continue;
640                         end if;
641                      end loop;
642                   end;
643                end if;
644
645                --  If we have a Result_Type, then we must have a function with
646                --  the proper result type.
647
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;
655
656                --  If we have Parameter_Types, they must match
657
658                if Elmt.Parameter_Types /= null then
659                   Form := First_Formal (E);
660
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
666
667                      null;
668
669                   elsif Elmt.Parameter_Types = null then
670                      goto Continue;
671
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;
683
684                      if Present (Form) then
685                         goto Continue;
686                      end if;
687                   end if;
688                end if;
689
690                --  If we fall through, this is match
691
692                Set_Eliminated;
693                return;
694             end if;
695          end Check_Homonyms;
696
697       <<Continue>>
698          Elmt := Elmt.Homonym;
699       end loop;
700
701       return;
702    end Check_Eliminated;
703
704    -------------------------------------
705    -- Check_For_Eliminated_Subprogram --
706    -------------------------------------
707
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;
711
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;
722
723             Enclosing_Subp := Enclosing_Subprogram (Enclosing_Subp);
724          end loop;
725
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.
730
731          if In_Instance_Body and then not Expander_Active then
732             null;
733
734          elsif Comes_From_Source (Ultimate_Subp) then
735             Eliminate_Error_Msg (N, Ultimate_Subp);
736
737          else
738             Eliminate_Error_Msg (N, S);
739          end if;
740       end if;
741    end Check_For_Eliminated_Subprogram;
742
743    -------------------------
744    -- Eliminate_Error_Msg --
745    -------------------------
746
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;
756
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.
759
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);
766
767       --  Otherwise should not fall through, entry should be in table
768
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;
775
776    ----------------
777    -- Initialize --
778    ----------------
779
780    procedure Initialize is
781    begin
782       Elim_Hash_Table.Reset;
783       Elim_Entities.Init;
784       No_Elimination := True;
785    end Initialize;
786
787    ------------------------------
788    -- Process_Eliminate_Pragma --
789    ------------------------------
790
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)
798    is
799       Data : constant Access_Elim_Data := new Elim_Data;
800       --  Build result data here
801
802       Elmt : Access_Elim_Data;
803
804       Num_Names : Nat := 0;
805       --  Number of names in unit name
806
807       Lit       : Node_Id;
808       Arg_Ent   : Entity_Id;
809       Arg_Uname : Node_Id;
810
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).
816
817       ---------------------------
818       -- OK_Selected_Component --
819       ---------------------------
820
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;
828
829          elsif Nkind (N) = N_Selected_Component then
830             return OK_Selected_Component (Prefix (N))
831               and then OK_Selected_Component (Selector_Name (N));
832
833          else
834             return False;
835          end if;
836       end OK_Selected_Component;
837
838    --  Start of processing for Process_Eliminate_Pragma
839
840    begin
841       Data.Prag := Pragma_Node;
842       Error_Msg_Name_1 := Name_Eliminate;
843
844       --  Process Unit_Name argument
845
846       if Nkind (Arg_Unit_Name) = N_Identifier then
847          Data.Unit_Name := new Names'(1 => Chars (Arg_Unit_Name));
848          Num_Names := 1;
849
850       elsif OK_Selected_Component (Arg_Unit_Name) then
851          Data.Unit_Name := new Names (1 .. Num_Names);
852
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;
858
859          Data.Unit_Name (1) := Chars (Arg_Uname);
860
861       else
862          Error_Msg_N
863            ("wrong form for Unit_Name parameter of pragma%", Arg_Unit_Name);
864          return;
865       end if;
866
867       --  Process Entity argument
868
869       if Present (Arg_Entity) then
870          Num_Names := 0;
871
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;
878
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;
883
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;
889
890             Data.Entity_Scope (1) := Chars (Arg_Ent);
891
892          elsif Is_Config_Static_String (Arg_Entity) then
893             Data.Entity_Name := Name_Find;
894             Data.Entity_Node := Arg_Entity;
895
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;
903
904       --  Process Parameter_Types argument
905
906       if Present (Arg_Parameter_Types) then
907
908          --  Here for aggregate case
909
910          if Nkind (Arg_Parameter_Types) = N_Aggregate then
911             Data.Parameter_Types :=
912               new Names
913                 (1 .. List_Length (Expressions (Arg_Parameter_Types)));
914
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;
924
925          --  Otherwise we must have case of one name, which looks like a
926          --  parenthesized literal rather than an aggregate.
927
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;
933
934          elsif Is_Config_Static_String (Arg_Parameter_Types) then
935             String_To_Name_Buffer (Strval (Arg_Parameter_Types));
936
937             if Name_Len = 0 then
938
939                --  Parameterless procedure
940
941                Data.Parameter_Types := new Names'(1 => No_Name);
942
943             else
944                Data.Parameter_Types := new Names'(1 => Name_Find);
945             end if;
946
947          else
948             return;
949          end if;
950       end if;
951
952       --  Process Result_Types argument
953
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;
960
961       --  Here if no Result_Types argument
962
963       else
964          Data.Result_Type := No_Name;
965       end if;
966
967       --  Process Source_Location argument
968
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;
978
979       Elmt := Elim_Hash_Table.Get (Hash_Subprograms.Get_Key (Data));
980
981       --  If we already have an entry with this same key, then link
982       --  it into the chain of entries for this key.
983
984       if Elmt /= null then
985          Data.Homonym := Elmt.Homonym;
986          Elmt.Homonym := Data;
987
988       --  Otherwise create a new entry
989
990       else
991          Elim_Hash_Table.Set (Data);
992       end if;
993
994       No_Elimination := False;
995    end Process_Eliminate_Pragma;
996
997 end Sem_Elim;