OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [sem_elim.adb] - Blame information for rev 749

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
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;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.