]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ada/sem_spark.adb
[Ada] Fix spurious ownership error in GNATprove
[thirdparty/gcc.git] / gcc / ada / sem_spark.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S E M _ S P A R K --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2017-2019, 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 Namet; use Namet;
30 with Nlists; use Nlists;
31 with Opt; use Opt;
32 with Osint; use Osint;
33 with Sem_Prag; use Sem_Prag;
34 with Sem_Util; use Sem_Util;
35 with Sem_Aux; use Sem_Aux;
36 with Sinfo; use Sinfo;
37 with Snames; use Snames;
38 with Treepr; use Treepr;
39
40 with Ada.Unchecked_Deallocation;
41 with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
42
43 package body Sem_SPARK is
44
45 ---------------------------------------------------
46 -- Handling of Permissions Associated with Paths --
47 ---------------------------------------------------
48
49 package Permissions is
50 Elaboration_Context_Max : constant := 1009;
51 -- The hash range
52
53 type Elaboration_Context_Index is range 0 .. Elaboration_Context_Max - 1;
54
55 function Elaboration_Context_Hash
56 (Key : Entity_Id) return Elaboration_Context_Index;
57 -- The hash function
58
59 -- Permission type associated with paths. These are related to but not
60 -- the same as the states associated with names used in SPARK RM 3.10:
61 -- Unrestricted, Observed, Borrowed, Moved. When ownership rules lead to
62 -- a state change for a name, this may correspond to multiple permission
63 -- changes for the paths corresponding to the name, its prefixes, and
64 -- its extensions. For example, when an object is assigned to, the
65 -- corresponding name gets into state Moved, while the path for the name
66 -- gets permission Write_Only as well as every prefix of the name, and
67 -- every suffix gets permission No_Access.
68
69 type Perm_Kind_Option is
70 (None,
71 -- Special value used when no permission is passed around
72
73 No_Access,
74 -- The path cannot be accessed for reading or writing. This is the
75 -- case for the path of a name in the Borrowed state.
76
77 Read_Only,
78 -- The path can only be accessed for reading. This is the case for
79 -- the path of a name in the Observed state.
80
81 Read_Write,
82 -- The path can be accessed for both reading and writing. This is the
83 -- case for the path of a name in the Unrestricted state.
84
85 Write_Only
86 -- The path can only be accessed for writing. This is the case for
87 -- the path of a name in the Moved state.
88 );
89
90 subtype Perm_Kind is Perm_Kind_Option range No_Access .. Write_Only;
91 subtype Read_Perm is Perm_Kind range Read_Only .. Read_Write;
92 subtype Write_Perm is Perm_Kind range Read_Write .. Write_Only;
93
94 type Perm_Tree_Wrapper;
95
96 type Perm_Tree_Access is access Perm_Tree_Wrapper;
97 -- A tree of permissions is defined, where the root is a whole object
98 -- and tree branches follow access paths in memory. As Perm_Tree is a
99 -- discriminated record, a wrapper type is used for the access type
100 -- designating a subtree, to make it unconstrained so that it can be
101 -- updated.
102
103 -- Nodes in the permission tree are of different kinds
104
105 type Path_Kind is
106 (Entire_Object, -- Scalar object, or folded object of any type
107 Reference, -- Unfolded object of access type
108 Array_Component, -- Unfolded object of array type
109 Record_Component -- Unfolded object of record type
110 );
111
112 package Perm_Tree_Maps is new Simple_HTable
113 (Header_Num => Elaboration_Context_Index,
114 Key => Entity_Id,
115 Element => Perm_Tree_Access,
116 No_Element => null,
117 Hash => Elaboration_Context_Hash,
118 Equal => "=");
119 -- The instantation of a hash table, with keys being entities and values
120 -- being pointers to permission trees. This is used to define global
121 -- environment permissions (entities in that case are stand-alone
122 -- objects or formal parameters), as well as the permissions for the
123 -- extensions of a Record_Component node (entities in that case are
124 -- record components).
125
126 -- The definition of permission trees. This is a tree, which has a
127 -- permission at each node, and depending on the type of the node, can
128 -- have zero, one, or more children reached through an access to tree.
129
130 type Perm_Tree (Kind : Path_Kind := Entire_Object) is record
131 Permission : Perm_Kind;
132 -- Permission at this level in the path
133
134 Is_Node_Deep : Boolean;
135 -- Whether this node is of a "deep" type, i.e. an access type or a
136 -- composite type containing access type subcomponents. This
137 -- corresponds to both "observing" and "owning" types in SPARK RM
138 -- 3.10. To be used when moving the path.
139
140 Explanation : Node_Id;
141 -- Node that can be used in an explanation for a permission mismatch
142
143 case Kind is
144 -- An entire object is either a leaf (an object which cannot be
145 -- extended further in a path) or a subtree in folded form (which
146 -- could later be unfolded further in another kind of node). The
147 -- field Children_Permission specifies a permission for every
148 -- extension of that node if that permission is different from the
149 -- node's permission.
150
151 when Entire_Object =>
152 Children_Permission : Perm_Kind;
153
154 -- Unfolded path of access type. The permission of the object
155 -- pointed to is given in Get_All.
156
157 when Reference =>
158 Get_All : Perm_Tree_Access;
159
160 -- Unfolded path of array type. The permission of elements is
161 -- given in Get_Elem.
162
163 when Array_Component =>
164 Get_Elem : Perm_Tree_Access;
165
166 -- Unfolded path of record type. The permission of the components
167 -- is given in Component.
168
169 when Record_Component =>
170 Component : Perm_Tree_Maps.Instance;
171 end case;
172 end record;
173
174 type Perm_Tree_Wrapper is record
175 Tree : Perm_Tree;
176 end record;
177 -- We use this wrapper in order to have unconstrained discriminants
178
179 type Perm_Env is new Perm_Tree_Maps.Instance;
180 -- The definition of a permission environment for the analysis. This is
181 -- just a hash table from entities to permission trees.
182
183 type Perm_Env_Access is access Perm_Env;
184 -- Access to permission environments
185
186 package Env_Maps is new Simple_HTable
187 (Header_Num => Elaboration_Context_Index,
188 Key => Entity_Id,
189 Element => Perm_Env_Access,
190 No_Element => null,
191 Hash => Elaboration_Context_Hash,
192 Equal => "=");
193 -- The instantiation of a hash table whose elements are permission
194 -- environments. This hash table is used to save the environments at
195 -- the entry of each loop, with the key being the loop label.
196
197 type Env_Backups is new Env_Maps.Instance;
198 -- The type defining the hash table saving the environments at the entry
199 -- of each loop.
200
201 package Variable_Maps is new Simple_HTable
202 (Header_Num => Elaboration_Context_Index,
203 Key => Entity_Id,
204 Element => Node_Id,
205 No_Element => Empty,
206 Hash => Elaboration_Context_Hash,
207 Equal => "=");
208
209 type Variable_Mapping is new Variable_Maps.Instance;
210 -- Mapping from variables to nodes denoting paths that are observed or
211 -- borrowed by the variable.
212
213 --------------------
214 -- Simple Getters --
215 --------------------
216
217 -- Simple getters to avoid having .all.Tree.Field everywhere. Of course,
218 -- that's only for the top access, as otherwise this reverses the order
219 -- in accesses visually.
220
221 function Children_Permission (T : Perm_Tree_Access) return Perm_Kind;
222 function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance;
223 function Explanation (T : Perm_Tree_Access) return Node_Id;
224 function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access;
225 function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access;
226 function Is_Node_Deep (T : Perm_Tree_Access) return Boolean;
227 function Kind (T : Perm_Tree_Access) return Path_Kind;
228 function Permission (T : Perm_Tree_Access) return Perm_Kind;
229
230 -----------------------
231 -- Memory Management --
232 -----------------------
233
234 procedure Copy_Env
235 (From : Perm_Env;
236 To : in out Perm_Env);
237 -- Procedure to copy a permission environment
238
239 procedure Move_Env (From, To : in out Perm_Env);
240 -- Procedure to move a permission environment. It frees To, moves From
241 -- in To and sets From to Nil.
242
243 procedure Move_Variable_Mapping (From, To : in out Variable_Mapping);
244 -- Move a variable mapping, freeing memory as needed and resetting the
245 -- source mapping.
246
247 procedure Copy_Tree (From, To : Perm_Tree_Access);
248 -- Procedure to copy a permission tree
249
250 procedure Free_Env (PE : in out Perm_Env);
251 -- Procedure to free a permission environment
252
253 procedure Free_Tree (PT : in out Perm_Tree_Access);
254 -- Procedure to free a permission tree
255
256 --------------------
257 -- Error Messages --
258 --------------------
259
260 procedure Perm_Mismatch
261 (N : Node_Id;
262 Exp_Perm : Perm_Kind;
263 Act_Perm : Perm_Kind;
264 Expl : Node_Id;
265 Forbidden_Perm : Boolean := False);
266 -- Issues a continuation error message about a mismatch between a
267 -- desired permission Exp_Perm and a permission obtained Act_Perm. N
268 -- is the node on which the error is reported.
269
270 end Permissions;
271
272 package body Permissions is
273
274 -------------------------
275 -- Children_Permission --
276 -------------------------
277
278 function Children_Permission (T : Perm_Tree_Access) return Perm_Kind is
279 begin
280 return T.all.Tree.Children_Permission;
281 end Children_Permission;
282
283 ---------------
284 -- Component --
285 ---------------
286
287 function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance
288 is
289 begin
290 return T.all.Tree.Component;
291 end Component;
292
293 --------------
294 -- Copy_Env --
295 --------------
296
297 procedure Copy_Env (From : Perm_Env; To : in out Perm_Env) is
298 Comp_From : Perm_Tree_Access;
299 Key_From : Perm_Tree_Maps.Key_Option;
300 Son : Perm_Tree_Access;
301
302 begin
303 Free_Env (To);
304 Key_From := Get_First_Key (From);
305 while Key_From.Present loop
306 Comp_From := Get (From, Key_From.K);
307 pragma Assert (Comp_From /= null);
308
309 Son := new Perm_Tree_Wrapper;
310 Copy_Tree (Comp_From, Son);
311
312 Set (To, Key_From.K, Son);
313 Key_From := Get_Next_Key (From);
314 end loop;
315 end Copy_Env;
316
317 ---------------
318 -- Copy_Tree --
319 ---------------
320
321 procedure Copy_Tree (From, To : Perm_Tree_Access) is
322 begin
323 -- Copy the direct components of the tree
324
325 To.all := From.all;
326
327 -- Now reallocate access components for a deep copy of the tree
328
329 case Kind (From) is
330 when Entire_Object =>
331 null;
332
333 when Reference =>
334 To.all.Tree.Get_All := new Perm_Tree_Wrapper;
335 Copy_Tree (Get_All (From), Get_All (To));
336
337 when Array_Component =>
338 To.all.Tree.Get_Elem := new Perm_Tree_Wrapper;
339 Copy_Tree (Get_Elem (From), Get_Elem (To));
340
341 when Record_Component =>
342 declare
343 Comp_From : Perm_Tree_Access;
344 Key_From : Perm_Tree_Maps.Key_Option;
345 Son : Perm_Tree_Access;
346 Hash_Table : Perm_Tree_Maps.Instance;
347 begin
348 -- We put a new hash table, so that it gets dealiased from
349 -- the Component (From) hash table.
350 To.all.Tree.Component := Hash_Table;
351 Key_From := Perm_Tree_Maps.Get_First_Key
352 (Component (From));
353
354 while Key_From.Present loop
355 Comp_From := Perm_Tree_Maps.Get
356 (Component (From), Key_From.K);
357 pragma Assert (Comp_From /= null);
358 Son := new Perm_Tree_Wrapper;
359 Copy_Tree (Comp_From, Son);
360 Perm_Tree_Maps.Set
361 (To.all.Tree.Component, Key_From.K, Son);
362 Key_From := Perm_Tree_Maps.Get_Next_Key
363 (Component (From));
364 end loop;
365 end;
366 end case;
367 end Copy_Tree;
368
369 ------------------------------
370 -- Elaboration_Context_Hash --
371 ------------------------------
372
373 function Elaboration_Context_Hash
374 (Key : Entity_Id) return Elaboration_Context_Index
375 is
376 begin
377 return Elaboration_Context_Index (Key mod Elaboration_Context_Max);
378 end Elaboration_Context_Hash;
379
380 --------------
381 -- Free_Env --
382 --------------
383
384 procedure Free_Env (PE : in out Perm_Env) is
385 CompO : Perm_Tree_Access;
386 begin
387 CompO := Get_First (PE);
388 while CompO /= null loop
389 Free_Tree (CompO);
390 CompO := Get_Next (PE);
391 end loop;
392
393 Reset (PE);
394 end Free_Env;
395
396 ---------------
397 -- Free_Tree --
398 ---------------
399
400 procedure Free_Tree (PT : in out Perm_Tree_Access) is
401 procedure Free_Perm_Tree_Dealloc is
402 new Ada.Unchecked_Deallocation
403 (Perm_Tree_Wrapper, Perm_Tree_Access);
404 -- The deallocator for permission_trees
405
406 begin
407 case Kind (PT) is
408 when Entire_Object =>
409 null;
410
411 when Reference =>
412 Free_Tree (PT.all.Tree.Get_All);
413
414 when Array_Component =>
415 Free_Tree (PT.all.Tree.Get_Elem);
416
417 when Record_Component =>
418 declare
419 Comp : Perm_Tree_Access;
420
421 begin
422 Comp := Perm_Tree_Maps.Get_First (Component (PT));
423 while Comp /= null loop
424
425 -- Free every Component subtree
426
427 Free_Tree (Comp);
428 Comp := Perm_Tree_Maps.Get_Next (Component (PT));
429 end loop;
430 end;
431 end case;
432
433 Free_Perm_Tree_Dealloc (PT);
434 end Free_Tree;
435
436 -----------------
437 -- Explanation --
438 -----------------
439
440 function Explanation (T : Perm_Tree_Access) return Node_Id is
441 begin
442 return T.all.Tree.Explanation;
443 end Explanation;
444
445 -------------
446 -- Get_All --
447 -------------
448
449 function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access is
450 begin
451 return T.all.Tree.Get_All;
452 end Get_All;
453
454 --------------
455 -- Get_Elem --
456 --------------
457
458 function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access is
459 begin
460 return T.all.Tree.Get_Elem;
461 end Get_Elem;
462
463 ------------------
464 -- Is_Node_Deep --
465 ------------------
466
467 function Is_Node_Deep (T : Perm_Tree_Access) return Boolean is
468 begin
469 return T.all.Tree.Is_Node_Deep;
470 end Is_Node_Deep;
471
472 ----------
473 -- Kind --
474 ----------
475
476 function Kind (T : Perm_Tree_Access) return Path_Kind is
477 begin
478 return T.all.Tree.Kind;
479 end Kind;
480
481 --------------
482 -- Move_Env --
483 --------------
484
485 procedure Move_Env (From, To : in out Perm_Env) is
486 begin
487 Free_Env (To);
488 To := From;
489 From := Perm_Env (Perm_Tree_Maps.Nil);
490 end Move_Env;
491
492 ---------------------------
493 -- Move_Variable_Mapping --
494 ---------------------------
495
496 procedure Move_Variable_Mapping (From, To : in out Variable_Mapping) is
497 begin
498 Reset (To);
499 To := From;
500 From := Variable_Mapping (Variable_Maps.Nil);
501 end Move_Variable_Mapping;
502
503 ----------------
504 -- Permission --
505 ----------------
506
507 function Permission (T : Perm_Tree_Access) return Perm_Kind is
508 begin
509 return T.all.Tree.Permission;
510 end Permission;
511
512 -------------------
513 -- Perm_Mismatch --
514 -------------------
515
516 procedure Perm_Mismatch
517 (N : Node_Id;
518 Exp_Perm : Perm_Kind;
519 Act_Perm : Perm_Kind;
520 Expl : Node_Id;
521 Forbidden_Perm : Boolean := False)
522 is
523 begin
524 Error_Msg_Sloc := Sloc (Expl);
525
526 if Forbidden_Perm then
527 if Exp_Perm = No_Access then
528 Error_Msg_N ("\object was moved #", N);
529 else
530 raise Program_Error;
531 end if;
532 else
533 case Exp_Perm is
534 when Write_Perm =>
535 if Act_Perm = Read_Only then
536 Error_Msg_N
537 ("\object was declared as not writeable #", N);
538 else
539 Error_Msg_N ("\object was moved #", N);
540 end if;
541
542 when Read_Only =>
543 Error_Msg_N ("\object was moved #", N);
544
545 when No_Access =>
546 raise Program_Error;
547 end case;
548 end if;
549 end Perm_Mismatch;
550
551 end Permissions;
552
553 use Permissions;
554
555 --------------------------------------
556 -- Analysis modes for AST traversal --
557 --------------------------------------
558
559 -- The different modes for analysis. This allows checking whether a path
560 -- has the right permission, and also updating permissions when a path is
561 -- moved, borrowed, or observed.
562
563 type Extended_Checking_Mode is
564
565 (Read_Subexpr,
566 -- Special value used for assignment, to check that subexpressions of
567 -- the assigned path are readable.
568
569 Read,
570 -- Default mode
571
572 Move,
573 -- Move semantics. Checks that paths have Read_Write permission. After
574 -- moving a path, its permission and the permission of its prefixes are
575 -- set to Write_Only, while the permission of its extensions is set to
576 -- No_Access.
577
578 Assign,
579 -- Used for the target of an assignment, or an actual parameter with
580 -- mode OUT. Checks that paths have Write_Perm permission. After
581 -- assigning to a path, its permission and the permission of its
582 -- extensions are set to Read_Write. The permission of its prefixes may
583 -- be normalized from Write_Only to Read_Write depending on other
584 -- permissions in the tree (a prefix gets permission Read_Write when all
585 -- its extensions become Read_Write).
586
587 Borrow,
588 -- Borrow semantics. Checks that paths have Read_Write permission. After
589 -- borrowing a path, its permission and the permission of its prefixes
590 -- and extensions are set to No_Access.
591
592 Observe
593 -- Observe semantics. Checks that paths have Read_Perm permission. After
594 -- observing a path, its permission and the permission of its prefixes
595 -- and extensions are set to Read_Only.
596 );
597
598 subtype Checking_Mode is Extended_Checking_Mode range Read .. Observe;
599
600 type Result_Kind is (Folded, Unfolded);
601 -- The type declaration to discriminate in the Perm_Or_Tree type
602
603 -- The result type of the function Get_Perm_Or_Tree. This returns either a
604 -- tree when it found the appropriate tree, or a permission when the search
605 -- finds a leaf and the subtree we are looking for is folded. In the last
606 -- case, we return instead the Children_Permission field of the leaf.
607
608 type Perm_Or_Tree (R : Result_Kind) is record
609 case R is
610 when Folded =>
611 Found_Permission : Perm_Kind;
612 Explanation : Node_Id;
613 when Unfolded =>
614 Tree_Access : Perm_Tree_Access;
615 end case;
616 end record;
617
618 type Error_Status is (OK, Error);
619
620 -----------------------
621 -- Local subprograms --
622 -----------------------
623
624 function "<=" (P1, P2 : Perm_Kind) return Boolean;
625 function ">=" (P1, P2 : Perm_Kind) return Boolean;
626 function Glb (P1, P2 : Perm_Kind) return Perm_Kind;
627 function Lub (P1, P2 : Perm_Kind) return Perm_Kind;
628
629 procedure Check_Assignment (Target : Node_Or_Entity_Id; Expr : Node_Id);
630 -- Handle assignment as part of an assignment statement or an object
631 -- declaration.
632
633 procedure Check_Call_Statement (Call : Node_Id);
634
635 procedure Check_Callable_Body (Body_N : Node_Id);
636 -- Entry point for the analysis of a subprogram or entry body
637
638 procedure Check_Declaration (Decl : Node_Id);
639
640 procedure Check_Expression (Expr : Node_Id; Mode : Extended_Checking_Mode);
641 pragma Precondition (Nkind_In (Expr, N_Index_Or_Discriminant_Constraint,
642 N_Range_Constraint,
643 N_Subtype_Indication,
644 N_Digits_Constraint,
645 N_Delta_Constraint)
646 or else Nkind (Expr) in N_Subexpr);
647
648 procedure Check_Globals (Subp : Entity_Id);
649 -- This procedure takes a subprogram called and checks the permission of
650 -- globals.
651
652 -- Checking proceduress for safe pointer usage. These procedures traverse
653 -- the AST, check nodes for correct permissions according to SPARK RM 3.10,
654 -- and update permissions depending on the node kind. The main procedure
655 -- Check_Node is mutually recursive with the specialized procedures that
656 -- follow.
657
658 procedure Check_List (L : List_Id);
659 -- Calls Check_Node on each element of the list
660
661 procedure Check_Loop_Statement (Stmt : Node_Id);
662
663 procedure Check_Node (N : Node_Id);
664 -- Main traversal procedure to check safe pointer usage
665
666 procedure Check_Package_Body (Pack : Node_Id);
667
668 procedure Check_Package_Spec (Pack : Node_Id);
669
670 procedure Check_Parameter_Or_Global
671 (Expr : Node_Id;
672 Typ : Entity_Id;
673 Kind : Formal_Kind;
674 Subp : Entity_Id;
675 Global_Var : Boolean);
676 -- Check the permission of every actual parameter or global
677
678 procedure Check_Pragma (Prag : Node_Id);
679
680 procedure Check_Source_Of_Borrow_Or_Observe
681 (Expr : Node_Id;
682 Status : out Error_Status);
683
684 procedure Check_Statement (Stmt : Node_Id);
685
686 procedure Check_Type (Typ : Entity_Id);
687 -- Check that type Typ is either not deep, or that it is an observing or
688 -- owning type according to SPARK RM 3.10
689
690 function Get_Expl (N : Node_Or_Entity_Id) return Node_Id;
691 -- The function that takes a name as input and returns an explanation node
692 -- for the permission associated with it.
693
694 function Get_Observed_Or_Borrowed_Expr (Expr : Node_Id) return Node_Id;
695 pragma Precondition (Is_Path_Expression (Expr));
696 -- Return the expression being borrowed/observed when borrowing or
697 -- observing Expr. If Expr is a call to a traversal function, this is
698 -- the first actual, otherwise it is Expr.
699
700 function Get_Perm (N : Node_Or_Entity_Id) return Perm_Kind;
701 -- The function that takes a name as input and returns a permission
702 -- associated with it.
703
704 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree;
705 pragma Precondition (Is_Path_Expression (N));
706 -- This function gets a node and looks recursively to find the appropriate
707 -- subtree for that node. If the tree is folded on that node, then it
708 -- returns the permission given at the right level.
709
710 function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access;
711 pragma Precondition (Is_Path_Expression (N));
712 -- This function gets a node and looks recursively to find the appropriate
713 -- subtree for that node. If the tree is folded, then it unrolls the tree
714 -- up to the appropriate level.
715
716 function Get_Root_Object
717 (Expr : Node_Id;
718 Through_Traversal : Boolean := True;
719 Is_Traversal : Boolean := False) return Entity_Id;
720 -- Return the root of the path expression Expr, or Empty for an allocator,
721 -- NULL, or a function call. Through_Traversal is True if it should follow
722 -- through calls to traversal functions. Is_Traversal is True if this
723 -- corresponds to a value returned from a traversal function, which should
724 -- allow if-expressions and case-expressions that refer to the same root,
725 -- even if the paths are not the same in all branches.
726
727 generic
728 with procedure Handle_Parameter_Or_Global
729 (Expr : Node_Id;
730 Formal_Typ : Entity_Id;
731 Param_Mode : Formal_Kind;
732 Subp : Entity_Id;
733 Global_Var : Boolean);
734 procedure Handle_Globals (Subp : Entity_Id);
735 -- Handling of globals is factored in a generic instantiated below
736
737 function Has_Array_Component (Expr : Node_Id) return Boolean;
738 pragma Precondition (Is_Path_Expression (Expr));
739 -- This function gets a node and looks recursively to determine whether the
740 -- given path has any array component.
741
742 procedure Hp (P : Perm_Env);
743 -- A procedure that outputs the hash table. This function is used only in
744 -- the debugger to look into a hash table.
745 pragma Unreferenced (Hp);
746
747 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id; E : Entity_Id);
748 pragma No_Return (Illegal_Global_Usage);
749 -- A procedure that is called when deep globals or aliased globals are used
750 -- without any global aspect.
751
752 function Is_Path_Expression
753 (Expr : Node_Id;
754 Is_Traversal : Boolean := False) return Boolean;
755 -- Return whether Expr corresponds to a path. Is_Traversal is True if this
756 -- corresponds to a value returned from a traversal function, which should
757 -- allow if-expressions and case-expressions.
758
759 function Is_Subpath_Expression
760 (Expr : Node_Id;
761 Is_Traversal : Boolean := False) return Boolean;
762 -- Return True if Expr can be part of a path expression. Is_Traversal is
763 -- True if this corresponds to a value returned from a traversal function,
764 -- which should allow if-expressions and case-expressions.
765
766 function Is_Prefix_Or_Almost (Pref, Expr : Node_Id) return Boolean;
767 -- Determine if the candidate Prefix is indeed a prefix of Expr, or almost
768 -- a prefix, in the sense that they could still refer to overlapping memory
769 -- locations.
770
771 function Is_Traversal_Function_Call (Expr : Node_Id) return Boolean;
772
773 function Loop_Of_Exit (N : Node_Id) return Entity_Id;
774 -- A function that takes an exit statement node and returns the entity of
775 -- the loop that this statement is exiting from.
776
777 procedure Merge_Env (Source : in out Perm_Env; Target : in out Perm_Env);
778 -- Merge Target and Source into Target, and then deallocate the Source
779
780 procedure Perm_Error
781 (N : Node_Id;
782 Perm : Perm_Kind;
783 Found_Perm : Perm_Kind;
784 Expl : Node_Id;
785 Forbidden_Perm : Boolean := False);
786 -- A procedure that is called when the permissions found contradict the
787 -- rules established by the RM. This function is called with the node and
788 -- the permission that was expected, and issues an error message with the
789 -- appropriate values.
790
791 procedure Perm_Error_Subprogram_End
792 (E : Entity_Id;
793 Subp : Entity_Id;
794 Perm : Perm_Kind;
795 Found_Perm : Perm_Kind;
796 Expl : Node_Id);
797 -- A procedure that is called when the permissions found contradict the
798 -- rules established by the RM at the end of subprograms. This function is
799 -- called with the node, the node of the returning function, and the
800 -- permission that was expected, and adds an error message with the
801 -- appropriate values.
802
803 procedure Process_Path (Expr : Node_Id; Mode : Checking_Mode);
804 pragma Precondition (Is_Path_Expression (Expr));
805 -- Check correct permission for the path in the checking mode Mode, and
806 -- update permissions of the path and its prefixes/extensions.
807
808 procedure Return_Globals (Subp : Entity_Id);
809 -- Takes a subprogram as input, and checks that all borrowed global items
810 -- of the subprogram indeed have Read_Write permission at the end of the
811 -- subprogram execution.
812
813 procedure Return_Parameter_Or_Global
814 (Id : Entity_Id;
815 Typ : Entity_Id;
816 Kind : Formal_Kind;
817 Subp : Entity_Id;
818 Global_Var : Boolean);
819 -- Auxiliary procedure to Return_Parameters and Return_Globals
820
821 procedure Return_Parameters (Subp : Entity_Id);
822 -- Takes a subprogram as input, and checks that all out parameters of the
823 -- subprogram indeed have Read_Write permission at the end of the
824 -- subprogram execution.
825
826 procedure Set_Perm_Extensions
827 (T : Perm_Tree_Access;
828 P : Perm_Kind;
829 Expl : Node_Id);
830 -- This procedure takes an access to a permission tree and modifies the
831 -- tree so that any strict extensions of the given tree become of the
832 -- access specified by parameter P.
833
834 procedure Set_Perm_Extensions_Move
835 (T : Perm_Tree_Access;
836 E : Entity_Id;
837 Expl : Node_Id);
838 -- Set permissions to
839 -- No for any extension with more .all
840 -- W for any deep extension with same number of .all
841 -- RW for any shallow extension with same number of .all
842
843 function Set_Perm_Prefixes
844 (N : Node_Id;
845 Perm : Perm_Kind_Option;
846 Expl : Node_Id) return Perm_Tree_Access;
847 pragma Precondition (Is_Path_Expression (N));
848 -- This function modifies the permissions of a given node in the permission
849 -- environment as well as all the prefixes of the path, to the new
850 -- permission Perm. The general rule here is that everybody updates the
851 -- permission of the subtree they are returning.
852
853 procedure Set_Perm_Prefixes_Assign (N : Node_Id);
854 pragma Precondition (Is_Path_Expression (N));
855 -- This procedure takes a name as an input and sets in the permission
856 -- tree the given permission to the given name. The general rule here is
857 -- that everybody updates the permission of the subtree it is returning.
858 -- The permission of the assigned path has been set to RW by the caller.
859 --
860 -- Case where we have to normalize a tree after the correct permissions
861 -- have been assigned already. We look for the right subtree at the given
862 -- path, actualize its permissions, and then call the normalization on its
863 -- parent.
864 --
865 -- Example: We assign x.y and x.z, and then Set_Perm_Prefixes_Assign will
866 -- change the permission of x to RW because all of its components have
867 -- permission RW.
868
869 procedure Setup_Globals (Subp : Entity_Id);
870 -- Takes a subprogram as input, and sets up the environment by adding
871 -- global items with appropriate permissions.
872
873 procedure Setup_Parameter_Or_Global
874 (Id : Entity_Id;
875 Typ : Entity_Id;
876 Kind : Formal_Kind;
877 Subp : Entity_Id;
878 Global_Var : Boolean;
879 Expl : Node_Id);
880 -- Auxiliary procedure to Setup_Parameters and Setup_Globals
881
882 procedure Setup_Parameters (Subp : Entity_Id);
883 -- Takes a subprogram as input, and sets up the environment by adding
884 -- formal parameters with appropriate permissions.
885
886 procedure Setup_Protected_Components (Subp : Entity_Id);
887 -- Takes a protected operation as input, and sets up the environment by
888 -- adding protected components with appropriate permissions.
889
890 ----------------------
891 -- Global Variables --
892 ----------------------
893
894 Current_Perm_Env : Perm_Env;
895 -- The permission environment that is used for the analysis. This
896 -- environment can be saved, modified, reinitialized, but should be the
897 -- only one valid from which to extract the permissions of the paths in
898 -- scope. The analysis ensures at each point that this variables contains
899 -- a valid permission environment with all bindings in scope.
900
901 Inside_Procedure_Call : Boolean := False;
902 -- Set while checking the actual parameters of a procedure or entry call
903
904 Inside_Elaboration : Boolean := False;
905 -- Set during package spec/body elaboration, during which move and local
906 -- observe/borrow are not allowed. As a result, no other checking is needed
907 -- during elaboration.
908
909 Current_Loops_Envs : Env_Backups;
910 -- This variable contains saves of permission environments at each loop the
911 -- analysis entered. Each saved environment can be reached with the label
912 -- of the loop.
913
914 Current_Loops_Accumulators : Env_Backups;
915 -- This variable contains the environments used as accumulators for loops,
916 -- that consist of the merge of all environments at each exit point of
917 -- the loop (which can also be the entry point of the loop in the case of
918 -- non-infinite loops), each of them reachable from the label of the loop.
919 -- We require that the environment stored in the accumulator be less
920 -- restrictive than the saved environment at the beginning of the loop, and
921 -- the permission environment after the loop is equal to the accumulator.
922
923 Current_Borrowers : Variable_Mapping;
924 -- Mapping from borrowers to the path borrowed
925
926 Current_Observers : Variable_Mapping;
927 -- Mapping from observers to the path observed
928
929 --------------------
930 -- Handle_Globals --
931 --------------------
932
933 -- Generic procedure is defined first so that instantiations can be defined
934 -- anywhere afterwards.
935
936 procedure Handle_Globals (Subp : Entity_Id) is
937
938 -- Local subprograms
939
940 procedure Handle_Globals_From_List
941 (First_Item : Node_Id;
942 Kind : Formal_Kind);
943 -- Handle global items from the list starting at Item
944
945 procedure Handle_Globals_Of_Mode (Global_Mode : Name_Id);
946 -- Handle global items for the mode Global_Mode
947
948 ------------------------------
949 -- Handle_Globals_From_List --
950 ------------------------------
951
952 procedure Handle_Globals_From_List
953 (First_Item : Node_Id;
954 Kind : Formal_Kind)
955 is
956 Item : Node_Id := First_Item;
957 E : Entity_Id;
958
959 begin
960 while Present (Item) loop
961 E := Entity (Item);
962
963 -- Ignore abstract states, which play no role in pointer aliasing
964
965 if Ekind (E) = E_Abstract_State then
966 null;
967 else
968 Handle_Parameter_Or_Global (Expr => Item,
969 Formal_Typ => Retysp (Etype (Item)),
970 Param_Mode => Kind,
971 Subp => Subp,
972 Global_Var => True);
973 end if;
974
975 Next_Global (Item);
976 end loop;
977 end Handle_Globals_From_List;
978
979 ----------------------------
980 -- Handle_Globals_Of_Mode --
981 ----------------------------
982
983 procedure Handle_Globals_Of_Mode (Global_Mode : Name_Id) is
984 Kind : Formal_Kind;
985
986 begin
987 case Global_Mode is
988 when Name_Input
989 | Name_Proof_In
990 =>
991 Kind := E_In_Parameter;
992
993 when Name_Output =>
994 Kind := E_Out_Parameter;
995
996 when Name_In_Out =>
997 Kind := E_In_Out_Parameter;
998
999 when others =>
1000 raise Program_Error;
1001 end case;
1002
1003 -- Check both global items from Global and Refined_Global pragmas
1004
1005 Handle_Globals_From_List (First_Global (Subp, Global_Mode), Kind);
1006 Handle_Globals_From_List
1007 (First_Global (Subp, Global_Mode, Refined => True), Kind);
1008 end Handle_Globals_Of_Mode;
1009
1010 -- Start of processing for Handle_Globals
1011
1012 begin
1013 Handle_Globals_Of_Mode (Name_Proof_In);
1014 Handle_Globals_Of_Mode (Name_Input);
1015 Handle_Globals_Of_Mode (Name_Output);
1016 Handle_Globals_Of_Mode (Name_In_Out);
1017 end Handle_Globals;
1018
1019 ----------
1020 -- "<=" --
1021 ----------
1022
1023 function "<=" (P1, P2 : Perm_Kind) return Boolean is
1024 begin
1025 return P2 >= P1;
1026 end "<=";
1027
1028 ----------
1029 -- ">=" --
1030 ----------
1031
1032 function ">=" (P1, P2 : Perm_Kind) return Boolean is
1033 begin
1034 case P2 is
1035 when No_Access => return True;
1036 when Read_Only => return P1 in Read_Perm;
1037 when Write_Only => return P1 in Write_Perm;
1038 when Read_Write => return P1 = Read_Write;
1039 end case;
1040 end ">=";
1041
1042 ----------------------
1043 -- Check_Assignment --
1044 ----------------------
1045
1046 procedure Check_Assignment (Target : Node_Or_Entity_Id; Expr : Node_Id) is
1047
1048 -- Local subprograms
1049
1050 procedure Handle_Borrow
1051 (Var : Entity_Id;
1052 Expr : Node_Id;
1053 Is_Decl : Boolean);
1054 -- Update map of current borrowers
1055
1056 procedure Handle_Observe
1057 (Var : Entity_Id;
1058 Expr : Node_Id;
1059 Is_Decl : Boolean);
1060 -- Update map of current observers
1061
1062 -------------------
1063 -- Handle_Borrow --
1064 -------------------
1065
1066 procedure Handle_Borrow
1067 (Var : Entity_Id;
1068 Expr : Node_Id;
1069 Is_Decl : Boolean)
1070 is
1071 Borrowed : constant Node_Id := Get_Observed_Or_Borrowed_Expr (Expr);
1072
1073 begin
1074 -- SPARK RM 3.10(8): If the type of the target is an anonymous
1075 -- access-to-variable type (an owning access type), the source shall
1076 -- be an owning access object [..] whose root object is the target
1077 -- object itself.
1078
1079 -- ??? In fact we could be slightly more permissive in allowing even
1080 -- a call to a traversal function of the right form.
1081
1082 if not Is_Decl
1083 and then (Is_Traversal_Function_Call (Expr)
1084 or else Get_Root_Object (Borrowed) /= Var)
1085 then
1086 if Emit_Messages then
1087 Error_Msg_NE
1088 ("source of assignment must have & as root" &
1089 " (SPARK RM 3.10(8)))",
1090 Expr, Var);
1091 end if;
1092 return;
1093 end if;
1094
1095 Set (Current_Borrowers, Var, Borrowed);
1096 end Handle_Borrow;
1097
1098 --------------------
1099 -- Handle_Observe --
1100 --------------------
1101
1102 procedure Handle_Observe
1103 (Var : Entity_Id;
1104 Expr : Node_Id;
1105 Is_Decl : Boolean)
1106 is
1107 Observed : constant Node_Id := Get_Observed_Or_Borrowed_Expr (Expr);
1108
1109 begin
1110 -- ??? We are currently using the same restriction for observers
1111 -- as for borrowers. To be seen if the SPARK RM current rule really
1112 -- allows more uses.
1113
1114 if not Is_Decl
1115 and then (Is_Traversal_Function_Call (Expr)
1116 or else Get_Root_Object (Observed) /= Var)
1117 then
1118 if Emit_Messages then
1119 Error_Msg_NE
1120 ("source of assignment must have & as root" &
1121 " (SPARK RM 3.10(8)))",
1122 Expr, Var);
1123 end if;
1124 return;
1125 end if;
1126
1127 Set (Current_Observers, Var, Observed);
1128 end Handle_Observe;
1129
1130 -- Local variables
1131
1132 Target_Typ : constant Node_Id := Etype (Target);
1133 Is_Decl : constant Boolean := Nkind (Target) = N_Defining_Identifier;
1134 Target_Root : Entity_Id;
1135 Expr_Root : Entity_Id;
1136 Perm : Perm_Kind;
1137 Status : Error_Status;
1138
1139 -- Start of processing for Check_Assignment
1140
1141 begin
1142 Check_Type (Target_Typ);
1143
1144 if Is_Anonymous_Access_Type (Target_Typ) then
1145 Check_Source_Of_Borrow_Or_Observe (Expr, Status);
1146
1147 if Status /= OK then
1148 return;
1149 end if;
1150
1151 if Is_Decl then
1152 Target_Root := Target;
1153 else
1154 Target_Root := Get_Root_Object (Target);
1155 end if;
1156
1157 Expr_Root := Get_Root_Object (Expr);
1158
1159 -- SPARK RM 3.10(8): For an assignment statement where
1160 -- the target is a stand-alone object of an anonymous
1161 -- access-to-object type
1162
1163 pragma Assert (Present (Target_Root));
1164
1165 -- If the type of the target is an anonymous
1166 -- access-to-constant type (an observing access type), the
1167 -- source shall be an owning access object denoted by a name
1168 -- that is not in the Moved state, and whose root object
1169 -- is not in the Moved state and is not declared at a
1170 -- statically deeper accessibility level than that of
1171 -- the target object.
1172
1173 if Is_Access_Constant (Target_Typ) then
1174 Perm := Get_Perm (Expr);
1175
1176 if Perm = No_Access then
1177 Perm_Error (Expr, No_Access, No_Access,
1178 Expl => Get_Expl (Expr),
1179 Forbidden_Perm => True);
1180 return;
1181 end if;
1182
1183 Perm := Get_Perm (Expr_Root);
1184
1185 if Perm = No_Access then
1186 Perm_Error (Expr, No_Access, No_Access,
1187 Expl => Get_Expl (Expr_Root),
1188 Forbidden_Perm => True);
1189 return;
1190 end if;
1191
1192 -- ??? check accessibility level
1193
1194 -- If the type of the target is an anonymous
1195 -- access-to-variable type (an owning access type), the
1196 -- source shall be an owning access object denoted by a
1197 -- name that is in the Unrestricted state, and whose root
1198 -- object is the target object itself.
1199
1200 Check_Expression (Expr, Observe);
1201 Handle_Observe (Target_Root, Expr, Is_Decl);
1202
1203 else
1204 Perm := Get_Perm (Expr);
1205
1206 if Perm /= Read_Write then
1207 Perm_Error (Expr, Read_Write, Perm, Expl => Get_Expl (Expr));
1208 return;
1209 end if;
1210
1211 if not Is_Decl then
1212 if not Is_Entity_Name (Target) then
1213 if Emit_Messages then
1214 Error_Msg_N
1215 ("target of borrow must be stand-alone variable",
1216 Target);
1217 end if;
1218 return;
1219
1220 elsif Target_Root /= Expr_Root then
1221 if Emit_Messages then
1222 Error_Msg_NE
1223 ("source of borrow must be variable &",
1224 Expr, Target);
1225 end if;
1226 return;
1227 end if;
1228 end if;
1229
1230 Check_Expression (Expr, Borrow);
1231 Handle_Borrow (Target_Root, Expr, Is_Decl);
1232 end if;
1233
1234 elsif Is_Deep (Target_Typ) then
1235
1236 if Is_Path_Expression (Expr) then
1237 Check_Expression (Expr, Move);
1238
1239 else
1240 if Emit_Messages then
1241 Error_Msg_N ("expression not allowed as source of move", Expr);
1242 end if;
1243 return;
1244 end if;
1245
1246 else
1247 Check_Expression (Expr, Read);
1248 end if;
1249 end Check_Assignment;
1250
1251 --------------------------
1252 -- Check_Call_Statement --
1253 --------------------------
1254
1255 procedure Check_Call_Statement (Call : Node_Id) is
1256
1257 Subp : constant Entity_Id := Get_Called_Entity (Call);
1258
1259 -- Local subprograms
1260
1261 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id);
1262 -- Check the permission of every actual parameter
1263
1264 procedure Update_Param (Formal : Entity_Id; Actual : Node_Id);
1265 -- Update the permission of OUT actual parameters
1266
1267 -----------------
1268 -- Check_Param --
1269 -----------------
1270
1271 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id) is
1272 begin
1273 Check_Parameter_Or_Global
1274 (Expr => Actual,
1275 Typ => Retysp (Etype (Formal)),
1276 Kind => Ekind (Formal),
1277 Subp => Subp,
1278 Global_Var => False);
1279 end Check_Param;
1280
1281 ------------------
1282 -- Update_Param --
1283 ------------------
1284
1285 procedure Update_Param (Formal : Entity_Id; Actual : Node_Id) is
1286 Mode : constant Entity_Kind := Ekind (Formal);
1287
1288 begin
1289 case Formal_Kind'(Mode) is
1290 when E_Out_Parameter =>
1291 Check_Expression (Actual, Assign);
1292
1293 when others =>
1294 null;
1295 end case;
1296 end Update_Param;
1297
1298 procedure Check_Params is new
1299 Iterate_Call_Parameters (Check_Param);
1300
1301 procedure Update_Params is new
1302 Iterate_Call_Parameters (Update_Param);
1303
1304 -- Start of processing for Check_Call_Statement
1305
1306 begin
1307 Inside_Procedure_Call := True;
1308 Check_Params (Call);
1309 if Ekind (Get_Called_Entity (Call)) = E_Subprogram_Type then
1310 if Emit_Messages then
1311 Error_Msg_N
1312 ("call through access to subprogram is not allowed in SPARK",
1313 Call);
1314 end if;
1315 else
1316 Check_Globals (Get_Called_Entity (Call));
1317 end if;
1318
1319 Inside_Procedure_Call := False;
1320 Update_Params (Call);
1321 end Check_Call_Statement;
1322
1323 -------------------------
1324 -- Check_Callable_Body --
1325 -------------------------
1326
1327 procedure Check_Callable_Body (Body_N : Node_Id) is
1328 Save_In_Elab : constant Boolean := Inside_Elaboration;
1329 Body_Id : constant Entity_Id := Defining_Entity (Body_N);
1330 Spec_Id : constant Entity_Id := Unique_Entity (Body_Id);
1331 Prag : constant Node_Id := SPARK_Pragma (Body_Id);
1332
1333 Saved_Env : Perm_Env;
1334 Saved_Borrowers : Variable_Mapping;
1335 Saved_Observers : Variable_Mapping;
1336
1337 begin
1338 -- Only SPARK bodies are analyzed
1339
1340 if No (Prag)
1341 or else Get_SPARK_Mode_From_Annotation (Prag) /= Opt.On
1342 then
1343 return;
1344 end if;
1345
1346 Inside_Elaboration := False;
1347
1348 if Ekind (Spec_Id) = E_Function
1349 and then Is_Anonymous_Access_Type (Etype (Spec_Id))
1350 and then not Is_Traversal_Function (Spec_Id)
1351 then
1352 if Emit_Messages then
1353 Error_Msg_N ("anonymous access type for result only allowed for "
1354 & "traversal functions", Spec_Id);
1355 end if;
1356 return;
1357 end if;
1358
1359 -- Save environment and put a new one in place
1360
1361 Move_Env (Current_Perm_Env, Saved_Env);
1362 Move_Variable_Mapping (Current_Borrowers, Saved_Borrowers);
1363 Move_Variable_Mapping (Current_Observers, Saved_Observers);
1364
1365 -- Add formals and globals to the environment with adequate permissions
1366
1367 if Is_Subprogram_Or_Entry (Spec_Id) then
1368 Setup_Parameters (Spec_Id);
1369 Setup_Globals (Spec_Id);
1370 end if;
1371
1372 -- For protected operations, add protected components to the environment
1373 -- with adequate permissions.
1374
1375 if Is_Protected_Operation (Spec_Id) then
1376 Setup_Protected_Components (Spec_Id);
1377 end if;
1378
1379 -- Analyze the body of the subprogram
1380
1381 Check_List (Declarations (Body_N));
1382 Check_Node (Handled_Statement_Sequence (Body_N));
1383
1384 -- Check the read-write permissions of borrowed parameters/globals
1385
1386 if Ekind_In (Spec_Id, E_Procedure, E_Entry)
1387 and then not No_Return (Spec_Id)
1388 then
1389 Return_Parameters (Spec_Id);
1390 Return_Globals (Spec_Id);
1391 end if;
1392
1393 -- Restore the saved environment and free the current one
1394
1395 Move_Env (Saved_Env, Current_Perm_Env);
1396 Move_Variable_Mapping (Saved_Borrowers, Current_Borrowers);
1397 Move_Variable_Mapping (Saved_Observers, Current_Observers);
1398
1399 Inside_Elaboration := Save_In_Elab;
1400 end Check_Callable_Body;
1401
1402 -----------------------
1403 -- Check_Declaration --
1404 -----------------------
1405
1406 procedure Check_Declaration (Decl : Node_Id) is
1407 Target : constant Entity_Id := Defining_Identifier (Decl);
1408 Target_Typ : constant Node_Id := Etype (Target);
1409 Expr : Node_Id;
1410
1411 begin
1412 case N_Declaration'(Nkind (Decl)) is
1413 when N_Full_Type_Declaration =>
1414 Check_Type (Target);
1415
1416 -- ??? What about component declarations with defaults.
1417
1418 when N_Subtype_Declaration =>
1419 Check_Expression (Subtype_Indication (Decl), Read);
1420
1421 when N_Object_Declaration =>
1422 Expr := Expression (Decl);
1423
1424 Check_Type (Target_Typ);
1425
1426 -- A declaration of a stand-alone object of an anonymous access
1427 -- type shall have an explicit initial value and shall occur
1428 -- immediately within a subprogram body, an entry body, or a
1429 -- block statement (SPARK RM 3.10(4)).
1430
1431 if Is_Anonymous_Access_Type (Target_Typ) then
1432 declare
1433 Scop : constant Entity_Id := Scope (Target);
1434 begin
1435 if not Is_Local_Context (Scop) then
1436 if Emit_Messages then
1437 Error_Msg_N
1438 ("object of anonymous access type must be declared "
1439 & "immediately within a subprogram, entry or block "
1440 & "(SPARK RM 3.10(4))", Decl);
1441 end if;
1442 end if;
1443 end;
1444
1445 if No (Expr) then
1446 if Emit_Messages then
1447 Error_Msg_N ("object of anonymous access type must be "
1448 & "initialized (SPARK RM 3.10(4))", Decl);
1449 end if;
1450 end if;
1451 end if;
1452
1453 if Present (Expr) then
1454 Check_Assignment (Target => Target,
1455 Expr => Expr);
1456 end if;
1457
1458 if Is_Deep (Target_Typ) then
1459 declare
1460 Tree : constant Perm_Tree_Access :=
1461 new Perm_Tree_Wrapper'
1462 (Tree =>
1463 (Kind => Entire_Object,
1464 Is_Node_Deep => True,
1465 Explanation => Decl,
1466 Permission => Read_Write,
1467 Children_Permission => Read_Write));
1468 begin
1469 Set (Current_Perm_Env, Target, Tree);
1470 end;
1471 end if;
1472
1473 when N_Iterator_Specification =>
1474 null;
1475
1476 when N_Loop_Parameter_Specification =>
1477 null;
1478
1479 -- Checking should not be called directly on these nodes
1480
1481 when N_Function_Specification
1482 | N_Entry_Declaration
1483 | N_Procedure_Specification
1484 | N_Component_Declaration
1485 =>
1486 raise Program_Error;
1487
1488 -- Ignored constructs for pointer checking
1489
1490 when N_Formal_Object_Declaration
1491 | N_Formal_Type_Declaration
1492 | N_Incomplete_Type_Declaration
1493 | N_Private_Extension_Declaration
1494 | N_Private_Type_Declaration
1495 | N_Protected_Type_Declaration
1496 =>
1497 null;
1498
1499 -- The following nodes are rewritten by semantic analysis
1500
1501 when N_Expression_Function =>
1502 raise Program_Error;
1503 end case;
1504 end Check_Declaration;
1505
1506 ----------------------
1507 -- Check_Expression --
1508 ----------------------
1509
1510 procedure Check_Expression
1511 (Expr : Node_Id;
1512 Mode : Extended_Checking_Mode)
1513 is
1514 -- Local subprograms
1515
1516 function Is_Type_Name (Expr : Node_Id) return Boolean;
1517 -- Detect when a path expression is in fact a type name
1518
1519 procedure Move_Expression (Expr : Node_Id);
1520 -- Some subexpressions are only analyzed in Move mode. This is a
1521 -- specialized version of Check_Expression for that case.
1522
1523 procedure Move_Expression_List (L : List_Id);
1524 -- Call Move_Expression on every expression in the list L
1525
1526 procedure Read_Expression (Expr : Node_Id);
1527 -- Most subexpressions are only analyzed in Read mode. This is a
1528 -- specialized version of Check_Expression for that case.
1529
1530 procedure Read_Expression_List (L : List_Id);
1531 -- Call Read_Expression on every expression in the list L
1532
1533 procedure Read_Indexes (Expr : Node_Id);
1534 -- When processing a path, the index expressions and function call
1535 -- arguments occurring on the path should be analyzed in Read mode.
1536
1537 ------------------
1538 -- Is_Type_Name --
1539 ------------------
1540
1541 function Is_Type_Name (Expr : Node_Id) return Boolean is
1542 begin
1543 return Nkind_In (Expr, N_Expanded_Name, N_Identifier)
1544 and then Is_Type (Entity (Expr));
1545 end Is_Type_Name;
1546
1547 ---------------------
1548 -- Move_Expression --
1549 ---------------------
1550
1551 -- Distinguish the case where the argument is a path expression that
1552 -- needs explicit moving.
1553
1554 procedure Move_Expression (Expr : Node_Id) is
1555 begin
1556 if Is_Path_Expression (Expr) then
1557 Check_Expression (Expr, Move);
1558 else
1559 Read_Expression (Expr);
1560 end if;
1561 end Move_Expression;
1562
1563 --------------------------
1564 -- Move_Expression_List --
1565 --------------------------
1566
1567 procedure Move_Expression_List (L : List_Id) is
1568 N : Node_Id;
1569 begin
1570 N := First (L);
1571 while Present (N) loop
1572 Move_Expression (N);
1573 Next (N);
1574 end loop;
1575 end Move_Expression_List;
1576
1577 ---------------------
1578 -- Read_Expression --
1579 ---------------------
1580
1581 procedure Read_Expression (Expr : Node_Id) is
1582 begin
1583 Check_Expression (Expr, Read);
1584 end Read_Expression;
1585
1586 --------------------------
1587 -- Read_Expression_List --
1588 --------------------------
1589
1590 procedure Read_Expression_List (L : List_Id) is
1591 N : Node_Id;
1592 begin
1593 N := First (L);
1594 while Present (N) loop
1595 Read_Expression (N);
1596 Next (N);
1597 end loop;
1598 end Read_Expression_List;
1599
1600 ------------------
1601 -- Read_Indexes --
1602 ------------------
1603
1604 procedure Read_Indexes (Expr : Node_Id) is
1605
1606 -- Local subprograms
1607
1608 function Is_Singleton_Choice (Choices : List_Id) return Boolean;
1609 -- Return whether Choices is a singleton choice
1610
1611 procedure Read_Param (Formal : Entity_Id; Actual : Node_Id);
1612 -- Call Read_Expression on the actual
1613
1614 -------------------------
1615 -- Is_Singleton_Choice --
1616 -------------------------
1617
1618 function Is_Singleton_Choice (Choices : List_Id) return Boolean is
1619 Choice : constant Node_Id := First (Choices);
1620 begin
1621 return List_Length (Choices) = 1
1622 and then Nkind (Choice) /= N_Others_Choice
1623 and then not Nkind_In (Choice, N_Subtype_Indication, N_Range)
1624 and then not
1625 (Nkind_In (Choice, N_Identifier, N_Expanded_Name)
1626 and then Is_Type (Entity (Choice)));
1627 end Is_Singleton_Choice;
1628
1629 ----------------
1630 -- Read_Param --
1631 ----------------
1632
1633 procedure Read_Param (Formal : Entity_Id; Actual : Node_Id) is
1634 pragma Unreferenced (Formal);
1635 begin
1636 Read_Expression (Actual);
1637 end Read_Param;
1638
1639 procedure Read_Params is new Iterate_Call_Parameters (Read_Param);
1640
1641 -- Start of processing for Read_Indexes
1642
1643 begin
1644 if not Is_Subpath_Expression (Expr) then
1645 if Emit_Messages then
1646 Error_Msg_N
1647 ("name expected here for move/borrow/observe", Expr);
1648 end if;
1649 return;
1650 end if;
1651
1652 case N_Subexpr'(Nkind (Expr)) is
1653 when N_Identifier
1654 | N_Expanded_Name
1655 | N_Null
1656 =>
1657 null;
1658
1659 when N_Explicit_Dereference
1660 | N_Selected_Component
1661 =>
1662 Read_Indexes (Prefix (Expr));
1663
1664 when N_Indexed_Component =>
1665 Read_Indexes (Prefix (Expr));
1666 Read_Expression_List (Expressions (Expr));
1667
1668 when N_Slice =>
1669 Read_Indexes (Prefix (Expr));
1670 Read_Expression (Discrete_Range (Expr));
1671
1672 -- The argument of an allocator is moved as part of the implicit
1673 -- assignment.
1674
1675 when N_Allocator =>
1676 Move_Expression (Expression (Expr));
1677
1678 when N_Function_Call =>
1679 Read_Params (Expr);
1680 if Ekind (Get_Called_Entity (Expr)) = E_Subprogram_Type then
1681 if Emit_Messages then
1682 Error_Msg_N
1683 ("call through access to subprogram is not allowed in "
1684 & "SPARK", Expr);
1685 end if;
1686 else
1687 Check_Globals (Get_Called_Entity (Expr));
1688 end if;
1689
1690 when N_Op_Concat =>
1691 Read_Expression (Left_Opnd (Expr));
1692 Read_Expression (Right_Opnd (Expr));
1693
1694 when N_Qualified_Expression
1695 | N_Type_Conversion
1696 | N_Unchecked_Type_Conversion
1697 =>
1698 Read_Indexes (Expression (Expr));
1699
1700 when N_Aggregate =>
1701 declare
1702 Assocs : constant List_Id := Component_Associations (Expr);
1703 CL : List_Id;
1704 Assoc : Node_Id := Nlists.First (Assocs);
1705 Choice : Node_Id;
1706
1707 begin
1708 -- The subexpressions of an aggregate are moved as part
1709 -- of the implicit assignments. Handle the positional
1710 -- components first.
1711
1712 Move_Expression_List (Expressions (Expr));
1713
1714 -- Handle the named components next
1715
1716 while Present (Assoc) loop
1717 CL := Choices (Assoc);
1718
1719 -- For an array aggregate, we should also check that the
1720 -- expressions used in choices are readable.
1721
1722 if Is_Array_Type (Etype (Expr)) then
1723 Choice := Nlists.First (CL);
1724 while Present (Choice) loop
1725 if Nkind (Choice) /= N_Others_Choice then
1726 Read_Expression (Choice);
1727 end if;
1728 Next (Choice);
1729 end loop;
1730 end if;
1731
1732 -- There can be only one element for a value of deep type
1733 -- in order to avoid aliasing.
1734
1735 if not Box_Present (Assoc)
1736 and then Is_Deep (Etype (Expression (Assoc)))
1737 and then not Is_Singleton_Choice (CL)
1738 and then Emit_Messages
1739 then
1740 Error_Msg_F
1741 ("singleton choice required to prevent aliasing",
1742 First (CL));
1743 end if;
1744
1745 -- The subexpressions of an aggregate are moved as part
1746 -- of the implicit assignments.
1747
1748 if not Box_Present (Assoc) then
1749 Move_Expression (Expression (Assoc));
1750 end if;
1751
1752 Next (Assoc);
1753 end loop;
1754 end;
1755
1756 when N_Extension_Aggregate =>
1757 declare
1758 Exprs : constant List_Id := Expressions (Expr);
1759 Assocs : constant List_Id := Component_Associations (Expr);
1760 CL : List_Id;
1761 Assoc : Node_Id := Nlists.First (Assocs);
1762
1763 begin
1764 Move_Expression (Ancestor_Part (Expr));
1765
1766 -- No positional components allowed at this stage
1767
1768 if Present (Exprs) then
1769 raise Program_Error;
1770 end if;
1771
1772 while Present (Assoc) loop
1773 CL := Choices (Assoc);
1774
1775 -- Only singleton components allowed at this stage
1776
1777 if not Is_Singleton_Choice (CL) then
1778 raise Program_Error;
1779 end if;
1780
1781 -- The subexpressions of an aggregate are moved as part
1782 -- of the implicit assignments.
1783
1784 if not Box_Present (Assoc) then
1785 Move_Expression (Expression (Assoc));
1786 end if;
1787
1788 Next (Assoc);
1789 end loop;
1790 end;
1791
1792 when N_If_Expression =>
1793 declare
1794 Cond : constant Node_Id := First (Expressions (Expr));
1795 Then_Part : constant Node_Id := Next (Cond);
1796 Else_Part : constant Node_Id := Next (Then_Part);
1797 begin
1798 Read_Expression (Cond);
1799 Read_Indexes (Then_Part);
1800 Read_Indexes (Else_Part);
1801 end;
1802
1803 when N_Case_Expression =>
1804 declare
1805 Cases : constant List_Id := Alternatives (Expr);
1806 Cur_Case : Node_Id := First (Cases);
1807
1808 begin
1809 Read_Expression (Expression (Expr));
1810
1811 while Present (Cur_Case) loop
1812 Read_Indexes (Expression (Cur_Case));
1813 Next (Cur_Case);
1814 end loop;
1815 end;
1816
1817 when N_Attribute_Reference =>
1818 pragma Assert
1819 (Get_Attribute_Id (Attribute_Name (Expr)) =
1820 Attribute_Loop_Entry
1821 or else
1822 Get_Attribute_Id (Attribute_Name (Expr)) = Attribute_Update
1823 or else
1824 Get_Attribute_Id (Attribute_Name (Expr)) = Attribute_Image);
1825
1826 Read_Expression (Prefix (Expr));
1827
1828 if Get_Attribute_Id (Attribute_Name (Expr)) = Attribute_Update
1829 or else (Get_Attribute_Id (Attribute_Name (Expr)) =
1830 Attribute_Image
1831 and then Is_Type_Name (Prefix (Expr)))
1832 then
1833 Read_Expression_List (Expressions (Expr));
1834 end if;
1835
1836 when others =>
1837 raise Program_Error;
1838 end case;
1839 end Read_Indexes;
1840
1841 -- Start of processing for Check_Expression
1842
1843 begin
1844 if Is_Type_Name (Expr) then
1845 return;
1846
1847 elsif Is_Path_Expression (Expr) then
1848 if Mode /= Assign then
1849 Read_Indexes (Expr);
1850 end if;
1851
1852 if Mode /= Read_Subexpr then
1853 Process_Path (Expr, Mode);
1854 end if;
1855
1856 return;
1857 end if;
1858
1859 -- Expressions that are not path expressions should only be analyzed in
1860 -- Read mode.
1861
1862 if Mode /= Read then
1863 if Emit_Messages then
1864 Error_Msg_N ("name expected here for move/borrow/observe", Expr);
1865 end if;
1866 return;
1867 end if;
1868
1869 -- Special handling for nodes that may contain evaluated expressions in
1870 -- the form of constraints.
1871
1872 case Nkind (Expr) is
1873 when N_Index_Or_Discriminant_Constraint =>
1874 declare
1875 Assn : Node_Id := First (Constraints (Expr));
1876 begin
1877 while Present (Assn) loop
1878 case Nkind (Assn) is
1879 when N_Discriminant_Association =>
1880 Read_Expression (Expression (Assn));
1881
1882 when others =>
1883 Read_Expression (Assn);
1884 end case;
1885
1886 Next (Assn);
1887 end loop;
1888 end;
1889 return;
1890
1891 when N_Range_Constraint =>
1892 Read_Expression (Range_Expression (Expr));
1893 return;
1894
1895 when N_Subtype_Indication =>
1896 if Present (Constraint (Expr)) then
1897 Read_Expression (Constraint (Expr));
1898 end if;
1899 return;
1900
1901 when N_Digits_Constraint =>
1902 Read_Expression (Digits_Expression (Expr));
1903 if Present (Range_Constraint (Expr)) then
1904 Read_Expression (Range_Constraint (Expr));
1905 end if;
1906 return;
1907
1908 when N_Delta_Constraint =>
1909 Read_Expression (Delta_Expression (Expr));
1910 if Present (Range_Constraint (Expr)) then
1911 Read_Expression (Range_Constraint (Expr));
1912 end if;
1913 return;
1914
1915 when others =>
1916 null;
1917 end case;
1918
1919 -- At this point Expr can only be a subexpression
1920
1921 case N_Subexpr'(Nkind (Expr)) is
1922
1923 when N_Binary_Op
1924 | N_Short_Circuit
1925 =>
1926 Read_Expression (Left_Opnd (Expr));
1927 Read_Expression (Right_Opnd (Expr));
1928
1929 when N_Membership_Test =>
1930 Read_Expression (Left_Opnd (Expr));
1931 if Present (Right_Opnd (Expr)) then
1932 Read_Expression (Right_Opnd (Expr));
1933 else
1934 declare
1935 Cases : constant List_Id := Alternatives (Expr);
1936 Cur_Case : Node_Id := First (Cases);
1937
1938 begin
1939 while Present (Cur_Case) loop
1940 Read_Expression (Cur_Case);
1941 Next (Cur_Case);
1942 end loop;
1943 end;
1944 end if;
1945
1946 when N_Unary_Op =>
1947 Read_Expression (Right_Opnd (Expr));
1948
1949 when N_Attribute_Reference =>
1950 declare
1951 Aname : constant Name_Id := Attribute_Name (Expr);
1952 Attr_Id : constant Attribute_Id := Get_Attribute_Id (Aname);
1953 Pref : constant Node_Id := Prefix (Expr);
1954 Args : constant List_Id := Expressions (Expr);
1955
1956 begin
1957 case Attr_Id is
1958
1959 -- The following attributes take either no arguments, or
1960 -- arguments that do not refer to evaluated expressions
1961 -- (like Length or Loop_Entry), hence only the prefix
1962 -- needs to be read.
1963
1964 when Attribute_Address
1965 | Attribute_Alignment
1966 | Attribute_Callable
1967 | Attribute_Component_Size
1968 | Attribute_Constrained
1969 | Attribute_First
1970 | Attribute_First_Bit
1971 | Attribute_Last
1972 | Attribute_Last_Bit
1973 | Attribute_Length
1974 | Attribute_Loop_Entry
1975 | Attribute_Object_Size
1976 | Attribute_Position
1977 | Attribute_Size
1978 | Attribute_Terminated
1979 | Attribute_Valid
1980 | Attribute_Value_Size
1981 =>
1982 Read_Expression (Pref);
1983
1984 -- The following attributes take a type name as prefix,
1985 -- hence only the arguments need to be read.
1986
1987 when Attribute_Ceiling
1988 | Attribute_Floor
1989 | Attribute_Max
1990 | Attribute_Min
1991 | Attribute_Mod
1992 | Attribute_Pos
1993 | Attribute_Pred
1994 | Attribute_Remainder
1995 | Attribute_Rounding
1996 | Attribute_Succ
1997 | Attribute_Truncation
1998 | Attribute_Val
1999 | Attribute_Value
2000 =>
2001 Read_Expression_List (Args);
2002
2003 -- Attributes Image and Img either take a type name as
2004 -- prefix with an expression in argument, or the expression
2005 -- directly as prefix. Adapt to each case.
2006
2007 when Attribute_Image
2008 | Attribute_Img
2009 =>
2010 if No (Args) then
2011 Read_Expression (Pref);
2012 else
2013 Read_Expression_List (Args);
2014 end if;
2015
2016 -- Attribute Update takes expressions as both prefix and
2017 -- arguments, so both need to be read.
2018
2019 when Attribute_Update =>
2020 Read_Expression (Pref);
2021 Read_Expression_List (Args);
2022
2023 -- Attribute Modulus does not reference the evaluated
2024 -- expression, so it can be ignored for this analysis.
2025
2026 when Attribute_Modulus =>
2027 null;
2028
2029 -- The following attributes apply to types; there are no
2030 -- expressions to read.
2031
2032 when Attribute_Class
2033 | Attribute_Storage_Size
2034 =>
2035 null;
2036
2037 -- Postconditions should not be analyzed
2038
2039 when Attribute_Old
2040 | Attribute_Result
2041 =>
2042 raise Program_Error;
2043
2044 when others =>
2045 null;
2046 end case;
2047 end;
2048
2049 when N_Range =>
2050 Read_Expression (Low_Bound (Expr));
2051 Read_Expression (High_Bound (Expr));
2052
2053 when N_If_Expression =>
2054 Read_Expression_List (Expressions (Expr));
2055
2056 when N_Case_Expression =>
2057 declare
2058 Cases : constant List_Id := Alternatives (Expr);
2059 Cur_Case : Node_Id := First (Cases);
2060
2061 begin
2062 while Present (Cur_Case) loop
2063 Read_Expression (Expression (Cur_Case));
2064 Next (Cur_Case);
2065 end loop;
2066
2067 Read_Expression (Expression (Expr));
2068 end;
2069
2070 when N_Qualified_Expression
2071 | N_Type_Conversion
2072 | N_Unchecked_Type_Conversion
2073 =>
2074 Read_Expression (Expression (Expr));
2075
2076 when N_Quantified_Expression =>
2077 declare
2078 For_In_Spec : constant Node_Id :=
2079 Loop_Parameter_Specification (Expr);
2080 For_Of_Spec : constant Node_Id :=
2081 Iterator_Specification (Expr);
2082 For_Of_Spec_Typ : Node_Id;
2083
2084 begin
2085 if Present (For_In_Spec) then
2086 Read_Expression (Discrete_Subtype_Definition (For_In_Spec));
2087 else
2088 Read_Expression (Name (For_Of_Spec));
2089 For_Of_Spec_Typ := Subtype_Indication (For_Of_Spec);
2090 if Present (For_Of_Spec_Typ) then
2091 Read_Expression (For_Of_Spec_Typ);
2092 end if;
2093 end if;
2094
2095 Read_Expression (Condition (Expr));
2096 end;
2097
2098 when N_Character_Literal
2099 | N_Numeric_Or_String_Literal
2100 | N_Operator_Symbol
2101 | N_Raise_Expression
2102 | N_Raise_xxx_Error
2103 =>
2104 null;
2105
2106 when N_Delta_Aggregate
2107 | N_Target_Name
2108 =>
2109 null;
2110
2111 -- Procedure calls are handled in Check_Node
2112
2113 when N_Procedure_Call_Statement =>
2114 raise Program_Error;
2115
2116 -- Path expressions are handled before this point
2117
2118 when N_Aggregate
2119 | N_Allocator
2120 | N_Expanded_Name
2121 | N_Explicit_Dereference
2122 | N_Extension_Aggregate
2123 | N_Function_Call
2124 | N_Identifier
2125 | N_Indexed_Component
2126 | N_Null
2127 | N_Selected_Component
2128 | N_Slice
2129 =>
2130 raise Program_Error;
2131
2132 -- The following nodes are never generated in GNATprove mode
2133
2134 when N_Expression_With_Actions
2135 | N_Reference
2136 | N_Unchecked_Expression
2137 =>
2138 raise Program_Error;
2139 end case;
2140 end Check_Expression;
2141
2142 ----------------
2143 -- Check_List --
2144 ----------------
2145
2146 procedure Check_List (L : List_Id) is
2147 N : Node_Id;
2148 begin
2149 N := First (L);
2150 while Present (N) loop
2151 Check_Node (N);
2152 Next (N);
2153 end loop;
2154 end Check_List;
2155
2156 --------------------------
2157 -- Check_Loop_Statement --
2158 --------------------------
2159
2160 procedure Check_Loop_Statement (Stmt : Node_Id) is
2161
2162 -- Local Subprograms
2163
2164 procedure Check_Is_Less_Restrictive_Env
2165 (Exiting_Env : Perm_Env;
2166 Entry_Env : Perm_Env);
2167 -- This procedure checks that the Exiting_Env environment is less
2168 -- restrictive than the Entry_Env environment.
2169
2170 procedure Check_Is_Less_Restrictive_Tree
2171 (New_Tree : Perm_Tree_Access;
2172 Orig_Tree : Perm_Tree_Access;
2173 E : Entity_Id);
2174 -- Auxiliary procedure to check that the tree New_Tree is less
2175 -- restrictive than the tree Orig_Tree for the entity E.
2176
2177 procedure Perm_Error_Loop_Exit
2178 (E : Entity_Id;
2179 Loop_Id : Node_Id;
2180 Perm : Perm_Kind;
2181 Found_Perm : Perm_Kind;
2182 Expl : Node_Id);
2183 -- A procedure that is called when the permissions found contradict
2184 -- the rules established by the RM at the exit of loops. This function
2185 -- is called with the entity, the node of the enclosing loop, the
2186 -- permission that was expected, and the permission found, and issues
2187 -- an appropriate error message.
2188
2189 -----------------------------------
2190 -- Check_Is_Less_Restrictive_Env --
2191 -----------------------------------
2192
2193 procedure Check_Is_Less_Restrictive_Env
2194 (Exiting_Env : Perm_Env;
2195 Entry_Env : Perm_Env)
2196 is
2197 Comp_Entry : Perm_Tree_Maps.Key_Option;
2198 Iter_Entry, Iter_Exit : Perm_Tree_Access;
2199
2200 begin
2201 Comp_Entry := Get_First_Key (Entry_Env);
2202 while Comp_Entry.Present loop
2203 Iter_Entry := Get (Entry_Env, Comp_Entry.K);
2204 pragma Assert (Iter_Entry /= null);
2205 Iter_Exit := Get (Exiting_Env, Comp_Entry.K);
2206 pragma Assert (Iter_Exit /= null);
2207 Check_Is_Less_Restrictive_Tree
2208 (New_Tree => Iter_Exit,
2209 Orig_Tree => Iter_Entry,
2210 E => Comp_Entry.K);
2211 Comp_Entry := Get_Next_Key (Entry_Env);
2212 end loop;
2213 end Check_Is_Less_Restrictive_Env;
2214
2215 ------------------------------------
2216 -- Check_Is_Less_Restrictive_Tree --
2217 ------------------------------------
2218
2219 procedure Check_Is_Less_Restrictive_Tree
2220 (New_Tree : Perm_Tree_Access;
2221 Orig_Tree : Perm_Tree_Access;
2222 E : Entity_Id)
2223 is
2224 -- Local subprograms
2225
2226 procedure Check_Is_Less_Restrictive_Tree_Than
2227 (Tree : Perm_Tree_Access;
2228 Perm : Perm_Kind;
2229 E : Entity_Id);
2230 -- Auxiliary procedure to check that the tree N is less restrictive
2231 -- than the given permission P.
2232
2233 procedure Check_Is_More_Restrictive_Tree_Than
2234 (Tree : Perm_Tree_Access;
2235 Perm : Perm_Kind;
2236 E : Entity_Id);
2237 -- Auxiliary procedure to check that the tree N is more restrictive
2238 -- than the given permission P.
2239
2240 -----------------------------------------
2241 -- Check_Is_Less_Restrictive_Tree_Than --
2242 -----------------------------------------
2243
2244 procedure Check_Is_Less_Restrictive_Tree_Than
2245 (Tree : Perm_Tree_Access;
2246 Perm : Perm_Kind;
2247 E : Entity_Id)
2248 is
2249 begin
2250 if not (Permission (Tree) >= Perm) then
2251 Perm_Error_Loop_Exit
2252 (E, Stmt, Permission (Tree), Perm, Explanation (Tree));
2253 end if;
2254
2255 case Kind (Tree) is
2256 when Entire_Object =>
2257 if not (Children_Permission (Tree) >= Perm) then
2258 Perm_Error_Loop_Exit
2259 (E, Stmt, Children_Permission (Tree), Perm,
2260 Explanation (Tree));
2261
2262 end if;
2263
2264 when Reference =>
2265 Check_Is_Less_Restrictive_Tree_Than
2266 (Get_All (Tree), Perm, E);
2267
2268 when Array_Component =>
2269 Check_Is_Less_Restrictive_Tree_Than
2270 (Get_Elem (Tree), Perm, E);
2271
2272 when Record_Component =>
2273 declare
2274 Comp : Perm_Tree_Access;
2275 begin
2276 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
2277 while Comp /= null loop
2278 Check_Is_Less_Restrictive_Tree_Than (Comp, Perm, E);
2279 Comp :=
2280 Perm_Tree_Maps.Get_Next (Component (Tree));
2281 end loop;
2282 end;
2283 end case;
2284 end Check_Is_Less_Restrictive_Tree_Than;
2285
2286 -----------------------------------------
2287 -- Check_Is_More_Restrictive_Tree_Than --
2288 -----------------------------------------
2289
2290 procedure Check_Is_More_Restrictive_Tree_Than
2291 (Tree : Perm_Tree_Access;
2292 Perm : Perm_Kind;
2293 E : Entity_Id)
2294 is
2295 begin
2296 if not (Perm >= Permission (Tree)) then
2297 Perm_Error_Loop_Exit
2298 (E, Stmt, Permission (Tree), Perm, Explanation (Tree));
2299 end if;
2300
2301 case Kind (Tree) is
2302 when Entire_Object =>
2303 if not (Perm >= Children_Permission (Tree)) then
2304 Perm_Error_Loop_Exit
2305 (E, Stmt, Children_Permission (Tree), Perm,
2306 Explanation (Tree));
2307 end if;
2308
2309 when Reference =>
2310 Check_Is_More_Restrictive_Tree_Than
2311 (Get_All (Tree), Perm, E);
2312
2313 when Array_Component =>
2314 Check_Is_More_Restrictive_Tree_Than
2315 (Get_Elem (Tree), Perm, E);
2316
2317 when Record_Component =>
2318 declare
2319 Comp : Perm_Tree_Access;
2320 begin
2321 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
2322 while Comp /= null loop
2323 Check_Is_More_Restrictive_Tree_Than (Comp, Perm, E);
2324 Comp :=
2325 Perm_Tree_Maps.Get_Next (Component (Tree));
2326 end loop;
2327 end;
2328 end case;
2329 end Check_Is_More_Restrictive_Tree_Than;
2330
2331 -- Start of processing for Check_Is_Less_Restrictive_Tree
2332
2333 begin
2334 if not (Permission (New_Tree) <= Permission (Orig_Tree)) then
2335 Perm_Error_Loop_Exit
2336 (E => E,
2337 Loop_Id => Stmt,
2338 Perm => Permission (New_Tree),
2339 Found_Perm => Permission (Orig_Tree),
2340 Expl => Explanation (New_Tree));
2341 end if;
2342
2343 case Kind (New_Tree) is
2344
2345 -- Potentially folded tree. We check the other tree Orig_Tree to
2346 -- check whether it is folded or not. If folded we just compare
2347 -- their Permission and Children_Permission, if not, then we
2348 -- look at the Children_Permission of the folded tree against
2349 -- the unfolded tree Orig_Tree.
2350
2351 when Entire_Object =>
2352 case Kind (Orig_Tree) is
2353 when Entire_Object =>
2354 if not (Children_Permission (New_Tree) <=
2355 Children_Permission (Orig_Tree))
2356 then
2357 Perm_Error_Loop_Exit
2358 (E, Stmt,
2359 Children_Permission (New_Tree),
2360 Children_Permission (Orig_Tree),
2361 Explanation (New_Tree));
2362 end if;
2363
2364 when Reference =>
2365 Check_Is_More_Restrictive_Tree_Than
2366 (Get_All (Orig_Tree), Children_Permission (New_Tree), E);
2367
2368 when Array_Component =>
2369 Check_Is_More_Restrictive_Tree_Than
2370 (Get_Elem (Orig_Tree), Children_Permission (New_Tree), E);
2371
2372 when Record_Component =>
2373 declare
2374 Comp : Perm_Tree_Access;
2375 begin
2376 Comp := Perm_Tree_Maps.Get_First
2377 (Component (Orig_Tree));
2378 while Comp /= null loop
2379 Check_Is_More_Restrictive_Tree_Than
2380 (Comp, Children_Permission (New_Tree), E);
2381 Comp := Perm_Tree_Maps.Get_Next
2382 (Component (Orig_Tree));
2383 end loop;
2384 end;
2385 end case;
2386
2387 when Reference =>
2388 case Kind (Orig_Tree) is
2389 when Entire_Object =>
2390 Check_Is_Less_Restrictive_Tree_Than
2391 (Get_All (New_Tree), Children_Permission (Orig_Tree), E);
2392
2393 when Reference =>
2394 Check_Is_Less_Restrictive_Tree
2395 (Get_All (New_Tree), Get_All (Orig_Tree), E);
2396
2397 when others =>
2398 raise Program_Error;
2399 end case;
2400
2401 when Array_Component =>
2402 case Kind (Orig_Tree) is
2403 when Entire_Object =>
2404 Check_Is_Less_Restrictive_Tree_Than
2405 (Get_Elem (New_Tree), Children_Permission (Orig_Tree), E);
2406
2407 when Array_Component =>
2408 Check_Is_Less_Restrictive_Tree
2409 (Get_Elem (New_Tree), Get_Elem (Orig_Tree), E);
2410
2411 when others =>
2412 raise Program_Error;
2413 end case;
2414
2415 when Record_Component =>
2416 declare
2417 CompN : Perm_Tree_Access;
2418 begin
2419 CompN :=
2420 Perm_Tree_Maps.Get_First (Component (New_Tree));
2421 case Kind (Orig_Tree) is
2422 when Entire_Object =>
2423 while CompN /= null loop
2424 Check_Is_Less_Restrictive_Tree_Than
2425 (CompN, Children_Permission (Orig_Tree), E);
2426
2427 CompN :=
2428 Perm_Tree_Maps.Get_Next (Component (New_Tree));
2429 end loop;
2430
2431 when Record_Component =>
2432 declare
2433
2434 KeyO : Perm_Tree_Maps.Key_Option;
2435 CompO : Perm_Tree_Access;
2436 begin
2437 KeyO := Perm_Tree_Maps.Get_First_Key
2438 (Component (Orig_Tree));
2439 while KeyO.Present loop
2440 CompN := Perm_Tree_Maps.Get
2441 (Component (New_Tree), KeyO.K);
2442 CompO := Perm_Tree_Maps.Get
2443 (Component (Orig_Tree), KeyO.K);
2444 pragma Assert (CompO /= null);
2445
2446 Check_Is_Less_Restrictive_Tree (CompN, CompO, E);
2447
2448 KeyO := Perm_Tree_Maps.Get_Next_Key
2449 (Component (Orig_Tree));
2450 end loop;
2451 end;
2452
2453 when others =>
2454 raise Program_Error;
2455 end case;
2456 end;
2457 end case;
2458 end Check_Is_Less_Restrictive_Tree;
2459
2460 --------------------------
2461 -- Perm_Error_Loop_Exit --
2462 --------------------------
2463
2464 procedure Perm_Error_Loop_Exit
2465 (E : Entity_Id;
2466 Loop_Id : Node_Id;
2467 Perm : Perm_Kind;
2468 Found_Perm : Perm_Kind;
2469 Expl : Node_Id)
2470 is
2471 begin
2472 if Emit_Messages then
2473 Error_Msg_Node_2 := Loop_Id;
2474 Error_Msg_N
2475 ("insufficient permission for & when exiting loop &", E);
2476 Perm_Mismatch (Exp_Perm => Perm,
2477 Act_Perm => Found_Perm,
2478 N => Loop_Id,
2479 Expl => Expl);
2480 end if;
2481 end Perm_Error_Loop_Exit;
2482
2483 -- Local variables
2484
2485 Loop_Name : constant Entity_Id := Entity (Identifier (Stmt));
2486 Loop_Env : constant Perm_Env_Access := new Perm_Env;
2487 Scheme : constant Node_Id := Iteration_Scheme (Stmt);
2488
2489 -- Start of processing for Check_Loop_Statement
2490
2491 begin
2492 -- Save environment prior to the loop
2493
2494 Copy_Env (From => Current_Perm_Env, To => Loop_Env.all);
2495
2496 -- Add saved environment to loop environment
2497
2498 Set (Current_Loops_Envs, Loop_Name, Loop_Env);
2499
2500 -- If the loop is not a plain-loop, then it may either never be entered,
2501 -- or it may be exited after a number of iterations. Hence add the
2502 -- current permission environment as the initial loop exit environment.
2503 -- Otherwise, the loop exit environment remains empty until it is
2504 -- populated by analyzing exit statements.
2505
2506 if Present (Iteration_Scheme (Stmt)) then
2507 declare
2508 Exit_Env : constant Perm_Env_Access := new Perm_Env;
2509
2510 begin
2511 Copy_Env (From => Current_Perm_Env, To => Exit_Env.all);
2512 Set (Current_Loops_Accumulators, Loop_Name, Exit_Env);
2513 end;
2514 end if;
2515
2516 -- Analyze loop
2517
2518 if Present (Scheme) then
2519
2520 -- Case of a WHILE loop
2521
2522 if Present (Condition (Scheme)) then
2523 Check_Expression (Condition (Scheme), Read);
2524
2525 -- Case of a FOR loop
2526
2527 else
2528 declare
2529 Param_Spec : constant Node_Id :=
2530 Loop_Parameter_Specification (Scheme);
2531 Iter_Spec : constant Node_Id := Iterator_Specification (Scheme);
2532 begin
2533 if Present (Param_Spec) then
2534 Check_Expression
2535 (Discrete_Subtype_Definition (Param_Spec), Read);
2536 else
2537 Check_Expression (Name (Iter_Spec), Read);
2538 if Present (Subtype_Indication (Iter_Spec)) then
2539 Check_Expression (Subtype_Indication (Iter_Spec), Read);
2540 end if;
2541 end if;
2542 end;
2543 end if;
2544 end if;
2545
2546 Check_List (Statements (Stmt));
2547
2548 -- Check that environment gets less restrictive at end of loop
2549
2550 Check_Is_Less_Restrictive_Env
2551 (Exiting_Env => Current_Perm_Env,
2552 Entry_Env => Loop_Env.all);
2553
2554 -- Set environment to the one for exiting the loop
2555
2556 declare
2557 Exit_Env : constant Perm_Env_Access :=
2558 Get (Current_Loops_Accumulators, Loop_Name);
2559 begin
2560 Free_Env (Current_Perm_Env);
2561
2562 -- In the normal case, Exit_Env is not null and we use it. In the
2563 -- degraded case of a plain-loop without exit statements, Exit_Env is
2564 -- null, and we use the initial permission environment at the start
2565 -- of the loop to continue analysis. Any environment would be fine
2566 -- here, since the code after the loop is dead code, but this way we
2567 -- avoid spurious errors by having at least variables in scope inside
2568 -- the environment.
2569
2570 if Exit_Env /= null then
2571 Copy_Env (From => Exit_Env.all, To => Current_Perm_Env);
2572 Free_Env (Loop_Env.all);
2573 Free_Env (Exit_Env.all);
2574 else
2575 Copy_Env (From => Loop_Env.all, To => Current_Perm_Env);
2576 Free_Env (Loop_Env.all);
2577 end if;
2578 end;
2579 end Check_Loop_Statement;
2580
2581 ----------------
2582 -- Check_Node --
2583 ----------------
2584
2585 procedure Check_Node (N : Node_Id) is
2586 begin
2587 case Nkind (N) is
2588 when N_Declaration =>
2589 Check_Declaration (N);
2590
2591 when N_Body_Stub =>
2592 Check_Node (Get_Body_From_Stub (N));
2593
2594 when N_Statement_Other_Than_Procedure_Call =>
2595 Check_Statement (N);
2596
2597 when N_Procedure_Call_Statement =>
2598 Check_Call_Statement (N);
2599
2600 when N_Package_Body =>
2601 if not Is_Generic_Unit (Unique_Defining_Entity (N)) then
2602 Check_Package_Body (N);
2603 end if;
2604
2605 when N_Subprogram_Body
2606 | N_Entry_Body
2607 | N_Task_Body
2608 =>
2609 if not Is_Generic_Unit (Unique_Defining_Entity (N)) then
2610 Check_Callable_Body (N);
2611 end if;
2612
2613 when N_Protected_Body =>
2614 Check_List (Declarations (N));
2615
2616 when N_Package_Declaration =>
2617 Check_Package_Spec (N);
2618
2619 when N_Handled_Sequence_Of_Statements =>
2620 Check_List (Statements (N));
2621
2622 when N_Pragma =>
2623 Check_Pragma (N);
2624
2625 -- Ignored constructs for pointer checking
2626
2627 when N_Abstract_Subprogram_Declaration
2628 | N_At_Clause
2629 | N_Attribute_Definition_Clause
2630 | N_Call_Marker
2631 | N_Delta_Constraint
2632 | N_Digits_Constraint
2633 | N_Empty
2634 | N_Enumeration_Representation_Clause
2635 | N_Exception_Declaration
2636 | N_Exception_Renaming_Declaration
2637 | N_Formal_Package_Declaration
2638 | N_Formal_Subprogram_Declaration
2639 | N_Freeze_Entity
2640 | N_Freeze_Generic_Entity
2641 | N_Function_Instantiation
2642 | N_Generic_Function_Renaming_Declaration
2643 | N_Generic_Package_Declaration
2644 | N_Generic_Package_Renaming_Declaration
2645 | N_Generic_Procedure_Renaming_Declaration
2646 | N_Generic_Subprogram_Declaration
2647 | N_Implicit_Label_Declaration
2648 | N_Itype_Reference
2649 | N_Label
2650 | N_Number_Declaration
2651 | N_Object_Renaming_Declaration
2652 | N_Others_Choice
2653 | N_Package_Instantiation
2654 | N_Package_Renaming_Declaration
2655 | N_Procedure_Instantiation
2656 | N_Raise_xxx_Error
2657 | N_Record_Representation_Clause
2658 | N_Subprogram_Declaration
2659 | N_Subprogram_Renaming_Declaration
2660 | N_Task_Type_Declaration
2661 | N_Use_Package_Clause
2662 | N_With_Clause
2663 | N_Use_Type_Clause
2664 | N_Validate_Unchecked_Conversion
2665 | N_Variable_Reference_Marker
2666 | N_Discriminant_Association
2667
2668 -- ??? check whether we should do something special for
2669 -- N_Discriminant_Association, or maybe raise Program_Error.
2670 =>
2671 null;
2672
2673 -- Checking should not be called directly on these nodes
2674
2675 when others =>
2676 raise Program_Error;
2677 end case;
2678 end Check_Node;
2679
2680 ------------------------
2681 -- Check_Package_Body --
2682 ------------------------
2683
2684 procedure Check_Package_Body (Pack : Node_Id) is
2685 Save_In_Elab : constant Boolean := Inside_Elaboration;
2686 Spec : constant Node_Id :=
2687 Package_Specification (Corresponding_Spec (Pack));
2688 Id : constant Entity_Id := Defining_Entity (Pack);
2689 Prag : constant Node_Id := SPARK_Pragma (Id);
2690 Aux_Prag : constant Node_Id := SPARK_Aux_Pragma (Id);
2691 Saved_Env : Perm_Env;
2692
2693 begin
2694 if Present (Prag)
2695 and then Get_SPARK_Mode_From_Annotation (Prag) = Opt.On
2696 then
2697 Inside_Elaboration := True;
2698
2699 -- Save environment and put a new one in place
2700
2701 Move_Env (Current_Perm_Env, Saved_Env);
2702
2703 -- Reanalyze package spec to have its variables in the environment
2704
2705 Check_List (Visible_Declarations (Spec));
2706 Check_List (Private_Declarations (Spec));
2707
2708 -- Check declarations and statements in the special mode for
2709 -- elaboration.
2710
2711 Check_List (Declarations (Pack));
2712
2713 if Present (Aux_Prag)
2714 and then Get_SPARK_Mode_From_Annotation (Aux_Prag) = Opt.On
2715 then
2716 Check_Node (Handled_Statement_Sequence (Pack));
2717 end if;
2718
2719 -- Restore the saved environment and free the current one
2720
2721 Move_Env (Saved_Env, Current_Perm_Env);
2722
2723 Inside_Elaboration := Save_In_Elab;
2724 end if;
2725 end Check_Package_Body;
2726
2727 ------------------------
2728 -- Check_Package_Spec --
2729 ------------------------
2730
2731 procedure Check_Package_Spec (Pack : Node_Id) is
2732 Save_In_Elab : constant Boolean := Inside_Elaboration;
2733 Spec : constant Node_Id := Specification (Pack);
2734 Id : constant Entity_Id := Defining_Entity (Pack);
2735 Prag : constant Node_Id := SPARK_Pragma (Id);
2736 Aux_Prag : constant Node_Id := SPARK_Aux_Pragma (Id);
2737 Saved_Env : Perm_Env;
2738
2739 begin
2740 if Present (Prag)
2741 and then Get_SPARK_Mode_From_Annotation (Prag) = Opt.On
2742 then
2743 Inside_Elaboration := True;
2744
2745 -- Save environment and put a new one in place
2746
2747 Move_Env (Current_Perm_Env, Saved_Env);
2748
2749 -- Check declarations in the special mode for elaboration
2750
2751 Check_List (Visible_Declarations (Spec));
2752
2753 if Present (Aux_Prag)
2754 and then Get_SPARK_Mode_From_Annotation (Aux_Prag) = Opt.On
2755 then
2756 Check_List (Private_Declarations (Spec));
2757 end if;
2758
2759 -- Restore the saved environment and free the current one. As part of
2760 -- the restoration, the environment of the package spec is merged in
2761 -- the enclosing environment, which may be an enclosing
2762 -- package/subprogram spec or body which has access to the variables
2763 -- of the package spec.
2764
2765 Merge_Env (Saved_Env, Current_Perm_Env);
2766
2767 Inside_Elaboration := Save_In_Elab;
2768 end if;
2769 end Check_Package_Spec;
2770
2771 -------------------------------
2772 -- Check_Parameter_Or_Global --
2773 -------------------------------
2774
2775 procedure Check_Parameter_Or_Global
2776 (Expr : Node_Id;
2777 Typ : Entity_Id;
2778 Kind : Formal_Kind;
2779 Subp : Entity_Id;
2780 Global_Var : Boolean)
2781 is
2782 Mode : Checking_Mode;
2783 Status : Error_Status;
2784
2785 begin
2786 if not Global_Var
2787 and then Is_Anonymous_Access_Type (Typ)
2788 then
2789 Check_Source_Of_Borrow_Or_Observe (Expr, Status);
2790
2791 if Status /= OK then
2792 return;
2793 end if;
2794 end if;
2795
2796 case Kind is
2797 when E_In_Parameter =>
2798
2799 -- Inputs of functions have R permission only
2800
2801 if Ekind (Subp) = E_Function then
2802 Mode := Read;
2803
2804 -- Input global variables have R permission only
2805
2806 elsif Global_Var then
2807 Mode := Read;
2808
2809 -- Anonymous access to constant is an observe
2810
2811 elsif Is_Anonymous_Access_Type (Typ)
2812 and then Is_Access_Constant (Typ)
2813 then
2814 Mode := Observe;
2815
2816 -- Other access types are a borrow
2817
2818 elsif Is_Access_Type (Typ) then
2819 Mode := Borrow;
2820
2821 -- Deep types other than access types define an observe
2822
2823 elsif Is_Deep (Typ) then
2824 Mode := Observe;
2825
2826 -- Otherwise the variable is read
2827
2828 else
2829 Mode := Read;
2830 end if;
2831
2832 when E_Out_Parameter =>
2833 Mode := Assign;
2834
2835 when E_In_Out_Parameter =>
2836 Mode := Move;
2837 end case;
2838
2839 if Mode = Assign then
2840 Check_Expression (Expr, Read_Subexpr);
2841 end if;
2842
2843 Check_Expression (Expr, Mode);
2844 end Check_Parameter_Or_Global;
2845
2846 procedure Check_Globals_Inst is
2847 new Handle_Globals (Check_Parameter_Or_Global);
2848
2849 procedure Check_Globals (Subp : Entity_Id) renames Check_Globals_Inst;
2850
2851 ------------------
2852 -- Check_Pragma --
2853 ------------------
2854
2855 procedure Check_Pragma (Prag : Node_Id) is
2856 Prag_Id : constant Pragma_Id := Get_Pragma_Id (Prag);
2857 Arg1 : constant Node_Id :=
2858 First (Pragma_Argument_Associations (Prag));
2859 Arg2 : Node_Id := Empty;
2860
2861 begin
2862 if Present (Arg1) then
2863 Arg2 := Next (Arg1);
2864 end if;
2865
2866 case Prag_Id is
2867 when Pragma_Check =>
2868 declare
2869 Expr : constant Node_Id := Expression (Arg2);
2870 begin
2871 Check_Expression (Expr, Read);
2872 end;
2873
2874 -- There is no need to check contracts, as these can only access
2875 -- inputs and outputs of the subprogram. Inputs are checked
2876 -- independently for R permission. Outputs are checked
2877 -- independently to have RW permission on exit.
2878
2879 -- Postconditions are checked for correct use of 'Old, but starting
2880 -- from the corresponding declaration, in order to avoid dealing with
2881 -- with contracts on generic subprograms, which are not handled in
2882 -- GNATprove.
2883
2884 when Pragma_Precondition
2885 | Pragma_Postcondition
2886 | Pragma_Contract_Cases
2887 | Pragma_Refined_Post
2888 =>
2889 null;
2890
2891 -- The same holds for the initial condition after package
2892 -- elaboration, for the different reason that library-level
2893 -- variables can only be left in RW state after elaboration.
2894
2895 when Pragma_Initial_Condition =>
2896 null;
2897
2898 -- These pragmas should have been rewritten and/or removed in
2899 -- GNATprove mode.
2900
2901 when Pragma_Assert
2902 | Pragma_Assert_And_Cut
2903 | Pragma_Assume
2904 | Pragma_Compile_Time_Error
2905 | Pragma_Compile_Time_Warning
2906 | Pragma_Debug
2907 | Pragma_Loop_Invariant
2908 =>
2909 raise Program_Error;
2910
2911 when others =>
2912 null;
2913 end case;
2914 end Check_Pragma;
2915
2916 -------------------------
2917 -- Check_Safe_Pointers --
2918 -------------------------
2919
2920 procedure Check_Safe_Pointers (N : Node_Id) is
2921
2922 -- Local subprograms
2923
2924 procedure Check_List (L : List_Id);
2925 -- Call the main analysis procedure on each element of the list
2926
2927 procedure Initialize;
2928 -- Initialize global variables before starting the analysis of a body
2929
2930 ----------------
2931 -- Check_List --
2932 ----------------
2933
2934 procedure Check_List (L : List_Id) is
2935 N : Node_Id;
2936 begin
2937 N := First (L);
2938 while Present (N) loop
2939 Check_Safe_Pointers (N);
2940 Next (N);
2941 end loop;
2942 end Check_List;
2943
2944 ----------------
2945 -- Initialize --
2946 ----------------
2947
2948 procedure Initialize is
2949 begin
2950 Reset (Current_Loops_Envs);
2951 Reset (Current_Loops_Accumulators);
2952 Reset (Current_Perm_Env);
2953 end Initialize;
2954
2955 -- Start of processing for Check_Safe_Pointers
2956
2957 begin
2958 Initialize;
2959
2960 case Nkind (N) is
2961 when N_Compilation_Unit =>
2962 Check_Safe_Pointers (Unit (N));
2963
2964 when N_Package_Body
2965 | N_Package_Declaration
2966 | N_Subprogram_Body
2967 =>
2968 declare
2969 E : constant Entity_Id := Defining_Entity (N);
2970 Prag : constant Node_Id := SPARK_Pragma (E);
2971 -- SPARK_Mode pragma in application
2972
2973 begin
2974 if Ekind (Unique_Entity (E)) in Generic_Unit_Kind then
2975 null;
2976
2977 elsif Present (Prag) then
2978 if Get_SPARK_Mode_From_Annotation (Prag) = Opt.On then
2979 Check_Node (N);
2980 end if;
2981
2982 elsif Nkind (N) = N_Package_Body then
2983 Check_List (Declarations (N));
2984
2985 elsif Nkind (N) = N_Package_Declaration then
2986 Check_List (Private_Declarations (Specification (N)));
2987 Check_List (Visible_Declarations (Specification (N)));
2988 end if;
2989 end;
2990
2991 when others =>
2992 null;
2993 end case;
2994 end Check_Safe_Pointers;
2995
2996 ---------------------------------------
2997 -- Check_Source_Of_Borrow_Or_Observe --
2998 ---------------------------------------
2999
3000 procedure Check_Source_Of_Borrow_Or_Observe
3001 (Expr : Node_Id;
3002 Status : out Error_Status)
3003 is
3004 Root : Entity_Id;
3005
3006 begin
3007 if Is_Path_Expression (Expr) then
3008 Root := Get_Root_Object (Expr);
3009 else
3010 Root := Empty;
3011 end if;
3012
3013 Status := OK;
3014
3015 -- SPARK RM 3.10(3): If the target of an assignment operation is an
3016 -- object of an anonymous access-to-object type (including copy-in for
3017 -- a parameter), then the source shall be a name denoting a part of a
3018 -- stand-alone object, a part of a parameter, or a call to a traversal
3019 -- function.
3020
3021 if No (Root) then
3022 if Emit_Messages then
3023 if Nkind (Expr) = N_Function_Call then
3024 Error_Msg_N
3025 ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr);
3026 Error_Msg_N
3027 ("\function called must be a traversal function", Expr);
3028 else
3029 Error_Msg_N
3030 ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr);
3031 Error_Msg_N
3032 ("\expression must be part of stand-alone object or " &
3033 "parameter",
3034 Expr);
3035 end if;
3036 end if;
3037
3038 Status := Error;
3039 end if;
3040 end Check_Source_Of_Borrow_Or_Observe;
3041
3042 ---------------------
3043 -- Check_Statement --
3044 ---------------------
3045
3046 procedure Check_Statement (Stmt : Node_Id) is
3047 begin
3048 case N_Statement_Other_Than_Procedure_Call'(Nkind (Stmt)) is
3049
3050 -- An entry call is handled like other calls
3051
3052 when N_Entry_Call_Statement =>
3053 Check_Call_Statement (Stmt);
3054
3055 -- An assignment may correspond to a move, a borrow, or an observe
3056
3057 when N_Assignment_Statement =>
3058 declare
3059 Target : constant Node_Id := Name (Stmt);
3060
3061 begin
3062 -- Start with checking that the subexpressions of the target
3063 -- path are readable, before possibly updating the permission
3064 -- of these subexpressions in Check_Assignment.
3065
3066 Check_Expression (Target, Read_Subexpr);
3067
3068 Check_Assignment (Target => Target,
3069 Expr => Expression (Stmt));
3070
3071 -- ??? We need a rule that forbids targets of assignment for
3072 -- which the path is not known, for example when there is a
3073 -- function call involved (which includes calls to traversal
3074 -- functions). Otherwise there is no way to update the
3075 -- corresponding path permission.
3076
3077 if No (Get_Root_Object
3078 (Target, Through_Traversal => False))
3079 then
3080 if Emit_Messages then
3081 Error_Msg_N ("illegal target for assignment", Target);
3082 end if;
3083 return;
3084 end if;
3085
3086 Check_Expression (Target, Assign);
3087 end;
3088
3089 when N_Block_Statement =>
3090 Check_List (Declarations (Stmt));
3091 Check_Node (Handled_Statement_Sequence (Stmt));
3092
3093 -- Remove local borrowers and observers
3094
3095 declare
3096 Decl : Node_Id := First (Declarations (Stmt));
3097 Var : Entity_Id;
3098 begin
3099 while Present (Decl) loop
3100 if Nkind (Decl) = N_Object_Declaration then
3101 Var := Defining_Identifier (Decl);
3102 Remove (Current_Borrowers, Var);
3103 Remove (Current_Observers, Var);
3104 end if;
3105
3106 Next (Decl);
3107 end loop;
3108 end;
3109
3110 when N_Case_Statement =>
3111 declare
3112 Alt : Node_Id;
3113 Saved_Env : Perm_Env;
3114 -- Copy of environment for analysis of the different cases
3115 New_Env : Perm_Env;
3116 -- Accumulator for the different cases
3117
3118 begin
3119 Check_Expression (Expression (Stmt), Read);
3120
3121 -- Save environment
3122
3123 Copy_Env (Current_Perm_Env, Saved_Env);
3124
3125 -- First alternative
3126
3127 Alt := First (Alternatives (Stmt));
3128 Check_List (Statements (Alt));
3129 Next (Alt);
3130
3131 -- Cleanup
3132
3133 Move_Env (Current_Perm_Env, New_Env);
3134
3135 -- Other alternatives
3136
3137 while Present (Alt) loop
3138
3139 -- Restore environment
3140
3141 Copy_Env (Saved_Env, Current_Perm_Env);
3142
3143 -- Next alternative
3144
3145 Check_List (Statements (Alt));
3146 Next (Alt);
3147
3148 -- Merge Current_Perm_Env into New_Env
3149
3150 Merge_Env (Source => Current_Perm_Env, Target => New_Env);
3151 end loop;
3152
3153 Move_Env (New_Env, Current_Perm_Env);
3154 Free_Env (Saved_Env);
3155 end;
3156
3157 when N_Delay_Relative_Statement
3158 | N_Delay_Until_Statement
3159 =>
3160 Check_Expression (Expression (Stmt), Read);
3161
3162 when N_Loop_Statement =>
3163 Check_Loop_Statement (Stmt);
3164
3165 when N_Simple_Return_Statement =>
3166 declare
3167 Subp : constant Entity_Id :=
3168 Return_Applies_To (Return_Statement_Entity (Stmt));
3169 Expr : constant Node_Id := Expression (Stmt);
3170 begin
3171 if Present (Expression (Stmt)) then
3172 declare
3173 Return_Typ : constant Entity_Id :=
3174 Etype (Expression (Stmt));
3175
3176 begin
3177 -- SPARK RM 3.10(5): A return statement that applies
3178 -- to a traversal function that has an anonymous
3179 -- access-to-constant (respectively, access-to-variable)
3180 -- result type, shall return either the literal null
3181 -- or an access object denoted by a direct or indirect
3182 -- observer (respectively, borrower) of the traversed
3183 -- parameter.
3184
3185 if Is_Anonymous_Access_Type (Return_Typ) then
3186 pragma Assert (Is_Traversal_Function (Subp));
3187
3188 if Nkind (Expr) /= N_Null then
3189 declare
3190 Expr_Root : constant Entity_Id :=
3191 Get_Root_Object (Expr, Is_Traversal => True);
3192 Param : constant Entity_Id :=
3193 First_Formal (Subp);
3194 begin
3195 if Param /= Expr_Root and then Emit_Messages then
3196 Error_Msg_NE
3197 ("returned value must be rooted in "
3198 & "traversed parameter & "
3199 & "(SPARK RM 3.10(5))",
3200 Stmt, Param);
3201 end if;
3202 end;
3203 end if;
3204
3205 -- Move expression to caller
3206
3207 elsif Is_Deep (Return_Typ) then
3208
3209 if Is_Path_Expression (Expr) then
3210 Check_Expression (Expr, Move);
3211
3212 else
3213 if Emit_Messages then
3214 Error_Msg_N
3215 ("expression not allowed as source of move",
3216 Expr);
3217 end if;
3218 return;
3219 end if;
3220
3221 else
3222 Check_Expression (Expr, Read);
3223 end if;
3224
3225 if Ekind_In (Subp, E_Procedure, E_Entry)
3226 and then not No_Return (Subp)
3227 then
3228 Return_Parameters (Subp);
3229 Return_Globals (Subp);
3230 end if;
3231 end;
3232 end if;
3233 end;
3234
3235 when N_Extended_Return_Statement =>
3236 declare
3237 Subp : constant Entity_Id :=
3238 Return_Applies_To (Return_Statement_Entity (Stmt));
3239 Decls : constant List_Id := Return_Object_Declarations (Stmt);
3240 Decl : constant Node_Id := Last_Non_Pragma (Decls);
3241 Obj : constant Entity_Id := Defining_Identifier (Decl);
3242 Perm : Perm_Kind;
3243
3244 begin
3245 -- SPARK RM 3.10(5): return statement of traversal function
3246
3247 if Is_Traversal_Function (Subp) and then Emit_Messages then
3248 Error_Msg_N
3249 ("extended return cannot apply to a traversal function",
3250 Stmt);
3251 end if;
3252
3253 Check_List (Return_Object_Declarations (Stmt));
3254 Check_Node (Handled_Statement_Sequence (Stmt));
3255
3256 if Is_Deep (Etype (Obj)) then
3257 Perm := Get_Perm (Obj);
3258
3259 if Perm /= Read_Write then
3260 Perm_Error (Decl, Read_Write, Perm,
3261 Expl => Get_Expl (Obj));
3262 end if;
3263 end if;
3264
3265 if Ekind_In (Subp, E_Procedure, E_Entry)
3266 and then not No_Return (Subp)
3267 then
3268 Return_Parameters (Subp);
3269 Return_Globals (Subp);
3270 end if;
3271 end;
3272
3273 -- On loop exit, merge the current permission environment with the
3274 -- accumulator for the given loop.
3275
3276 when N_Exit_Statement =>
3277 declare
3278 Loop_Name : constant Entity_Id := Loop_Of_Exit (Stmt);
3279 Saved_Accumulator : constant Perm_Env_Access :=
3280 Get (Current_Loops_Accumulators, Loop_Name);
3281 Environment_Copy : constant Perm_Env_Access :=
3282 new Perm_Env;
3283 begin
3284 Copy_Env (Current_Perm_Env, Environment_Copy.all);
3285
3286 if Saved_Accumulator = null then
3287 Set (Current_Loops_Accumulators,
3288 Loop_Name, Environment_Copy);
3289 else
3290 Merge_Env (Source => Environment_Copy.all,
3291 Target => Saved_Accumulator.all);
3292 -- ??? Either free Environment_Copy, or change the type
3293 -- of loop accumulators to directly store permission
3294 -- environments.
3295 end if;
3296 end;
3297
3298 -- On branches, analyze each branch independently on a fresh copy of
3299 -- the permission environment, then merge the resulting permission
3300 -- environments.
3301
3302 when N_If_Statement =>
3303 declare
3304 Saved_Env : Perm_Env;
3305 New_Env : Perm_Env;
3306 -- Accumulator for the different branches
3307
3308 begin
3309 Check_Expression (Condition (Stmt), Read);
3310
3311 -- Save environment
3312
3313 Copy_Env (Current_Perm_Env, Saved_Env);
3314
3315 -- THEN branch
3316
3317 Check_List (Then_Statements (Stmt));
3318 Move_Env (Current_Perm_Env, New_Env);
3319
3320 -- ELSIF branches
3321
3322 declare
3323 Branch : Node_Id;
3324 begin
3325 Branch := First (Elsif_Parts (Stmt));
3326 while Present (Branch) loop
3327
3328 -- Restore current permission environment
3329
3330 Copy_Env (Saved_Env, Current_Perm_Env);
3331 Check_Expression (Condition (Branch), Read);
3332 Check_List (Then_Statements (Branch));
3333
3334 -- Merge current permission environment
3335
3336 Merge_Env (Source => Current_Perm_Env, Target => New_Env);
3337 Next (Branch);
3338 end loop;
3339 end;
3340
3341 -- ELSE branch
3342
3343 -- Restore current permission environment
3344
3345 Copy_Env (Saved_Env, Current_Perm_Env);
3346 Check_List (Else_Statements (Stmt));
3347
3348 -- Merge current permission environment
3349
3350 Merge_Env (Source => Current_Perm_Env, Target => New_Env);
3351
3352 -- Cleanup
3353
3354 Move_Env (New_Env, Current_Perm_Env);
3355 Free_Env (Saved_Env);
3356 end;
3357
3358 -- We should ideally ignore the branch after raising an exception,
3359 -- so that it is not taken into account in merges. For now, just
3360 -- propagate the current environment.
3361
3362 when N_Raise_Statement =>
3363 null;
3364
3365 when N_Null_Statement =>
3366 null;
3367
3368 -- Unsupported constructs in SPARK
3369
3370 when N_Abort_Statement
3371 | N_Accept_Statement
3372 | N_Asynchronous_Select
3373 | N_Code_Statement
3374 | N_Conditional_Entry_Call
3375 | N_Goto_Statement
3376 | N_Requeue_Statement
3377 | N_Selective_Accept
3378 | N_Timed_Entry_Call
3379 =>
3380 null;
3381
3382 -- The following nodes are never generated in GNATprove mode
3383
3384 when N_Compound_Statement
3385 | N_Free_Statement
3386 =>
3387 raise Program_Error;
3388 end case;
3389 end Check_Statement;
3390
3391 ----------------
3392 -- Check_Type --
3393 ----------------
3394
3395 procedure Check_Type (Typ : Entity_Id) is
3396 Check_Typ : constant Entity_Id := Retysp (Typ);
3397
3398 begin
3399 case Type_Kind'(Ekind (Check_Typ)) is
3400 when Access_Kind =>
3401 case Access_Kind'(Ekind (Check_Typ)) is
3402 when E_Access_Type
3403 | E_Anonymous_Access_Type
3404 =>
3405 null;
3406 when E_Access_Subtype =>
3407 Check_Type (Base_Type (Check_Typ));
3408 when E_Access_Attribute_Type =>
3409 if Emit_Messages then
3410 Error_Msg_N ("access attribute not allowed in SPARK",
3411 Check_Typ);
3412 end if;
3413 when E_Allocator_Type =>
3414 if Emit_Messages then
3415 Error_Msg_N ("missing type resolution", Check_Typ);
3416 end if;
3417 when E_General_Access_Type =>
3418 if Emit_Messages then
3419 Error_Msg_NE
3420 ("general access type & not allowed in SPARK",
3421 Check_Typ, Check_Typ);
3422 end if;
3423 when Access_Subprogram_Kind =>
3424 if Emit_Messages then
3425 Error_Msg_NE
3426 ("access to subprogram type & not allowed in SPARK",
3427 Check_Typ, Check_Typ);
3428 end if;
3429 end case;
3430
3431 when E_Array_Type
3432 | E_Array_Subtype
3433 =>
3434 Check_Type (Component_Type (Check_Typ));
3435
3436 when Record_Kind =>
3437 if Is_Deep (Check_Typ)
3438 and then (Is_Tagged_Type (Check_Typ)
3439 or else Is_Class_Wide_Type (Check_Typ))
3440 then
3441 if Emit_Messages then
3442 Error_Msg_NE
3443 ("tagged type & cannot be owning in SPARK",
3444 Check_Typ, Check_Typ);
3445 end if;
3446
3447 else
3448 declare
3449 Comp : Entity_Id;
3450 begin
3451 Comp := First_Component_Or_Discriminant (Check_Typ);
3452 while Present (Comp) loop
3453
3454 -- Ignore components which are not visible in SPARK
3455
3456 if Component_Is_Visible_In_SPARK (Comp) then
3457 Check_Type (Etype (Comp));
3458 end if;
3459 Next_Component_Or_Discriminant (Comp);
3460 end loop;
3461 end;
3462 end if;
3463
3464 when Scalar_Kind
3465 | E_String_Literal_Subtype
3466 | Protected_Kind
3467 | Task_Kind
3468 | Incomplete_Kind
3469 | E_Exception_Type
3470 | E_Subprogram_Type
3471 =>
3472 null;
3473
3474 -- Do not check type whose full view is not SPARK
3475
3476 when E_Private_Type
3477 | E_Private_Subtype
3478 | E_Limited_Private_Type
3479 | E_Limited_Private_Subtype
3480 =>
3481 null;
3482 end case;
3483 end Check_Type;
3484
3485 --------------
3486 -- Get_Expl --
3487 --------------
3488
3489 function Get_Expl (N : Node_Or_Entity_Id) return Node_Id is
3490 begin
3491 -- Special case for the object declared in an extended return statement
3492
3493 if Nkind (N) = N_Defining_Identifier then
3494 declare
3495 C : constant Perm_Tree_Access :=
3496 Get (Current_Perm_Env, Unique_Entity (N));
3497 begin
3498 pragma Assert (C /= null);
3499 return Explanation (C);
3500 end;
3501
3502 -- The expression is a call to a traversal function
3503
3504 elsif Is_Traversal_Function_Call (N) then
3505 return N;
3506
3507 -- The expression is directly rooted in an object
3508
3509 elsif Present (Get_Root_Object (N, Through_Traversal => False)) then
3510 declare
3511 Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N);
3512 begin
3513 case Tree_Or_Perm.R is
3514 when Folded =>
3515 return Tree_Or_Perm.Explanation;
3516
3517 when Unfolded =>
3518 pragma Assert (Tree_Or_Perm.Tree_Access /= null);
3519 return Explanation (Tree_Or_Perm.Tree_Access);
3520 end case;
3521 end;
3522
3523 -- The expression is a function call, an allocation, or null
3524
3525 else
3526 return N;
3527 end if;
3528 end Get_Expl;
3529
3530 -----------------------------------
3531 -- Get_Observed_Or_Borrowed_Expr --
3532 -----------------------------------
3533
3534 function Get_Observed_Or_Borrowed_Expr (Expr : Node_Id) return Node_Id is
3535 begin
3536 if Is_Traversal_Function_Call (Expr) then
3537 return First_Actual (Expr);
3538 else
3539 return Expr;
3540 end if;
3541 end Get_Observed_Or_Borrowed_Expr;
3542
3543 --------------
3544 -- Get_Perm --
3545 --------------
3546
3547 function Get_Perm (N : Node_Or_Entity_Id) return Perm_Kind is
3548 begin
3549 -- Special case for the object declared in an extended return statement
3550
3551 if Nkind (N) = N_Defining_Identifier then
3552 declare
3553 C : constant Perm_Tree_Access :=
3554 Get (Current_Perm_Env, Unique_Entity (N));
3555 begin
3556 pragma Assert (C /= null);
3557 return Permission (C);
3558 end;
3559
3560 -- The expression is a call to a traversal function
3561
3562 elsif Is_Traversal_Function_Call (N) then
3563 declare
3564 Callee : constant Entity_Id := Get_Called_Entity (N);
3565 begin
3566 if Is_Access_Constant (Etype (Callee)) then
3567 return Read_Only;
3568 else
3569 return Read_Write;
3570 end if;
3571 end;
3572
3573 -- The expression is directly rooted in an object
3574
3575 elsif Present (Get_Root_Object (N, Through_Traversal => False)) then
3576 declare
3577 Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N);
3578 begin
3579 case Tree_Or_Perm.R is
3580 when Folded =>
3581 return Tree_Or_Perm.Found_Permission;
3582
3583 when Unfolded =>
3584 pragma Assert (Tree_Or_Perm.Tree_Access /= null);
3585 return Permission (Tree_Or_Perm.Tree_Access);
3586 end case;
3587 end;
3588
3589 -- The expression is a function call, an allocation, or null
3590
3591 else
3592 return Read_Write;
3593 end if;
3594 end Get_Perm;
3595
3596 ----------------------
3597 -- Get_Perm_Or_Tree --
3598 ----------------------
3599
3600 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree is
3601 begin
3602 case Nkind (N) is
3603
3604 when N_Expanded_Name
3605 | N_Identifier
3606 =>
3607 declare
3608 C : constant Perm_Tree_Access :=
3609 Get (Current_Perm_Env, Unique_Entity (Entity (N)));
3610 begin
3611 -- Except during elaboration, the root object should have been
3612 -- declared and entered into the current permission
3613 -- environment.
3614
3615 if not Inside_Elaboration
3616 and then C = null
3617 then
3618 Illegal_Global_Usage (N, N);
3619 end if;
3620
3621 return (R => Unfolded, Tree_Access => C);
3622 end;
3623
3624 -- For a nonterminal path, we get the permission tree of its
3625 -- prefix, and then get the subtree associated with the extension,
3626 -- if unfolded. If folded, we return the permission associated with
3627 -- children.
3628
3629 when N_Explicit_Dereference
3630 | N_Indexed_Component
3631 | N_Selected_Component
3632 | N_Slice
3633 =>
3634 declare
3635 C : constant Perm_Or_Tree := Get_Perm_Or_Tree (Prefix (N));
3636 begin
3637 case C.R is
3638
3639 -- Some earlier prefix was already folded, return the
3640 -- permission found.
3641
3642 when Folded =>
3643 return C;
3644
3645 when Unfolded =>
3646 case Kind (C.Tree_Access) is
3647
3648 -- If the prefix tree is already folded, return the
3649 -- children permission.
3650
3651 when Entire_Object =>
3652 return (R => Folded,
3653 Found_Permission =>
3654 Children_Permission (C.Tree_Access),
3655 Explanation =>
3656 Explanation (C.Tree_Access));
3657
3658 when Reference =>
3659 pragma Assert (Nkind (N) = N_Explicit_Dereference);
3660 return (R => Unfolded,
3661 Tree_Access => Get_All (C.Tree_Access));
3662
3663 when Record_Component =>
3664 pragma Assert (Nkind (N) = N_Selected_Component);
3665 declare
3666 Comp : constant Entity_Id :=
3667 Original_Record_Component
3668 (Entity (Selector_Name (N)));
3669 D : constant Perm_Tree_Access :=
3670 Perm_Tree_Maps.Get
3671 (Component (C.Tree_Access), Comp);
3672 begin
3673 pragma Assert (D /= null);
3674 return (R => Unfolded,
3675 Tree_Access => D);
3676 end;
3677
3678 when Array_Component =>
3679 pragma Assert (Nkind (N) = N_Indexed_Component
3680 or else
3681 Nkind (N) = N_Slice);
3682 pragma Assert (Get_Elem (C.Tree_Access) /= null);
3683 return (R => Unfolded,
3684 Tree_Access => Get_Elem (C.Tree_Access));
3685 end case;
3686 end case;
3687 end;
3688
3689 when N_Qualified_Expression
3690 | N_Type_Conversion
3691 | N_Unchecked_Type_Conversion
3692 =>
3693 return Get_Perm_Or_Tree (Expression (N));
3694
3695 when others =>
3696 raise Program_Error;
3697 end case;
3698 end Get_Perm_Or_Tree;
3699
3700 -------------------
3701 -- Get_Perm_Tree --
3702 -------------------
3703
3704 function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access is
3705 begin
3706 return Set_Perm_Prefixes (N, None, Empty);
3707 end Get_Perm_Tree;
3708
3709 ---------------------
3710 -- Get_Root_Object --
3711 ---------------------
3712
3713 function Get_Root_Object
3714 (Expr : Node_Id;
3715 Through_Traversal : Boolean := True;
3716 Is_Traversal : Boolean := False) return Entity_Id
3717 is
3718 function GRO (Expr : Node_Id) return Entity_Id;
3719 -- Local wrapper on the actual function, to propagate the values of
3720 -- optional parameters.
3721
3722 ---------
3723 -- GRO --
3724 ---------
3725
3726 function GRO (Expr : Node_Id) return Entity_Id is
3727 begin
3728 return Get_Root_Object (Expr, Through_Traversal, Is_Traversal);
3729 end GRO;
3730
3731 Get_Root_Object : Boolean;
3732 pragma Unmodified (Get_Root_Object);
3733 -- Local variable to mask the name of function Get_Root_Object, to
3734 -- prevent direct call. Instead GRO wrapper should be called.
3735
3736 -- Start of processing for Get_Root_Object
3737
3738 begin
3739 if not Is_Subpath_Expression (Expr, Is_Traversal) then
3740 if Emit_Messages then
3741 Error_Msg_N ("name expected here for path", Expr);
3742 end if;
3743 return Empty;
3744 end if;
3745
3746 case Nkind (Expr) is
3747 when N_Expanded_Name
3748 | N_Identifier
3749 =>
3750 return Entity (Expr);
3751
3752 when N_Explicit_Dereference
3753 | N_Indexed_Component
3754 | N_Selected_Component
3755 | N_Slice
3756 =>
3757 return GRO (Prefix (Expr));
3758
3759 -- There is no root object for an (extension) aggregate, allocator,
3760 -- concat, or NULL.
3761
3762 when N_Aggregate
3763 | N_Allocator
3764 | N_Extension_Aggregate
3765 | N_Null
3766 | N_Op_Concat
3767 =>
3768 return Empty;
3769
3770 -- In the case of a call to a traversal function, the root object is
3771 -- the root of the traversed parameter. Otherwise there is no root
3772 -- object.
3773
3774 when N_Function_Call =>
3775 if Through_Traversal
3776 and then Is_Traversal_Function_Call (Expr)
3777 then
3778 return GRO (First_Actual (Expr));
3779 else
3780 return Empty;
3781 end if;
3782
3783 when N_Qualified_Expression
3784 | N_Type_Conversion
3785 | N_Unchecked_Type_Conversion
3786 =>
3787 return GRO (Expression (Expr));
3788
3789 when N_Attribute_Reference =>
3790 pragma Assert
3791 (Get_Attribute_Id (Attribute_Name (Expr)) =
3792 Attribute_Loop_Entry
3793 or else
3794 Get_Attribute_Id (Attribute_Name (Expr)) =
3795 Attribute_Update
3796 or else Get_Attribute_Id (Attribute_Name (Expr)) =
3797 Attribute_Image);
3798 return Empty;
3799
3800 when N_If_Expression =>
3801 if Is_Traversal then
3802 declare
3803 Cond : constant Node_Id := First (Expressions (Expr));
3804 Then_Part : constant Node_Id := Next (Cond);
3805 Else_Part : constant Node_Id := Next (Then_Part);
3806 Then_Root : constant Entity_Id := GRO (Then_Part);
3807 Else_Root : constant Entity_Id := GRO (Else_Part);
3808 begin
3809 if Nkind (Then_Part) = N_Null then
3810 return Else_Root;
3811 elsif Nkind (Else_Part) = N_Null then
3812 return Then_Part;
3813 elsif Then_Root = Else_Root then
3814 return Then_Root;
3815 else
3816 if Emit_Messages then
3817 Error_Msg_N
3818 ("same name expected here in each branch", Expr);
3819 end if;
3820 return Empty;
3821 end if;
3822 end;
3823 else
3824 if Emit_Messages then
3825 Error_Msg_N ("name expected here for path", Expr);
3826 end if;
3827 return Empty;
3828 end if;
3829
3830 when N_Case_Expression =>
3831 if Is_Traversal then
3832 declare
3833 Cases : constant List_Id := Alternatives (Expr);
3834 Cur_Case : Node_Id := First (Cases);
3835 Cur_Root : Entity_Id;
3836 Common_Root : Entity_Id := Empty;
3837
3838 begin
3839 while Present (Cur_Case) loop
3840 Cur_Root := GRO (Expression (Cur_Case));
3841
3842 if Common_Root = Empty then
3843 Common_Root := Cur_Root;
3844 elsif Common_Root /= Cur_Root then
3845 if Emit_Messages then
3846 Error_Msg_N
3847 ("same name expected here in each branch", Expr);
3848 end if;
3849 return Empty;
3850 end if;
3851 Next (Cur_Case);
3852 end loop;
3853
3854 return Common_Root;
3855 end;
3856 else
3857 if Emit_Messages then
3858 Error_Msg_N ("name expected here for path", Expr);
3859 end if;
3860 return Empty;
3861 end if;
3862
3863 when others =>
3864 raise Program_Error;
3865 end case;
3866 end Get_Root_Object;
3867
3868 ---------
3869 -- Glb --
3870 ---------
3871
3872 function Glb (P1, P2 : Perm_Kind) return Perm_Kind
3873 is
3874 begin
3875 case P1 is
3876 when No_Access =>
3877 return No_Access;
3878
3879 when Read_Only =>
3880 case P2 is
3881 when No_Access
3882 | Write_Only
3883 =>
3884 return No_Access;
3885
3886 when Read_Perm =>
3887 return Read_Only;
3888 end case;
3889
3890 when Write_Only =>
3891 case P2 is
3892 when No_Access
3893 | Read_Only
3894 =>
3895 return No_Access;
3896
3897 when Write_Perm =>
3898 return Write_Only;
3899 end case;
3900
3901 when Read_Write =>
3902 return P2;
3903 end case;
3904 end Glb;
3905
3906 -------------------------
3907 -- Has_Array_Component --
3908 -------------------------
3909
3910 function Has_Array_Component (Expr : Node_Id) return Boolean is
3911 begin
3912 case Nkind (Expr) is
3913 when N_Expanded_Name
3914 | N_Identifier
3915 =>
3916 return False;
3917
3918 when N_Explicit_Dereference
3919 | N_Selected_Component
3920 =>
3921 return Has_Array_Component (Prefix (Expr));
3922
3923 when N_Indexed_Component
3924 | N_Slice
3925 =>
3926 return True;
3927
3928 when N_Allocator
3929 | N_Null
3930 | N_Function_Call
3931 =>
3932 return False;
3933
3934 when N_Qualified_Expression
3935 | N_Type_Conversion
3936 | N_Unchecked_Type_Conversion
3937 =>
3938 return Has_Array_Component (Expression (Expr));
3939
3940 when others =>
3941 raise Program_Error;
3942 end case;
3943 end Has_Array_Component;
3944
3945 --------
3946 -- Hp --
3947 --------
3948
3949 procedure Hp (P : Perm_Env) is
3950 Elem : Perm_Tree_Maps.Key_Option;
3951
3952 begin
3953 Elem := Get_First_Key (P);
3954 while Elem.Present loop
3955 Print_Node_Briefly (Elem.K);
3956 Elem := Get_Next_Key (P);
3957 end loop;
3958 end Hp;
3959
3960 --------------------------
3961 -- Illegal_Global_Usage --
3962 --------------------------
3963
3964 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id; E : Entity_Id)
3965 is
3966 begin
3967 Error_Msg_NE ("cannot use global variable & of deep type", N, E);
3968 Error_Msg_N ("\without prior declaration in a Global aspect", N);
3969 Errout.Finalize (Last_Call => True);
3970 Errout.Output_Messages;
3971 Exit_Program (E_Errors);
3972 end Illegal_Global_Usage;
3973
3974 -------------
3975 -- Is_Deep --
3976 -------------
3977
3978 function Is_Deep (Typ : Entity_Id) return Boolean is
3979 begin
3980 case Type_Kind'(Ekind (Retysp (Typ))) is
3981 when Access_Kind =>
3982 return True;
3983
3984 when E_Array_Type
3985 | E_Array_Subtype
3986 =>
3987 return Is_Deep (Component_Type (Retysp (Typ)));
3988
3989 when Record_Kind =>
3990 declare
3991 Comp : Entity_Id;
3992 begin
3993 Comp := First_Component_Or_Discriminant (Retysp (Typ));
3994 while Present (Comp) loop
3995
3996 -- Ignore components not visible in SPARK
3997
3998 if Component_Is_Visible_In_SPARK (Comp)
3999 and then Is_Deep (Etype (Comp))
4000 then
4001 return True;
4002 end if;
4003 Next_Component_Or_Discriminant (Comp);
4004 end loop;
4005 end;
4006 return False;
4007
4008 when Scalar_Kind
4009 | E_String_Literal_Subtype
4010 | Protected_Kind
4011 | Task_Kind
4012 | Incomplete_Kind
4013 | E_Exception_Type
4014 | E_Subprogram_Type
4015 =>
4016 return False;
4017
4018 -- Ignore full view of types if it is not in SPARK
4019
4020 when E_Private_Type
4021 | E_Private_Subtype
4022 | E_Limited_Private_Type
4023 | E_Limited_Private_Subtype
4024 =>
4025 return False;
4026 end case;
4027 end Is_Deep;
4028
4029 ----------------------
4030 -- Is_Local_Context --
4031 ----------------------
4032
4033 function Is_Local_Context (Scop : Entity_Id) return Boolean is
4034 begin
4035 return Is_Subprogram_Or_Entry (Scop)
4036 or else Ekind (Scop) = E_Block;
4037 end Is_Local_Context;
4038
4039 ------------------------
4040 -- Is_Path_Expression --
4041 ------------------------
4042
4043 function Is_Path_Expression
4044 (Expr : Node_Id;
4045 Is_Traversal : Boolean := False) return Boolean
4046 is
4047 function IPE (Expr : Node_Id) return Boolean;
4048 -- Local wrapper on the actual function, to propagate the values of
4049 -- optional parameter Is_Traversal.
4050
4051 ---------
4052 -- IPE --
4053 ---------
4054
4055 function IPE (Expr : Node_Id) return Boolean is
4056 begin
4057 return Is_Path_Expression (Expr, Is_Traversal);
4058 end IPE;
4059
4060 Is_Path_Expression : Boolean;
4061 pragma Unmodified (Is_Path_Expression);
4062 -- Local variable to mask the name of function Is_Path_Expression, to
4063 -- prevent direct call. Instead IPE wrapper should be called.
4064
4065 -- Start of processing for Is_Path_Expression
4066
4067 begin
4068 case Nkind (Expr) is
4069 when N_Expanded_Name
4070 | N_Explicit_Dereference
4071 | N_Identifier
4072 | N_Indexed_Component
4073 | N_Selected_Component
4074 | N_Slice
4075 =>
4076 return True;
4077
4078 -- Special value NULL corresponds to an empty path
4079
4080 when N_Null =>
4081 return True;
4082
4083 -- Object returned by an (extension) aggregate, an allocator, or
4084 -- a function call corresponds to a path.
4085
4086 when N_Aggregate
4087 | N_Allocator
4088 | N_Extension_Aggregate
4089 | N_Function_Call
4090 =>
4091 return True;
4092
4093 when N_Qualified_Expression
4094 | N_Type_Conversion
4095 | N_Unchecked_Type_Conversion
4096 =>
4097 return IPE (Expression (Expr));
4098
4099 -- When returning from a traversal function, consider an
4100 -- if-expression as a possible path expression.
4101
4102 when N_If_Expression =>
4103 if Is_Traversal then
4104 declare
4105 Cond : constant Node_Id := First (Expressions (Expr));
4106 Then_Part : constant Node_Id := Next (Cond);
4107 Else_Part : constant Node_Id := Next (Then_Part);
4108 begin
4109 return IPE (Then_Part)
4110 and then IPE (Else_Part);
4111 end;
4112 else
4113 return False;
4114 end if;
4115
4116 -- When returning from a traversal function, consider
4117 -- a case-expression as a possible path expression.
4118
4119 when N_Case_Expression =>
4120 if Is_Traversal then
4121 declare
4122 Cases : constant List_Id := Alternatives (Expr);
4123 Cur_Case : Node_Id := First (Cases);
4124
4125 begin
4126 while Present (Cur_Case) loop
4127 if not IPE (Expression (Cur_Case)) then
4128 return False;
4129 end if;
4130 Next (Cur_Case);
4131 end loop;
4132
4133 return True;
4134 end;
4135 else
4136 return False;
4137 end if;
4138
4139 when others =>
4140 return False;
4141 end case;
4142 end Is_Path_Expression;
4143
4144 -------------------------
4145 -- Is_Prefix_Or_Almost --
4146 -------------------------
4147
4148 function Is_Prefix_Or_Almost (Pref, Expr : Node_Id) return Boolean is
4149
4150 type Expr_Array is array (Positive range <>) of Node_Id;
4151 -- Sequence of expressions that make up a path
4152
4153 function Get_Expr_Array (Expr : Node_Id) return Expr_Array;
4154 pragma Precondition (Is_Path_Expression (Expr));
4155 -- Return the sequence of expressions that make up a path
4156
4157 --------------------
4158 -- Get_Expr_Array --
4159 --------------------
4160
4161 function Get_Expr_Array (Expr : Node_Id) return Expr_Array is
4162 begin
4163 case Nkind (Expr) is
4164 when N_Expanded_Name
4165 | N_Identifier
4166 =>
4167 return Expr_Array'(1 => Expr);
4168
4169 when N_Explicit_Dereference
4170 | N_Indexed_Component
4171 | N_Selected_Component
4172 | N_Slice
4173 =>
4174 return Get_Expr_Array (Prefix (Expr)) & Expr;
4175
4176 when N_Qualified_Expression
4177 | N_Type_Conversion
4178 | N_Unchecked_Type_Conversion
4179 =>
4180 return Get_Expr_Array (Expression (Expr));
4181
4182 when others =>
4183 raise Program_Error;
4184 end case;
4185 end Get_Expr_Array;
4186
4187 -- Local variables
4188
4189 Prefix_Path : constant Expr_Array := Get_Expr_Array (Pref);
4190 Expr_Path : constant Expr_Array := Get_Expr_Array (Expr);
4191
4192 Prefix_Root : constant Node_Id := Prefix_Path (1);
4193 Expr_Root : constant Node_Id := Expr_Path (1);
4194
4195 Common_Len : constant Positive :=
4196 Positive'Min (Prefix_Path'Length, Expr_Path'Length);
4197
4198 -- Start of processing for Is_Prefix_Or_Almost
4199
4200 begin
4201 if Entity (Prefix_Root) /= Entity (Expr_Root) then
4202 return False;
4203 end if;
4204
4205 for J in 2 .. Common_Len loop
4206 declare
4207 Prefix_Elt : constant Node_Id := Prefix_Path (J);
4208 Expr_Elt : constant Node_Id := Expr_Path (J);
4209 begin
4210 case Nkind (Prefix_Elt) is
4211 when N_Explicit_Dereference =>
4212 if Nkind (Expr_Elt) /= N_Explicit_Dereference then
4213 return False;
4214 end if;
4215
4216 when N_Selected_Component =>
4217 if Nkind (Expr_Elt) /= N_Selected_Component
4218 or else Original_Record_Component
4219 (Entity (Selector_Name (Prefix_Elt)))
4220 /= Original_Record_Component
4221 (Entity (Selector_Name (Expr_Elt)))
4222 then
4223 return False;
4224 end if;
4225
4226 when N_Indexed_Component
4227 | N_Slice
4228 =>
4229 if not Nkind_In (Expr_Elt, N_Indexed_Component, N_Slice) then
4230 return False;
4231 end if;
4232
4233 when others =>
4234 raise Program_Error;
4235 end case;
4236 end;
4237 end loop;
4238
4239 -- If the expression path is longer than the prefix one, then at this
4240 -- point the prefix property holds.
4241
4242 if Expr_Path'Length > Prefix_Path'Length then
4243 return True;
4244
4245 -- Otherwise check if none of the remaining path elements in the
4246 -- candidate prefix involve a dereference.
4247
4248 else
4249 for J in Common_Len + 1 .. Prefix_Path'Length loop
4250 if Nkind (Prefix_Path (J)) = N_Explicit_Dereference then
4251 return False;
4252 end if;
4253 end loop;
4254
4255 return True;
4256 end if;
4257 end Is_Prefix_Or_Almost;
4258
4259 ---------------------------
4260 -- Is_Subpath_Expression --
4261 ---------------------------
4262
4263 function Is_Subpath_Expression
4264 (Expr : Node_Id;
4265 Is_Traversal : Boolean := False) return Boolean
4266 is
4267 begin
4268 return Is_Path_Expression (Expr, Is_Traversal)
4269
4270 or else (Nkind_In (Expr, N_Qualified_Expression,
4271 N_Type_Conversion,
4272 N_Unchecked_Type_Conversion)
4273 and then Is_Subpath_Expression (Expression (Expr)))
4274
4275 or else (Nkind (Expr) = N_Attribute_Reference
4276 and then
4277 (Get_Attribute_Id (Attribute_Name (Expr)) =
4278 Attribute_Update
4279 or else
4280 Get_Attribute_Id (Attribute_Name (Expr)) =
4281 Attribute_Loop_Entry
4282 or else
4283 Get_Attribute_Id (Attribute_Name (Expr)) =
4284 Attribute_Image))
4285
4286 or else Nkind (Expr) = N_Op_Concat;
4287 end Is_Subpath_Expression;
4288
4289 ---------------------------
4290 -- Is_Traversal_Function --
4291 ---------------------------
4292
4293 function Is_Traversal_Function (E : Entity_Id) return Boolean is
4294 begin
4295 return Ekind (E) = E_Function
4296
4297 -- A function is said to be a traversal function if the result type of
4298 -- the function is an anonymous access-to-object type,
4299
4300 and then Is_Anonymous_Access_Type (Etype (E))
4301
4302 -- the function has at least one formal parameter,
4303
4304 and then Present (First_Formal (E))
4305
4306 -- and the function's first parameter is of an access type.
4307
4308 and then Is_Access_Type (Retysp (Etype (First_Formal (E))));
4309 end Is_Traversal_Function;
4310
4311 --------------------------------
4312 -- Is_Traversal_Function_Call --
4313 --------------------------------
4314
4315 function Is_Traversal_Function_Call (Expr : Node_Id) return Boolean is
4316 begin
4317 return Nkind (Expr) = N_Function_Call
4318 and then Present (Get_Called_Entity (Expr))
4319 and then Is_Traversal_Function (Get_Called_Entity (Expr));
4320 end Is_Traversal_Function_Call;
4321
4322 ------------------
4323 -- Loop_Of_Exit --
4324 ------------------
4325
4326 function Loop_Of_Exit (N : Node_Id) return Entity_Id is
4327 Nam : Node_Id := Name (N);
4328 Stmt : Node_Id := N;
4329 begin
4330 if No (Nam) then
4331 while Present (Stmt) loop
4332 Stmt := Parent (Stmt);
4333 if Nkind (Stmt) = N_Loop_Statement then
4334 Nam := Identifier (Stmt);
4335 exit;
4336 end if;
4337 end loop;
4338 end if;
4339 return Entity (Nam);
4340 end Loop_Of_Exit;
4341
4342 ---------
4343 -- Lub --
4344 ---------
4345
4346 function Lub (P1, P2 : Perm_Kind) return Perm_Kind is
4347 begin
4348 case P1 is
4349 when No_Access =>
4350 return P2;
4351
4352 when Read_Only =>
4353 case P2 is
4354 when No_Access
4355 | Read_Only
4356 =>
4357 return Read_Only;
4358
4359 when Write_Perm =>
4360 return Read_Write;
4361 end case;
4362
4363 when Write_Only =>
4364 case P2 is
4365 when No_Access
4366 | Write_Only
4367 =>
4368 return Write_Only;
4369
4370 when Read_Perm =>
4371 return Read_Write;
4372 end case;
4373
4374 when Read_Write =>
4375 return Read_Write;
4376 end case;
4377 end Lub;
4378
4379 ---------------
4380 -- Merge_Env --
4381 ---------------
4382
4383 procedure Merge_Env (Source : in out Perm_Env; Target : in out Perm_Env) is
4384
4385 -- Local subprograms
4386
4387 procedure Apply_Glb_Tree
4388 (A : Perm_Tree_Access;
4389 P : Perm_Kind);
4390
4391 procedure Merge_Trees
4392 (Target : Perm_Tree_Access;
4393 Source : Perm_Tree_Access);
4394
4395 --------------------
4396 -- Apply_Glb_Tree --
4397 --------------------
4398
4399 procedure Apply_Glb_Tree
4400 (A : Perm_Tree_Access;
4401 P : Perm_Kind)
4402 is
4403 begin
4404 A.all.Tree.Permission := Glb (Permission (A), P);
4405
4406 case Kind (A) is
4407 when Entire_Object =>
4408 A.all.Tree.Children_Permission :=
4409 Glb (Children_Permission (A), P);
4410
4411 when Reference =>
4412 Apply_Glb_Tree (Get_All (A), P);
4413
4414 when Array_Component =>
4415 Apply_Glb_Tree (Get_Elem (A), P);
4416
4417 when Record_Component =>
4418 declare
4419 Comp : Perm_Tree_Access;
4420 begin
4421 Comp := Perm_Tree_Maps.Get_First (Component (A));
4422 while Comp /= null loop
4423 Apply_Glb_Tree (Comp, P);
4424 Comp := Perm_Tree_Maps.Get_Next (Component (A));
4425 end loop;
4426 end;
4427 end case;
4428 end Apply_Glb_Tree;
4429
4430 -----------------
4431 -- Merge_Trees --
4432 -----------------
4433
4434 procedure Merge_Trees
4435 (Target : Perm_Tree_Access;
4436 Source : Perm_Tree_Access)
4437 is
4438 Perm : constant Perm_Kind :=
4439 Glb (Permission (Target), Permission (Source));
4440
4441 begin
4442 pragma Assert (Is_Node_Deep (Target) = Is_Node_Deep (Source));
4443 Target.all.Tree.Permission := Perm;
4444
4445 case Kind (Target) is
4446 when Entire_Object =>
4447 declare
4448 Child_Perm : constant Perm_Kind :=
4449 Children_Permission (Target);
4450
4451 begin
4452 case Kind (Source) is
4453 when Entire_Object =>
4454 Target.all.Tree.Children_Permission :=
4455 Glb (Child_Perm, Children_Permission (Source));
4456
4457 when Reference =>
4458 Copy_Tree (Source, Target);
4459 Target.all.Tree.Permission := Perm;
4460 Apply_Glb_Tree (Get_All (Target), Child_Perm);
4461
4462 when Array_Component =>
4463 Copy_Tree (Source, Target);
4464 Target.all.Tree.Permission := Perm;
4465 Apply_Glb_Tree (Get_Elem (Target), Child_Perm);
4466
4467 when Record_Component =>
4468 Copy_Tree (Source, Target);
4469 Target.all.Tree.Permission := Perm;
4470 declare
4471 Comp : Perm_Tree_Access;
4472
4473 begin
4474 Comp :=
4475 Perm_Tree_Maps.Get_First (Component (Target));
4476 while Comp /= null loop
4477 -- Apply glb tree on every component subtree
4478
4479 Apply_Glb_Tree (Comp, Child_Perm);
4480 Comp := Perm_Tree_Maps.Get_Next
4481 (Component (Target));
4482 end loop;
4483 end;
4484 end case;
4485 end;
4486
4487 when Reference =>
4488 case Kind (Source) is
4489 when Entire_Object =>
4490 Apply_Glb_Tree (Get_All (Target),
4491 Children_Permission (Source));
4492
4493 when Reference =>
4494 Merge_Trees (Get_All (Target), Get_All (Source));
4495
4496 when others =>
4497 raise Program_Error;
4498
4499 end case;
4500
4501 when Array_Component =>
4502 case Kind (Source) is
4503 when Entire_Object =>
4504 Apply_Glb_Tree (Get_Elem (Target),
4505 Children_Permission (Source));
4506
4507 when Array_Component =>
4508 Merge_Trees (Get_Elem (Target), Get_Elem (Source));
4509
4510 when others =>
4511 raise Program_Error;
4512
4513 end case;
4514
4515 when Record_Component =>
4516 case Kind (Source) is
4517 when Entire_Object =>
4518 declare
4519 Child_Perm : constant Perm_Kind :=
4520 Children_Permission (Source);
4521
4522 Comp : Perm_Tree_Access;
4523
4524 begin
4525 Comp := Perm_Tree_Maps.Get_First
4526 (Component (Target));
4527 while Comp /= null loop
4528 -- Apply glb tree on every component subtree
4529
4530 Apply_Glb_Tree (Comp, Child_Perm);
4531 Comp :=
4532 Perm_Tree_Maps.Get_Next (Component (Target));
4533 end loop;
4534 end;
4535
4536 when Record_Component =>
4537 declare
4538 Key_Source : Perm_Tree_Maps.Key_Option;
4539 CompTarget : Perm_Tree_Access;
4540 CompSource : Perm_Tree_Access;
4541
4542 begin
4543 Key_Source := Perm_Tree_Maps.Get_First_Key
4544 (Component (Source));
4545
4546 while Key_Source.Present loop
4547 CompSource := Perm_Tree_Maps.Get
4548 (Component (Source), Key_Source.K);
4549 CompTarget := Perm_Tree_Maps.Get
4550 (Component (Target), Key_Source.K);
4551
4552 pragma Assert (CompSource /= null);
4553 Merge_Trees (CompTarget, CompSource);
4554
4555 Key_Source := Perm_Tree_Maps.Get_Next_Key
4556 (Component (Source));
4557 end loop;
4558 end;
4559
4560 when others =>
4561 raise Program_Error;
4562 end case;
4563 end case;
4564 end Merge_Trees;
4565
4566 -- Local variables
4567
4568 CompTarget : Perm_Tree_Access;
4569 CompSource : Perm_Tree_Access;
4570 KeyTarget : Perm_Tree_Maps.Key_Option;
4571
4572 -- Start of processing for Merge_Env
4573
4574 begin
4575 KeyTarget := Get_First_Key (Target);
4576 -- Iterate over every tree of the environment in the target, and merge
4577 -- it with the source if there is such a similar one that exists. If
4578 -- there is none, then skip.
4579 while KeyTarget.Present loop
4580
4581 CompSource := Get (Source, KeyTarget.K);
4582 CompTarget := Get (Target, KeyTarget.K);
4583
4584 pragma Assert (CompTarget /= null);
4585
4586 if CompSource /= null then
4587 Merge_Trees (CompTarget, CompSource);
4588 Remove (Source, KeyTarget.K);
4589 end if;
4590
4591 KeyTarget := Get_Next_Key (Target);
4592 end loop;
4593
4594 -- Iterate over every tree of the environment of the source. And merge
4595 -- again. If there is not any tree of the target then just copy the tree
4596 -- from source to target.
4597 declare
4598 KeySource : Perm_Tree_Maps.Key_Option;
4599 begin
4600 KeySource := Get_First_Key (Source);
4601 while KeySource.Present loop
4602
4603 CompSource := Get (Source, KeySource.K);
4604 CompTarget := Get (Target, KeySource.K);
4605
4606 if CompTarget = null then
4607 CompTarget := new Perm_Tree_Wrapper'(CompSource.all);
4608 Copy_Tree (CompSource, CompTarget);
4609 Set (Target, KeySource.K, CompTarget);
4610 else
4611 Merge_Trees (CompTarget, CompSource);
4612 end if;
4613
4614 KeySource := Get_Next_Key (Source);
4615 end loop;
4616 end;
4617
4618 Free_Env (Source);
4619 end Merge_Env;
4620
4621 ----------------
4622 -- Perm_Error --
4623 ----------------
4624
4625 procedure Perm_Error
4626 (N : Node_Id;
4627 Perm : Perm_Kind;
4628 Found_Perm : Perm_Kind;
4629 Expl : Node_Id;
4630 Forbidden_Perm : Boolean := False)
4631 is
4632 procedure Set_Root_Object
4633 (Path : Node_Id;
4634 Obj : out Entity_Id;
4635 Deref : out Boolean);
4636 -- Set the root object Obj, and whether the path contains a dereference,
4637 -- from a path Path.
4638
4639 ---------------------
4640 -- Set_Root_Object --
4641 ---------------------
4642
4643 procedure Set_Root_Object
4644 (Path : Node_Id;
4645 Obj : out Entity_Id;
4646 Deref : out Boolean)
4647 is
4648 begin
4649 case Nkind (Path) is
4650 when N_Identifier
4651 | N_Expanded_Name
4652 =>
4653 Obj := Entity (Path);
4654 Deref := False;
4655
4656 when N_Type_Conversion
4657 | N_Unchecked_Type_Conversion
4658 | N_Qualified_Expression
4659 =>
4660 Set_Root_Object (Expression (Path), Obj, Deref);
4661
4662 when N_Indexed_Component
4663 | N_Selected_Component
4664 | N_Slice
4665 =>
4666 Set_Root_Object (Prefix (Path), Obj, Deref);
4667
4668 when N_Explicit_Dereference =>
4669 Set_Root_Object (Prefix (Path), Obj, Deref);
4670 Deref := True;
4671
4672 when others =>
4673 raise Program_Error;
4674 end case;
4675 end Set_Root_Object;
4676 -- Local variables
4677
4678 Root : Entity_Id;
4679 Is_Deref : Boolean;
4680
4681 -- Start of processing for Perm_Error
4682
4683 begin
4684 Set_Root_Object (N, Root, Is_Deref);
4685
4686 if Emit_Messages then
4687 if Is_Deref then
4688 Error_Msg_NE
4689 ("insufficient permission on dereference from &", N, Root);
4690 else
4691 Error_Msg_NE ("insufficient permission for &", N, Root);
4692 end if;
4693
4694 Perm_Mismatch (N, Perm, Found_Perm, Expl, Forbidden_Perm);
4695 end if;
4696 end Perm_Error;
4697
4698 -------------------------------
4699 -- Perm_Error_Subprogram_End --
4700 -------------------------------
4701
4702 procedure Perm_Error_Subprogram_End
4703 (E : Entity_Id;
4704 Subp : Entity_Id;
4705 Perm : Perm_Kind;
4706 Found_Perm : Perm_Kind;
4707 Expl : Node_Id)
4708 is
4709 begin
4710 if Emit_Messages then
4711 Error_Msg_Node_2 := Subp;
4712 Error_Msg_NE ("insufficient permission for & when returning from &",
4713 Subp, E);
4714 Perm_Mismatch (Subp, Perm, Found_Perm, Expl);
4715 end if;
4716 end Perm_Error_Subprogram_End;
4717
4718 ------------------
4719 -- Process_Path --
4720 ------------------
4721
4722 procedure Process_Path (Expr : Node_Id; Mode : Checking_Mode) is
4723
4724 procedure Check_Not_Borrowed (Expr : Node_Id; Root : Entity_Id);
4725 -- Check expression Expr originating in Root was not borrowed
4726
4727 procedure Check_Not_Observed (Expr : Node_Id; Root : Entity_Id);
4728 -- Check expression Expr originating in Root was not observed
4729
4730 ------------------------
4731 -- Check_Not_Borrowed --
4732 ------------------------
4733
4734 procedure Check_Not_Borrowed (Expr : Node_Id; Root : Entity_Id) is
4735 begin
4736 -- An expression without root object cannot be borrowed
4737
4738 if No (Root) then
4739 return;
4740 end if;
4741
4742 -- Otherwise, try to match the expression with one of the borrowed
4743 -- expressions.
4744
4745 declare
4746 Key : Variable_Maps.Key_Option :=
4747 Get_First_Key (Current_Borrowers);
4748 Var : Entity_Id;
4749 Borrowed : Node_Id;
4750
4751 begin
4752 while Key.Present loop
4753 Var := Key.K;
4754 Borrowed := Get (Current_Borrowers, Var);
4755
4756 if Is_Prefix_Or_Almost (Pref => Borrowed, Expr => Expr)
4757 and then Emit_Messages
4758 then
4759 Error_Msg_Sloc := Sloc (Borrowed);
4760 Error_Msg_N ("object was borrowed #", Expr);
4761 end if;
4762
4763 Key := Get_Next_Key (Current_Borrowers);
4764 end loop;
4765 end;
4766 end Check_Not_Borrowed;
4767
4768 ------------------------
4769 -- Check_Not_Observed --
4770 ------------------------
4771
4772 procedure Check_Not_Observed (Expr : Node_Id; Root : Entity_Id) is
4773 begin
4774 -- An expression without root object cannot be observed
4775
4776 if No (Root) then
4777 return;
4778 end if;
4779
4780 -- Otherwise, try to match the expression with one of the observed
4781 -- expressions.
4782
4783 declare
4784 Key : Variable_Maps.Key_Option :=
4785 Get_First_Key (Current_Observers);
4786 Var : Entity_Id;
4787 Observed : Node_Id;
4788
4789 begin
4790 while Key.Present loop
4791 Var := Key.K;
4792 Observed := Get (Current_Observers, Var);
4793
4794 if Is_Prefix_Or_Almost (Pref => Observed, Expr => Expr)
4795 and then Emit_Messages
4796 then
4797 Error_Msg_Sloc := Sloc (Observed);
4798 Error_Msg_N ("object was observed #", Expr);
4799 end if;
4800
4801 Key := Get_Next_Key (Current_Observers);
4802 end loop;
4803 end;
4804 end Check_Not_Observed;
4805
4806 -- Local variables
4807
4808 Expr_Type : constant Entity_Id := Etype (Expr);
4809 Root : Entity_Id := Get_Root_Object (Expr);
4810 Perm : Perm_Kind_Option;
4811
4812 -- Start of processing for Process_Path
4813
4814 begin
4815 -- Nothing to do if the root type is not deep, or the path is not rooted
4816 -- in an object.
4817
4818 if not Present (Root)
4819 or else not Is_Deep (Etype (Root))
4820 then
4821 return;
4822 end if;
4823
4824 -- Identify the root type for the path
4825
4826 Root := Unique_Entity (Root);
4827
4828 -- Except during elaboration, the root object should have been declared
4829 -- and entered into the current permission environment.
4830
4831 if not Inside_Elaboration
4832 and then Get (Current_Perm_Env, Root) = null
4833 then
4834 Illegal_Global_Usage (Expr, Root);
4835 end if;
4836
4837 -- During elaboration, only the validity of operations is checked, no
4838 -- need to compute the permission of Expr.
4839
4840 if Inside_Elaboration then
4841 Perm := None;
4842 else
4843 Perm := Get_Perm (Expr);
4844 end if;
4845
4846 -- Check permissions
4847
4848 case Mode is
4849
4850 when Read =>
4851
4852 -- No checking needed during elaboration
4853
4854 if Inside_Elaboration then
4855 return;
4856 end if;
4857
4858 -- Check path is readable
4859
4860 if Perm not in Read_Perm then
4861 Perm_Error (Expr, Read_Only, Perm, Expl => Get_Expl (Expr));
4862 return;
4863 end if;
4864
4865 when Move =>
4866
4867 -- Forbidden on deep path during elaboration, otherwise no
4868 -- checking needed.
4869
4870 if Inside_Elaboration then
4871 if Is_Deep (Expr_Type)
4872 and then not Inside_Procedure_Call
4873 and then Present (Get_Root_Object (Expr))
4874 and then Emit_Messages
4875 then
4876 Error_Msg_N ("illegal move during elaboration", Expr);
4877 end if;
4878
4879 return;
4880 end if;
4881
4882 -- For deep path, check RW permission, otherwise R permission
4883
4884 if not Is_Deep (Expr_Type) then
4885 if Perm not in Read_Perm then
4886 Perm_Error (Expr, Read_Only, Perm, Expl => Get_Expl (Expr));
4887 end if;
4888 return;
4889 end if;
4890
4891 -- SPARK RM 3.10(1): At the point of a move operation the state of
4892 -- the source object (if any) shall be Unrestricted.
4893
4894 if Perm /= Read_Write then
4895 Perm_Error (Expr, Read_Write, Perm, Expl => Get_Expl (Expr));
4896 return;
4897 end if;
4898
4899 when Assign =>
4900
4901 -- No checking needed during elaboration
4902
4903 if Inside_Elaboration then
4904 return;
4905 end if;
4906
4907 -- For assignment, check W permission
4908
4909 if Perm not in Write_Perm then
4910 Perm_Error (Expr, Write_Only, Perm, Expl => Get_Expl (Expr));
4911 return;
4912 end if;
4913
4914 when Borrow =>
4915
4916 -- Forbidden during elaboration, an error is already issued in
4917 -- Check_Declaration, just return.
4918
4919 if Inside_Elaboration then
4920 return;
4921 end if;
4922
4923 -- For borrowing, check RW permission
4924
4925 if Perm /= Read_Write then
4926 Perm_Error (Expr, Read_Write, Perm, Expl => Get_Expl (Expr));
4927 return;
4928 end if;
4929
4930 when Observe =>
4931
4932 -- Forbidden during elaboration, an error is already issued in
4933 -- Check_Declaration, just return.
4934
4935 if Inside_Elaboration then
4936 return;
4937 end if;
4938
4939 -- For borrowing, check R permission
4940
4941 if Perm not in Read_Perm then
4942 Perm_Error (Expr, Read_Only, Perm, Expl => Get_Expl (Expr));
4943 return;
4944 end if;
4945 end case;
4946
4947 -- Check path was not borrowed
4948
4949 Check_Not_Borrowed (Expr, Root);
4950
4951 -- For modes that require W permission, check path was not observed
4952
4953 case Mode is
4954 when Read | Observe =>
4955 null;
4956 when Assign | Move | Borrow =>
4957 Check_Not_Observed (Expr, Root);
4958 end case;
4959
4960 -- Do not update permission environment when handling calls
4961
4962 if Inside_Procedure_Call then
4963 return;
4964 end if;
4965
4966 -- Update the permissions
4967
4968 case Mode is
4969
4970 when Read =>
4971 null;
4972
4973 when Move =>
4974
4975 -- SPARK RM 3.10(1): After a move operation, the state of the
4976 -- source object (if any) becomes Moved.
4977
4978 if Present (Get_Root_Object (Expr)) then
4979 declare
4980 Tree : constant Perm_Tree_Access :=
4981 Set_Perm_Prefixes (Expr, Write_Only, Expl => Expr);
4982 begin
4983 pragma Assert (Tree /= null);
4984 Set_Perm_Extensions_Move (Tree, Etype (Expr), Expl => Expr);
4985 end;
4986 end if;
4987
4988 when Assign =>
4989
4990 -- If there is no root object, or the tree has an array component,
4991 -- then the permissions do not get modified by the assignment.
4992
4993 if No (Get_Root_Object (Expr))
4994 or else Has_Array_Component (Expr)
4995 then
4996 return;
4997 end if;
4998
4999 -- Set permission RW for the path and its extensions
5000
5001 declare
5002 Tree : constant Perm_Tree_Access := Get_Perm_Tree (Expr);
5003 begin
5004 Tree.all.Tree.Permission := Read_Write;
5005 Set_Perm_Extensions (Tree, Read_Write, Expl => Expr);
5006
5007 -- Normalize the permission tree
5008
5009 Set_Perm_Prefixes_Assign (Expr);
5010 end;
5011
5012 -- Borrowing and observing of paths is handled by the variables
5013 -- Current_Borrowers and Current_Observers.
5014
5015 when Borrow | Observe =>
5016 null;
5017 end case;
5018 end Process_Path;
5019
5020 --------------------
5021 -- Return_Globals --
5022 --------------------
5023
5024 procedure Return_Globals (Subp : Entity_Id) is
5025
5026 procedure Return_Global
5027 (Expr : Node_Id;
5028 Typ : Entity_Id;
5029 Kind : Formal_Kind;
5030 Subp : Entity_Id;
5031 Global_Var : Boolean);
5032 -- Proxy procedure to return globals, to adjust for the type of first
5033 -- parameter expected by Return_Parameter_Or_Global.
5034
5035 -------------------
5036 -- Return_Global --
5037 -------------------
5038
5039 procedure Return_Global
5040 (Expr : Node_Id;
5041 Typ : Entity_Id;
5042 Kind : Formal_Kind;
5043 Subp : Entity_Id;
5044 Global_Var : Boolean)
5045 is
5046 begin
5047 Return_Parameter_Or_Global
5048 (Id => Entity (Expr),
5049 Typ => Typ,
5050 Kind => Kind,
5051 Subp => Subp,
5052 Global_Var => Global_Var);
5053 end Return_Global;
5054
5055 procedure Return_Globals_Inst is new Handle_Globals (Return_Global);
5056
5057 -- Start of processing for Return_Globals
5058
5059 begin
5060 Return_Globals_Inst (Subp);
5061 end Return_Globals;
5062
5063 --------------------------------
5064 -- Return_Parameter_Or_Global --
5065 --------------------------------
5066
5067 procedure Return_Parameter_Or_Global
5068 (Id : Entity_Id;
5069 Typ : Entity_Id;
5070 Kind : Formal_Kind;
5071 Subp : Entity_Id;
5072 Global_Var : Boolean)
5073 is
5074 begin
5075 -- Shallow parameters and globals need not be considered
5076
5077 if not Is_Deep (Typ) then
5078 return;
5079
5080 elsif Kind = E_In_Parameter then
5081
5082 -- Input global variables are observed only
5083
5084 if Global_Var then
5085 return;
5086
5087 -- Anonymous access to constant is an observe
5088
5089 elsif Is_Anonymous_Access_Type (Typ)
5090 and then Is_Access_Constant (Typ)
5091 then
5092 return;
5093
5094 -- Deep types other than access types define an observe
5095
5096 elsif not Is_Access_Type (Typ) then
5097 return;
5098 end if;
5099 end if;
5100
5101 -- All other parameters and globals should return with mode RW to the
5102 -- caller.
5103
5104 declare
5105 Tree : constant Perm_Tree_Access := Get (Current_Perm_Env, Id);
5106 begin
5107 if Permission (Tree) /= Read_Write then
5108 Perm_Error_Subprogram_End
5109 (E => Id,
5110 Subp => Subp,
5111 Perm => Read_Write,
5112 Found_Perm => Permission (Tree),
5113 Expl => Explanation (Tree));
5114 end if;
5115 end;
5116 end Return_Parameter_Or_Global;
5117
5118 -----------------------
5119 -- Return_Parameters --
5120 -----------------------
5121
5122 procedure Return_Parameters (Subp : Entity_Id) is
5123 Formal : Entity_Id;
5124 begin
5125 Formal := First_Formal (Subp);
5126 while Present (Formal) loop
5127 Return_Parameter_Or_Global
5128 (Id => Formal,
5129 Typ => Retysp (Etype (Formal)),
5130 Kind => Ekind (Formal),
5131 Subp => Subp,
5132 Global_Var => False);
5133 Next_Formal (Formal);
5134 end loop;
5135 end Return_Parameters;
5136
5137 -------------------------
5138 -- Set_Perm_Extensions --
5139 -------------------------
5140
5141 procedure Set_Perm_Extensions
5142 (T : Perm_Tree_Access;
5143 P : Perm_Kind;
5144 Expl : Node_Id) is
5145
5146 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access);
5147 -- Free the permission tree of children if any, prio to replacing T
5148
5149 -----------------------------
5150 -- Free_Perm_Tree_Children --
5151 -----------------------------
5152
5153 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access) is
5154 begin
5155 case Kind (T) is
5156 when Entire_Object =>
5157 null;
5158
5159 when Reference =>
5160 Free_Tree (T.all.Tree.Get_All);
5161
5162 when Array_Component =>
5163 Free_Tree (T.all.Tree.Get_Elem);
5164
5165 when Record_Component =>
5166 declare
5167 Hashtbl : Perm_Tree_Maps.Instance := Component (T);
5168 Comp : Perm_Tree_Access;
5169
5170 begin
5171 Comp := Perm_Tree_Maps.Get_First (Hashtbl);
5172 while Comp /= null loop
5173 Free_Tree (Comp);
5174 Comp := Perm_Tree_Maps.Get_Next (Hashtbl);
5175 end loop;
5176
5177 Perm_Tree_Maps.Reset (Hashtbl);
5178 end;
5179 end case;
5180 end Free_Perm_Tree_Children;
5181
5182 -- Start of processing for Set_Perm_Extensions
5183
5184 begin
5185 Free_Perm_Tree_Children (T);
5186 T.all.Tree := Perm_Tree'(Kind => Entire_Object,
5187 Is_Node_Deep => Is_Node_Deep (T),
5188 Explanation => Expl,
5189 Permission => Permission (T),
5190 Children_Permission => P);
5191 end Set_Perm_Extensions;
5192
5193 ------------------------------
5194 -- Set_Perm_Extensions_Move --
5195 ------------------------------
5196
5197 procedure Set_Perm_Extensions_Move
5198 (T : Perm_Tree_Access;
5199 E : Entity_Id;
5200 Expl : Node_Id)
5201 is
5202 Check_Ty : constant Entity_Id := Retysp (E);
5203 begin
5204 -- Shallow extensions are set to RW
5205
5206 if not Is_Node_Deep (T) then
5207 Set_Perm_Extensions (T, Read_Write, Expl => Expl);
5208 return;
5209 end if;
5210
5211 -- Deep extensions are set to W before .all and NO afterwards
5212
5213 T.all.Tree.Permission := Write_Only;
5214
5215 case T.all.Tree.Kind is
5216
5217 -- For a folded tree of composite type, unfold the tree for better
5218 -- precision.
5219
5220 when Entire_Object =>
5221 case Ekind (Check_Ty) is
5222 when E_Array_Type
5223 | E_Array_Subtype
5224 =>
5225 declare
5226 C : constant Perm_Tree_Access :=
5227 new Perm_Tree_Wrapper'
5228 (Tree =>
5229 (Kind => Entire_Object,
5230 Is_Node_Deep => Is_Node_Deep (T),
5231 Explanation => Expl,
5232 Permission => Read_Write,
5233 Children_Permission => Read_Write));
5234 begin
5235 Set_Perm_Extensions_Move
5236 (C, Component_Type (Check_Ty), Expl);
5237 T.all.Tree := (Kind => Array_Component,
5238 Is_Node_Deep => Is_Node_Deep (T),
5239 Explanation => Expl,
5240 Permission => Write_Only,
5241 Get_Elem => C);
5242 end;
5243
5244 when Record_Kind =>
5245 declare
5246 C : Perm_Tree_Access;
5247 Comp : Entity_Id;
5248 Hashtbl : Perm_Tree_Maps.Instance;
5249
5250 begin
5251 Comp := First_Component_Or_Discriminant (Check_Ty);
5252 while Present (Comp) loop
5253
5254 -- Unfold components which are visible in SPARK
5255
5256 if Component_Is_Visible_In_SPARK (Comp) then
5257 C := new Perm_Tree_Wrapper'
5258 (Tree =>
5259 (Kind => Entire_Object,
5260 Is_Node_Deep => Is_Deep (Etype (Comp)),
5261 Explanation => Expl,
5262 Permission => Read_Write,
5263 Children_Permission => Read_Write));
5264 Set_Perm_Extensions_Move (C, Etype (Comp), Expl);
5265
5266 -- Hidden components are never deep
5267
5268 else
5269 C := new Perm_Tree_Wrapper'
5270 (Tree =>
5271 (Kind => Entire_Object,
5272 Is_Node_Deep => False,
5273 Explanation => Expl,
5274 Permission => Read_Write,
5275 Children_Permission => Read_Write));
5276 Set_Perm_Extensions (C, Read_Write, Expl => Expl);
5277 end if;
5278
5279 Perm_Tree_Maps.Set
5280 (Hashtbl, Original_Record_Component (Comp), C);
5281 Next_Component_Or_Discriminant (Comp);
5282 end loop;
5283
5284 T.all.Tree :=
5285 (Kind => Record_Component,
5286 Is_Node_Deep => Is_Node_Deep (T),
5287 Explanation => Expl,
5288 Permission => Write_Only,
5289 Component => Hashtbl);
5290 end;
5291
5292 -- Otherwise, extensions are set to NO
5293
5294 when others =>
5295 Set_Perm_Extensions (T, No_Access, Expl);
5296 end case;
5297
5298 when Reference =>
5299 Set_Perm_Extensions (T, No_Access, Expl);
5300
5301 when Array_Component =>
5302 Set_Perm_Extensions_Move
5303 (Get_Elem (T), Component_Type (Check_Ty), Expl);
5304
5305 when Record_Component =>
5306 declare
5307 C : Perm_Tree_Access;
5308 Comp : Entity_Id;
5309
5310 begin
5311 Comp := First_Component_Or_Discriminant (Check_Ty);
5312 while Present (Comp) loop
5313 C := Perm_Tree_Maps.Get
5314 (Component (T), Original_Record_Component (Comp));
5315 pragma Assert (C /= null);
5316
5317 -- Move visible components
5318
5319 if Component_Is_Visible_In_SPARK (Comp) then
5320 Set_Perm_Extensions_Move (C, Etype (Comp), Expl);
5321
5322 -- Hidden components are never deep
5323
5324 else
5325 Set_Perm_Extensions (C, Read_Write, Expl => Expl);
5326 end if;
5327
5328 Next_Component_Or_Discriminant (Comp);
5329 end loop;
5330 end;
5331 end case;
5332 end Set_Perm_Extensions_Move;
5333
5334 -----------------------
5335 -- Set_Perm_Prefixes --
5336 -----------------------
5337
5338 function Set_Perm_Prefixes
5339 (N : Node_Id;
5340 Perm : Perm_Kind_Option;
5341 Expl : Node_Id) return Perm_Tree_Access
5342 is
5343 begin
5344 case Nkind (N) is
5345 when N_Expanded_Name
5346 | N_Identifier
5347 =>
5348 declare
5349 E : constant Entity_Id := Unique_Entity (Entity (N));
5350 C : constant Perm_Tree_Access := Get (Current_Perm_Env, E);
5351 pragma Assert (C /= null);
5352
5353 begin
5354 if Perm /= None then
5355 C.all.Tree.Permission := Glb (Perm, Permission (C));
5356 end if;
5357
5358 return C;
5359 end;
5360
5361 -- For a nonterminal path, we set the permission tree of its prefix,
5362 -- and then we extract from the returned pointer the subtree and
5363 -- assign an adequate permission to it, if unfolded. If folded,
5364 -- we unroll the tree one level.
5365
5366 when N_Explicit_Dereference =>
5367 declare
5368 C : constant Perm_Tree_Access :=
5369 Set_Perm_Prefixes (Prefix (N), Perm, Expl);
5370 pragma Assert (C /= null);
5371 pragma Assert (Kind (C) = Entire_Object
5372 or else Kind (C) = Reference);
5373 begin
5374 -- The tree is already unfolded. Replace the permission of the
5375 -- dereference.
5376
5377 if Kind (C) = Reference then
5378 declare
5379 D : constant Perm_Tree_Access := Get_All (C);
5380 pragma Assert (D /= null);
5381
5382 begin
5383 if Perm /= None then
5384 D.all.Tree.Permission := Glb (Perm, Permission (D));
5385 end if;
5386
5387 return D;
5388 end;
5389
5390 -- The tree is folded. Expand it.
5391
5392 else
5393 declare
5394 pragma Assert (Kind (C) = Entire_Object);
5395
5396 Child_P : constant Perm_Kind := Children_Permission (C);
5397 D : constant Perm_Tree_Access :=
5398 new Perm_Tree_Wrapper'
5399 (Tree =>
5400 (Kind => Entire_Object,
5401 Is_Node_Deep => Is_Deep (Etype (N)),
5402 Explanation => Expl,
5403 Permission => Child_P,
5404 Children_Permission => Child_P));
5405 begin
5406 if Perm /= None then
5407 D.all.Tree.Permission := Perm;
5408 end if;
5409
5410 C.all.Tree := (Kind => Reference,
5411 Is_Node_Deep => Is_Node_Deep (C),
5412 Explanation => Expl,
5413 Permission => Permission (C),
5414 Get_All => D);
5415 return D;
5416 end;
5417 end if;
5418 end;
5419
5420 when N_Selected_Component =>
5421 declare
5422 C : constant Perm_Tree_Access :=
5423 Set_Perm_Prefixes (Prefix (N), Perm, Expl);
5424 pragma Assert (C /= null);
5425 pragma Assert (Kind (C) = Entire_Object
5426 or else Kind (C) = Record_Component);
5427 begin
5428 -- The tree is already unfolded. Replace the permission of the
5429 -- component.
5430
5431 if Kind (C) = Record_Component then
5432 declare
5433 Comp : constant Entity_Id :=
5434 Original_Record_Component
5435 (Entity (Selector_Name (N)));
5436 D : constant Perm_Tree_Access :=
5437 Perm_Tree_Maps.Get (Component (C), Comp);
5438 pragma Assert (D /= null);
5439
5440 begin
5441 if Perm /= None then
5442 D.all.Tree.Permission := Glb (Perm, Permission (D));
5443 end if;
5444
5445 return D;
5446 end;
5447
5448 -- The tree is folded. Expand it.
5449
5450 else
5451 declare
5452 pragma Assert (Kind (C) = Entire_Object);
5453
5454 D : Perm_Tree_Access;
5455 D_This : Perm_Tree_Access;
5456 Comp : Node_Id;
5457 P : Perm_Kind;
5458 Child_P : constant Perm_Kind := Children_Permission (C);
5459 Hashtbl : Perm_Tree_Maps.Instance;
5460 -- Create an empty hash table
5461
5462 begin
5463 Comp :=
5464 First_Component_Or_Discriminant
5465 (Retysp (Etype (Prefix (N))));
5466
5467 while Present (Comp) loop
5468 if Perm /= None
5469 and then Original_Record_Component (Comp) =
5470 Original_Record_Component
5471 (Entity (Selector_Name (N)))
5472 then
5473 P := Perm;
5474 else
5475 P := Child_P;
5476 end if;
5477
5478 D := new Perm_Tree_Wrapper'
5479 (Tree =>
5480 (Kind => Entire_Object,
5481 Is_Node_Deep =>
5482 -- Hidden components are never deep
5483 Component_Is_Visible_In_SPARK (Comp)
5484 and then Is_Deep (Etype (Comp)),
5485 Explanation => Expl,
5486 Permission => P,
5487 Children_Permission => Child_P));
5488 Perm_Tree_Maps.Set
5489 (Hashtbl, Original_Record_Component (Comp), D);
5490
5491 -- Store the tree to return for this component
5492
5493 if Original_Record_Component (Comp) =
5494 Original_Record_Component
5495 (Entity (Selector_Name (N)))
5496 then
5497 D_This := D;
5498 end if;
5499
5500 Next_Component_Or_Discriminant (Comp);
5501 end loop;
5502
5503 C.all.Tree := (Kind => Record_Component,
5504 Is_Node_Deep => Is_Node_Deep (C),
5505 Explanation => Expl,
5506 Permission => Permission (C),
5507 Component => Hashtbl);
5508 return D_This;
5509 end;
5510 end if;
5511 end;
5512
5513 when N_Indexed_Component
5514 | N_Slice
5515 =>
5516 declare
5517 C : constant Perm_Tree_Access :=
5518 Set_Perm_Prefixes (Prefix (N), Perm, Expl);
5519 pragma Assert (C /= null);
5520 pragma Assert (Kind (C) = Entire_Object
5521 or else Kind (C) = Array_Component);
5522 begin
5523 -- The tree is already unfolded. Replace the permission of the
5524 -- component.
5525
5526 if Kind (C) = Array_Component then
5527 declare
5528 D : constant Perm_Tree_Access := Get_Elem (C);
5529 pragma Assert (D /= null);
5530
5531 begin
5532 if Perm /= None then
5533 D.all.Tree.Permission := Glb (Perm, Permission (D));
5534 end if;
5535
5536 return D;
5537 end;
5538
5539 -- The tree is folded. Expand it.
5540
5541 else
5542 declare
5543 pragma Assert (Kind (C) = Entire_Object);
5544
5545 Child_P : constant Perm_Kind := Children_Permission (C);
5546 D : constant Perm_Tree_Access :=
5547 new Perm_Tree_Wrapper'
5548 (Tree =>
5549 (Kind => Entire_Object,
5550 Is_Node_Deep => Is_Node_Deep (C),
5551 Explanation => Expl,
5552 Permission => Child_P,
5553 Children_Permission => Child_P));
5554 begin
5555 if Perm /= None then
5556 D.all.Tree.Permission := Perm;
5557 end if;
5558
5559 C.all.Tree := (Kind => Array_Component,
5560 Is_Node_Deep => Is_Node_Deep (C),
5561 Explanation => Expl,
5562 Permission => Permission (C),
5563 Get_Elem => D);
5564 return D;
5565 end;
5566 end if;
5567 end;
5568
5569 when N_Qualified_Expression
5570 | N_Type_Conversion
5571 | N_Unchecked_Type_Conversion
5572 =>
5573 return Set_Perm_Prefixes (Expression (N), Perm, Expl);
5574
5575 when others =>
5576 raise Program_Error;
5577 end case;
5578 end Set_Perm_Prefixes;
5579
5580 ------------------------------
5581 -- Set_Perm_Prefixes_Assign --
5582 ------------------------------
5583
5584 procedure Set_Perm_Prefixes_Assign (N : Node_Id) is
5585 C : constant Perm_Tree_Access := Get_Perm_Tree (N);
5586
5587 begin
5588 case Kind (C) is
5589 when Entire_Object =>
5590 pragma Assert (Children_Permission (C) = Read_Write);
5591 C.all.Tree.Permission := Read_Write;
5592
5593 when Reference =>
5594 C.all.Tree.Permission :=
5595 Lub (Permission (C), Permission (Get_All (C)));
5596
5597 when Array_Component =>
5598 null;
5599
5600 when Record_Component =>
5601 declare
5602 Comp : Perm_Tree_Access;
5603 Perm : Perm_Kind := Read_Write;
5604
5605 begin
5606 -- We take the Glb of all the descendants, and then update the
5607 -- permission of the node with it.
5608
5609 Comp := Perm_Tree_Maps.Get_First (Component (C));
5610 while Comp /= null loop
5611 Perm := Glb (Perm, Permission (Comp));
5612 Comp := Perm_Tree_Maps.Get_Next (Component (C));
5613 end loop;
5614
5615 C.all.Tree.Permission := Lub (Permission (C), Perm);
5616 end;
5617 end case;
5618
5619 case Nkind (N) is
5620
5621 -- Base identifier end recursion
5622
5623 when N_Expanded_Name
5624 | N_Identifier
5625 =>
5626 null;
5627
5628 when N_Explicit_Dereference
5629 | N_Indexed_Component
5630 | N_Selected_Component
5631 | N_Slice
5632 =>
5633 Set_Perm_Prefixes_Assign (Prefix (N));
5634
5635 when N_Qualified_Expression
5636 | N_Type_Conversion
5637 | N_Unchecked_Type_Conversion
5638 =>
5639 Set_Perm_Prefixes_Assign (Expression (N));
5640
5641 when others =>
5642 raise Program_Error;
5643 end case;
5644 end Set_Perm_Prefixes_Assign;
5645
5646 -------------------
5647 -- Setup_Globals --
5648 -------------------
5649
5650 procedure Setup_Globals (Subp : Entity_Id) is
5651
5652 procedure Setup_Global
5653 (Expr : Node_Id;
5654 Typ : Entity_Id;
5655 Kind : Formal_Kind;
5656 Subp : Entity_Id;
5657 Global_Var : Boolean);
5658 -- Proxy procedure to set up globals, to adjust for the type of first
5659 -- parameter expected by Setup_Parameter_Or_Global.
5660
5661 ------------------
5662 -- Setup_Global --
5663 ------------------
5664
5665 procedure Setup_Global
5666 (Expr : Node_Id;
5667 Typ : Entity_Id;
5668 Kind : Formal_Kind;
5669 Subp : Entity_Id;
5670 Global_Var : Boolean)
5671 is
5672 begin
5673 Setup_Parameter_Or_Global
5674 (Id => Entity (Expr),
5675 Typ => Typ,
5676 Kind => Kind,
5677 Subp => Subp,
5678 Global_Var => Global_Var,
5679 Expl => Expr);
5680 end Setup_Global;
5681
5682 procedure Setup_Globals_Inst is new Handle_Globals (Setup_Global);
5683
5684 -- Start of processing for Setup_Globals
5685
5686 begin
5687 Setup_Globals_Inst (Subp);
5688 end Setup_Globals;
5689
5690 -------------------------------
5691 -- Setup_Parameter_Or_Global --
5692 -------------------------------
5693
5694 procedure Setup_Parameter_Or_Global
5695 (Id : Entity_Id;
5696 Typ : Entity_Id;
5697 Kind : Formal_Kind;
5698 Subp : Entity_Id;
5699 Global_Var : Boolean;
5700 Expl : Node_Id)
5701 is
5702 Perm : Perm_Kind_Option;
5703
5704 begin
5705 case Kind is
5706 when E_In_Parameter =>
5707
5708 -- Shallow parameters and globals need not be considered
5709
5710 if not Is_Deep (Typ) then
5711 Perm := None;
5712
5713 -- Inputs of functions have R permission only
5714
5715 elsif Ekind (Subp) = E_Function then
5716 Perm := Read_Only;
5717
5718 -- Input global variables have R permission only
5719
5720 elsif Global_Var then
5721 Perm := Read_Only;
5722
5723 -- Anonymous access to constant is an observe
5724
5725 elsif Is_Anonymous_Access_Type (Typ)
5726 and then Is_Access_Constant (Typ)
5727 then
5728 Perm := Read_Only;
5729
5730 -- Other access types are a borrow
5731
5732 elsif Is_Access_Type (Typ) then
5733 Perm := Read_Write;
5734
5735 -- Deep types other than access types define an observe
5736
5737 else
5738 Perm := Read_Only;
5739 end if;
5740
5741 when E_Out_Parameter
5742 | E_In_Out_Parameter
5743 =>
5744 -- Shallow parameters and globals need not be considered
5745
5746 if not Is_Deep (Typ) then
5747 Perm := None;
5748
5749 -- Functions cannot have outputs in SPARK
5750
5751 elsif Ekind (Subp) = E_Function then
5752 return;
5753
5754 -- Deep types define a borrow or a move
5755
5756 else
5757 Perm := Read_Write;
5758 end if;
5759 end case;
5760
5761 if Perm /= None then
5762 declare
5763 Tree : constant Perm_Tree_Access :=
5764 new Perm_Tree_Wrapper'
5765 (Tree =>
5766 (Kind => Entire_Object,
5767 Is_Node_Deep => Is_Deep (Etype (Id)),
5768 Explanation => Expl,
5769 Permission => Perm,
5770 Children_Permission => Perm));
5771 begin
5772 Set (Current_Perm_Env, Id, Tree);
5773 end;
5774 end if;
5775 end Setup_Parameter_Or_Global;
5776
5777 ----------------------
5778 -- Setup_Parameters --
5779 ----------------------
5780
5781 procedure Setup_Parameters (Subp : Entity_Id) is
5782 Formal : Entity_Id;
5783 begin
5784 Formal := First_Formal (Subp);
5785 while Present (Formal) loop
5786 Setup_Parameter_Or_Global
5787 (Id => Formal,
5788 Typ => Retysp (Etype (Formal)),
5789 Kind => Ekind (Formal),
5790 Subp => Subp,
5791 Global_Var => False,
5792 Expl => Formal);
5793 Next_Formal (Formal);
5794 end loop;
5795 end Setup_Parameters;
5796
5797 --------------------------------
5798 -- Setup_Protected_Components --
5799 --------------------------------
5800
5801 procedure Setup_Protected_Components (Subp : Entity_Id) is
5802 Typ : constant Entity_Id := Scope (Subp);
5803 Comp : Entity_Id;
5804 Kind : Formal_Kind;
5805
5806 begin
5807 Comp := First_Component_Or_Discriminant (Typ);
5808
5809 -- The protected object is an implicit input of protected functions, and
5810 -- an implicit input-output of protected procedures and entries.
5811
5812 if Ekind (Subp) = E_Function then
5813 Kind := E_In_Parameter;
5814 else
5815 Kind := E_In_Out_Parameter;
5816 end if;
5817
5818 while Present (Comp) loop
5819 Setup_Parameter_Or_Global
5820 (Id => Comp,
5821 Typ => Retysp (Etype (Comp)),
5822 Kind => Kind,
5823 Subp => Subp,
5824 Global_Var => False,
5825 Expl => Comp);
5826
5827 Next_Component_Or_Discriminant (Comp);
5828 end loop;
5829 end Setup_Protected_Components;
5830
5831 end Sem_SPARK;