]> gcc.gnu.org Git - gcc.git/blob - gcc/ada/lib-xref-spark_specific.adb
8cc2e7299fd37ba20122b3c77c4a5b85307f7e72
[gcc.git] / gcc / ada / lib-xref-spark_specific.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- L I B . X R E F . S P A R K _ S P E C I F I C --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2011-2017, 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 Einfo; use Einfo;
27 with Nmake; use Nmake;
28 with SPARK_Xrefs; use SPARK_Xrefs;
29
30 with GNAT.HTable;
31
32 separate (Lib.Xref)
33 package body SPARK_Specific is
34
35 ---------------------
36 -- Local Constants --
37 ---------------------
38
39 -- Table of SPARK_Entities, True for each entity kind used in SPARK
40
41 SPARK_Entities : constant array (Entity_Kind) of Boolean :=
42 (E_Constant => True,
43 E_Entry => True,
44 E_Function => True,
45 E_In_Out_Parameter => True,
46 E_In_Parameter => True,
47 E_Loop_Parameter => True,
48 E_Operator => True,
49 E_Out_Parameter => True,
50 E_Procedure => True,
51 E_Variable => True,
52 others => False);
53
54 -- True for each reference type used in SPARK
55
56 SPARK_References : constant array (Character) of Boolean :=
57 ('m' => True,
58 'r' => True,
59 's' => True,
60 others => False);
61
62 type Entity_Hashed_Range is range 0 .. 255;
63 -- Size of hash table headers
64
65 ---------------------
66 -- Local Variables --
67 ---------------------
68
69 package Drefs is new Table.Table (
70 Table_Component_Type => Xref_Entry,
71 Table_Index_Type => Xref_Entry_Number,
72 Table_Low_Bound => 1,
73 Table_Initial => Alloc.Drefs_Initial,
74 Table_Increment => Alloc.Drefs_Increment,
75 Table_Name => "Drefs");
76 -- Table of cross-references for reads and writes through explicit
77 -- dereferences, that are output as reads/writes to the special variable
78 -- "Heap". These references are added to the regular references when
79 -- computing SPARK cross-references.
80
81 -----------------------
82 -- Local Subprograms --
83 -----------------------
84
85 procedure Add_SPARK_File (Uspec, Ubody : Unit_Number_Type; Dspec : Nat);
86 -- Add file and corresponding scopes for unit to the tables
87 -- SPARK_File_Table and SPARK_Scope_Table. When two units are present
88 -- for the same compilation unit, as it happens for library-level
89 -- instantiations of generics, then Ubody is the number of the body
90 -- unit; otherwise it is No_Unit.
91
92 procedure Add_SPARK_Xrefs;
93 -- Filter table Xrefs to add all references used in SPARK to the table
94 -- SPARK_Xref_Table.
95
96 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range;
97 -- Hash function for hash table
98
99 --------------------
100 -- Add_SPARK_File --
101 --------------------
102
103 procedure Add_SPARK_File (Uspec, Ubody : Unit_Number_Type; Dspec : Nat) is
104 File : constant Source_File_Index := Source_Index (Uspec);
105 From : constant Scope_Index := SPARK_Scope_Table.Last + 1;
106
107 Scope_Id : Pos := 1;
108
109 procedure Add_SPARK_Scope (N : Node_Id);
110 -- Add scope N to the table SPARK_Scope_Table
111
112 procedure Detect_And_Add_SPARK_Scope (N : Node_Id);
113 -- Call Add_SPARK_Scope on scopes
114
115 ---------------------
116 -- Add_SPARK_Scope --
117 ---------------------
118
119 procedure Add_SPARK_Scope (N : Node_Id) is
120 E : constant Entity_Id := Defining_Entity (N);
121
122 begin
123 -- Ignore scopes without a proper location
124
125 if Sloc (N) = No_Location then
126 return;
127 end if;
128
129 case Ekind (E) is
130 when E_Entry
131 | E_Entry_Family
132 | E_Function
133 | E_Generic_Function
134 | E_Generic_Package
135 | E_Generic_Procedure
136 | E_Package
137 | E_Package_Body
138 | E_Procedure
139 | E_Protected_Body
140 | E_Protected_Type
141 | E_Task_Body
142 | E_Task_Type
143 | E_Subprogram_Body
144 =>
145 null;
146
147 when E_Void =>
148
149 -- Compilation of prj-attr.adb with -gnatn creates a node with
150 -- entity E_Void for the package defined at a-charac.ads16:13.
151 -- ??? TBD
152
153 return;
154
155 when others =>
156 raise Program_Error;
157 end case;
158
159 -- File_Num and Scope_Num are filled later. From_Xref and To_Xref
160 -- are filled even later, but are initialized to represent an empty
161 -- range.
162
163 SPARK_Scope_Table.Append
164 ((Entity => E,
165 File_Num => Dspec,
166 Scope_Num => Scope_Id,
167 Spec_File_Num => 0,
168 Spec_Scope_Num => 0,
169 From_Xref => 1,
170 To_Xref => 0));
171
172 Scope_Id := Scope_Id + 1;
173 end Add_SPARK_Scope;
174
175 --------------------------------
176 -- Detect_And_Add_SPARK_Scope --
177 --------------------------------
178
179 procedure Detect_And_Add_SPARK_Scope (N : Node_Id) is
180 begin
181 -- Entries
182
183 if Nkind_In (N, N_Entry_Body, N_Entry_Declaration)
184
185 -- Packages
186
187 or else Nkind_In (N, N_Package_Body,
188 N_Package_Declaration)
189 -- Protected units
190
191 or else Nkind_In (N, N_Protected_Body,
192 N_Protected_Type_Declaration)
193
194 -- Subprograms
195
196 or else Nkind_In (N, N_Subprogram_Body,
197 N_Subprogram_Declaration)
198
199 -- Task units
200
201 or else Nkind_In (N, N_Task_Body,
202 N_Task_Type_Declaration)
203 then
204 Add_SPARK_Scope (N);
205 end if;
206 end Detect_And_Add_SPARK_Scope;
207
208 procedure Traverse_Scopes is new
209 Traverse_Compilation_Unit (Detect_And_Add_SPARK_Scope);
210
211 -- Start of processing for Add_SPARK_File
212
213 begin
214 -- Source file could be inexistant as a result of an error, if option
215 -- gnatQ is used.
216
217 if File <= No_Source_File then
218 return;
219 end if;
220
221 -- Subunits are traversed as part of the top-level unit to which they
222 -- belong.
223
224 if Nkind (Unit (Cunit (Uspec))) = N_Subunit then
225 return;
226 end if;
227
228 Traverse_Scopes (CU => Cunit (Uspec));
229
230 -- When two units are present for the same compilation unit, as it
231 -- happens for library-level instantiations of generics, then add all
232 -- scopes to the same SPARK file.
233
234 if Ubody /= No_Unit then
235 Traverse_Scopes (CU => Cunit (Ubody));
236 end if;
237
238 SPARK_File_Table.Append (
239 (File_Num => Dspec,
240 From_Scope => From,
241 To_Scope => SPARK_Scope_Table.Last));
242 end Add_SPARK_File;
243
244 ---------------------
245 -- Add_SPARK_Xrefs --
246 ---------------------
247
248 procedure Add_SPARK_Xrefs is
249 function Entity_Of_Scope (S : Scope_Index) return Entity_Id;
250 -- Return the entity which maps to the input scope index
251
252 function Get_Scope_Num (E : Entity_Id) return Nat;
253 -- Return the scope number associated with the entity E
254
255 function Is_Constant_Object_Without_Variable_Input
256 (E : Entity_Id) return Boolean;
257 -- Return True if E is known to have no variable input, as defined in
258 -- SPARK RM.
259
260 function Is_Future_Scope_Entity
261 (E : Entity_Id;
262 S : Scope_Index) return Boolean;
263 -- Check whether entity E is in SPARK_Scope_Table at index S or higher
264
265 function Is_SPARK_Reference
266 (E : Entity_Id;
267 Typ : Character) return Boolean;
268 -- Return whether entity reference E meets SPARK requirements. Typ is
269 -- the reference type.
270
271 function Is_SPARK_Scope (E : Entity_Id) return Boolean;
272 -- Return whether the entity or reference scope meets requirements for
273 -- being a SPARK scope.
274
275 function Lt (Op1 : Natural; Op2 : Natural) return Boolean;
276 -- Comparison function for Sort call
277
278 procedure Move (From : Natural; To : Natural);
279 -- Move procedure for Sort call
280
281 procedure Set_Scope_Num (E : Entity_Id; Num : Nat);
282 -- Associate entity E with the scope number Num
283
284 procedure Update_Scope_Range
285 (S : Scope_Index;
286 From : Xref_Index;
287 To : Xref_Index);
288 -- Update the scope which maps to S with the new range From .. To
289
290 package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
291
292 No_Scope : constant Nat := 0;
293 -- Initial scope counter
294
295 package Scopes is new GNAT.HTable.Simple_HTable
296 (Header_Num => Entity_Hashed_Range,
297 Element => Nat,
298 No_Element => No_Scope,
299 Key => Entity_Id,
300 Hash => Entity_Hash,
301 Equal => "=");
302 -- Package used to build a correspondence between entities and scope
303 -- numbers used in SPARK cross references.
304
305 Nrefs : Nat := Xrefs.Last;
306 -- Number of references in table. This value may get reset (reduced)
307 -- when we eliminate duplicate reference entries as well as references
308 -- not suitable for local cross-references.
309
310 Nrefs_Add : constant Nat := Drefs.Last;
311 -- Number of additional references which correspond to dereferences in
312 -- the source code.
313
314 Rnums : array (0 .. Nrefs + Nrefs_Add) of Nat;
315 -- This array contains numbers of references in the Xrefs table. This
316 -- list is sorted in output order. The extra 0'th entry is convenient
317 -- for the call to sort. When we sort the table, we move the indices in
318 -- Rnums around, but we do not move the original table entries.
319
320 ---------------------
321 -- Entity_Of_Scope --
322 ---------------------
323
324 function Entity_Of_Scope (S : Scope_Index) return Entity_Id is
325 begin
326 return SPARK_Scope_Table.Table (S).Entity;
327 end Entity_Of_Scope;
328
329 -------------------
330 -- Get_Scope_Num --
331 -------------------
332
333 function Get_Scope_Num (E : Entity_Id) return Nat renames Scopes.Get;
334
335 -----------------------------------------------
336 -- Is_Constant_Object_Without_Variable_Input --
337 -----------------------------------------------
338
339 function Is_Constant_Object_Without_Variable_Input
340 (E : Entity_Id) return Boolean
341 is
342 begin
343 case Ekind (E) is
344
345 -- A constant is known to have no variable input if its
346 -- initializing expression is static (a value which is
347 -- compile-time-known is not guaranteed to have no variable input
348 -- as defined in the SPARK RM). Otherwise, the constant may or not
349 -- have variable input.
350
351 when E_Constant =>
352 declare
353 Decl : Node_Id;
354 begin
355 if Present (Full_View (E)) then
356 Decl := Parent (Full_View (E));
357 else
358 Decl := Parent (E);
359 end if;
360
361 if Is_Imported (E) then
362 return False;
363 else
364 pragma Assert (Present (Expression (Decl)));
365 return Is_Static_Expression (Expression (Decl));
366 end if;
367 end;
368
369 when E_In_Parameter
370 | E_Loop_Parameter
371 =>
372 return True;
373
374 when others =>
375 return False;
376 end case;
377 end Is_Constant_Object_Without_Variable_Input;
378
379 ----------------------------
380 -- Is_Future_Scope_Entity --
381 ----------------------------
382
383 function Is_Future_Scope_Entity
384 (E : Entity_Id;
385 S : Scope_Index) return Boolean
386 is
387 function Is_Past_Scope_Entity return Boolean;
388 -- Check whether entity E is in SPARK_Scope_Table at index strictly
389 -- lower than S.
390
391 --------------------------
392 -- Is_Past_Scope_Entity --
393 --------------------------
394
395 function Is_Past_Scope_Entity return Boolean is
396 begin
397 for Index in SPARK_Scope_Table.First .. S - 1 loop
398 if SPARK_Scope_Table.Table (Index).Entity = E then
399 return True;
400 end if;
401 end loop;
402
403 return False;
404 end Is_Past_Scope_Entity;
405
406 -- Start of processing for Is_Future_Scope_Entity
407
408 begin
409 for Index in S .. SPARK_Scope_Table.Last loop
410 if SPARK_Scope_Table.Table (Index).Entity = E then
411 return True;
412 end if;
413 end loop;
414
415 -- If this assertion fails, this means that the scope which we are
416 -- looking for has been treated already, which reveals a problem in
417 -- the order of cross-references.
418
419 pragma Assert (not Is_Past_Scope_Entity);
420
421 return False;
422 end Is_Future_Scope_Entity;
423
424 ------------------------
425 -- Is_SPARK_Reference --
426 ------------------------
427
428 function Is_SPARK_Reference
429 (E : Entity_Id;
430 Typ : Character) return Boolean
431 is
432 begin
433 -- The only references of interest on callable entities are calls. On
434 -- uncallable entities, the only references of interest are reads and
435 -- writes.
436
437 if Ekind (E) in Overloadable_Kind then
438 return Typ = 's';
439
440 -- In all other cases, result is true for reference/modify cases,
441 -- and false for all other cases.
442
443 else
444 return Typ = 'r' or else Typ = 'm';
445 end if;
446 end Is_SPARK_Reference;
447
448 --------------------
449 -- Is_SPARK_Scope --
450 --------------------
451
452 function Is_SPARK_Scope (E : Entity_Id) return Boolean is
453 Can_Be_Renamed : constant Boolean :=
454 Present (E)
455 and then (Is_Subprogram_Or_Entry (E)
456 or else Ekind (E) = E_Package);
457 begin
458 return Present (E)
459 and then not Is_Generic_Unit (E)
460 and then (not Can_Be_Renamed or else No (Renamed_Entity (E)))
461 and then Get_Scope_Num (E) /= No_Scope;
462 end Is_SPARK_Scope;
463
464 --------
465 -- Lt --
466 --------
467
468 function Lt (Op1 : Natural; Op2 : Natural) return Boolean is
469 T1 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op1)));
470 T2 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op2)));
471
472 begin
473 -- First test: if entity is in different unit, sort by unit. Note:
474 -- that we use Ent_Scope_File rather than Eun, as Eun may refer to
475 -- the file where the generic scope is defined, which may differ from
476 -- the file where the enclosing scope is defined. It is the latter
477 -- which matters for a correct order here.
478
479 if T1.Ent_Scope_File /= T2.Ent_Scope_File then
480 return Dependency_Num (T1.Ent_Scope_File) <
481 Dependency_Num (T2.Ent_Scope_File);
482
483 -- Second test: within same unit, sort by location of the scope of
484 -- the entity definition.
485
486 elsif Get_Scope_Num (T1.Key.Ent_Scope) /=
487 Get_Scope_Num (T2.Key.Ent_Scope)
488 then
489 return Get_Scope_Num (T1.Key.Ent_Scope) <
490 Get_Scope_Num (T2.Key.Ent_Scope);
491
492 -- Third test: within same unit and scope, sort by location of
493 -- entity definition.
494
495 elsif T1.Def /= T2.Def then
496 return T1.Def < T2.Def;
497
498 else
499 -- Both entities must be equal at this point
500
501 pragma Assert (T1.Key.Ent = T2.Key.Ent);
502 pragma Assert (T1.Key.Ent_Scope = T2.Key.Ent_Scope);
503 pragma Assert (T1.Ent_Scope_File = T2.Ent_Scope_File);
504
505 -- Fourth test: if reference is in same unit as entity definition,
506 -- sort first.
507
508 if T1.Key.Lun /= T2.Key.Lun
509 and then T1.Ent_Scope_File = T1.Key.Lun
510 then
511 return True;
512
513 elsif T1.Key.Lun /= T2.Key.Lun
514 and then T2.Ent_Scope_File = T2.Key.Lun
515 then
516 return False;
517
518 -- Fifth test: if reference is in same unit and same scope as
519 -- entity definition, sort first.
520
521 elsif T1.Ent_Scope_File = T1.Key.Lun
522 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
523 and then T1.Key.Ent_Scope = T1.Key.Ref_Scope
524 then
525 return True;
526
527 elsif T2.Ent_Scope_File = T2.Key.Lun
528 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
529 and then T2.Key.Ent_Scope = T2.Key.Ref_Scope
530 then
531 return False;
532
533 -- Sixth test: for same entity, sort by reference location unit
534
535 elsif T1.Key.Lun /= T2.Key.Lun then
536 return Dependency_Num (T1.Key.Lun) <
537 Dependency_Num (T2.Key.Lun);
538
539 -- Seventh test: for same entity, sort by reference location scope
540
541 elsif Get_Scope_Num (T1.Key.Ref_Scope) /=
542 Get_Scope_Num (T2.Key.Ref_Scope)
543 then
544 return Get_Scope_Num (T1.Key.Ref_Scope) <
545 Get_Scope_Num (T2.Key.Ref_Scope);
546
547 -- Eighth test: order of location within referencing unit
548
549 elsif T1.Key.Loc /= T2.Key.Loc then
550 return T1.Key.Loc < T2.Key.Loc;
551
552 -- Finally, for two locations at the same address prefer the one
553 -- that does NOT have the type 'r', so that a modification or
554 -- extension takes preference, when there are more than one
555 -- reference at the same location. As a result, in the case of
556 -- entities that are in-out actuals, the read reference follows
557 -- the modify reference.
558
559 else
560 return T2.Key.Typ = 'r';
561 end if;
562 end if;
563 end Lt;
564
565 ----------
566 -- Move --
567 ----------
568
569 procedure Move (From : Natural; To : Natural) is
570 begin
571 Rnums (Nat (To)) := Rnums (Nat (From));
572 end Move;
573
574 -------------------
575 -- Set_Scope_Num --
576 -------------------
577
578 procedure Set_Scope_Num (E : Entity_Id; Num : Nat) renames Scopes.Set;
579
580 ------------------------
581 -- Update_Scope_Range --
582 ------------------------
583
584 procedure Update_Scope_Range
585 (S : Scope_Index;
586 From : Xref_Index;
587 To : Xref_Index)
588 is
589 begin
590 SPARK_Scope_Table.Table (S).From_Xref := From;
591 SPARK_Scope_Table.Table (S).To_Xref := To;
592 end Update_Scope_Range;
593
594 -- Local variables
595
596 From_Index : Xref_Index;
597 Prev_Loc : Source_Ptr;
598 Prev_Typ : Character;
599 Ref_Count : Nat;
600 Scope_Id : Scope_Index;
601
602 -- Start of processing for Add_SPARK_Xrefs
603
604 begin
605 for Index in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
606 declare
607 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
608 begin
609 Set_Scope_Num (S.Entity, S.Scope_Num);
610 end;
611 end loop;
612
613 declare
614 Drefs_Table : Drefs.Table_Type
615 renames Drefs.Table (Drefs.First .. Drefs.Last);
616 begin
617 Xrefs.Append_All (Xrefs.Table_Type (Drefs_Table));
618 Nrefs := Nrefs + Drefs_Table'Length;
619 end;
620
621 -- Capture the definition Sloc values. As in the case of normal cross
622 -- references, we have to wait until now to get the correct value.
623
624 for Index in 1 .. Nrefs loop
625 Xrefs.Table (Index).Def := Sloc (Xrefs.Table (Index).Key.Ent);
626 end loop;
627
628 -- Eliminate entries not appropriate for SPARK. Done prior to sorting
629 -- cross-references, as it discards useless references which do not have
630 -- a proper format for the comparison function (like no location).
631
632 Ref_Count := Nrefs;
633 Nrefs := 0;
634
635 for Index in 1 .. Ref_Count loop
636 declare
637 Ref : Xref_Key renames Xrefs.Table (Index).Key;
638
639 begin
640 if SPARK_Entities (Ekind (Ref.Ent))
641 and then SPARK_References (Ref.Typ)
642 and then Is_SPARK_Scope (Ref.Ent_Scope)
643 and then Is_SPARK_Scope (Ref.Ref_Scope)
644 and then Is_SPARK_Reference (Ref.Ent, Ref.Typ)
645
646 -- Discard references from unknown scopes, e.g. generic scopes
647
648 and then Get_Scope_Num (Ref.Ent_Scope) /= No_Scope
649 and then Get_Scope_Num (Ref.Ref_Scope) /= No_Scope
650
651 -- Discard references to loop parameters introduced within
652 -- expression functions, as they give two references: one from
653 -- the analysis of the expression function itself and one from
654 -- the analysis of the expanded body. We don't lose any globals
655 -- by discarding them, because such loop parameters can only be
656 -- accessed locally from within the expression function body.
657
658 and then not
659 (Ekind (Ref.Ent) = E_Loop_Parameter
660 and then Scope_Within
661 (Ref.Ent, Unique_Entity (Ref.Ref_Scope))
662 and then Is_Expression_Function (Ref.Ref_Scope))
663 then
664 Nrefs := Nrefs + 1;
665 Rnums (Nrefs) := Index;
666 end if;
667 end;
668 end loop;
669
670 -- Sort the references
671
672 Sorting.Sort (Integer (Nrefs));
673
674 -- Eliminate duplicate entries
675
676 -- We need this test for Ref_Count because if we force ALI file
677 -- generation in case of errors detected, it may be the case that
678 -- Nrefs is 0, so we should not reset it here.
679
680 if Nrefs >= 2 then
681 Ref_Count := Nrefs;
682 Nrefs := 1;
683
684 for Index in 2 .. Ref_Count loop
685 if Xrefs.Table (Rnums (Index)) /= Xrefs.Table (Rnums (Nrefs)) then
686 Nrefs := Nrefs + 1;
687 Rnums (Nrefs) := Rnums (Index);
688 end if;
689 end loop;
690 end if;
691
692 -- Eliminate the reference if it is at the same location as the previous
693 -- one, unless it is a read-reference indicating that the entity is an
694 -- in-out actual in a call.
695
696 Ref_Count := Nrefs;
697 Nrefs := 0;
698 Prev_Loc := No_Location;
699 Prev_Typ := 'm';
700
701 for Index in 1 .. Ref_Count loop
702 declare
703 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
704
705 begin
706 if Ref.Loc /= Prev_Loc
707 or else (Prev_Typ = 'm' and then Ref.Typ = 'r')
708 then
709 Prev_Loc := Ref.Loc;
710 Prev_Typ := Ref.Typ;
711 Nrefs := Nrefs + 1;
712 Rnums (Nrefs) := Rnums (Index);
713 end if;
714 end;
715 end loop;
716
717 -- The two steps have eliminated all references, nothing to do
718
719 if SPARK_Scope_Table.Last = 0 then
720 return;
721 end if;
722
723 Scope_Id := 1;
724 From_Index := 1;
725
726 -- Loop to output references
727
728 for Refno in 1 .. Nrefs loop
729 declare
730 Ref_Entry : Xref_Entry renames Xrefs.Table (Rnums (Refno));
731 Ref : Xref_Key renames Ref_Entry.Key;
732 Typ : Character;
733
734 begin
735 -- If this assertion fails, the scope which we are looking for is
736 -- not in SPARK scope table, which reveals either a problem in the
737 -- construction of the scope table, or an erroneous scope for the
738 -- current cross-reference.
739
740 pragma Assert (Is_Future_Scope_Entity (Ref.Ent_Scope, Scope_Id));
741
742 -- Update the range of cross references to which the current scope
743 -- refers to. This may be the empty range only for the first scope
744 -- considered.
745
746 if Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) then
747 Update_Scope_Range
748 (S => Scope_Id,
749 From => From_Index,
750 To => SPARK_Xref_Table.Last);
751
752 From_Index := SPARK_Xref_Table.Last + 1;
753 end if;
754
755 while Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) loop
756 Scope_Id := Scope_Id + 1;
757 pragma Assert (Scope_Id <= SPARK_Scope_Table.Last);
758 end loop;
759
760 -- References to constant objects without variable inputs (see
761 -- SPARK RM 3.3.1) are considered specially in SPARK section,
762 -- because these will be translated as constants in the
763 -- intermediate language for formal verification, and should
764 -- therefore never appear in frame conditions. Other constants may
765 -- later be treated the same, up to GNATprove to decide based on
766 -- its flow analysis.
767
768 if Is_Constant_Object_Without_Variable_Input (Ref.Ent) then
769 Typ := 'c';
770 else
771 Typ := Ref.Typ;
772 end if;
773
774 SPARK_Xref_Table.Append (
775 (Entity => Unique_Entity (Ref.Ent),
776 Ref_Scope => Ref.Ref_Scope,
777 Rtype => Typ));
778 end;
779 end loop;
780
781 -- Update the range of cross references to which the scope refers to
782
783 Update_Scope_Range
784 (S => Scope_Id,
785 From => From_Index,
786 To => SPARK_Xref_Table.Last);
787 end Add_SPARK_Xrefs;
788
789 -------------------------
790 -- Collect_SPARK_Xrefs --
791 -------------------------
792
793 procedure Collect_SPARK_Xrefs
794 (Sdep_Table : Unit_Ref_Table;
795 Num_Sdep : Nat)
796 is
797 Sdep : Pos;
798 Sdep_Next : Pos;
799 -- Index of the current and next source dependency
800
801 Sdep_File : Pos;
802 -- Index of the file to which the scopes need to be assigned; for
803 -- library-level instances of generic units this points to the unit
804 -- of the body, because this is where references are assigned to.
805
806 Ubody : Unit_Number_Type;
807 Uspec : Unit_Number_Type;
808 -- Unit numbers for the dependency spec and possibly its body (only in
809 -- the case of library-level instance of a generic package).
810
811 begin
812 -- Cross-references should have been computed first
813
814 pragma Assert (Xrefs.Last /= 0);
815
816 Initialize_SPARK_Tables;
817
818 -- Generate file and scope SPARK cross-reference information
819
820 Sdep := 1;
821 while Sdep <= Num_Sdep loop
822
823 -- Skip dependencies with no entity node, e.g. configuration files
824 -- with pragmas (.adc) or target description (.atp), since they
825 -- present no interest for SPARK cross references.
826
827 if No (Cunit_Entity (Sdep_Table (Sdep))) then
828 Sdep_Next := Sdep + 1;
829
830 -- For library-level instantiation of a generic, two consecutive
831 -- units refer to the same compilation unit node and entity (one to
832 -- body, one to spec). In that case, treat them as a single unit for
833 -- the sake of SPARK cross references by passing to Add_SPARK_File.
834
835 else
836 if Sdep < Num_Sdep
837 and then Cunit_Entity (Sdep_Table (Sdep)) =
838 Cunit_Entity (Sdep_Table (Sdep + 1))
839 then
840 declare
841 Cunit1 : Node_Id renames Cunit (Sdep_Table (Sdep));
842 Cunit2 : Node_Id renames Cunit (Sdep_Table (Sdep + 1));
843
844 begin
845 -- Both Cunits point to compilation unit nodes
846
847 pragma Assert
848 (Nkind (Cunit1) = N_Compilation_Unit
849 and then Nkind (Cunit2) = N_Compilation_Unit);
850
851 -- Do not depend on the sorting order, which is based on
852 -- Unit_Name, and for library-level instances of nested
853 -- generic packages they are equal.
854
855 -- If declaration comes before the body
856
857 if Nkind (Unit (Cunit1)) = N_Package_Declaration
858 and then Nkind (Unit (Cunit2)) = N_Package_Body
859 then
860 Uspec := Sdep_Table (Sdep);
861 Ubody := Sdep_Table (Sdep + 1);
862
863 Sdep_File := Sdep + 1;
864
865 -- If body comes before declaration
866
867 elsif Nkind (Unit (Cunit1)) = N_Package_Body
868 and then Nkind (Unit (Cunit2)) = N_Package_Declaration
869 then
870 Uspec := Sdep_Table (Sdep + 1);
871 Ubody := Sdep_Table (Sdep);
872
873 Sdep_File := Sdep;
874
875 -- Otherwise it is an error
876
877 else
878 raise Program_Error;
879 end if;
880
881 Sdep_Next := Sdep + 2;
882 end;
883
884 -- ??? otherwise?
885
886 else
887 Uspec := Sdep_Table (Sdep);
888 Ubody := No_Unit;
889
890 Sdep_File := Sdep;
891 Sdep_Next := Sdep + 1;
892 end if;
893
894 Add_SPARK_File
895 (Uspec => Uspec,
896 Ubody => Ubody,
897 Dspec => Sdep_File);
898 end if;
899
900 Sdep := Sdep_Next;
901 end loop;
902
903 -- Fill in the spec information when relevant
904
905 declare
906 package Entity_Hash_Table is new
907 GNAT.HTable.Simple_HTable
908 (Header_Num => Entity_Hashed_Range,
909 Element => Scope_Index,
910 No_Element => 0,
911 Key => Entity_Id,
912 Hash => Entity_Hash,
913 Equal => "=");
914
915 begin
916 -- Fill in the hash-table
917
918 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
919 declare
920 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
921 begin
922 Entity_Hash_Table.Set (Srec.Entity, S);
923 end;
924 end loop;
925
926 -- Use the hash-table to locate spec entities
927
928 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
929 declare
930 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
931
932 Spec_Entity : constant Entity_Id :=
933 Unique_Entity (Srec.Entity);
934 Spec_Scope : constant Scope_Index :=
935 Entity_Hash_Table.Get (Spec_Entity);
936
937 begin
938 -- Generic spec may be missing in which case Spec_Scope is zero
939
940 if Spec_Entity /= Srec.Entity
941 and then Spec_Scope /= 0
942 then
943 Srec.Spec_File_Num :=
944 SPARK_Scope_Table.Table (Spec_Scope).File_Num;
945 Srec.Spec_Scope_Num :=
946 SPARK_Scope_Table.Table (Spec_Scope).Scope_Num;
947 end if;
948 end;
949 end loop;
950 end;
951
952 -- Generate SPARK cross-reference information
953
954 Add_SPARK_Xrefs;
955 end Collect_SPARK_Xrefs;
956
957 -------------------------------------
958 -- Enclosing_Subprogram_Or_Package --
959 -------------------------------------
960
961 function Enclosing_Subprogram_Or_Library_Package
962 (N : Node_Id) return Entity_Id
963 is
964 Context : Entity_Id;
965
966 begin
967 -- If N is the defining identifier for a subprogram, then return the
968 -- enclosing subprogram or package, not this subprogram.
969
970 if Nkind_In (N, N_Defining_Identifier, N_Defining_Operator_Symbol)
971 and then (Ekind (N) in Entry_Kind
972 or else Ekind (N) = E_Subprogram_Body
973 or else Ekind (N) in Generic_Subprogram_Kind
974 or else Ekind (N) in Subprogram_Kind)
975 then
976 Context := Parent (Unit_Declaration_Node (N));
977
978 -- If this was a library-level subprogram then replace Context with
979 -- its Unit, which points to N_Subprogram_* node.
980
981 if Nkind (Context) = N_Compilation_Unit then
982 Context := Unit (Context);
983 end if;
984 else
985 Context := N;
986 end if;
987
988 while Present (Context) loop
989 case Nkind (Context) is
990 when N_Package_Body
991 | N_Package_Specification
992 =>
993 -- Only return a library-level package
994
995 if Is_Library_Level_Entity (Defining_Entity (Context)) then
996 Context := Defining_Entity (Context);
997 exit;
998 else
999 Context := Parent (Context);
1000 end if;
1001
1002 when N_Pragma =>
1003
1004 -- The enclosing subprogram for a precondition, postcondition,
1005 -- or contract case should be the declaration preceding the
1006 -- pragma (skipping any other pragmas between this pragma and
1007 -- this declaration.
1008
1009 while Nkind (Context) = N_Pragma
1010 and then Is_List_Member (Context)
1011 and then Present (Prev (Context))
1012 loop
1013 Context := Prev (Context);
1014 end loop;
1015
1016 if Nkind (Context) = N_Pragma then
1017 Context := Parent (Context);
1018 end if;
1019
1020 when N_Entry_Body
1021 | N_Entry_Declaration
1022 | N_Protected_Type_Declaration
1023 | N_Subprogram_Body
1024 | N_Subprogram_Declaration
1025 | N_Subprogram_Specification
1026 | N_Task_Body
1027 | N_Task_Type_Declaration
1028 =>
1029 Context := Defining_Entity (Context);
1030 exit;
1031
1032 when others =>
1033 Context := Parent (Context);
1034 end case;
1035 end loop;
1036
1037 if Nkind (Context) = N_Defining_Program_Unit_Name then
1038 Context := Defining_Identifier (Context);
1039 end if;
1040
1041 -- Do not return a scope without a proper location
1042
1043 if Present (Context)
1044 and then Sloc (Context) = No_Location
1045 then
1046 return Empty;
1047 end if;
1048
1049 return Context;
1050 end Enclosing_Subprogram_Or_Library_Package;
1051
1052 -----------------
1053 -- Entity_Hash --
1054 -----------------
1055
1056 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range is
1057 begin
1058 return
1059 Entity_Hashed_Range (E mod (Entity_Id (Entity_Hashed_Range'Last) + 1));
1060 end Entity_Hash;
1061
1062 --------------------------
1063 -- Generate_Dereference --
1064 --------------------------
1065
1066 procedure Generate_Dereference
1067 (N : Node_Id;
1068 Typ : Character := 'r')
1069 is
1070 procedure Create_Heap;
1071 -- Create and decorate the special entity which denotes the heap
1072
1073 -----------------
1074 -- Create_Heap --
1075 -----------------
1076
1077 procedure Create_Heap is
1078 begin
1079 Name_Len := Name_Of_Heap_Variable'Length;
1080 Name_Buffer (1 .. Name_Len) := Name_Of_Heap_Variable;
1081
1082 Heap := Make_Defining_Identifier (Standard_Location, Name_Enter);
1083
1084 Set_Ekind (Heap, E_Variable);
1085 Set_Is_Internal (Heap, True);
1086 Set_Has_Fully_Qualified_Name (Heap);
1087 end Create_Heap;
1088
1089 -- Local variables
1090
1091 Loc : constant Source_Ptr := Sloc (N);
1092
1093 -- Start of processing for Generate_Dereference
1094
1095 begin
1096 if Loc > No_Location then
1097 Drefs.Increment_Last;
1098
1099 declare
1100 Deref_Entry : Xref_Entry renames Drefs.Table (Drefs.Last);
1101 Deref : Xref_Key renames Deref_Entry.Key;
1102
1103 begin
1104 if No (Heap) then
1105 Create_Heap;
1106 end if;
1107
1108 Deref.Ent := Heap;
1109 Deref.Loc := Loc;
1110 Deref.Typ := Typ;
1111
1112 -- It is as if the special "Heap" was defined in the main unit,
1113 -- in the scope of the entity for the main unit. This single
1114 -- definition point is required to ensure that sorting cross
1115 -- references works for "Heap" references as well.
1116
1117 Deref.Eun := Main_Unit;
1118 Deref.Lun := Get_Top_Level_Code_Unit (Loc);
1119
1120 Deref.Ref_Scope := Enclosing_Subprogram_Or_Library_Package (N);
1121 Deref.Ent_Scope := Cunit_Entity (Main_Unit);
1122
1123 Deref_Entry.Def := No_Location;
1124
1125 Deref_Entry.Ent_Scope_File := Main_Unit;
1126 end;
1127 end if;
1128 end Generate_Dereference;
1129
1130 -------------------------------
1131 -- Traverse_Compilation_Unit --
1132 -------------------------------
1133
1134 procedure Traverse_Compilation_Unit (CU : Node_Id) is
1135 procedure Traverse_Block (N : Node_Id);
1136 procedure Traverse_Declaration_Or_Statement (N : Node_Id);
1137 procedure Traverse_Declarations_And_HSS (N : Node_Id);
1138 procedure Traverse_Declarations_Or_Statements (L : List_Id);
1139 procedure Traverse_Handled_Statement_Sequence (N : Node_Id);
1140 procedure Traverse_Package_Body (N : Node_Id);
1141 procedure Traverse_Visible_And_Private_Parts (N : Node_Id);
1142 procedure Traverse_Protected_Body (N : Node_Id);
1143 procedure Traverse_Subprogram_Body (N : Node_Id);
1144 procedure Traverse_Task_Body (N : Node_Id);
1145
1146 -- Traverse corresponding construct, calling Process on all declarations
1147
1148 --------------------
1149 -- Traverse_Block --
1150 --------------------
1151
1152 procedure Traverse_Block (N : Node_Id) renames
1153 Traverse_Declarations_And_HSS;
1154
1155 ---------------------------------------
1156 -- Traverse_Declaration_Or_Statement --
1157 ---------------------------------------
1158
1159 procedure Traverse_Declaration_Or_Statement (N : Node_Id) is
1160 function Traverse_Stub (N : Node_Id) return Boolean;
1161 -- Returns True iff stub N should be traversed
1162
1163 function Traverse_Stub (N : Node_Id) return Boolean is
1164 begin
1165 pragma Assert (Nkind_In (N, N_Package_Body_Stub,
1166 N_Protected_Body_Stub,
1167 N_Subprogram_Body_Stub,
1168 N_Task_Body_Stub));
1169
1170 return Present (Library_Unit (N));
1171 end Traverse_Stub;
1172
1173 -- Start of processing for Traverse_Declaration_Or_Statement
1174
1175 begin
1176 case Nkind (N) is
1177 when N_Package_Declaration =>
1178 Traverse_Visible_And_Private_Parts (Specification (N));
1179
1180 when N_Package_Body =>
1181 Traverse_Package_Body (N);
1182
1183 when N_Package_Body_Stub =>
1184 if Traverse_Stub (N) then
1185 Traverse_Package_Body (Get_Body_From_Stub (N));
1186 end if;
1187
1188 when N_Subprogram_Body =>
1189 Traverse_Subprogram_Body (N);
1190
1191 when N_Entry_Body =>
1192 Traverse_Subprogram_Body (N);
1193
1194 when N_Subprogram_Body_Stub =>
1195 if Traverse_Stub (N) then
1196 Traverse_Subprogram_Body (Get_Body_From_Stub (N));
1197 end if;
1198
1199 when N_Protected_Body =>
1200 Traverse_Protected_Body (N);
1201
1202 when N_Protected_Body_Stub =>
1203 if Traverse_Stub (N) then
1204 Traverse_Protected_Body (Get_Body_From_Stub (N));
1205 end if;
1206
1207 when N_Protected_Type_Declaration =>
1208 Traverse_Visible_And_Private_Parts (Protected_Definition (N));
1209
1210 when N_Task_Type_Declaration =>
1211
1212 -- Task type definition is optional (unlike protected type
1213 -- definition, which is mandatory).
1214
1215 declare
1216 Task_Def : constant Node_Id := Task_Definition (N);
1217 begin
1218 if Present (Task_Def) then
1219 Traverse_Visible_And_Private_Parts (Task_Def);
1220 end if;
1221 end;
1222
1223 when N_Task_Body =>
1224 Traverse_Task_Body (N);
1225
1226 when N_Task_Body_Stub =>
1227 if Traverse_Stub (N) then
1228 Traverse_Task_Body (Get_Body_From_Stub (N));
1229 end if;
1230
1231 when N_Block_Statement =>
1232 Traverse_Block (N);
1233
1234 when N_If_Statement =>
1235
1236 -- Traverse the statements in the THEN part
1237
1238 Traverse_Declarations_Or_Statements (Then_Statements (N));
1239
1240 -- Loop through ELSIF parts if present
1241
1242 if Present (Elsif_Parts (N)) then
1243 declare
1244 Elif : Node_Id := First (Elsif_Parts (N));
1245
1246 begin
1247 while Present (Elif) loop
1248 Traverse_Declarations_Or_Statements
1249 (Then_Statements (Elif));
1250 Next (Elif);
1251 end loop;
1252 end;
1253 end if;
1254
1255 -- Finally traverse the ELSE statements if present
1256
1257 Traverse_Declarations_Or_Statements (Else_Statements (N));
1258
1259 when N_Case_Statement =>
1260
1261 -- Process case branches
1262
1263 declare
1264 Alt : Node_Id := First (Alternatives (N));
1265 begin
1266 loop
1267 Traverse_Declarations_Or_Statements (Statements (Alt));
1268 Next (Alt);
1269 exit when No (Alt);
1270 end loop;
1271 end;
1272
1273 when N_Extended_Return_Statement =>
1274 Traverse_Handled_Statement_Sequence
1275 (Handled_Statement_Sequence (N));
1276
1277 when N_Loop_Statement =>
1278 Traverse_Declarations_Or_Statements (Statements (N));
1279
1280 -- Generic declarations are ignored
1281
1282 when others =>
1283 null;
1284 end case;
1285 end Traverse_Declaration_Or_Statement;
1286
1287 -----------------------------------
1288 -- Traverse_Declarations_And_HSS --
1289 -----------------------------------
1290
1291 procedure Traverse_Declarations_And_HSS (N : Node_Id) is
1292 begin
1293 Traverse_Declarations_Or_Statements (Declarations (N));
1294 Traverse_Handled_Statement_Sequence (Handled_Statement_Sequence (N));
1295 end Traverse_Declarations_And_HSS;
1296
1297 -----------------------------------------
1298 -- Traverse_Declarations_Or_Statements --
1299 -----------------------------------------
1300
1301 procedure Traverse_Declarations_Or_Statements (L : List_Id) is
1302 N : Node_Id;
1303
1304 begin
1305 -- Loop through statements or declarations
1306
1307 N := First (L);
1308 while Present (N) loop
1309
1310 -- Call Process on all declarations
1311
1312 if Nkind (N) in N_Declaration
1313 or else Nkind (N) in N_Later_Decl_Item
1314 or else Nkind (N) = N_Entry_Body
1315 then
1316 if Nkind (N) in N_Body_Stub then
1317 Process (Get_Body_From_Stub (N));
1318 else
1319 Process (N);
1320 end if;
1321 end if;
1322
1323 Traverse_Declaration_Or_Statement (N);
1324
1325 Next (N);
1326 end loop;
1327 end Traverse_Declarations_Or_Statements;
1328
1329 -----------------------------------------
1330 -- Traverse_Handled_Statement_Sequence --
1331 -----------------------------------------
1332
1333 procedure Traverse_Handled_Statement_Sequence (N : Node_Id) is
1334 Handler : Node_Id;
1335
1336 begin
1337 if Present (N) then
1338 Traverse_Declarations_Or_Statements (Statements (N));
1339
1340 if Present (Exception_Handlers (N)) then
1341 Handler := First (Exception_Handlers (N));
1342 while Present (Handler) loop
1343 Traverse_Declarations_Or_Statements (Statements (Handler));
1344 Next (Handler);
1345 end loop;
1346 end if;
1347 end if;
1348 end Traverse_Handled_Statement_Sequence;
1349
1350 ---------------------------
1351 -- Traverse_Package_Body --
1352 ---------------------------
1353
1354 procedure Traverse_Package_Body (N : Node_Id) is
1355 Spec_E : constant Entity_Id := Unique_Defining_Entity (N);
1356
1357 begin
1358 case Ekind (Spec_E) is
1359 when E_Package =>
1360 Traverse_Declarations_And_HSS (N);
1361
1362 when E_Generic_Package =>
1363 null;
1364
1365 when others =>
1366 raise Program_Error;
1367 end case;
1368 end Traverse_Package_Body;
1369
1370 -----------------------------
1371 -- Traverse_Protected_Body --
1372 -----------------------------
1373
1374 procedure Traverse_Protected_Body (N : Node_Id) is
1375 begin
1376 Traverse_Declarations_Or_Statements (Declarations (N));
1377 end Traverse_Protected_Body;
1378
1379 ------------------------------
1380 -- Traverse_Subprogram_Body --
1381 ------------------------------
1382
1383 procedure Traverse_Subprogram_Body (N : Node_Id) is
1384 Spec_E : constant Entity_Id := Unique_Defining_Entity (N);
1385
1386 begin
1387 case Ekind (Spec_E) is
1388 when Entry_Kind
1389 | E_Function
1390 | E_Procedure
1391 =>
1392 Traverse_Declarations_And_HSS (N);
1393
1394 when Generic_Subprogram_Kind =>
1395 null;
1396
1397 when others =>
1398 raise Program_Error;
1399 end case;
1400 end Traverse_Subprogram_Body;
1401
1402 ------------------------
1403 -- Traverse_Task_Body --
1404 ------------------------
1405
1406 procedure Traverse_Task_Body (N : Node_Id) renames
1407 Traverse_Declarations_And_HSS;
1408
1409 ----------------------------------------
1410 -- Traverse_Visible_And_Private_Parts --
1411 ----------------------------------------
1412
1413 procedure Traverse_Visible_And_Private_Parts (N : Node_Id) is
1414 begin
1415 Traverse_Declarations_Or_Statements (Visible_Declarations (N));
1416 Traverse_Declarations_Or_Statements (Private_Declarations (N));
1417 end Traverse_Visible_And_Private_Parts;
1418
1419 -- Local variables
1420
1421 Lu : Node_Id;
1422
1423 -- Start of processing for Traverse_Compilation_Unit
1424
1425 begin
1426 -- Get Unit (checking case of subunit)
1427
1428 Lu := Unit (CU);
1429
1430 if Nkind (Lu) = N_Subunit then
1431 Lu := Proper_Body (Lu);
1432 end if;
1433
1434 -- Do not add scopes for generic units
1435
1436 if Nkind (Lu) = N_Package_Body
1437 and then Ekind (Corresponding_Spec (Lu)) in Generic_Unit_Kind
1438 then
1439 return;
1440 end if;
1441
1442 -- Call Process on all declarations
1443
1444 if Nkind (Lu) in N_Declaration
1445 or else Nkind (Lu) in N_Later_Decl_Item
1446 then
1447 Process (Lu);
1448 end if;
1449
1450 -- Traverse the unit
1451
1452 Traverse_Declaration_Or_Statement (Lu);
1453 end Traverse_Compilation_Unit;
1454
1455 end SPARK_Specific;
This page took 0.097468 seconds and 4 git commands to generate.