]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ada/sem_spark.adb
[Ada] SPARK support for pointers through ownership
[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
51 Elaboration_Context_Max : constant := 1009;
52 -- The hash range
53
54 type Elaboration_Context_Index is range 0 .. Elaboration_Context_Max - 1;
55
56 function Elaboration_Context_Hash
57 (Key : Entity_Id) return Elaboration_Context_Index;
58 -- The hash function
59
60 -- Permission type associated with paths. These are related to but not
61 -- the same as the states associated with names used in SPARK RM 3.10:
62 -- Unrestricted, Observed, Borrowed, Moved. When ownership rules lead to
63 -- a state change for a name, this may correspond to multiple permission
64 -- changes for the paths corresponding to the name, its prefixes, and
65 -- its extensions. For example, when an object is assigned to, the
66 -- corresponding name gets into state Moved, while the path for the name
67 -- gets permission Write_Only as well as every prefix of the name, and
68 -- every suffix gets permission No_Access.
69
70 type Perm_Kind_Option is
71 (None,
72 -- Special value used when no permission is passed around
73
74 No_Access,
75 -- The path cannot be accessed for reading or writing. This is the
76 -- case for the path of a name in the Borrowed state.
77
78 Read_Only,
79 -- The path can only be accessed for reading. This is the case for
80 -- the path of a name in the Observed state.
81
82 Read_Write,
83 -- The path can be accessed for both reading and writing. This is the
84 -- case for the path of a name in the Unrestricted state.
85
86 Write_Only
87 -- The path can only be accessed for writing. This is the case for
88 -- the path of a name in the Moved state.
89 );
90
91 subtype Perm_Kind is Perm_Kind_Option range No_Access .. Write_Only;
92 subtype Read_Perm is Perm_Kind range Read_Only .. Read_Write;
93 subtype Write_Perm is Perm_Kind range Read_Write .. Write_Only;
94
95 type Perm_Tree_Wrapper;
96
97 type Perm_Tree_Access is access Perm_Tree_Wrapper;
98 -- A tree of permissions is defined, where the root is a whole object
99 -- and tree branches follow access paths in memory. As Perm_Tree is a
100 -- discriminated record, a wrapper type is used for the access type
101 -- designating a subtree, to make it unconstrained so that it can be
102 -- updated.
103
104 -- Nodes in the permission tree are of different kinds
105
106 type Path_Kind is
107 (Entire_Object, -- Scalar object, or folded object of any type
108 Reference, -- Unfolded object of access type
109 Array_Component, -- Unfolded object of array type
110 Record_Component -- Unfolded object of record type
111 );
112
113 package Perm_Tree_Maps is new Simple_HTable
114 (Header_Num => Elaboration_Context_Index,
115 Key => Entity_Id,
116 Element => Perm_Tree_Access,
117 No_Element => null,
118 Hash => Elaboration_Context_Hash,
119 Equal => "=");
120 -- The instantation of a hash table, with keys being entities and values
121 -- being pointers to permission trees. This is used to define global
122 -- environment permissions (entities in that case are stand-alone
123 -- objects or formal parameters), as well as the permissions for the
124 -- extensions of a Record_Component node (entities in that case are
125 -- record components).
126
127 -- The definition of permission trees. This is a tree, which has a
128 -- permission at each node, and depending on the type of the node, can
129 -- have zero, one, or more children reached through an access to tree.
130
131 type Perm_Tree (Kind : Path_Kind := Entire_Object) is record
132 Permission : Perm_Kind;
133 -- Permission at this level in the path
134
135 Is_Node_Deep : Boolean;
136 -- Whether this node is of a "deep" type, i.e. an access type or a
137 -- composite type containing access type subcomponents. This
138 -- corresponds to both "observing" and "owning" types in SPARK RM
139 -- 3.10. To be used when moving the path.
140
141 case Kind is
142 -- An entire object is either a leaf (an object which cannot be
143 -- extended further in a path) or a subtree in folded form (which
144 -- could later be unfolded further in another kind of node). The
145 -- field Children_Permission specifies a permission for every
146 -- extension of that node if that permission is different from the
147 -- node's permission.
148
149 when Entire_Object =>
150 Children_Permission : Perm_Kind;
151
152 -- Unfolded path of access type. The permission of the object
153 -- pointed to is given in Get_All.
154
155 when Reference =>
156 Get_All : Perm_Tree_Access;
157
158 -- Unfolded path of array type. The permission of elements is
159 -- given in Get_Elem.
160
161 when Array_Component =>
162 Get_Elem : Perm_Tree_Access;
163
164 -- Unfolded path of record type. The permission of the components
165 -- is given in Component.
166
167 when Record_Component =>
168 Component : Perm_Tree_Maps.Instance;
169 end case;
170 end record;
171
172 type Perm_Tree_Wrapper is record
173 Tree : Perm_Tree;
174 end record;
175 -- We use this wrapper in order to have unconstrained discriminants
176
177 type Perm_Env is new Perm_Tree_Maps.Instance;
178 -- The definition of a permission environment for the analysis. This is
179 -- just a hash table from entities to permission trees.
180
181 type Perm_Env_Access is access Perm_Env;
182 -- Access to permission environments
183
184 package Env_Maps is new Simple_HTable
185 (Header_Num => Elaboration_Context_Index,
186 Key => Entity_Id,
187 Element => Perm_Env_Access,
188 No_Element => null,
189 Hash => Elaboration_Context_Hash,
190 Equal => "=");
191 -- The instantiation of a hash table whose elements are permission
192 -- environments. This hash table is used to save the environments at
193 -- the entry of each loop, with the key being the loop label.
194
195 type Env_Backups is new Env_Maps.Instance;
196 -- The type defining the hash table saving the environments at the entry
197 -- of each loop.
198
199 --------------------
200 -- Simple Getters --
201 --------------------
202
203 -- Simple getters to avoid having .all.Tree.Field everywhere. Of course,
204 -- that's only for the top access, as otherwise this reverses the order
205 -- in accesses visually.
206
207 function Children_Permission (T : Perm_Tree_Access) return Perm_Kind;
208 function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance;
209 function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access;
210 function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access;
211 function Is_Node_Deep (T : Perm_Tree_Access) return Boolean;
212 function Kind (T : Perm_Tree_Access) return Path_Kind;
213 function Permission (T : Perm_Tree_Access) return Perm_Kind;
214
215 -----------------------
216 -- Memory Management --
217 -----------------------
218
219 procedure Copy_Env
220 (From : Perm_Env;
221 To : in out Perm_Env);
222 -- Procedure to copy a permission environment
223
224 procedure Move_Env
225 (From : in out Perm_Env;
226 To : in out Perm_Env);
227 -- Procedure to move a permission environment. It frees To, moves From
228 -- in To and sets From to Nil.
229
230 procedure Copy_Tree
231 (From : Perm_Tree_Access;
232 To : Perm_Tree_Access);
233 -- Procedure to copy a permission tree
234
235 procedure Free_Env (PE : in out Perm_Env);
236 -- Procedure to free a permission environment
237
238 procedure Free_Tree (PT : in out Perm_Tree_Access);
239 -- Procedure to free a permission tree
240
241 --------------------
242 -- Error Messages --
243 --------------------
244
245 procedure Perm_Mismatch
246 (N : Node_Id;
247 Exp_Perm : Perm_Kind;
248 Act_Perm : Perm_Kind;
249 Forbidden_Perm : Boolean := False);
250 -- Issues a continuation error message about a mismatch between a
251 -- desired permission Exp_Perm and a permission obtained Act_Perm. N
252 -- is the node on which the error is reported.
253
254 end Permissions;
255
256 package body Permissions is
257
258 -------------------------
259 -- Children_Permission --
260 -------------------------
261
262 function Children_Permission (T : Perm_Tree_Access) return Perm_Kind is
263 begin
264 return T.all.Tree.Children_Permission;
265 end Children_Permission;
266
267 ---------------
268 -- Component --
269 ---------------
270
271 function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance
272 is
273 begin
274 return T.all.Tree.Component;
275 end Component;
276
277 --------------
278 -- Copy_Env --
279 --------------
280
281 procedure Copy_Env (From : Perm_Env; To : in out Perm_Env) is
282 Comp_From : Perm_Tree_Access;
283 Key_From : Perm_Tree_Maps.Key_Option;
284 Son : Perm_Tree_Access;
285
286 begin
287 Free_Env (To);
288 Key_From := Get_First_Key (From);
289 while Key_From.Present loop
290 Comp_From := Get (From, Key_From.K);
291 pragma Assert (Comp_From /= null);
292
293 Son := new Perm_Tree_Wrapper;
294 Copy_Tree (Comp_From, Son);
295
296 Set (To, Key_From.K, Son);
297 Key_From := Get_Next_Key (From);
298 end loop;
299 end Copy_Env;
300
301 ---------------
302 -- Copy_Tree --
303 ---------------
304
305 procedure Copy_Tree (From : Perm_Tree_Access; To : Perm_Tree_Access) is
306 begin
307 -- Copy the direct components of the tree
308
309 To.all := From.all;
310
311 -- Now reallocate access components for a deep copy of the tree
312
313 case Kind (From) is
314 when Entire_Object =>
315 null;
316
317 when Reference =>
318 To.all.Tree.Get_All := new Perm_Tree_Wrapper;
319 Copy_Tree (Get_All (From), Get_All (To));
320
321 when Array_Component =>
322 To.all.Tree.Get_Elem := new Perm_Tree_Wrapper;
323 Copy_Tree (Get_Elem (From), Get_Elem (To));
324
325 when Record_Component =>
326 declare
327 Comp_From : Perm_Tree_Access;
328 Key_From : Perm_Tree_Maps.Key_Option;
329 Son : Perm_Tree_Access;
330 Hash_Table : Perm_Tree_Maps.Instance;
331 begin
332 -- We put a new hash table, so that it gets dealiased from
333 -- the Component (From) hash table.
334 To.all.Tree.Component := Hash_Table;
335 Key_From := Perm_Tree_Maps.Get_First_Key
336 (Component (From));
337
338 while Key_From.Present loop
339 Comp_From := Perm_Tree_Maps.Get
340 (Component (From), Key_From.K);
341 pragma Assert (Comp_From /= null);
342 Son := new Perm_Tree_Wrapper;
343 Copy_Tree (Comp_From, Son);
344 Perm_Tree_Maps.Set
345 (To.all.Tree.Component, Key_From.K, Son);
346 Key_From := Perm_Tree_Maps.Get_Next_Key
347 (Component (From));
348 end loop;
349 end;
350 end case;
351 end Copy_Tree;
352
353 ------------------------------
354 -- Elaboration_Context_Hash --
355 ------------------------------
356
357 function Elaboration_Context_Hash
358 (Key : Entity_Id) return Elaboration_Context_Index
359 is
360 begin
361 return Elaboration_Context_Index (Key mod Elaboration_Context_Max);
362 end Elaboration_Context_Hash;
363
364 --------------
365 -- Free_Env --
366 --------------
367
368 procedure Free_Env (PE : in out Perm_Env) is
369 CompO : Perm_Tree_Access;
370 begin
371 CompO := Get_First (PE);
372 while CompO /= null loop
373 Free_Tree (CompO);
374 CompO := Get_Next (PE);
375 end loop;
376
377 Reset (PE);
378 end Free_Env;
379
380 ---------------
381 -- Free_Tree --
382 ---------------
383
384 procedure Free_Tree (PT : in out Perm_Tree_Access) is
385 procedure Free_Perm_Tree_Dealloc is
386 new Ada.Unchecked_Deallocation
387 (Perm_Tree_Wrapper, Perm_Tree_Access);
388 -- The deallocator for permission_trees
389
390 begin
391 case Kind (PT) is
392 when Entire_Object =>
393 null;
394
395 when Reference =>
396 Free_Tree (PT.all.Tree.Get_All);
397
398 when Array_Component =>
399 Free_Tree (PT.all.Tree.Get_Elem);
400
401 when Record_Component =>
402 declare
403 Comp : Perm_Tree_Access;
404
405 begin
406 Comp := Perm_Tree_Maps.Get_First (Component (PT));
407 while Comp /= null loop
408
409 -- Free every Component subtree
410
411 Free_Tree (Comp);
412 Comp := Perm_Tree_Maps.Get_Next (Component (PT));
413 end loop;
414 end;
415 end case;
416
417 Free_Perm_Tree_Dealloc (PT);
418 end Free_Tree;
419
420 -------------
421 -- Get_All --
422 -------------
423
424 function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access is
425 begin
426 return T.all.Tree.Get_All;
427 end Get_All;
428
429 --------------
430 -- Get_Elem --
431 --------------
432
433 function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access is
434 begin
435 return T.all.Tree.Get_Elem;
436 end Get_Elem;
437
438 ------------------
439 -- Is_Node_Deep --
440 ------------------
441
442 function Is_Node_Deep (T : Perm_Tree_Access) return Boolean is
443 begin
444 return T.all.Tree.Is_Node_Deep;
445 end Is_Node_Deep;
446
447 ----------
448 -- Kind --
449 ----------
450
451 function Kind (T : Perm_Tree_Access) return Path_Kind is
452 begin
453 return T.all.Tree.Kind;
454 end Kind;
455
456 --------------
457 -- Move_Env --
458 --------------
459
460 procedure Move_Env (From : in out Perm_Env; To : in out Perm_Env) is
461 begin
462 Free_Env (To);
463 To := From;
464 From := Perm_Env (Perm_Tree_Maps.Nil);
465 end Move_Env;
466
467 ----------------
468 -- Permission --
469 ----------------
470
471 function Permission (T : Perm_Tree_Access) return Perm_Kind is
472 begin
473 return T.all.Tree.Permission;
474 end Permission;
475
476 -------------------
477 -- Perm_Mismatch --
478 -------------------
479
480 procedure Perm_Mismatch
481 (N : Node_Id;
482 Exp_Perm : Perm_Kind;
483 Act_Perm : Perm_Kind;
484 Forbidden_Perm : Boolean := False)
485 is
486 begin
487 if Forbidden_Perm then
488 if Exp_Perm = Act_Perm then
489 Error_Msg_N ("\got forbidden state `"
490 & Perm_Kind'Image (Exp_Perm), N);
491 else
492 Error_Msg_N ("\forbidden state `"
493 & Perm_Kind'Image (Exp_Perm) & "`, got `"
494 & Perm_Kind'Image (Act_Perm) & "`", N);
495 end if;
496 else
497 Error_Msg_N ("\expected state `"
498 & Perm_Kind'Image (Exp_Perm) & "` at least, got `"
499 & Perm_Kind'Image (Act_Perm) & "`", N);
500 end if;
501 end Perm_Mismatch;
502
503 end Permissions;
504
505 use Permissions;
506
507 --------------------------------------
508 -- Analysis modes for AST traversal --
509 --------------------------------------
510
511 -- The different modes for analysis. This allows checking whether a path
512 -- has the right permission, and also updating permissions when a path is
513 -- moved, borrowed, or observed.
514
515 type Checking_Mode is
516
517 (Read,
518 -- Default mode
519
520 Move,
521 -- Move semantics. Checks that paths have Read_Write permission. After
522 -- moving a path, its permission and the permission of its prefixes are
523 -- set to Write_Only, while the permission of its extensions is set to
524 -- No_Access.
525
526 Assign,
527 -- Used for the target of an assignment, or an actual parameter with
528 -- mode OUT. Checks that paths have Write_Perm permission. After
529 -- assigning to a path, its permission and the permission of its
530 -- extensions are set to Read_Write. The permission of its prefixes may
531 -- be normalized from Write_Only to Read_Write depending on other
532 -- permissions in the tree (a prefix gets permission Read_Write when all
533 -- its extensions become Read_Write).
534
535 Borrow,
536 -- Borrow semantics. Checks that paths have Read_Write permission. After
537 -- borrowing a path, its permission and the permission of its prefixes
538 -- and extensions are set to No_Access.
539
540 Observe
541 -- Observe semantics. Checks that paths have Read_Perm permission. After
542 -- observing a path, its permission and the permission of its prefixes
543 -- and extensions are set to Read_Only.
544 );
545
546 type Result_Kind is (Folded, Unfolded);
547 -- The type declaration to discriminate in the Perm_Or_Tree type
548
549 -- The result type of the function Get_Perm_Or_Tree. This returns either a
550 -- tree when it found the appropriate tree, or a permission when the search
551 -- finds a leaf and the subtree we are looking for is folded. In the last
552 -- case, we return instead the Children_Permission field of the leaf.
553
554 type Perm_Or_Tree (R : Result_Kind) is record
555 case R is
556 when Folded => Found_Permission : Perm_Kind;
557 when Unfolded => Tree_Access : Perm_Tree_Access;
558 end case;
559 end record;
560
561 type Error_Status is (OK, Error);
562
563 -----------------------
564 -- Local subprograms --
565 -----------------------
566
567 function "<=" (P1, P2 : Perm_Kind) return Boolean;
568 function ">=" (P1, P2 : Perm_Kind) return Boolean;
569 function Glb (P1, P2 : Perm_Kind) return Perm_Kind;
570 function Lub (P1, P2 : Perm_Kind) return Perm_Kind;
571
572 procedure Check_Assignment (Target : Node_Or_Entity_Id; Expr : Node_Id);
573 -- Handle assignment as part of an assignment statement or an object
574 -- declaration.
575
576 procedure Check_Call_Statement (Call : Node_Id);
577
578 procedure Check_Callable_Body (Body_N : Node_Id);
579 -- Entry point for the analysis of a subprogram or entry body
580
581 procedure Check_Declaration (Decl : Node_Id);
582
583 procedure Check_Expression (Expr : Node_Id; Mode : Checking_Mode);
584 pragma Precondition (Nkind_In (Expr, N_Index_Or_Discriminant_Constraint,
585 N_Range_Constraint,
586 N_Subtype_Indication)
587 or else Nkind (Expr) in N_Subexpr);
588
589 procedure Check_Globals (Subp : Entity_Id);
590 -- This procedure takes a subprogram called and checks the permission of
591 -- globals.
592
593 -- Checking proceduress for safe pointer usage. These procedures traverse
594 -- the AST, check nodes for correct permissions according to SPARK RM 3.10,
595 -- and update permissions depending on the node kind. The main procedure
596 -- Check_Node is mutually recursive with the specialized procedures that
597 -- follow.
598
599 procedure Check_List (L : List_Id);
600 -- Calls Check_Node on each element of the list
601
602 procedure Check_Loop_Statement (Stmt : Node_Id);
603
604 procedure Check_Node (N : Node_Id);
605 -- Main traversal procedure to check safe pointer usage
606
607 procedure Check_Package_Body (Pack : Node_Id);
608
609 procedure Check_Package_Spec (Pack : Node_Id);
610
611 procedure Check_Parameter_Or_Global
612 (Expr : Node_Id;
613 Param_Mode : Formal_Kind;
614 Subp : Entity_Id;
615 Global_Var : Boolean);
616 -- Check the permission of every actual parameter or global
617
618 procedure Check_Source_Of_Borrow_Or_Observe
619 (Expr : Node_Id;
620 Status : out Error_Status);
621
622 procedure Check_Statement (Stmt : Node_Id);
623
624 procedure Check_Type (Typ : Entity_Id);
625 -- Check that type Typ is either not deep, or that it is an observing or
626 -- owning type according to SPARK RM 3.10
627
628 function Get_Perm (N : Node_Or_Entity_Id) return Perm_Kind;
629 -- The function that takes a name as input and returns a permission
630 -- associated with it.
631
632 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree;
633 pragma Precondition (Is_Path_Expression (N));
634 -- This function gets a node and looks recursively to find the appropriate
635 -- subtree for that node. If the tree is folded on that node, then it
636 -- returns the permission given at the right level.
637
638 function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access;
639 pragma Precondition (Is_Path_Expression (N));
640 -- This function gets a node and looks recursively to find the appropriate
641 -- subtree for that node. If the tree is folded, then it unrolls the tree
642 -- up to the appropriate level.
643
644 function Get_Root_Object (Expr : Node_Id) return Entity_Id;
645 pragma Precondition (Is_Path_Expression (Expr));
646 -- Return the root of the path expression Expr, or Empty for an allocator,
647 -- NULL, or a function call.
648
649 generic
650 with procedure Handle_Parameter_Or_Global
651 (Expr : Node_Id;
652 Param_Mode : Formal_Kind;
653 Subp : Entity_Id;
654 Global_Var : Boolean);
655 procedure Handle_Globals (Subp : Entity_Id);
656 -- Handling of globals is factored in a generic instantiated below
657
658 function Has_Array_Component (Expr : Node_Id) return Boolean;
659 pragma Precondition (Is_Path_Expression (Expr));
660 -- This function gets a node and looks recursively to determine whether the
661 -- given path has any array component.
662
663 procedure Hp (P : Perm_Env);
664 -- A procedure that outputs the hash table. This function is used only in
665 -- the debugger to look into a hash table.
666 pragma Unreferenced (Hp);
667
668 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id);
669 pragma No_Return (Illegal_Global_Usage);
670 -- A procedure that is called when deep globals or aliased globals are used
671 -- without any global aspect.
672
673 function Is_Deep (Typ : Entity_Id) return Boolean;
674 -- A function that can tell if a type is deep or not. Returns true if the
675 -- type passed as argument is deep.
676
677 function Is_Path_Expression (Expr : Node_Id) return Boolean;
678 -- Return whether Expr corresponds to a path
679
680 function Is_Traversal_Function (E : Entity_Id) return Boolean;
681
682 function Loop_Of_Exit (N : Node_Id) return Entity_Id;
683 -- A function that takes an exit statement node and returns the entity of
684 -- the loop that this statement is exiting from.
685
686 procedure Merge_Env (Source : in out Perm_Env; Target : in out Perm_Env);
687 -- Merge Target and Source into Target, and then deallocate the Source
688
689 procedure Perm_Error
690 (N : Node_Id;
691 Perm : Perm_Kind;
692 Found_Perm : Perm_Kind;
693 Forbidden_Perm : Boolean := False);
694 -- A procedure that is called when the permissions found contradict the
695 -- rules established by the RM. This function is called with the node and
696 -- the permission that was expected, and issues an error message with the
697 -- appropriate values.
698
699 procedure Perm_Error_Subprogram_End
700 (E : Entity_Id;
701 Subp : Entity_Id;
702 Perm : Perm_Kind;
703 Found_Perm : Perm_Kind);
704 -- A procedure that is called when the permissions found contradict the
705 -- rules established by the RM at the end of subprograms. This function is
706 -- called with the node, the node of the returning function, and the
707 -- permission that was expected, and adds an error message with the
708 -- appropriate values.
709
710 procedure Process_Path (Expr : Node_Id; Mode : Checking_Mode);
711 pragma Precondition (Is_Path_Expression (Expr));
712 -- Check correct permission for the path in the checking mode Mode, and
713 -- update permissions of the path and its prefixes/extensions.
714
715 procedure Return_Globals (Subp : Entity_Id);
716 -- Takes a subprogram as input, and checks that all borrowed global items
717 -- of the subprogram indeed have Read_Write permission at the end of the
718 -- subprogram execution.
719
720 procedure Return_Parameter_Or_Global
721 (Id : Entity_Id;
722 Mode : Formal_Kind;
723 Subp : Entity_Id;
724 Global_Var : Boolean);
725 -- Auxiliary procedure to Return_Parameters and Return_Globals
726
727 procedure Return_Parameters (Subp : Entity_Id);
728 -- Takes a subprogram as input, and checks that all out parameters of the
729 -- subprogram indeed have Read_Write permission at the end of the
730 -- subprogram execution.
731
732 procedure Set_Perm_Extensions (T : Perm_Tree_Access; P : Perm_Kind);
733 -- This procedure takes an access to a permission tree and modifies the
734 -- tree so that any strict extensions of the given tree become of the
735 -- access specified by parameter P.
736
737 procedure Set_Perm_Extensions_Move (T : Perm_Tree_Access; E : Entity_Id);
738 -- Set permissions to
739 -- No for any extension with more .all
740 -- W for any deep extension with same number of .all
741 -- RW for any shallow extension with same number of .all
742
743 function Set_Perm_Prefixes
744 (N : Node_Id;
745 Perm : Perm_Kind_Option) return Perm_Tree_Access;
746 pragma Precondition (Is_Path_Expression (N));
747 -- This function modifies the permissions of a given node in the permission
748 -- environment as well as all the prefixes of the path, to the new
749 -- permission Perm. The general rule here is that everybody updates the
750 -- permission of the subtree they are returning.
751
752 procedure Set_Perm_Prefixes_Assign (N : Node_Id);
753 pragma Precondition (Is_Path_Expression (N));
754 -- This procedure takes a name as an input and sets in the permission
755 -- tree the given permission to the given name. The general rule here is
756 -- that everybody updates the permission of the subtree it is returning.
757 -- The permission of the assigned path has been set to RW by the caller.
758 --
759 -- Case where we have to normalize a tree after the correct permissions
760 -- have been assigned already. We look for the right subtree at the given
761 -- path, actualize its permissions, and then call the normalization on its
762 -- parent.
763 --
764 -- Example: We assign x.y and x.z, and then Set_Perm_Prefixes_Assign will
765 -- change the permission of x to RW because all of its components have
766 -- permission RW.
767
768 procedure Setup_Globals (Subp : Entity_Id);
769 -- Takes a subprogram as input, and sets up the environment by adding
770 -- global items with appropriate permissions.
771
772 procedure Setup_Parameter_Or_Global
773 (Id : Entity_Id;
774 Param_Mode : Formal_Kind;
775 Subp : Entity_Id;
776 Global_Var : Boolean);
777 -- Auxiliary procedure to Setup_Parameters and Setup_Globals
778
779 procedure Setup_Parameters (Subp : Entity_Id);
780 -- Takes a subprogram as input, and sets up the environment by adding
781 -- formal parameters with appropriate permissions.
782
783 ----------------------
784 -- Global Variables --
785 ----------------------
786
787 Current_Perm_Env : Perm_Env;
788 -- The permission environment that is used for the analysis. This
789 -- environment can be saved, modified, reinitialized, but should be the
790 -- only one valid from which to extract the permissions of the paths in
791 -- scope. The analysis ensures at each point that this variables contains
792 -- a valid permission environment with all bindings in scope.
793
794 Inside_Procedure_Call : Boolean := False;
795 -- Set while checking the actual parameters of a procedure or entry call
796
797 Inside_Elaboration : Boolean := False;
798 -- Set during package spec/body elaboration, during which move and local
799 -- observe/borrow are not allowed. As a result, no other checking is needed
800 -- during elaboration.
801
802 Current_Loops_Envs : Env_Backups;
803 -- This variable contains saves of permission environments at each loop the
804 -- analysis entered. Each saved environment can be reached with the label
805 -- of the loop.
806
807 Current_Loops_Accumulators : Env_Backups;
808 -- This variable contains the environments used as accumulators for loops,
809 -- that consist of the merge of all environments at each exit point of
810 -- the loop (which can also be the entry point of the loop in the case of
811 -- non-infinite loops), each of them reachable from the label of the loop.
812 -- We require that the environment stored in the accumulator be less
813 -- restrictive than the saved environment at the beginning of the loop, and
814 -- the permission environment after the loop is equal to the accumulator.
815
816 --------------------
817 -- Handle_Globals --
818 --------------------
819
820 -- Generic procedure is defined first so that instantiations can be defined
821 -- anywhere afterwards.
822
823 procedure Handle_Globals (Subp : Entity_Id) is
824
825 -- Local subprograms
826
827 procedure Handle_Globals_From_List
828 (First_Item : Node_Id;
829 Kind : Formal_Kind);
830 -- Handle global items from the list starting at Item
831
832 procedure Handle_Globals_Of_Mode (Global_Mode : Name_Id);
833 -- Handle global items for the mode Global_Mode
834
835 ------------------------------
836 -- Handle_Globals_From_List --
837 ------------------------------
838
839 procedure Handle_Globals_From_List
840 (First_Item : Node_Id;
841 Kind : Formal_Kind)
842 is
843 Item : Node_Id := First_Item;
844 E : Entity_Id;
845
846 begin
847 while Present (Item) loop
848 E := Entity (Item);
849
850 -- Ignore abstract states, which play no role in pointer aliasing
851
852 if Ekind (E) = E_Abstract_State then
853 null;
854 else
855 Handle_Parameter_Or_Global (Expr => Item,
856 Param_Mode => Kind,
857 Subp => Subp,
858 Global_Var => True);
859 end if;
860 Next_Global (Item);
861 end loop;
862 end Handle_Globals_From_List;
863
864 ----------------------------
865 -- Handle_Globals_Of_Mode --
866 ----------------------------
867
868 procedure Handle_Globals_Of_Mode (Global_Mode : Name_Id) is
869 Kind : Formal_Kind;
870
871 begin
872 case Global_Mode is
873 when Name_Input
874 | Name_Proof_In
875 =>
876 Kind := E_In_Parameter;
877
878 when Name_Output =>
879 Kind := E_Out_Parameter;
880
881 when Name_In_Out =>
882 Kind := E_In_Out_Parameter;
883
884 when others =>
885 raise Program_Error;
886 end case;
887
888 -- Check both global items from Global and Refined_Global pragmas
889
890 Handle_Globals_From_List (First_Global (Subp, Global_Mode), Kind);
891 Handle_Globals_From_List
892 (First_Global (Subp, Global_Mode, Refined => True), Kind);
893 end Handle_Globals_Of_Mode;
894
895 -- Start of processing for Handle_Globals
896
897 begin
898 Handle_Globals_Of_Mode (Name_Proof_In);
899 Handle_Globals_Of_Mode (Name_Input);
900 Handle_Globals_Of_Mode (Name_Output);
901 Handle_Globals_Of_Mode (Name_In_Out);
902 end Handle_Globals;
903
904 ----------
905 -- "<=" --
906 ----------
907
908 function "<=" (P1, P2 : Perm_Kind) return Boolean is
909 begin
910 return P2 >= P1;
911 end "<=";
912
913 ----------
914 -- ">=" --
915 ----------
916
917 function ">=" (P1, P2 : Perm_Kind) return Boolean is
918 begin
919 case P2 is
920 when No_Access => return True;
921 when Read_Only => return P1 in Read_Perm;
922 when Write_Only => return P1 in Write_Perm;
923 when Read_Write => return P1 = Read_Write;
924 end case;
925 end ">=";
926
927 ----------------------
928 -- Check_Assignment --
929 ----------------------
930
931 procedure Check_Assignment (Target : Node_Or_Entity_Id; Expr : Node_Id) is
932 Target_Typ : constant Node_Id := Etype (Target);
933 Target_Root : Entity_Id;
934 Expr_Root : Entity_Id;
935 Perm : Perm_Kind;
936 Status : Error_Status;
937
938 begin
939 Check_Type (Target_Typ);
940
941 if Is_Anonymous_Access_Type (Target_Typ) then
942 Check_Source_Of_Borrow_Or_Observe (Expr, Status);
943
944 if Status /= OK then
945 return;
946 end if;
947
948 if Nkind (Target) = N_Defining_Identifier then
949 Target_Root := Target;
950 else
951 Target_Root := Get_Root_Object (Target);
952 end if;
953
954 Expr_Root := Get_Root_Object (Expr);
955
956 -- SPARK RM 3.10(8): For an assignment statement where
957 -- the target is a stand-alone object of an anonymous
958 -- access-to-object type
959
960 pragma Assert
961 (Ekind_In (Target_Root, E_Variable, E_Constant));
962
963 -- If the type of the target is an anonymous
964 -- access-to-constant type (an observing access type), the
965 -- source shall be an owning access object denoted by a name
966 -- that is not in the Moved state, and whose root object
967 -- is not in the Moved state and is not declared at a
968 -- statically deeper accessibility level than that of
969 -- the target object.
970
971 if Is_Access_Constant (Target_Typ) then
972 Perm := Get_Perm (Expr);
973
974 if Perm = No_Access then
975 Perm_Error (Expr, No_Access, No_Access,
976 Forbidden_Perm => True);
977 return;
978 end if;
979
980 Perm := Get_Perm (Expr_Root);
981
982 if Perm = No_Access then
983 Perm_Error (Expr, No_Access, No_Access,
984 Forbidden_Perm => True);
985 return;
986 end if;
987
988 -- ??? check accessibility level
989
990 -- If the type of the target is an anonymous
991 -- access-to-variable type (an owning access type), the
992 -- source shall be an owning access object denoted by a
993 -- name that is in the Unrestricted state, and whose root
994 -- object is the target object itself.
995
996 else
997 Perm := Get_Perm (Expr);
998
999 if Perm /= Read_Write then
1000 Perm_Error (Expr, Read_Write, Perm);
1001 return;
1002 end if;
1003
1004 if not Is_Entity_Name (Target) then
1005 Error_Msg_N
1006 ("target of borrow must be stand-alone variable",
1007 Target);
1008 return;
1009
1010 elsif Target_Root /= Expr_Root then
1011 Error_Msg_NE
1012 ("source of borrow must be variable &",
1013 Expr, Target);
1014 return;
1015 end if;
1016 end if;
1017
1018 elsif Is_Deep (Target_Typ) then
1019
1020 if Is_Path_Expression (Expr) then
1021 Check_Expression (Expr, Move);
1022
1023 else
1024 Error_Msg_N ("expression not allowed as source of move", Expr);
1025 return;
1026 end if;
1027
1028 else
1029 Check_Expression (Expr, Read);
1030 end if;
1031 end Check_Assignment;
1032
1033 --------------------------
1034 -- Check_Call_Statement --
1035 --------------------------
1036
1037 procedure Check_Call_Statement (Call : Node_Id) is
1038
1039 Subp : constant Entity_Id := Get_Called_Entity (Call);
1040
1041 -- Local subprograms
1042
1043 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id);
1044 -- Check the permission of every actual parameter
1045
1046 procedure Update_Param (Formal : Entity_Id; Actual : Node_Id);
1047 -- Update the permission of OUT actual parameters
1048
1049 -----------------
1050 -- Check_Param --
1051 -----------------
1052
1053 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id) is
1054 begin
1055 Check_Parameter_Or_Global (Expr => Actual,
1056 Param_Mode => Formal_Kind'(Ekind (Formal)),
1057 Subp => Subp,
1058 Global_Var => False);
1059 end Check_Param;
1060
1061 ------------------
1062 -- Update_Param --
1063 ------------------
1064
1065 procedure Update_Param (Formal : Entity_Id; Actual : Node_Id) is
1066 Mode : constant Entity_Kind := Ekind (Formal);
1067
1068 begin
1069 case Formal_Kind'(Mode) is
1070 when E_Out_Parameter =>
1071 Check_Expression (Actual, Assign);
1072
1073 when others =>
1074 null;
1075 end case;
1076 end Update_Param;
1077
1078 procedure Check_Params is new
1079 Iterate_Call_Parameters (Check_Param);
1080
1081 procedure Update_Params is new
1082 Iterate_Call_Parameters (Update_Param);
1083
1084 -- Start of processing for Check_Call_Statement
1085
1086 begin
1087 Inside_Procedure_Call := True;
1088 Check_Params (Call);
1089 Check_Globals (Get_Called_Entity (Call));
1090
1091 Inside_Procedure_Call := False;
1092 Update_Params (Call);
1093 end Check_Call_Statement;
1094
1095 -------------------------
1096 -- Check_Callable_Body --
1097 -------------------------
1098
1099 procedure Check_Callable_Body (Body_N : Node_Id) is
1100 Save_In_Elab : constant Boolean := Inside_Elaboration;
1101 Body_Id : constant Entity_Id := Defining_Entity (Body_N);
1102 Spec_Id : constant Entity_Id := Unique_Entity (Body_Id);
1103 Prag : constant Node_Id := SPARK_Pragma (Body_Id);
1104 Saved_Env : Perm_Env;
1105
1106 begin
1107 -- Only SPARK bodies are analyzed
1108
1109 if No (Prag)
1110 or else Get_SPARK_Mode_From_Annotation (Prag) /= Opt.On
1111 then
1112 return;
1113 end if;
1114
1115 Inside_Elaboration := False;
1116
1117 -- Save environment and put a new one in place
1118
1119 Move_Env (Current_Perm_Env, Saved_Env);
1120
1121 -- Add formals and globals to the environment with adequate permissions
1122
1123 if Is_Subprogram_Or_Entry (Spec_Id) then
1124 Setup_Parameters (Spec_Id);
1125 Setup_Globals (Spec_Id);
1126 end if;
1127
1128 -- Analyze the body of the subprogram
1129
1130 Check_List (Declarations (Body_N));
1131 Check_Node (Handled_Statement_Sequence (Body_N));
1132
1133 -- Check the read-write permissions of borrowed parameters/globals
1134
1135 if Ekind_In (Spec_Id, E_Procedure, E_Entry)
1136 and then not No_Return (Spec_Id)
1137 then
1138 Return_Parameters (Spec_Id);
1139 Return_Globals (Spec_Id);
1140 end if;
1141
1142 -- Restore the saved environment and free the current one
1143
1144 Move_Env (Saved_Env, Current_Perm_Env);
1145
1146 Inside_Elaboration := Save_In_Elab;
1147 end Check_Callable_Body;
1148
1149 -----------------------
1150 -- Check_Declaration --
1151 -----------------------
1152
1153 procedure Check_Declaration (Decl : Node_Id) is
1154 Target : constant Entity_Id := Defining_Identifier (Decl);
1155 Target_Typ : constant Node_Id := Etype (Target);
1156 Expr : Node_Id;
1157
1158 begin
1159 case N_Declaration'(Nkind (Decl)) is
1160 when N_Full_Type_Declaration =>
1161 Check_Type (Target);
1162
1163 -- ??? What about component declarations with defaults.
1164
1165 when N_Subtype_Declaration =>
1166 Check_Expression (Subtype_Indication (Decl), Read);
1167
1168 when N_Object_Declaration =>
1169 Check_Type (Target_Typ);
1170
1171 Expr := Expression (Decl);
1172 if Present (Expr) then
1173 Check_Assignment (Target => Target,
1174 Expr => Expr);
1175 end if;
1176
1177 if Is_Deep (Target_Typ) then
1178 declare
1179 Tree : constant Perm_Tree_Access :=
1180 new Perm_Tree_Wrapper'
1181 (Tree =>
1182 (Kind => Entire_Object,
1183 Is_Node_Deep => True,
1184 Permission => Read_Write,
1185 Children_Permission => Read_Write));
1186 begin
1187 Set (Current_Perm_Env, Target, Tree);
1188 end;
1189 end if;
1190
1191 when N_Iterator_Specification =>
1192 null;
1193
1194 when N_Loop_Parameter_Specification =>
1195 null;
1196
1197 -- Checking should not be called directly on these nodes
1198
1199 when N_Function_Specification
1200 | N_Entry_Declaration
1201 | N_Procedure_Specification
1202 | N_Component_Declaration
1203 =>
1204 raise Program_Error;
1205
1206 -- Ignored constructs for pointer checking
1207
1208 when N_Formal_Object_Declaration
1209 | N_Formal_Type_Declaration
1210 | N_Incomplete_Type_Declaration
1211 | N_Private_Extension_Declaration
1212 | N_Private_Type_Declaration
1213 | N_Protected_Type_Declaration
1214 =>
1215 null;
1216
1217 -- The following nodes are rewritten by semantic analysis
1218
1219 when N_Expression_Function =>
1220 raise Program_Error;
1221 end case;
1222 end Check_Declaration;
1223
1224 ----------------------
1225 -- Check_Expression --
1226 ----------------------
1227
1228 procedure Check_Expression (Expr : Node_Id; Mode : Checking_Mode) is
1229
1230 -- Local subprograms
1231
1232 function Is_Type_Name (Expr : Node_Id) return Boolean;
1233 -- Detect when a path expression is in fact a type name
1234
1235 procedure Read_Expression (Expr : Node_Id);
1236 -- Most subexpressions are only analyzed in Read mode. This is a
1237 -- specialized version of Check_Expression for that case.
1238
1239 procedure Read_Expression_List (L : List_Id);
1240 -- Call Read_Expression on every expression in the list L
1241
1242 procedure Read_Indexes (Expr : Node_Id);
1243 pragma Precondition (Is_Path_Expression (Expr));
1244 -- When processing a path, the index expressions and function call
1245 -- arguments occurring on the path should be analyzed in Read mode.
1246
1247 ------------------
1248 -- Is_Type_Name --
1249 ------------------
1250
1251 function Is_Type_Name (Expr : Node_Id) return Boolean is
1252 begin
1253 return Nkind_In (Expr, N_Expanded_Name, N_Identifier)
1254 and then Is_Type (Entity (Expr));
1255 end Is_Type_Name;
1256
1257 ---------------------
1258 -- Read_Expression --
1259 ---------------------
1260
1261 procedure Read_Expression (Expr : Node_Id) is
1262 begin
1263 Check_Expression (Expr, Read);
1264 end Read_Expression;
1265
1266 --------------------------
1267 -- Read_Expression_List --
1268 --------------------------
1269
1270 procedure Read_Expression_List (L : List_Id) is
1271 N : Node_Id;
1272 begin
1273 N := First (L);
1274 while Present (N) loop
1275 Read_Expression (N);
1276 Next (N);
1277 end loop;
1278 end Read_Expression_List;
1279
1280 ------------------
1281 -- Read_Indexes --
1282 ------------------
1283
1284 procedure Read_Indexes (Expr : Node_Id) is
1285
1286 -- Local subprograms
1287
1288 procedure Read_Param (Formal : Entity_Id; Actual : Node_Id);
1289
1290 ----------------
1291 -- Read_Param --
1292 ----------------
1293
1294 procedure Read_Param (Formal : Entity_Id; Actual : Node_Id) is
1295 pragma Unreferenced (Formal);
1296 begin
1297 Read_Expression (Actual);
1298 end Read_Param;
1299
1300 procedure Read_Params is new Iterate_Call_Parameters (Read_Param);
1301
1302 -- Start of processing for Read_Indexes
1303
1304 begin
1305 case N_Subexpr'(Nkind (Expr)) is
1306 when N_Identifier
1307 | N_Expanded_Name
1308 | N_Null
1309 =>
1310 null;
1311
1312 when N_Explicit_Dereference
1313 | N_Selected_Component
1314 =>
1315 Read_Indexes (Prefix (Expr));
1316
1317 when N_Indexed_Component =>
1318 Read_Indexes (Prefix (Expr));
1319 Read_Expression_List (Expressions (Expr));
1320
1321 when N_Slice =>
1322 Read_Indexes (Prefix (Expr));
1323 Read_Expression (Discrete_Range (Expr));
1324
1325 when N_Allocator =>
1326 Read_Expression (Expression (Expr));
1327
1328 when N_Function_Call =>
1329 Read_Params (Expr);
1330 Check_Globals (Get_Called_Entity (Expr));
1331
1332 when N_Qualified_Expression
1333 | N_Type_Conversion
1334 | N_Unchecked_Type_Conversion
1335 =>
1336 Read_Indexes (Expression (Expr));
1337
1338 when others =>
1339 raise Program_Error;
1340 end case;
1341 end Read_Indexes;
1342
1343 -- Start of processing for Check_Expression
1344
1345 begin
1346 if Is_Type_Name (Expr) then
1347 return;
1348
1349 elsif Is_Path_Expression (Expr) then
1350 Read_Indexes (Expr);
1351 Process_Path (Expr, Mode);
1352 return;
1353 end if;
1354
1355 -- Expressions that are not path expressions should only be analyzed in
1356 -- Read mode.
1357
1358 pragma Assert (Mode = Read);
1359
1360 -- Special handling for nodes that may contain evaluated expressions in
1361 -- the form of constraints.
1362
1363 case Nkind (Expr) is
1364 when N_Index_Or_Discriminant_Constraint =>
1365 declare
1366 Assn : Node_Id := First (Constraints (Expr));
1367 begin
1368 while Present (Assn) loop
1369 case Nkind (Assn) is
1370 when N_Discriminant_Association =>
1371 Read_Expression (Expression (Assn));
1372
1373 when others =>
1374 Read_Expression (Assn);
1375 end case;
1376
1377 Next (Assn);
1378 end loop;
1379 end;
1380 return;
1381
1382 when N_Range_Constraint =>
1383 Read_Expression (Range_Expression (Expr));
1384 return;
1385
1386 when N_Subtype_Indication =>
1387 if Present (Constraint (Expr)) then
1388 Read_Expression (Constraint (Expr));
1389 end if;
1390 return;
1391
1392 when others =>
1393 null;
1394 end case;
1395
1396 -- At this point Expr can only be a subexpression
1397
1398 case N_Subexpr'(Nkind (Expr)) is
1399
1400 when N_Binary_Op
1401 | N_Membership_Test
1402 | N_Short_Circuit
1403 =>
1404 Read_Expression (Left_Opnd (Expr));
1405 Read_Expression (Right_Opnd (Expr));
1406
1407 when N_Unary_Op =>
1408 Read_Expression (Right_Opnd (Expr));
1409
1410 when N_Attribute_Reference =>
1411 declare
1412 Aname : constant Name_Id := Attribute_Name (Expr);
1413 Attr_Id : constant Attribute_Id := Get_Attribute_Id (Aname);
1414 Pref : constant Node_Id := Prefix (Expr);
1415 Args : constant List_Id := Expressions (Expr);
1416
1417 begin
1418 case Attr_Id is
1419
1420 -- The following attributes take either no arguments, or
1421 -- arguments that do not refer to evaluated expressions
1422 -- (like Length or Loop_Entry), hence only the prefix
1423 -- needs to be read.
1424
1425 when Attribute_Address
1426 | Attribute_Alignment
1427 | Attribute_Callable
1428 | Attribute_Component_Size
1429 | Attribute_Constrained
1430 | Attribute_First
1431 | Attribute_First_Bit
1432 | Attribute_Last
1433 | Attribute_Last_Bit
1434 | Attribute_Length
1435 | Attribute_Loop_Entry
1436 | Attribute_Object_Size
1437 | Attribute_Position
1438 | Attribute_Size
1439 | Attribute_Terminated
1440 | Attribute_Valid
1441 | Attribute_Value_Size
1442 =>
1443 Read_Expression (Pref);
1444
1445 -- The following attributes take a type name as prefix,
1446 -- hence only the arguments need to be read.
1447
1448 when Attribute_Ceiling
1449 | Attribute_Floor
1450 | Attribute_Max
1451 | Attribute_Min
1452 | Attribute_Mod
1453 | Attribute_Pos
1454 | Attribute_Pred
1455 | Attribute_Remainder
1456 | Attribute_Rounding
1457 | Attribute_Succ
1458 | Attribute_Truncation
1459 | Attribute_Val
1460 | Attribute_Value
1461 =>
1462 Read_Expression_List (Args);
1463
1464 -- Attributes Image and Img either take a type name as
1465 -- prefix with an expression in argument, or the expression
1466 -- directly as prefix. Adapt to each case.
1467
1468 when Attribute_Image
1469 | Attribute_Img
1470 =>
1471 if No (Args) then
1472 Read_Expression (Pref);
1473 else
1474 Read_Expression_List (Args);
1475 end if;
1476
1477 -- Attribute Update takes expressions as both prefix and
1478 -- arguments, so both need to be read.
1479
1480 when Attribute_Update =>
1481 Read_Expression (Pref);
1482 Read_Expression_List (Args);
1483
1484 -- Attribute Modulus does not reference the evaluated
1485 -- expression, so it can be ignored for this analysis.
1486
1487 when Attribute_Modulus =>
1488 null;
1489
1490 -- Postconditions should not be analyzed
1491
1492 when Attribute_Old
1493 | Attribute_Result
1494 =>
1495 raise Program_Error;
1496
1497 when others =>
1498 Error_Msg_Name_1 := Aname;
1499 Error_Msg_N ("attribute % not allowed in SPARK", Expr);
1500 end case;
1501 end;
1502
1503 when N_Range =>
1504 Read_Expression (Low_Bound (Expr));
1505 Read_Expression (High_Bound (Expr));
1506
1507 when N_If_Expression =>
1508 Read_Expression_List (Expressions (Expr));
1509
1510 when N_Case_Expression =>
1511 declare
1512 Cases : constant List_Id := Alternatives (Expr);
1513 Cur_Case : Node_Id := First (Cases);
1514
1515 begin
1516 while Present (Cur_Case) loop
1517 Read_Expression (Expression (Cur_Case));
1518 Next (Cur_Case);
1519 end loop;
1520
1521 Read_Expression (Expression (Expr));
1522 end;
1523
1524 when N_Qualified_Expression
1525 | N_Type_Conversion
1526 | N_Unchecked_Type_Conversion
1527 =>
1528 Read_Expression (Expression (Expr));
1529
1530 when N_Quantified_Expression =>
1531 declare
1532 For_In_Spec : constant Node_Id :=
1533 Loop_Parameter_Specification (Expr);
1534 For_Of_Spec : constant Node_Id :=
1535 Iterator_Specification (Expr);
1536 begin
1537 if Present (For_In_Spec) then
1538 Read_Expression (Discrete_Subtype_Definition (For_In_Spec));
1539 else
1540 Read_Expression (Name (For_Of_Spec));
1541 Read_Expression (Subtype_Indication (For_Of_Spec));
1542 end if;
1543
1544 Read_Expression (Condition (Expr));
1545 end;
1546
1547 when N_Aggregate =>
1548 declare
1549 Assocs : constant List_Id := Component_Associations (Expr);
1550 Assoc : Node_Id := First (Assocs);
1551 CL : List_Id;
1552 Choice : Node_Id;
1553
1554 begin
1555 while Present (Assoc) loop
1556
1557 -- An array aggregate with a single component association
1558 -- may have a nonstatic choice expression that needs to be
1559 -- analyzed. This can only occur for a single choice that
1560 -- is not the OTHERS one.
1561
1562 if Is_Array_Type (Etype (Expr)) then
1563 CL := Choices (Assoc);
1564 if List_Length (CL) = 1 then
1565 Choice := First (CL);
1566 if Nkind (Choice) /= N_Others_Choice then
1567 Read_Expression (Choice);
1568 end if;
1569 end if;
1570 end if;
1571
1572 -- The expression in the component association also needs to
1573 -- be analyzed.
1574
1575 Read_Expression (Expression (Assoc));
1576 Next (Assoc);
1577 end loop;
1578
1579 Read_Expression_List (Expressions (Expr));
1580 end;
1581
1582 when N_Extension_Aggregate =>
1583 Read_Expression (Ancestor_Part (Expr));
1584 Read_Expression_List (Expressions (Expr));
1585
1586 when N_Character_Literal
1587 | N_Numeric_Or_String_Literal
1588 | N_Operator_Symbol
1589 | N_Raise_Expression
1590 | N_Raise_xxx_Error
1591 =>
1592 null;
1593
1594 when N_Delta_Aggregate
1595 | N_Target_Name
1596 =>
1597 Error_Msg_N ("unsupported construct in SPARK", Expr);
1598
1599 -- Procedure calls are handled in Check_Node
1600
1601 when N_Procedure_Call_Statement =>
1602 raise Program_Error;
1603
1604 -- Path expressions are handled before this point
1605
1606 when N_Allocator
1607 | N_Expanded_Name
1608 | N_Explicit_Dereference
1609 | N_Function_Call
1610 | N_Identifier
1611 | N_Indexed_Component
1612 | N_Null
1613 | N_Selected_Component
1614 | N_Slice
1615 =>
1616 raise Program_Error;
1617
1618 -- The following nodes are never generated in GNATprove mode
1619
1620 when N_Expression_With_Actions
1621 | N_Reference
1622 | N_Unchecked_Expression
1623 =>
1624 raise Program_Error;
1625 end case;
1626 end Check_Expression;
1627
1628 ----------------
1629 -- Check_List --
1630 ----------------
1631
1632 procedure Check_List (L : List_Id) is
1633 N : Node_Id;
1634 begin
1635 N := First (L);
1636 while Present (N) loop
1637 Check_Node (N);
1638 Next (N);
1639 end loop;
1640 end Check_List;
1641
1642 --------------------------
1643 -- Check_Loop_Statement --
1644 --------------------------
1645
1646 procedure Check_Loop_Statement (Stmt : Node_Id) is
1647
1648 -- Local Subprograms
1649
1650 procedure Check_Is_Less_Restrictive_Env
1651 (Exiting_Env : Perm_Env;
1652 Entry_Env : Perm_Env);
1653 -- This procedure checks that the Exiting_Env environment is less
1654 -- restrictive than the Entry_Env environment.
1655
1656 procedure Check_Is_Less_Restrictive_Tree
1657 (New_Tree : Perm_Tree_Access;
1658 Orig_Tree : Perm_Tree_Access;
1659 E : Entity_Id);
1660 -- Auxiliary procedure to check that the tree New_Tree is less
1661 -- restrictive than the tree Orig_Tree for the entity E.
1662
1663 procedure Perm_Error_Loop_Exit
1664 (E : Entity_Id;
1665 Loop_Id : Node_Id;
1666 Perm : Perm_Kind;
1667 Found_Perm : Perm_Kind);
1668 -- A procedure that is called when the permissions found contradict
1669 -- the rules established by the RM at the exit of loops. This function
1670 -- is called with the entity, the node of the enclosing loop, the
1671 -- permission that was expected, and the permission found, and issues
1672 -- an appropriate error message.
1673
1674 -----------------------------------
1675 -- Check_Is_Less_Restrictive_Env --
1676 -----------------------------------
1677
1678 procedure Check_Is_Less_Restrictive_Env
1679 (Exiting_Env : Perm_Env;
1680 Entry_Env : Perm_Env)
1681 is
1682 Comp_Entry : Perm_Tree_Maps.Key_Option;
1683 Iter_Entry, Iter_Exit : Perm_Tree_Access;
1684
1685 begin
1686 Comp_Entry := Get_First_Key (Entry_Env);
1687 while Comp_Entry.Present loop
1688 Iter_Entry := Get (Entry_Env, Comp_Entry.K);
1689 pragma Assert (Iter_Entry /= null);
1690 Iter_Exit := Get (Exiting_Env, Comp_Entry.K);
1691 pragma Assert (Iter_Exit /= null);
1692 Check_Is_Less_Restrictive_Tree
1693 (New_Tree => Iter_Exit,
1694 Orig_Tree => Iter_Entry,
1695 E => Comp_Entry.K);
1696 Comp_Entry := Get_Next_Key (Entry_Env);
1697 end loop;
1698 end Check_Is_Less_Restrictive_Env;
1699
1700 ------------------------------------
1701 -- Check_Is_Less_Restrictive_Tree --
1702 ------------------------------------
1703
1704 procedure Check_Is_Less_Restrictive_Tree
1705 (New_Tree : Perm_Tree_Access;
1706 Orig_Tree : Perm_Tree_Access;
1707 E : Entity_Id)
1708 is
1709 -- Local subprograms
1710
1711 procedure Check_Is_Less_Restrictive_Tree_Than
1712 (Tree : Perm_Tree_Access;
1713 Perm : Perm_Kind;
1714 E : Entity_Id);
1715 -- Auxiliary procedure to check that the tree N is less restrictive
1716 -- than the given permission P.
1717
1718 procedure Check_Is_More_Restrictive_Tree_Than
1719 (Tree : Perm_Tree_Access;
1720 Perm : Perm_Kind;
1721 E : Entity_Id);
1722 -- Auxiliary procedure to check that the tree N is more restrictive
1723 -- than the given permission P.
1724
1725 -----------------------------------------
1726 -- Check_Is_Less_Restrictive_Tree_Than --
1727 -----------------------------------------
1728
1729 procedure Check_Is_Less_Restrictive_Tree_Than
1730 (Tree : Perm_Tree_Access;
1731 Perm : Perm_Kind;
1732 E : Entity_Id)
1733 is
1734 begin
1735 if not (Permission (Tree) >= Perm) then
1736 Perm_Error_Loop_Exit
1737 (E, Stmt, Permission (Tree), Perm);
1738 end if;
1739
1740 case Kind (Tree) is
1741 when Entire_Object =>
1742 if not (Children_Permission (Tree) >= Perm) then
1743 Perm_Error_Loop_Exit
1744 (E, Stmt, Children_Permission (Tree), Perm);
1745
1746 end if;
1747
1748 when Reference =>
1749 Check_Is_Less_Restrictive_Tree_Than
1750 (Get_All (Tree), Perm, E);
1751
1752 when Array_Component =>
1753 Check_Is_Less_Restrictive_Tree_Than
1754 (Get_Elem (Tree), Perm, E);
1755
1756 when Record_Component =>
1757 declare
1758 Comp : Perm_Tree_Access;
1759 begin
1760 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1761 while Comp /= null loop
1762 Check_Is_Less_Restrictive_Tree_Than (Comp, Perm, E);
1763 Comp :=
1764 Perm_Tree_Maps.Get_Next (Component (Tree));
1765 end loop;
1766 end;
1767 end case;
1768 end Check_Is_Less_Restrictive_Tree_Than;
1769
1770 -----------------------------------------
1771 -- Check_Is_More_Restrictive_Tree_Than --
1772 -----------------------------------------
1773
1774 procedure Check_Is_More_Restrictive_Tree_Than
1775 (Tree : Perm_Tree_Access;
1776 Perm : Perm_Kind;
1777 E : Entity_Id)
1778 is
1779 begin
1780 if not (Perm >= Permission (Tree)) then
1781 Perm_Error_Loop_Exit
1782 (E, Stmt, Permission (Tree), Perm);
1783 end if;
1784
1785 case Kind (Tree) is
1786 when Entire_Object =>
1787 if not (Perm >= Children_Permission (Tree)) then
1788 Perm_Error_Loop_Exit
1789 (E, Stmt, Children_Permission (Tree), Perm);
1790 end if;
1791
1792 when Reference =>
1793 Check_Is_More_Restrictive_Tree_Than
1794 (Get_All (Tree), Perm, E);
1795
1796 when Array_Component =>
1797 Check_Is_More_Restrictive_Tree_Than
1798 (Get_Elem (Tree), Perm, E);
1799
1800 when Record_Component =>
1801 declare
1802 Comp : Perm_Tree_Access;
1803 begin
1804 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1805 while Comp /= null loop
1806 Check_Is_More_Restrictive_Tree_Than (Comp, Perm, E);
1807 Comp :=
1808 Perm_Tree_Maps.Get_Next (Component (Tree));
1809 end loop;
1810 end;
1811 end case;
1812 end Check_Is_More_Restrictive_Tree_Than;
1813
1814 -- Start of processing for Check_Is_Less_Restrictive_Tree
1815
1816 begin
1817 if not (Permission (New_Tree) <= Permission (Orig_Tree)) then
1818 Perm_Error_Loop_Exit
1819 (E => E,
1820 Loop_Id => Stmt,
1821 Perm => Permission (New_Tree),
1822 Found_Perm => Permission (Orig_Tree));
1823 end if;
1824
1825 case Kind (New_Tree) is
1826
1827 -- Potentially folded tree. We check the other tree Orig_Tree to
1828 -- check whether it is folded or not. If folded we just compare
1829 -- their Permission and Children_Permission, if not, then we
1830 -- look at the Children_Permission of the folded tree against
1831 -- the unfolded tree Orig_Tree.
1832
1833 when Entire_Object =>
1834 case Kind (Orig_Tree) is
1835 when Entire_Object =>
1836 if not (Children_Permission (New_Tree) <=
1837 Children_Permission (Orig_Tree))
1838 then
1839 Perm_Error_Loop_Exit
1840 (E, Stmt,
1841 Children_Permission (New_Tree),
1842 Children_Permission (Orig_Tree));
1843 end if;
1844
1845 when Reference =>
1846 Check_Is_More_Restrictive_Tree_Than
1847 (Get_All (Orig_Tree), Children_Permission (New_Tree), E);
1848
1849 when Array_Component =>
1850 Check_Is_More_Restrictive_Tree_Than
1851 (Get_Elem (Orig_Tree), Children_Permission (New_Tree), E);
1852
1853 when Record_Component =>
1854 declare
1855 Comp : Perm_Tree_Access;
1856 begin
1857 Comp := Perm_Tree_Maps.Get_First
1858 (Component (Orig_Tree));
1859 while Comp /= null loop
1860 Check_Is_More_Restrictive_Tree_Than
1861 (Comp, Children_Permission (New_Tree), E);
1862 Comp := Perm_Tree_Maps.Get_Next
1863 (Component (Orig_Tree));
1864 end loop;
1865 end;
1866 end case;
1867
1868 when Reference =>
1869 case Kind (Orig_Tree) is
1870 when Entire_Object =>
1871 Check_Is_Less_Restrictive_Tree_Than
1872 (Get_All (New_Tree), Children_Permission (Orig_Tree), E);
1873
1874 when Reference =>
1875 Check_Is_Less_Restrictive_Tree
1876 (Get_All (New_Tree), Get_All (Orig_Tree), E);
1877
1878 when others =>
1879 raise Program_Error;
1880 end case;
1881
1882 when Array_Component =>
1883 case Kind (Orig_Tree) is
1884 when Entire_Object =>
1885 Check_Is_Less_Restrictive_Tree_Than
1886 (Get_Elem (New_Tree), Children_Permission (Orig_Tree), E);
1887
1888 when Array_Component =>
1889 Check_Is_Less_Restrictive_Tree
1890 (Get_Elem (New_Tree), Get_Elem (Orig_Tree), E);
1891
1892 when others =>
1893 raise Program_Error;
1894 end case;
1895
1896 when Record_Component =>
1897 declare
1898 CompN : Perm_Tree_Access;
1899 begin
1900 CompN :=
1901 Perm_Tree_Maps.Get_First (Component (New_Tree));
1902 case Kind (Orig_Tree) is
1903 when Entire_Object =>
1904 while CompN /= null loop
1905 Check_Is_Less_Restrictive_Tree_Than
1906 (CompN, Children_Permission (Orig_Tree), E);
1907
1908 CompN :=
1909 Perm_Tree_Maps.Get_Next (Component (New_Tree));
1910 end loop;
1911
1912 when Record_Component =>
1913 declare
1914
1915 KeyO : Perm_Tree_Maps.Key_Option;
1916 CompO : Perm_Tree_Access;
1917 begin
1918 KeyO := Perm_Tree_Maps.Get_First_Key
1919 (Component (Orig_Tree));
1920 while KeyO.Present loop
1921 pragma Assert (CompO /= null);
1922
1923 Check_Is_Less_Restrictive_Tree (CompN, CompO, E);
1924
1925 KeyO := Perm_Tree_Maps.Get_Next_Key
1926 (Component (Orig_Tree));
1927 CompN := Perm_Tree_Maps.Get
1928 (Component (New_Tree), KeyO.K);
1929 CompO := Perm_Tree_Maps.Get
1930 (Component (Orig_Tree), KeyO.K);
1931 end loop;
1932 end;
1933
1934 when others =>
1935 raise Program_Error;
1936 end case;
1937 end;
1938 end case;
1939 end Check_Is_Less_Restrictive_Tree;
1940
1941 --------------------------
1942 -- Perm_Error_Loop_Exit --
1943 --------------------------
1944
1945 procedure Perm_Error_Loop_Exit
1946 (E : Entity_Id;
1947 Loop_Id : Node_Id;
1948 Perm : Perm_Kind;
1949 Found_Perm : Perm_Kind)
1950 is
1951 begin
1952 Error_Msg_Node_2 := Loop_Id;
1953 Error_Msg_N ("insufficient permission for & when exiting loop &", E);
1954 Perm_Mismatch (Exp_Perm => Perm,
1955 Act_Perm => Found_Perm,
1956 N => Loop_Id);
1957 end Perm_Error_Loop_Exit;
1958
1959 -- Local variables
1960
1961 Loop_Name : constant Entity_Id := Entity (Identifier (Stmt));
1962 Loop_Env : constant Perm_Env_Access := new Perm_Env;
1963 Scheme : constant Node_Id := Iteration_Scheme (Stmt);
1964
1965 -- Start of processing for Check_Loop_Statement
1966
1967 begin
1968 -- Save environment prior to the loop
1969
1970 Copy_Env (From => Current_Perm_Env, To => Loop_Env.all);
1971
1972 -- Add saved environment to loop environment
1973
1974 Set (Current_Loops_Envs, Loop_Name, Loop_Env);
1975
1976 -- If the loop is not a plain-loop, then it may either never be entered,
1977 -- or it may be exited after a number of iterations. Hence add the
1978 -- current permission environment as the initial loop exit environment.
1979 -- Otherwise, the loop exit environment remains empty until it is
1980 -- populated by analyzing exit statements.
1981
1982 if Present (Iteration_Scheme (Stmt)) then
1983 declare
1984 Exit_Env : constant Perm_Env_Access := new Perm_Env;
1985
1986 begin
1987 Copy_Env (From => Current_Perm_Env, To => Exit_Env.all);
1988 Set (Current_Loops_Accumulators, Loop_Name, Exit_Env);
1989 end;
1990 end if;
1991
1992 -- Analyze loop
1993
1994 if Present (Scheme) then
1995
1996 -- Case of a WHILE loop
1997
1998 if Present (Condition (Scheme)) then
1999 Check_Expression (Condition (Scheme), Read);
2000
2001 -- Case of a FOR loop
2002
2003 else
2004 declare
2005 Param_Spec : constant Node_Id :=
2006 Loop_Parameter_Specification (Scheme);
2007 Iter_Spec : constant Node_Id := Iterator_Specification (Scheme);
2008 begin
2009 if Present (Param_Spec) then
2010 Check_Expression
2011 (Discrete_Subtype_Definition (Param_Spec), Read);
2012 else
2013 Check_Expression (Name (Iter_Spec), Read);
2014 if Present (Subtype_Indication (Iter_Spec)) then
2015 Check_Expression (Subtype_Indication (Iter_Spec), Read);
2016 end if;
2017 end if;
2018 end;
2019 end if;
2020 end if;
2021
2022 Check_List (Statements (Stmt));
2023
2024 -- Check that environment gets less restrictive at end of loop
2025
2026 Check_Is_Less_Restrictive_Env
2027 (Exiting_Env => Current_Perm_Env,
2028 Entry_Env => Loop_Env.all);
2029
2030 -- Set environment to the one for exiting the loop
2031
2032 declare
2033 Exit_Env : constant Perm_Env_Access :=
2034 Get (Current_Loops_Accumulators, Loop_Name);
2035 begin
2036 Free_Env (Current_Perm_Env);
2037
2038 -- In the normal case, Exit_Env is not null and we use it. In the
2039 -- degraded case of a plain-loop without exit statements, Exit_Env is
2040 -- null, and we use the initial permission environment at the start
2041 -- of the loop to continue analysis. Any environment would be fine
2042 -- here, since the code after the loop is dead code, but this way we
2043 -- avoid spurious errors by having at least variables in scope inside
2044 -- the environment.
2045
2046 if Exit_Env /= null then
2047 Copy_Env (From => Exit_Env.all, To => Current_Perm_Env);
2048 Free_Env (Loop_Env.all);
2049 Free_Env (Exit_Env.all);
2050 else
2051 Copy_Env (From => Loop_Env.all, To => Current_Perm_Env);
2052 Free_Env (Loop_Env.all);
2053 end if;
2054 end;
2055 end Check_Loop_Statement;
2056
2057 ----------------
2058 -- Check_Node --
2059 ----------------
2060
2061 procedure Check_Node (N : Node_Id) is
2062 begin
2063 case Nkind (N) is
2064 when N_Declaration =>
2065 Check_Declaration (N);
2066
2067 when N_Body_Stub =>
2068 Check_Node (Get_Body_From_Stub (N));
2069
2070 when N_Statement_Other_Than_Procedure_Call =>
2071 Check_Statement (N);
2072
2073 when N_Procedure_Call_Statement =>
2074 Check_Call_Statement (N);
2075
2076 when N_Package_Body =>
2077 Check_Package_Body (N);
2078
2079 when N_Subprogram_Body
2080 | N_Entry_Body
2081 | N_Task_Body
2082 =>
2083 Check_Callable_Body (N);
2084
2085 when N_Protected_Body =>
2086 Check_List (Declarations (N));
2087
2088 when N_Package_Declaration =>
2089 Check_Package_Spec (N);
2090
2091 when N_Handled_Sequence_Of_Statements =>
2092 Check_List (Statements (N));
2093
2094 -- Ignored constructs for pointer checking
2095
2096 when N_Abstract_Subprogram_Declaration
2097 | N_At_Clause
2098 | N_Attribute_Definition_Clause
2099 | N_Call_Marker
2100 | N_Delta_Constraint
2101 | N_Digits_Constraint
2102 | N_Empty
2103 | N_Enumeration_Representation_Clause
2104 | N_Exception_Declaration
2105 | N_Exception_Renaming_Declaration
2106 | N_Formal_Package_Declaration
2107 | N_Formal_Subprogram_Declaration
2108 | N_Freeze_Entity
2109 | N_Freeze_Generic_Entity
2110 | N_Function_Instantiation
2111 | N_Generic_Function_Renaming_Declaration
2112 | N_Generic_Package_Declaration
2113 | N_Generic_Package_Renaming_Declaration
2114 | N_Generic_Procedure_Renaming_Declaration
2115 | N_Generic_Subprogram_Declaration
2116 | N_Implicit_Label_Declaration
2117 | N_Itype_Reference
2118 | N_Label
2119 | N_Number_Declaration
2120 | N_Object_Renaming_Declaration
2121 | N_Others_Choice
2122 | N_Package_Instantiation
2123 | N_Package_Renaming_Declaration
2124 | N_Pragma
2125 | N_Procedure_Instantiation
2126 | N_Record_Representation_Clause
2127 | N_Subprogram_Declaration
2128 | N_Subprogram_Renaming_Declaration
2129 | N_Task_Type_Declaration
2130 | N_Use_Package_Clause
2131 | N_With_Clause
2132 | N_Use_Type_Clause
2133 | N_Validate_Unchecked_Conversion
2134 | N_Variable_Reference_Marker
2135 | N_Discriminant_Association
2136
2137 -- ??? check whether we should do something special for
2138 -- N_Discriminant_Association, or maybe raise Program_Error.
2139 =>
2140 null;
2141
2142 -- Checking should not be called directly on these nodes
2143
2144 when others =>
2145 raise Program_Error;
2146 end case;
2147 end Check_Node;
2148
2149 ------------------------
2150 -- Check_Package_Body --
2151 ------------------------
2152
2153 procedure Check_Package_Body (Pack : Node_Id) is
2154 Save_In_Elab : constant Boolean := Inside_Elaboration;
2155 Spec : constant Node_Id :=
2156 Package_Specification (Corresponding_Spec (Pack));
2157 Prag : constant Node_Id := SPARK_Pragma (Defining_Entity (Pack));
2158 Saved_Env : Perm_Env;
2159
2160 begin
2161 -- Only SPARK bodies are analyzed
2162
2163 if No (Prag)
2164 or else Get_SPARK_Mode_From_Annotation (Prag) /= Opt.On
2165 then
2166 return;
2167 end if;
2168
2169 Inside_Elaboration := True;
2170
2171 -- Save environment and put a new one in place
2172
2173 Move_Env (Current_Perm_Env, Saved_Env);
2174
2175 -- Reanalyze package spec to have its variables in the environment
2176
2177 Check_List (Visible_Declarations (Spec));
2178 Check_List (Private_Declarations (Spec));
2179
2180 -- Check declarations and statements in the special mode for elaboration
2181
2182 Check_List (Declarations (Pack));
2183 Check_Node (Handled_Statement_Sequence (Pack));
2184
2185 -- Restore the saved environment and free the current one
2186
2187 Move_Env (Saved_Env, Current_Perm_Env);
2188
2189 Inside_Elaboration := Save_In_Elab;
2190 end Check_Package_Body;
2191
2192 ------------------------
2193 -- Check_Package_Spec --
2194 ------------------------
2195
2196 procedure Check_Package_Spec (Pack : Node_Id) is
2197 Save_In_Elab : constant Boolean := Inside_Elaboration;
2198 Spec : constant Node_Id := Specification (Pack);
2199 Saved_Env : Perm_Env;
2200
2201 begin
2202 Inside_Elaboration := True;
2203
2204 -- Save environment and put a new one in place
2205
2206 Move_Env (Current_Perm_Env, Saved_Env);
2207
2208 -- Check declarations in the special mode for elaboration
2209
2210 Check_List (Visible_Declarations (Spec));
2211 Check_List (Private_Declarations (Spec));
2212
2213 -- Restore the saved environment and free the current one
2214
2215 Move_Env (Saved_Env, Current_Perm_Env);
2216
2217 Inside_Elaboration := Save_In_Elab;
2218 end Check_Package_Spec;
2219
2220 -------------------------------
2221 -- Check_Parameter_Or_Global --
2222 -------------------------------
2223
2224 procedure Check_Parameter_Or_Global
2225 (Expr : Node_Id;
2226 Param_Mode : Formal_Kind;
2227 Subp : Entity_Id;
2228 Global_Var : Boolean)
2229 is
2230 Typ : constant Entity_Id := Underlying_Type (Etype (Expr));
2231 Mode : Checking_Mode;
2232
2233 begin
2234 case Param_Mode is
2235 when E_In_Parameter =>
2236
2237 -- Inputs of functions have R permission only
2238
2239 if Ekind (Subp) = E_Function then
2240 Mode := Read;
2241
2242 -- Input global variables have R permission only
2243
2244 elsif Global_Var then
2245 Mode := Read;
2246
2247 -- Anonymous access to constant is an observe
2248
2249 elsif Is_Anonymous_Access_Type (Typ)
2250 and then Is_Access_Constant (Typ)
2251 then
2252 Mode := Observe;
2253
2254 -- Other access types are a borrow
2255
2256 elsif Is_Access_Type (Typ) then
2257 Mode := Borrow;
2258
2259 -- Deep types other than access types define an observe
2260
2261 elsif Is_Deep (Typ) then
2262 Mode := Observe;
2263
2264 -- Otherwise the variable is read
2265
2266 else
2267 Mode := Read;
2268 end if;
2269
2270 when E_Out_Parameter =>
2271 Mode := Assign;
2272
2273 when E_In_Out_Parameter =>
2274 Mode := Move;
2275 end case;
2276
2277 Check_Expression (Expr, Mode);
2278 end Check_Parameter_Or_Global;
2279
2280 procedure Check_Globals_Inst is
2281 new Handle_Globals (Check_Parameter_Or_Global);
2282
2283 procedure Check_Globals (Subp : Entity_Id) renames Check_Globals_Inst;
2284
2285 -------------------------
2286 -- Check_Safe_Pointers --
2287 -------------------------
2288
2289 procedure Check_Safe_Pointers (N : Node_Id) is
2290
2291 -- Local subprograms
2292
2293 procedure Check_List (L : List_Id);
2294 -- Call the main analysis procedure on each element of the list
2295
2296 procedure Initialize;
2297 -- Initialize global variables before starting the analysis of a body
2298
2299 ----------------
2300 -- Check_List --
2301 ----------------
2302
2303 procedure Check_List (L : List_Id) is
2304 N : Node_Id;
2305 begin
2306 N := First (L);
2307 while Present (N) loop
2308 Check_Safe_Pointers (N);
2309 Next (N);
2310 end loop;
2311 end Check_List;
2312
2313 ----------------
2314 -- Initialize --
2315 ----------------
2316
2317 procedure Initialize is
2318 begin
2319 Reset (Current_Loops_Envs);
2320 Reset (Current_Loops_Accumulators);
2321 Reset (Current_Perm_Env);
2322 end Initialize;
2323
2324 -- Local variables
2325
2326 Prag : Node_Id;
2327 -- SPARK_Mode pragma in application
2328
2329 -- Start of processing for Check_Safe_Pointers
2330
2331 begin
2332 Initialize;
2333
2334 case Nkind (N) is
2335 when N_Compilation_Unit =>
2336 Check_Safe_Pointers (Unit (N));
2337
2338 when N_Package_Body
2339 | N_Package_Declaration
2340 | N_Subprogram_Body
2341 =>
2342 Prag := SPARK_Pragma (Defining_Entity (N));
2343
2344 if Present (Prag) then
2345 if Get_SPARK_Mode_From_Annotation (Prag) = Opt.On then
2346 Check_Node (N);
2347 end if;
2348
2349 elsif Nkind (N) = N_Package_Body then
2350 Check_List (Declarations (N));
2351
2352 elsif Nkind (N) = N_Package_Declaration then
2353 Check_List (Private_Declarations (Specification (N)));
2354 Check_List (Visible_Declarations (Specification (N)));
2355 end if;
2356
2357 when others =>
2358 null;
2359 end case;
2360 end Check_Safe_Pointers;
2361
2362 ---------------------------------------
2363 -- Check_Source_Of_Borrow_Or_Observe --
2364 ---------------------------------------
2365
2366 procedure Check_Source_Of_Borrow_Or_Observe
2367 (Expr : Node_Id;
2368 Status : out Error_Status)
2369 is
2370 Root : constant Entity_Id := Get_Root_Object (Expr);
2371 begin
2372 Status := OK;
2373
2374 -- SPARK RM 3.10(3): If the target of an assignment operation is an
2375 -- object of an anonymous access-to-object type (including copy-in for
2376 -- a parameter), then the source shall be a name denoting a part of a
2377 -- stand-alone object, a part of a parameter, or a call to a traversal
2378 -- function.
2379
2380 if Present (Root) then
2381 if not Ekind_In (Root, E_Variable, E_Constant)
2382 and then Ekind (Root) not in Formal_Kind
2383 then
2384 Error_Msg_N
2385 ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr);
2386 Error_Msg_N
2387 ("\expression must be part of stand-alone object or parameter",
2388 Expr);
2389 Status := Error;
2390 end if;
2391
2392 elsif Nkind (Expr) = N_Function_Call then
2393 declare
2394 Callee : constant Entity_Id := Get_Called_Entity (Expr);
2395 begin
2396 if No (Callee)
2397 or else not Is_Traversal_Function (Callee)
2398 then
2399 Error_Msg_N
2400 ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr);
2401 Error_Msg_N
2402 ("\function called must be a traversal function", Expr);
2403 Status := Error;
2404 end if;
2405 end;
2406
2407 else
2408 Error_Msg_N ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr);
2409 Status := Error;
2410 end if;
2411 end Check_Source_Of_Borrow_Or_Observe;
2412
2413 ---------------------
2414 -- Check_Statement --
2415 ---------------------
2416
2417 procedure Check_Statement (Stmt : Node_Id) is
2418 begin
2419 case N_Statement_Other_Than_Procedure_Call'(Nkind (Stmt)) is
2420
2421 -- An entry call is handled like other calls
2422
2423 when N_Entry_Call_Statement =>
2424 Check_Call_Statement (Stmt);
2425
2426 -- An assignment may correspond to a move, a borrow, or an observe
2427
2428 when N_Assignment_Statement =>
2429 declare
2430 Target : constant Node_Id := Name (Stmt);
2431 Target_Typ : constant Entity_Id := Etype (Target);
2432 begin
2433 Check_Assignment (Target => Target,
2434 Expr => Expression (Stmt));
2435
2436 if Is_Deep (Target_Typ) then
2437 Check_Expression (Target, Assign);
2438 end if;
2439 end;
2440
2441 when N_Block_Statement =>
2442 declare
2443 Saved_Env : Perm_Env;
2444 begin
2445 -- Save environment
2446
2447 Copy_Env (Current_Perm_Env, Saved_Env);
2448
2449 -- Analyze declarations and Handled_Statement_Sequences
2450
2451 Check_List (Declarations (Stmt));
2452 Check_Node (Handled_Statement_Sequence (Stmt));
2453
2454 -- Restore environment
2455
2456 Free_Env (Current_Perm_Env);
2457 Copy_Env (Saved_Env, Current_Perm_Env);
2458 end;
2459
2460 when N_Case_Statement =>
2461 declare
2462 Alt : Node_Id;
2463 Saved_Env : Perm_Env;
2464 -- Copy of environment for analysis of the different cases
2465 New_Env : Perm_Env;
2466 -- Accumulator for the different cases
2467
2468 begin
2469 Check_Expression (Expression (Stmt), Read);
2470
2471 -- Save environment
2472
2473 Copy_Env (Current_Perm_Env, Saved_Env);
2474
2475 -- First alternative
2476
2477 Alt := First (Alternatives (Stmt));
2478 Check_List (Statements (Alt));
2479 Next (Alt);
2480
2481 -- Cleanup
2482
2483 Move_Env (Current_Perm_Env, New_Env);
2484
2485 -- Other alternatives
2486
2487 while Present (Alt) loop
2488
2489 -- Restore environment
2490
2491 Copy_Env (Saved_Env, Current_Perm_Env);
2492
2493 -- Next alternative
2494
2495 Check_List (Statements (Alt));
2496 Next (Alt);
2497
2498 -- Merge Current_Perm_Env into New_Env
2499
2500 Merge_Env (Source => Current_Perm_Env, Target => New_Env);
2501 end loop;
2502
2503 Move_Env (New_Env, Current_Perm_Env);
2504 Free_Env (Saved_Env);
2505 end;
2506
2507 when N_Delay_Relative_Statement
2508 | N_Delay_Until_Statement
2509 =>
2510 Check_Expression (Expression (Stmt), Read);
2511
2512 when N_Loop_Statement =>
2513 Check_Loop_Statement (Stmt);
2514
2515 when N_Simple_Return_Statement =>
2516 declare
2517 Subp : constant Entity_Id :=
2518 Return_Applies_To (Return_Statement_Entity (Stmt));
2519 Expr : constant Node_Id := Expression (Stmt);
2520 begin
2521 if Present (Expression (Stmt)) then
2522 declare
2523 Return_Typ : constant Entity_Id :=
2524 Etype (Expression (Stmt));
2525
2526 begin
2527 -- SPARK RM 3.10(5): A return statement that applies
2528 -- to a traversal function that has an anonymous
2529 -- access-to-constant (respectively, access-to-variable)
2530 -- result type, shall return either the literal null
2531 -- or an access object denoted by a direct or indirect
2532 -- observer (respectively, borrower) of the traversed
2533 -- parameter.
2534
2535 if Is_Anonymous_Access_Type (Return_Typ) then
2536 pragma Assert (Is_Traversal_Function (Subp));
2537
2538 if Nkind (Expr) /= N_Null then
2539 declare
2540 Expr_Root : constant Entity_Id :=
2541 Get_Root_Object (Expr);
2542 Param : constant Entity_Id :=
2543 First_Formal (Subp);
2544 begin
2545 if Param /= Expr_Root then
2546 Error_Msg_NE
2547 ("returned value must be rooted in "
2548 & "traversed parameter & "
2549 & "(SPARK RM 3.10(5))",
2550 Stmt, Param);
2551 end if;
2552 end;
2553 end if;
2554
2555 -- Move expression to caller
2556
2557 elsif Is_Deep (Return_Typ) then
2558
2559 if Is_Path_Expression (Expr) then
2560 Check_Expression (Expr, Move);
2561
2562 else
2563 Error_Msg_N
2564 ("expression not allowed as source of move",
2565 Expr);
2566 return;
2567 end if;
2568
2569 else
2570 Check_Expression (Expr, Read);
2571 end if;
2572
2573 Return_Parameters (Subp);
2574 Return_Globals (Subp);
2575 end;
2576 end if;
2577 end;
2578
2579 when N_Extended_Return_Statement =>
2580 declare
2581 Subp : constant Entity_Id :=
2582 Return_Applies_To (Return_Statement_Entity (Stmt));
2583 Decls : constant List_Id := Return_Object_Declarations (Stmt);
2584 Decl : constant Node_Id := Last (Decls);
2585 Obj : constant Entity_Id := Defining_Identifier (Decl);
2586 Perm : Perm_Kind;
2587
2588 begin
2589 -- SPARK RM 3.10(5): return statement of traversal function
2590
2591 if Is_Traversal_Function (Subp) then
2592 Error_Msg_N
2593 ("extended return cannot apply to a traversal function",
2594 Stmt);
2595 end if;
2596
2597 Check_List (Return_Object_Declarations (Stmt));
2598 Check_Node (Handled_Statement_Sequence (Stmt));
2599
2600 Perm := Get_Perm (Obj);
2601
2602 if Perm /= Read_Write then
2603 Perm_Error (Decl, Read_Write, Perm);
2604 end if;
2605
2606 Return_Parameters (Subp);
2607 Return_Globals (Subp);
2608 end;
2609
2610 -- On loop exit, merge the current permission environment with the
2611 -- accumulator for the given loop.
2612
2613 when N_Exit_Statement =>
2614 declare
2615 Loop_Name : constant Entity_Id := Loop_Of_Exit (Stmt);
2616 Saved_Accumulator : constant Perm_Env_Access :=
2617 Get (Current_Loops_Accumulators, Loop_Name);
2618 Environment_Copy : constant Perm_Env_Access :=
2619 new Perm_Env;
2620 begin
2621 Copy_Env (Current_Perm_Env, Environment_Copy.all);
2622
2623 if Saved_Accumulator = null then
2624 Set (Current_Loops_Accumulators,
2625 Loop_Name, Environment_Copy);
2626 else
2627 Merge_Env (Source => Environment_Copy.all,
2628 Target => Saved_Accumulator.all);
2629 -- ??? Either free Environment_Copy, or change the type
2630 -- of loop accumulators to directly store permission
2631 -- environments.
2632 end if;
2633 end;
2634
2635 -- On branches, analyze each branch independently on a fresh copy of
2636 -- the permission environment, then merge the resulting permission
2637 -- environments.
2638
2639 when N_If_Statement =>
2640 declare
2641 Saved_Env : Perm_Env;
2642 New_Env : Perm_Env;
2643 -- Accumulator for the different branches
2644
2645 begin
2646 Check_Expression (Condition (Stmt), Read);
2647
2648 -- Save environment
2649
2650 Copy_Env (Current_Perm_Env, Saved_Env);
2651
2652 -- THEN branch
2653
2654 Check_List (Then_Statements (Stmt));
2655 Move_Env (Current_Perm_Env, New_Env);
2656
2657 -- ELSIF branches
2658
2659 declare
2660 Branch : Node_Id;
2661 begin
2662 Branch := First (Elsif_Parts (Stmt));
2663 while Present (Branch) loop
2664
2665 -- Restore current permission environment
2666
2667 Copy_Env (Saved_Env, Current_Perm_Env);
2668 Check_Expression (Condition (Branch), Read);
2669 Check_List (Then_Statements (Branch));
2670
2671 -- Merge current permission environment
2672
2673 Merge_Env (Source => Current_Perm_Env, Target => New_Env);
2674 Next (Branch);
2675 end loop;
2676 end;
2677
2678 -- ELSE branch
2679
2680 -- Restore current permission environment
2681
2682 Copy_Env (Saved_Env, Current_Perm_Env);
2683 Check_List (Else_Statements (Stmt));
2684
2685 -- Merge current permission environment
2686
2687 Merge_Env (Source => Current_Perm_Env, Target => New_Env);
2688
2689 -- Cleanup
2690
2691 Move_Env (New_Env, Current_Perm_Env);
2692 Free_Env (Saved_Env);
2693 end;
2694
2695 -- We should ideally ignore the branch after raising an exception,
2696 -- so that it is not taken into account in merges. For now, just
2697 -- propagate the current environment.
2698
2699 when N_Raise_Statement =>
2700 null;
2701
2702 when N_Null_Statement =>
2703 null;
2704
2705 -- Unsupported constructs in SPARK
2706
2707 when N_Abort_Statement
2708 | N_Accept_Statement
2709 | N_Asynchronous_Select
2710 | N_Code_Statement
2711 | N_Conditional_Entry_Call
2712 | N_Goto_Statement
2713 | N_Requeue_Statement
2714 | N_Selective_Accept
2715 | N_Timed_Entry_Call
2716 =>
2717 Error_Msg_N ("unsupported construct in SPARK", Stmt);
2718
2719 -- The following nodes are never generated in GNATprove mode
2720
2721 when N_Compound_Statement
2722 | N_Free_Statement
2723 =>
2724 raise Program_Error;
2725 end case;
2726 end Check_Statement;
2727
2728 ----------------
2729 -- Check_Type --
2730 ----------------
2731
2732 procedure Check_Type (Typ : Entity_Id) is
2733 begin
2734 case Type_Kind'(Ekind (Underlying_Type (Typ))) is
2735 when Access_Kind =>
2736 case Access_Kind'(Ekind (Typ)) is
2737 when E_Access_Type =>
2738 null;
2739 when E_Access_Subtype =>
2740 Check_Type (Base_Type (Typ));
2741 when E_Access_Attribute_Type =>
2742 Error_Msg_N ("access attribute not allowed in SPARK", Typ);
2743 when E_Allocator_Type =>
2744 Error_Msg_N ("missing type resolution", Typ);
2745 when E_General_Access_Type =>
2746 Error_Msg_NE
2747 ("general access type & not allowed in SPARK", Typ, Typ);
2748 when Access_Subprogram_Kind =>
2749 Error_Msg_NE
2750 ("access to subprogram type & not allowed in SPARK",
2751 Typ, Typ);
2752 when E_Anonymous_Access_Type =>
2753 Error_Msg_N ("anonymous access type not yet supported", Typ);
2754 end case;
2755
2756 when E_Array_Type
2757 | E_Array_Subtype
2758 =>
2759 Check_Type (Component_Type (Typ));
2760
2761 when Record_Kind =>
2762 if Is_Deep (Typ)
2763 and then (Is_Tagged_Type (Typ) or else Is_Class_Wide_Type (Typ))
2764 then
2765 Error_Msg_NE
2766 ("tagged type & cannot be owning in SPARK", Typ, Typ);
2767
2768 else
2769 declare
2770 Comp : Entity_Id;
2771 begin
2772 Comp := First_Component_Or_Discriminant (Typ);
2773 while Present (Comp) loop
2774 Check_Type (Etype (Comp));
2775 Next_Component_Or_Discriminant (Comp);
2776 end loop;
2777 end;
2778 end if;
2779
2780 when Scalar_Kind
2781 | E_String_Literal_Subtype
2782 | Protected_Kind
2783 | Task_Kind
2784 | Incomplete_Kind
2785 | E_Exception_Type
2786 | E_Subprogram_Type
2787 =>
2788 null;
2789
2790 -- The following should not arise as underlying types
2791
2792 when E_Private_Type
2793 | E_Private_Subtype
2794 | E_Limited_Private_Type
2795 | E_Limited_Private_Subtype
2796 =>
2797 raise Program_Error;
2798 end case;
2799 end Check_Type;
2800
2801 --------------
2802 -- Get_Perm --
2803 --------------
2804
2805 function Get_Perm (N : Node_Or_Entity_Id) return Perm_Kind is
2806 begin
2807 -- Special case for the object declared in an extended return statement
2808
2809 if Nkind (N) = N_Defining_Identifier then
2810 declare
2811 C : constant Perm_Tree_Access :=
2812 Get (Current_Perm_Env, Unique_Entity (N));
2813 begin
2814 pragma Assert (C /= null);
2815 return Permission (C);
2816 end;
2817
2818 -- The expression is rooted in an object
2819
2820 elsif Present (Get_Root_Object (N)) then
2821 declare
2822 Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N);
2823 begin
2824 case Tree_Or_Perm.R is
2825 when Folded =>
2826 return Tree_Or_Perm.Found_Permission;
2827
2828 when Unfolded =>
2829 pragma Assert (Tree_Or_Perm.Tree_Access /= null);
2830 return Permission (Tree_Or_Perm.Tree_Access);
2831 end case;
2832 end;
2833
2834 -- The expression is a function call, an allocation, or null
2835
2836 else
2837 return Read_Write;
2838 end if;
2839 end Get_Perm;
2840
2841 ----------------------
2842 -- Get_Perm_Or_Tree --
2843 ----------------------
2844
2845 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree is
2846 begin
2847 case Nkind (N) is
2848
2849 when N_Expanded_Name
2850 | N_Identifier
2851 =>
2852 declare
2853 C : constant Perm_Tree_Access :=
2854 Get (Current_Perm_Env, Unique_Entity (Entity (N)));
2855 begin
2856 pragma Assert (C /= null);
2857 return (R => Unfolded, Tree_Access => C);
2858 end;
2859
2860 -- For a non-terminal path, we get the permission tree of its
2861 -- prefix, and then get the subtree associated with the extension,
2862 -- if unfolded. If folded, we return the permission associated with
2863 -- children.
2864
2865 when N_Explicit_Dereference
2866 | N_Indexed_Component
2867 | N_Selected_Component
2868 | N_Slice
2869 =>
2870 declare
2871 C : constant Perm_Or_Tree := Get_Perm_Or_Tree (Prefix (N));
2872 begin
2873 case C.R is
2874
2875 -- Some earlier prefix was already folded, return the
2876 -- permission found.
2877
2878 when Folded =>
2879 return C;
2880
2881 when Unfolded =>
2882 case Kind (C.Tree_Access) is
2883
2884 -- If the prefix tree is already folded, return the
2885 -- children permission.
2886
2887 when Entire_Object =>
2888 return (R => Folded,
2889 Found_Permission =>
2890 Children_Permission (C.Tree_Access));
2891
2892 when Reference =>
2893 pragma Assert (Nkind (N) = N_Explicit_Dereference);
2894 return (R => Unfolded,
2895 Tree_Access => Get_All (C.Tree_Access));
2896
2897 when Record_Component =>
2898 pragma Assert (Nkind (N) = N_Selected_Component);
2899 declare
2900 Comp : constant Entity_Id :=
2901 Entity (Selector_Name (N));
2902 D : constant Perm_Tree_Access :=
2903 Perm_Tree_Maps.Get
2904 (Component (C.Tree_Access), Comp);
2905 begin
2906 pragma Assert (D /= null);
2907 return (R => Unfolded,
2908 Tree_Access => D);
2909 end;
2910
2911 when Array_Component =>
2912 pragma Assert (Nkind (N) = N_Indexed_Component
2913 or else
2914 Nkind (N) = N_Slice);
2915 pragma Assert (Get_Elem (C.Tree_Access) /= null);
2916 return (R => Unfolded,
2917 Tree_Access => Get_Elem (C.Tree_Access));
2918 end case;
2919 end case;
2920 end;
2921
2922 when N_Qualified_Expression
2923 | N_Type_Conversion
2924 | N_Unchecked_Type_Conversion
2925 =>
2926 return Get_Perm_Or_Tree (Expression (N));
2927
2928 when others =>
2929 raise Program_Error;
2930 end case;
2931 end Get_Perm_Or_Tree;
2932
2933 -------------------
2934 -- Get_Perm_Tree --
2935 -------------------
2936
2937 function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access is
2938 begin
2939 return Set_Perm_Prefixes (N, None);
2940 end Get_Perm_Tree;
2941
2942 ---------------------
2943 -- Get_Root_Object --
2944 ---------------------
2945
2946 function Get_Root_Object (Expr : Node_Id) return Entity_Id is
2947 begin
2948 case Nkind (Expr) is
2949 when N_Expanded_Name
2950 | N_Identifier
2951 =>
2952 return Entity (Expr);
2953
2954 when N_Explicit_Dereference
2955 | N_Indexed_Component
2956 | N_Selected_Component
2957 | N_Slice
2958 =>
2959 return Get_Root_Object (Prefix (Expr));
2960
2961 -- There is no entity for an allocator, NULL or a function call
2962
2963 when N_Allocator
2964 | N_Null
2965 | N_Function_Call
2966 =>
2967 return Empty;
2968
2969 when N_Qualified_Expression
2970 | N_Type_Conversion
2971 | N_Unchecked_Type_Conversion
2972 =>
2973 return Get_Root_Object (Expression (Expr));
2974
2975 when others =>
2976 raise Program_Error;
2977 end case;
2978 end Get_Root_Object;
2979
2980 ---------
2981 -- Glb --
2982 ---------
2983
2984 function Glb (P1, P2 : Perm_Kind) return Perm_Kind
2985 is
2986 begin
2987 case P1 is
2988 when No_Access =>
2989 return No_Access;
2990
2991 when Read_Only =>
2992 case P2 is
2993 when No_Access
2994 | Write_Only
2995 =>
2996 return No_Access;
2997
2998 when Read_Perm =>
2999 return Read_Only;
3000 end case;
3001
3002 when Write_Only =>
3003 case P2 is
3004 when No_Access
3005 | Read_Only
3006 =>
3007 return No_Access;
3008
3009 when Write_Perm =>
3010 return Write_Only;
3011 end case;
3012
3013 when Read_Write =>
3014 return P2;
3015 end case;
3016 end Glb;
3017
3018 -------------------------
3019 -- Has_Array_Component --
3020 -------------------------
3021
3022 function Has_Array_Component (Expr : Node_Id) return Boolean is
3023 begin
3024 case Nkind (Expr) is
3025 when N_Expanded_Name
3026 | N_Identifier
3027 =>
3028 return False;
3029
3030 when N_Explicit_Dereference
3031 | N_Selected_Component
3032 =>
3033 return Has_Array_Component (Prefix (Expr));
3034
3035 when N_Indexed_Component
3036 | N_Slice
3037 =>
3038 return True;
3039
3040 when N_Allocator
3041 | N_Null
3042 | N_Function_Call
3043 =>
3044 return False;
3045
3046 when N_Qualified_Expression
3047 | N_Type_Conversion
3048 | N_Unchecked_Type_Conversion
3049 =>
3050 return Has_Array_Component (Expression (Expr));
3051
3052 when others =>
3053 raise Program_Error;
3054 end case;
3055 end Has_Array_Component;
3056
3057 --------
3058 -- Hp --
3059 --------
3060
3061 procedure Hp (P : Perm_Env) is
3062 Elem : Perm_Tree_Maps.Key_Option;
3063
3064 begin
3065 Elem := Get_First_Key (P);
3066 while Elem.Present loop
3067 Print_Node_Briefly (Elem.K);
3068 Elem := Get_Next_Key (P);
3069 end loop;
3070 end Hp;
3071
3072 --------------------------
3073 -- Illegal_Global_Usage --
3074 --------------------------
3075
3076 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id) is
3077 begin
3078 Error_Msg_NE ("cannot use global variable & of deep type", N, N);
3079 Error_Msg_N ("\without prior declaration in a Global aspect", N);
3080 Errout.Finalize (Last_Call => True);
3081 Errout.Output_Messages;
3082 Exit_Program (E_Errors);
3083 end Illegal_Global_Usage;
3084
3085 -------------
3086 -- Is_Deep --
3087 -------------
3088
3089 function Is_Deep (Typ : Entity_Id) return Boolean is
3090 begin
3091 case Type_Kind'(Ekind (Underlying_Type (Typ))) is
3092 when Access_Kind =>
3093 return True;
3094
3095 when E_Array_Type
3096 | E_Array_Subtype
3097 =>
3098 return Is_Deep (Component_Type (Typ));
3099
3100 when Record_Kind =>
3101 declare
3102 Comp : Entity_Id;
3103 begin
3104 Comp := First_Component_Or_Discriminant (Typ);
3105 while Present (Comp) loop
3106 if Is_Deep (Etype (Comp)) then
3107 return True;
3108 end if;
3109 Next_Component_Or_Discriminant (Comp);
3110 end loop;
3111 end;
3112 return False;
3113
3114 when Scalar_Kind
3115 | E_String_Literal_Subtype
3116 | Protected_Kind
3117 | Task_Kind
3118 | Incomplete_Kind
3119 | E_Exception_Type
3120 | E_Subprogram_Type
3121 =>
3122 return False;
3123
3124 -- The following should not arise as underlying types
3125
3126 when E_Private_Type
3127 | E_Private_Subtype
3128 | E_Limited_Private_Type
3129 | E_Limited_Private_Subtype
3130 =>
3131 raise Program_Error;
3132 end case;
3133 end Is_Deep;
3134
3135 ------------------------
3136 -- Is_Path_Expression --
3137 ------------------------
3138
3139 function Is_Path_Expression (Expr : Node_Id) return Boolean is
3140 begin
3141 case Nkind (Expr) is
3142 when N_Expanded_Name
3143 | N_Explicit_Dereference
3144 | N_Identifier
3145 | N_Indexed_Component
3146 | N_Selected_Component
3147 | N_Slice
3148 =>
3149 return True;
3150
3151 -- Special value NULL corresponds to an empty path
3152
3153 when N_Null =>
3154 return True;
3155
3156 -- Object returned by a allocator or function call corresponds to
3157 -- a path.
3158
3159 when N_Allocator
3160 | N_Function_Call
3161 =>
3162 return True;
3163
3164 when N_Qualified_Expression
3165 | N_Type_Conversion
3166 | N_Unchecked_Type_Conversion
3167 =>
3168 return Is_Path_Expression (Expression (Expr));
3169
3170 when others =>
3171 return False;
3172 end case;
3173 end Is_Path_Expression;
3174
3175 ---------------------------
3176 -- Is_Traversal_Function --
3177 ---------------------------
3178
3179 function Is_Traversal_Function (E : Entity_Id) return Boolean is
3180 begin
3181 return Ekind (E) = E_Function
3182
3183 -- A function is said to be a traversal function if the result type of
3184 -- the function is an anonymous access-to-object type,
3185
3186 and then Is_Anonymous_Access_Type (Etype (E))
3187
3188 -- the function has at least one formal parameter,
3189
3190 and then Present (First_Formal (E))
3191
3192 -- and the function's first parameter is of an access type.
3193
3194 and then Is_Access_Type (Etype (First_Formal (E)));
3195 end Is_Traversal_Function;
3196
3197 ------------------
3198 -- Loop_Of_Exit --
3199 ------------------
3200
3201 function Loop_Of_Exit (N : Node_Id) return Entity_Id is
3202 Nam : Node_Id := Name (N);
3203 Stmt : Node_Id := N;
3204 begin
3205 if No (Nam) then
3206 while Present (Stmt) loop
3207 Stmt := Parent (Stmt);
3208 if Nkind (Stmt) = N_Loop_Statement then
3209 Nam := Identifier (Stmt);
3210 exit;
3211 end if;
3212 end loop;
3213 end if;
3214 return Entity (Nam);
3215 end Loop_Of_Exit;
3216
3217 ---------
3218 -- Lub --
3219 ---------
3220
3221 function Lub (P1, P2 : Perm_Kind) return Perm_Kind is
3222 begin
3223 case P1 is
3224 when No_Access =>
3225 return P2;
3226
3227 when Read_Only =>
3228 case P2 is
3229 when No_Access
3230 | Read_Only
3231 =>
3232 return Read_Only;
3233
3234 when Write_Perm =>
3235 return Read_Write;
3236 end case;
3237
3238 when Write_Only =>
3239 case P2 is
3240 when No_Access
3241 | Write_Only
3242 =>
3243 return Write_Only;
3244
3245 when Read_Perm =>
3246 return Read_Write;
3247 end case;
3248
3249 when Read_Write =>
3250 return Read_Write;
3251 end case;
3252 end Lub;
3253
3254 ---------------
3255 -- Merge_Env --
3256 ---------------
3257
3258 procedure Merge_Env (Source : in out Perm_Env; Target : in out Perm_Env) is
3259
3260 -- Local subprograms
3261
3262 procedure Apply_Glb_Tree
3263 (A : Perm_Tree_Access;
3264 P : Perm_Kind);
3265
3266 procedure Merge_Trees
3267 (Target : Perm_Tree_Access;
3268 Source : Perm_Tree_Access);
3269
3270 --------------------
3271 -- Apply_Glb_Tree --
3272 --------------------
3273
3274 procedure Apply_Glb_Tree
3275 (A : Perm_Tree_Access;
3276 P : Perm_Kind)
3277 is
3278 begin
3279 A.all.Tree.Permission := Glb (Permission (A), P);
3280
3281 case Kind (A) is
3282 when Entire_Object =>
3283 A.all.Tree.Children_Permission :=
3284 Glb (Children_Permission (A), P);
3285
3286 when Reference =>
3287 Apply_Glb_Tree (Get_All (A), P);
3288
3289 when Array_Component =>
3290 Apply_Glb_Tree (Get_Elem (A), P);
3291
3292 when Record_Component =>
3293 declare
3294 Comp : Perm_Tree_Access;
3295 begin
3296 Comp := Perm_Tree_Maps.Get_First (Component (A));
3297 while Comp /= null loop
3298 Apply_Glb_Tree (Comp, P);
3299 Comp := Perm_Tree_Maps.Get_Next (Component (A));
3300 end loop;
3301 end;
3302 end case;
3303 end Apply_Glb_Tree;
3304
3305 -----------------
3306 -- Merge_Trees --
3307 -----------------
3308
3309 procedure Merge_Trees
3310 (Target : Perm_Tree_Access;
3311 Source : Perm_Tree_Access)
3312 is
3313 Perm : constant Perm_Kind :=
3314 Glb (Permission (Target), Permission (Source));
3315
3316 begin
3317 pragma Assert (Is_Node_Deep (Target) = Is_Node_Deep (Source));
3318 Target.all.Tree.Permission := Perm;
3319
3320 case Kind (Target) is
3321 when Entire_Object =>
3322 declare
3323 Child_Perm : constant Perm_Kind :=
3324 Children_Permission (Target);
3325
3326 begin
3327 case Kind (Source) is
3328 when Entire_Object =>
3329 Target.all.Tree.Children_Permission :=
3330 Glb (Child_Perm, Children_Permission (Source));
3331
3332 when Reference =>
3333 Copy_Tree (Source, Target);
3334 Target.all.Tree.Permission := Perm;
3335 Apply_Glb_Tree (Get_All (Target), Child_Perm);
3336
3337 when Array_Component =>
3338 Copy_Tree (Source, Target);
3339 Target.all.Tree.Permission := Perm;
3340 Apply_Glb_Tree (Get_Elem (Target), Child_Perm);
3341
3342 when Record_Component =>
3343 Copy_Tree (Source, Target);
3344 Target.all.Tree.Permission := Perm;
3345 declare
3346 Comp : Perm_Tree_Access;
3347
3348 begin
3349 Comp :=
3350 Perm_Tree_Maps.Get_First (Component (Target));
3351 while Comp /= null loop
3352 -- Apply glb tree on every component subtree
3353
3354 Apply_Glb_Tree (Comp, Child_Perm);
3355 Comp := Perm_Tree_Maps.Get_Next
3356 (Component (Target));
3357 end loop;
3358 end;
3359 end case;
3360 end;
3361
3362 when Reference =>
3363 case Kind (Source) is
3364 when Entire_Object =>
3365 Apply_Glb_Tree (Get_All (Target),
3366 Children_Permission (Source));
3367
3368 when Reference =>
3369 Merge_Trees (Get_All (Target), Get_All (Source));
3370
3371 when others =>
3372 raise Program_Error;
3373
3374 end case;
3375
3376 when Array_Component =>
3377 case Kind (Source) is
3378 when Entire_Object =>
3379 Apply_Glb_Tree (Get_Elem (Target),
3380 Children_Permission (Source));
3381
3382 when Array_Component =>
3383 Merge_Trees (Get_Elem (Target), Get_Elem (Source));
3384
3385 when others =>
3386 raise Program_Error;
3387
3388 end case;
3389
3390 when Record_Component =>
3391 case Kind (Source) is
3392 when Entire_Object =>
3393 declare
3394 Child_Perm : constant Perm_Kind :=
3395 Children_Permission (Source);
3396
3397 Comp : Perm_Tree_Access;
3398
3399 begin
3400 Comp := Perm_Tree_Maps.Get_First
3401 (Component (Target));
3402 while Comp /= null loop
3403 -- Apply glb tree on every component subtree
3404
3405 Apply_Glb_Tree (Comp, Child_Perm);
3406 Comp :=
3407 Perm_Tree_Maps.Get_Next (Component (Target));
3408 end loop;
3409 end;
3410
3411 when Record_Component =>
3412 declare
3413 Key_Source : Perm_Tree_Maps.Key_Option;
3414 CompTarget : Perm_Tree_Access;
3415 CompSource : Perm_Tree_Access;
3416
3417 begin
3418 Key_Source := Perm_Tree_Maps.Get_First_Key
3419 (Component (Source));
3420
3421 while Key_Source.Present loop
3422 CompSource := Perm_Tree_Maps.Get
3423 (Component (Source), Key_Source.K);
3424 CompTarget := Perm_Tree_Maps.Get
3425 (Component (Target), Key_Source.K);
3426
3427 pragma Assert (CompSource /= null);
3428 Merge_Trees (CompTarget, CompSource);
3429
3430 Key_Source := Perm_Tree_Maps.Get_Next_Key
3431 (Component (Source));
3432 end loop;
3433 end;
3434
3435 when others =>
3436 raise Program_Error;
3437 end case;
3438 end case;
3439 end Merge_Trees;
3440
3441 -- Local variables
3442
3443 CompTarget : Perm_Tree_Access;
3444 CompSource : Perm_Tree_Access;
3445 KeyTarget : Perm_Tree_Maps.Key_Option;
3446
3447 -- Start of processing for Merge_Env
3448
3449 begin
3450 KeyTarget := Get_First_Key (Target);
3451 -- Iterate over every tree of the environment in the target, and merge
3452 -- it with the source if there is such a similar one that exists. If
3453 -- there is none, then skip.
3454 while KeyTarget.Present loop
3455
3456 CompSource := Get (Source, KeyTarget.K);
3457 CompTarget := Get (Target, KeyTarget.K);
3458
3459 pragma Assert (CompTarget /= null);
3460
3461 if CompSource /= null then
3462 Merge_Trees (CompTarget, CompSource);
3463 Remove (Source, KeyTarget.K);
3464 end if;
3465
3466 KeyTarget := Get_Next_Key (Target);
3467 end loop;
3468
3469 -- Iterate over every tree of the environment of the source. And merge
3470 -- again. If there is not any tree of the target then just copy the tree
3471 -- from source to target.
3472 declare
3473 KeySource : Perm_Tree_Maps.Key_Option;
3474 begin
3475 KeySource := Get_First_Key (Source);
3476 while KeySource.Present loop
3477
3478 CompSource := Get (Source, KeySource.K);
3479 CompTarget := Get (Target, KeySource.K);
3480
3481 if CompTarget = null then
3482 CompTarget := new Perm_Tree_Wrapper'(CompSource.all);
3483 Copy_Tree (CompSource, CompTarget);
3484 Set (Target, KeySource.K, CompTarget);
3485 else
3486 Merge_Trees (CompTarget, CompSource);
3487 end if;
3488
3489 KeySource := Get_Next_Key (Source);
3490 end loop;
3491 end;
3492
3493 Free_Env (Source);
3494 end Merge_Env;
3495
3496 ----------------
3497 -- Perm_Error --
3498 ----------------
3499
3500 procedure Perm_Error
3501 (N : Node_Id;
3502 Perm : Perm_Kind;
3503 Found_Perm : Perm_Kind;
3504 Forbidden_Perm : Boolean := False)
3505 is
3506 procedure Set_Root_Object
3507 (Path : Node_Id;
3508 Obj : out Entity_Id;
3509 Deref : out Boolean);
3510 -- Set the root object Obj, and whether the path contains a dereference,
3511 -- from a path Path.
3512
3513 ---------------------
3514 -- Set_Root_Object --
3515 ---------------------
3516
3517 procedure Set_Root_Object
3518 (Path : Node_Id;
3519 Obj : out Entity_Id;
3520 Deref : out Boolean)
3521 is
3522 begin
3523 case Nkind (Path) is
3524 when N_Identifier
3525 | N_Expanded_Name
3526 =>
3527 Obj := Entity (Path);
3528 Deref := False;
3529
3530 when N_Type_Conversion
3531 | N_Unchecked_Type_Conversion
3532 | N_Qualified_Expression
3533 =>
3534 Set_Root_Object (Expression (Path), Obj, Deref);
3535
3536 when N_Indexed_Component
3537 | N_Selected_Component
3538 | N_Slice
3539 =>
3540 Set_Root_Object (Prefix (Path), Obj, Deref);
3541
3542 when N_Explicit_Dereference =>
3543 Set_Root_Object (Prefix (Path), Obj, Deref);
3544 Deref := True;
3545
3546 when others =>
3547 raise Program_Error;
3548 end case;
3549 end Set_Root_Object;
3550 -- Local variables
3551
3552 Root : Entity_Id;
3553 Is_Deref : Boolean;
3554
3555 -- Start of processing for Perm_Error
3556
3557 begin
3558 Set_Root_Object (N, Root, Is_Deref);
3559
3560 if Is_Deref then
3561 Error_Msg_NE
3562 ("insufficient permission on dereference from &", N, Root);
3563 else
3564 Error_Msg_NE ("insufficient permission for &", N, Root);
3565 end if;
3566
3567 Perm_Mismatch (N, Perm, Found_Perm, Forbidden_Perm);
3568 end Perm_Error;
3569
3570 -------------------------------
3571 -- Perm_Error_Subprogram_End --
3572 -------------------------------
3573
3574 procedure Perm_Error_Subprogram_End
3575 (E : Entity_Id;
3576 Subp : Entity_Id;
3577 Perm : Perm_Kind;
3578 Found_Perm : Perm_Kind)
3579 is
3580 begin
3581 Error_Msg_Node_2 := Subp;
3582 Error_Msg_NE ("insufficient permission for & when returning from &",
3583 Subp, E);
3584 Perm_Mismatch (Subp, Perm, Found_Perm);
3585 end Perm_Error_Subprogram_End;
3586
3587 ------------------
3588 -- Process_Path --
3589 ------------------
3590
3591 procedure Process_Path (Expr : Node_Id; Mode : Checking_Mode) is
3592 Expr_Type : constant Entity_Id := Etype (Expr);
3593 Root : Entity_Id := Get_Root_Object (Expr);
3594 Perm : Perm_Kind;
3595
3596 begin
3597 -- Nothing to do if the root type is not deep, or the path is not rooted
3598 -- in an object.
3599
3600 if not Present (Root)
3601 or else not Is_Deep (Etype (Root))
3602 then
3603 return;
3604 end if;
3605
3606 -- Identify the root type for the path
3607
3608 Root := Unique_Entity (Root);
3609
3610 -- The root object should have been declared and entered into the
3611 -- current permission environment.
3612
3613 if Get (Current_Perm_Env, Root) = null then
3614 Illegal_Global_Usage (Expr);
3615 end if;
3616
3617 Perm := Get_Perm (Expr);
3618
3619 case Mode is
3620
3621 when Read =>
3622
3623 -- No checking needed during elaboration
3624
3625 if Inside_Elaboration then
3626 return;
3627 end if;
3628
3629 -- Check path is readable
3630
3631 if Perm not in Read_Perm then
3632 Perm_Error (Expr, Read_Only, Perm);
3633 return;
3634 end if;
3635
3636 when Move =>
3637
3638 -- Forbidden on deep path during elaboration, otherwise no
3639 -- checking needed.
3640
3641 if Inside_Elaboration then
3642 if Is_Deep (Expr_Type)
3643 and then not Inside_Procedure_Call
3644 and then Present (Get_Root_Object (Expr))
3645 then
3646 Error_Msg_N ("illegal move during elaboration", Expr);
3647 end if;
3648
3649 return;
3650 end if;
3651
3652 -- For deep path, check RW permission, otherwise R permission
3653
3654 if not Is_Deep (Expr_Type) then
3655 if Perm not in Read_Perm then
3656 Perm_Error (Expr, Read_Only, Perm);
3657 end if;
3658 return;
3659 end if;
3660
3661 -- SPARK RM 3.10(1): At the point of a move operation the state of
3662 -- the source object (if any) shall be Unrestricted.
3663
3664 if Perm /= Read_Write then
3665 Perm_Error (Expr, Read_Write, Perm);
3666 return;
3667 end if;
3668
3669 -- Do not update permission environment when handling calls
3670
3671 if Inside_Procedure_Call then
3672 return;
3673 end if;
3674
3675 -- SPARK RM 3.10(1): After a move operation, the state of the
3676 -- source object (if any) becomes Moved.
3677
3678 if Present (Get_Root_Object (Expr)) then
3679 declare
3680 Tree : constant Perm_Tree_Access :=
3681 Set_Perm_Prefixes (Expr, Write_Only);
3682 begin
3683 pragma Assert (Tree /= null);
3684 Set_Perm_Extensions_Move (Tree, Etype (Expr));
3685 end;
3686 end if;
3687
3688 when Assign =>
3689
3690 -- No checking needed during elaboration
3691
3692 if Inside_Elaboration then
3693 return;
3694 end if;
3695
3696 -- For assignment, check W permission
3697
3698 if Perm not in Write_Perm then
3699 Perm_Error (Expr, Write_Only, Perm);
3700 return;
3701 end if;
3702
3703 -- Do not update permission environment when handling calls
3704
3705 if Inside_Procedure_Call then
3706 return;
3707 end if;
3708
3709 -- If there is no root object, or the tree has an array component,
3710 -- then the permissions do not get modified by the assignment.
3711
3712 if No (Get_Root_Object (Expr))
3713 or else Has_Array_Component (Expr)
3714 then
3715 return;
3716 end if;
3717
3718 -- Set permission RW for the path and its extensions
3719
3720 declare
3721 Tree : constant Perm_Tree_Access := Get_Perm_Tree (Expr);
3722 begin
3723 Tree.all.Tree.Permission := Read_Write;
3724 Set_Perm_Extensions (Tree, Read_Write);
3725
3726 -- Normalize the permission tree
3727
3728 Set_Perm_Prefixes_Assign (Expr);
3729 end;
3730
3731 when Borrow =>
3732
3733 -- Forbidden during elaboration
3734
3735 if Inside_Elaboration then
3736 if not Inside_Procedure_Call then
3737 Error_Msg_N ("illegal borrow during elaboration", Expr);
3738 end if;
3739
3740 return;
3741 end if;
3742
3743 -- For borrowing, check RW permission
3744
3745 if Perm /= Read_Write then
3746 Perm_Error (Expr, Read_Write, Perm);
3747 return;
3748 end if;
3749
3750 -- Do not update permission environment when handling calls
3751
3752 if Inside_Procedure_Call then
3753 return;
3754 end if;
3755
3756 -- Set permission NO for the path and its extensions
3757
3758 declare
3759 Tree : constant Perm_Tree_Access :=
3760 Set_Perm_Prefixes (Expr, No_Access);
3761 begin
3762 Set_Perm_Extensions (Tree, No_Access);
3763 end;
3764
3765 when Observe =>
3766
3767 -- Forbidden during elaboration
3768
3769 if Inside_Elaboration then
3770 if not Inside_Procedure_Call then
3771 Error_Msg_N ("illegal observe during elaboration", Expr);
3772 end if;
3773
3774 return;
3775 end if;
3776
3777 -- For borrowing, check R permission
3778
3779 if Perm not in Read_Perm then
3780 Perm_Error (Expr, Read_Only, Perm);
3781 return;
3782 end if;
3783
3784 -- Do not update permission environment when handling calls
3785
3786 if Inside_Procedure_Call then
3787 return;
3788 end if;
3789
3790 -- Set permission R for the path and its extensions
3791
3792 declare
3793 Tree : constant Perm_Tree_Access :=
3794 Set_Perm_Prefixes (Expr, Read_Only);
3795 begin
3796 Set_Perm_Extensions (Tree, Read_Only);
3797 end;
3798 end case;
3799 end Process_Path;
3800
3801 --------------------
3802 -- Return_Globals --
3803 --------------------
3804
3805 procedure Return_Globals (Subp : Entity_Id) is
3806
3807 procedure Return_Global
3808 (Expr : Node_Id;
3809 Param_Mode : Formal_Kind;
3810 Subp : Entity_Id;
3811 Global_Var : Boolean);
3812 -- Proxy procedure to return globals, to adjust for the type of first
3813 -- parameter expected by Return_Parameter_Or_Global.
3814
3815 -------------------
3816 -- Return_Global --
3817 -------------------
3818
3819 procedure Return_Global
3820 (Expr : Node_Id;
3821 Param_Mode : Formal_Kind;
3822 Subp : Entity_Id;
3823 Global_Var : Boolean)
3824 is
3825 begin
3826 Return_Parameter_Or_Global
3827 (Entity (Expr), Param_Mode, Subp, Global_Var);
3828 end Return_Global;
3829
3830 procedure Return_Globals_Inst is new Handle_Globals (Return_Global);
3831
3832 -- Start of processing for Return_Globals
3833
3834 begin
3835 Return_Globals_Inst (Subp);
3836 end Return_Globals;
3837
3838 --------------------------------
3839 -- Return_Parameter_Or_Global --
3840 --------------------------------
3841
3842 procedure Return_Parameter_Or_Global
3843 (Id : Entity_Id;
3844 Mode : Formal_Kind;
3845 Subp : Entity_Id;
3846 Global_Var : Boolean)
3847 is
3848 Typ : constant Entity_Id := Underlying_Type (Etype (Id));
3849 begin
3850 -- Shallow parameters and globals need not be considered
3851
3852 if not Is_Deep (Typ) then
3853 return;
3854
3855 elsif Mode = E_In_Parameter then
3856
3857 -- Input global variables are observed only
3858
3859 if Global_Var then
3860 return;
3861
3862 -- Anonymous access to constant is an observe
3863
3864 elsif Is_Anonymous_Access_Type (Typ)
3865 and then Is_Access_Constant (Typ)
3866 then
3867 return;
3868
3869 -- Deep types other than access types define an observe
3870
3871 elsif not Is_Access_Type (Typ) then
3872 return;
3873 end if;
3874 end if;
3875
3876 -- All other parameters and globals should return with mode RW to the
3877 -- caller.
3878
3879 declare
3880 Tree : constant Perm_Tree_Access := Get (Current_Perm_Env, Id);
3881 begin
3882 if Permission (Tree) /= Read_Write then
3883 Perm_Error_Subprogram_End
3884 (E => Id,
3885 Subp => Subp,
3886 Perm => Read_Write,
3887 Found_Perm => Permission (Tree));
3888 end if;
3889 end;
3890 end Return_Parameter_Or_Global;
3891
3892 -----------------------
3893 -- Return_Parameters --
3894 -----------------------
3895
3896 procedure Return_Parameters (Subp : Entity_Id) is
3897 Formal : Entity_Id;
3898 begin
3899 Formal := First_Formal (Subp);
3900 while Present (Formal) loop
3901 Return_Parameter_Or_Global (Formal, Ekind (Formal), Subp, False);
3902 Next_Formal (Formal);
3903 end loop;
3904 end Return_Parameters;
3905
3906 -------------------------
3907 -- Set_Perm_Extensions --
3908 -------------------------
3909
3910 procedure Set_Perm_Extensions (T : Perm_Tree_Access; P : Perm_Kind) is
3911
3912 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access);
3913 -- Free the permission tree of children if any, prio to replacing T
3914
3915 -----------------------------
3916 -- Free_Perm_Tree_Children --
3917 -----------------------------
3918
3919 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access) is
3920 begin
3921 case Kind (T) is
3922 when Entire_Object =>
3923 null;
3924
3925 when Reference =>
3926 Free_Tree (T.all.Tree.Get_All);
3927
3928 when Array_Component =>
3929 Free_Tree (T.all.Tree.Get_Elem);
3930
3931 when Record_Component =>
3932 declare
3933 Hashtbl : Perm_Tree_Maps.Instance := Component (T);
3934 Comp : Perm_Tree_Access;
3935
3936 begin
3937 Comp := Perm_Tree_Maps.Get_First (Hashtbl);
3938 while Comp /= null loop
3939 Free_Tree (Comp);
3940 Comp := Perm_Tree_Maps.Get_Next (Hashtbl);
3941 end loop;
3942
3943 Perm_Tree_Maps.Reset (Hashtbl);
3944 end;
3945 end case;
3946 end Free_Perm_Tree_Children;
3947
3948 -- Start of processing for Set_Perm_Extensions
3949
3950 begin
3951 Free_Perm_Tree_Children (T);
3952 T.all.Tree := Perm_Tree'(Kind => Entire_Object,
3953 Is_Node_Deep => Is_Node_Deep (T),
3954 Permission => Permission (T),
3955 Children_Permission => P);
3956 end Set_Perm_Extensions;
3957
3958 ------------------------------
3959 -- Set_Perm_Extensions_Move --
3960 ------------------------------
3961
3962 procedure Set_Perm_Extensions_Move
3963 (T : Perm_Tree_Access;
3964 E : Entity_Id)
3965 is
3966 begin
3967 -- Shallow extensions are set to RW
3968
3969 if not Is_Node_Deep (T) then
3970 Set_Perm_Extensions (T, Read_Write);
3971 return;
3972 end if;
3973
3974 -- Deep extensions are set to W before .all and NO afterwards
3975
3976 T.all.Tree.Permission := Write_Only;
3977
3978 case T.all.Tree.Kind is
3979
3980 -- For a folded tree of composite type, unfold the tree for better
3981 -- precision.
3982
3983 when Entire_Object =>
3984 case Ekind (E) is
3985 when E_Array_Type
3986 | E_Array_Subtype
3987 =>
3988 declare
3989 C : constant Perm_Tree_Access :=
3990 new Perm_Tree_Wrapper'
3991 (Tree =>
3992 (Kind => Entire_Object,
3993 Is_Node_Deep => Is_Node_Deep (T),
3994 Permission => Read_Write,
3995 Children_Permission => Read_Write));
3996 begin
3997 Set_Perm_Extensions_Move (C, Component_Type (E));
3998 T.all.Tree := (Kind => Array_Component,
3999 Is_Node_Deep => Is_Node_Deep (T),
4000 Permission => Write_Only,
4001 Get_Elem => C);
4002 end;
4003
4004 when Record_Kind =>
4005 declare
4006 C : Perm_Tree_Access;
4007 Comp : Entity_Id;
4008 Hashtbl : Perm_Tree_Maps.Instance;
4009
4010 begin
4011 Comp := First_Component_Or_Discriminant (E);
4012 while Present (Comp) loop
4013 C := new Perm_Tree_Wrapper'
4014 (Tree =>
4015 (Kind => Entire_Object,
4016 Is_Node_Deep => Is_Deep (Etype (Comp)),
4017 Permission => Read_Write,
4018 Children_Permission => Read_Write));
4019 Set_Perm_Extensions_Move (C, Etype (Comp));
4020 Perm_Tree_Maps.Set (Hashtbl, Comp, C);
4021 Next_Component_Or_Discriminant (Comp);
4022 end loop;
4023
4024 T.all.Tree :=
4025 (Kind => Record_Component,
4026 Is_Node_Deep => Is_Node_Deep (T),
4027 Permission => Write_Only,
4028 Component => Hashtbl);
4029 end;
4030
4031 -- Otherwise, extensions are set to NO
4032
4033 when others =>
4034 Set_Perm_Extensions (T, No_Access);
4035 end case;
4036
4037 when Reference =>
4038 Set_Perm_Extensions (T, No_Access);
4039
4040 when Array_Component =>
4041 Set_Perm_Extensions_Move (Get_Elem (T), Component_Type (E));
4042
4043 when Record_Component =>
4044 declare
4045 C : Perm_Tree_Access;
4046 Comp : Entity_Id;
4047
4048 begin
4049 Comp := First_Component_Or_Discriminant (E);
4050 while Present (Comp) loop
4051 C := Perm_Tree_Maps.Get (Component (T), Comp);
4052 pragma Assert (C /= null);
4053 Set_Perm_Extensions_Move (C, Etype (Comp));
4054 Next_Component_Or_Discriminant (Comp);
4055 end loop;
4056 end;
4057 end case;
4058 end Set_Perm_Extensions_Move;
4059
4060 -----------------------
4061 -- Set_Perm_Prefixes --
4062 -----------------------
4063
4064 function Set_Perm_Prefixes
4065 (N : Node_Id;
4066 Perm : Perm_Kind_Option) return Perm_Tree_Access
4067 is
4068 begin
4069 case Nkind (N) is
4070 when N_Expanded_Name
4071 | N_Identifier
4072 =>
4073 declare
4074 E : constant Entity_Id := Unique_Entity (Entity (N));
4075 C : constant Perm_Tree_Access := Get (Current_Perm_Env, E);
4076 pragma Assert (C /= null);
4077
4078 begin
4079 if Perm /= None then
4080 C.all.Tree.Permission := Glb (Perm, Permission (C));
4081 end if;
4082
4083 return C;
4084 end;
4085
4086 -- For a non-terminal path, we set the permission tree of its prefix,
4087 -- and then we extract from the returned pointer the subtree and
4088 -- assign an adequate permission to it, if unfolded. If folded,
4089 -- we unroll the tree one level.
4090
4091 when N_Explicit_Dereference =>
4092 declare
4093 C : constant Perm_Tree_Access :=
4094 Set_Perm_Prefixes (Prefix (N), Perm);
4095 pragma Assert (C /= null);
4096 pragma Assert (Kind (C) = Entire_Object
4097 or else Kind (C) = Reference);
4098 begin
4099 -- The tree is already unfolded. Replace the permission of the
4100 -- dereference.
4101
4102 if Kind (C) = Reference then
4103 declare
4104 D : constant Perm_Tree_Access := Get_All (C);
4105 pragma Assert (D /= null);
4106
4107 begin
4108 if Perm /= None then
4109 D.all.Tree.Permission := Glb (Perm, Permission (D));
4110 end if;
4111
4112 return D;
4113 end;
4114
4115 -- The tree is folded. Expand it.
4116
4117 else
4118 declare
4119 pragma Assert (Kind (C) = Entire_Object);
4120
4121 Child_P : constant Perm_Kind := Children_Permission (C);
4122 D : constant Perm_Tree_Access :=
4123 new Perm_Tree_Wrapper'
4124 (Tree =>
4125 (Kind => Entire_Object,
4126 Is_Node_Deep => Is_Deep (Etype (N)),
4127 Permission => Child_P,
4128 Children_Permission => Child_P));
4129 begin
4130 if Perm /= None then
4131 D.all.Tree.Permission := Perm;
4132 end if;
4133
4134 C.all.Tree := (Kind => Reference,
4135 Is_Node_Deep => Is_Node_Deep (C),
4136 Permission => Permission (C),
4137 Get_All => D);
4138 return D;
4139 end;
4140 end if;
4141 end;
4142
4143 when N_Selected_Component =>
4144 declare
4145 C : constant Perm_Tree_Access :=
4146 Set_Perm_Prefixes (Prefix (N), Perm);
4147 pragma Assert (C /= null);
4148 pragma Assert (Kind (C) = Entire_Object
4149 or else Kind (C) = Record_Component);
4150 begin
4151 -- The tree is already unfolded. Replace the permission of the
4152 -- component.
4153
4154 if Kind (C) = Record_Component then
4155 declare
4156 Comp : constant Entity_Id := Entity (Selector_Name (N));
4157 D : constant Perm_Tree_Access :=
4158 Perm_Tree_Maps.Get (Component (C), Comp);
4159 pragma Assert (D /= null);
4160
4161 begin
4162 if Perm /= None then
4163 D.all.Tree.Permission := Glb (Perm, Permission (D));
4164 end if;
4165
4166 return D;
4167 end;
4168
4169 -- The tree is folded. Expand it.
4170
4171 else
4172 declare
4173 pragma Assert (Kind (C) = Entire_Object);
4174
4175 D : Perm_Tree_Access;
4176 Comp : Node_Id;
4177 P : Perm_Kind;
4178 Child_P : constant Perm_Kind := Children_Permission (C);
4179 Hashtbl : Perm_Tree_Maps.Instance;
4180 -- Create an empty hash table
4181
4182 begin
4183 Comp :=
4184 First_Component_Or_Discriminant (Etype (Prefix (N)));
4185
4186 while Present (Comp) loop
4187 if Perm /= None
4188 and then Comp = Entity (Selector_Name (N))
4189 then
4190 P := Perm;
4191 else
4192 P := Child_P;
4193 end if;
4194
4195 D := new Perm_Tree_Wrapper'
4196 (Tree =>
4197 (Kind => Entire_Object,
4198 Is_Node_Deep => Is_Deep (Etype (Comp)),
4199 Permission => P,
4200 Children_Permission => Child_P));
4201 Perm_Tree_Maps.Set (Hashtbl, Comp, D);
4202 Next_Component_Or_Discriminant (Comp);
4203 end loop;
4204
4205 C.all.Tree := (Kind => Record_Component,
4206 Is_Node_Deep => Is_Node_Deep (C),
4207 Permission => Permission (C),
4208 Component => Hashtbl);
4209 return D;
4210 end;
4211 end if;
4212 end;
4213
4214 when N_Indexed_Component
4215 | N_Slice
4216 =>
4217 declare
4218 C : constant Perm_Tree_Access :=
4219 Set_Perm_Prefixes (Prefix (N), Perm);
4220 pragma Assert (C /= null);
4221 pragma Assert (Kind (C) = Entire_Object
4222 or else Kind (C) = Array_Component);
4223 begin
4224 -- The tree is already unfolded. Replace the permission of the
4225 -- component.
4226
4227 if Kind (C) = Array_Component then
4228 declare
4229 D : constant Perm_Tree_Access := Get_Elem (C);
4230 pragma Assert (D /= null);
4231
4232 begin
4233 if Perm /= None then
4234 D.all.Tree.Permission := Glb (Perm, Permission (D));
4235 end if;
4236
4237 return D;
4238 end;
4239
4240 -- The tree is folded. Expand it.
4241
4242 else
4243 declare
4244 pragma Assert (Kind (C) = Entire_Object);
4245
4246 Child_P : constant Perm_Kind := Children_Permission (C);
4247 D : constant Perm_Tree_Access :=
4248 new Perm_Tree_Wrapper'
4249 (Tree =>
4250 (Kind => Entire_Object,
4251 Is_Node_Deep => Is_Node_Deep (C),
4252 Permission => Child_P,
4253 Children_Permission => Child_P));
4254 begin
4255 if Perm /= None then
4256 D.all.Tree.Permission := Perm;
4257 end if;
4258
4259 C.all.Tree := (Kind => Array_Component,
4260 Is_Node_Deep => Is_Node_Deep (C),
4261 Permission => Permission (C),
4262 Get_Elem => D);
4263 return D;
4264 end;
4265 end if;
4266 end;
4267
4268 when N_Qualified_Expression
4269 | N_Type_Conversion
4270 | N_Unchecked_Type_Conversion
4271 =>
4272 return Set_Perm_Prefixes (Expression (N), Perm);
4273
4274 when others =>
4275 raise Program_Error;
4276 end case;
4277 end Set_Perm_Prefixes;
4278
4279 ------------------------------
4280 -- Set_Perm_Prefixes_Assign --
4281 ------------------------------
4282
4283 procedure Set_Perm_Prefixes_Assign (N : Node_Id) is
4284 C : constant Perm_Tree_Access := Get_Perm_Tree (N);
4285
4286 begin
4287 case Kind (C) is
4288 when Entire_Object =>
4289 pragma Assert (Children_Permission (C) = Read_Write);
4290 C.all.Tree.Permission := Read_Write;
4291
4292 when Reference =>
4293 C.all.Tree.Permission :=
4294 Lub (Permission (C), Permission (Get_All (C)));
4295
4296 when Array_Component =>
4297 null;
4298
4299 when Record_Component =>
4300 declare
4301 Comp : Perm_Tree_Access;
4302 Perm : Perm_Kind := Read_Write;
4303
4304 begin
4305 -- We take the Glb of all the descendants, and then update the
4306 -- permission of the node with it.
4307
4308 Comp := Perm_Tree_Maps.Get_First (Component (C));
4309 while Comp /= null loop
4310 Perm := Glb (Perm, Permission (Comp));
4311 Comp := Perm_Tree_Maps.Get_Next (Component (C));
4312 end loop;
4313
4314 C.all.Tree.Permission := Lub (Permission (C), Perm);
4315 end;
4316 end case;
4317
4318 case Nkind (N) is
4319
4320 -- Base identifier end recursion
4321
4322 when N_Expanded_Name
4323 | N_Identifier
4324 =>
4325 null;
4326
4327 when N_Explicit_Dereference
4328 | N_Indexed_Component
4329 | N_Selected_Component
4330 | N_Slice
4331 =>
4332 Set_Perm_Prefixes_Assign (Prefix (N));
4333
4334 when N_Qualified_Expression
4335 | N_Type_Conversion
4336 | N_Unchecked_Type_Conversion
4337 =>
4338 Set_Perm_Prefixes_Assign (Expression (N));
4339
4340 when others =>
4341 raise Program_Error;
4342 end case;
4343 end Set_Perm_Prefixes_Assign;
4344
4345 -------------------
4346 -- Setup_Globals --
4347 -------------------
4348
4349 procedure Setup_Globals (Subp : Entity_Id) is
4350
4351 procedure Setup_Global
4352 (Expr : Node_Id;
4353 Param_Mode : Formal_Kind;
4354 Subp : Entity_Id;
4355 Global_Var : Boolean);
4356 -- Proxy procedure to set up globals, to adjust for the type of first
4357 -- parameter expected by Setup_Parameter_Or_Global.
4358
4359 ------------------
4360 -- Setup_Global --
4361 ------------------
4362
4363 procedure Setup_Global
4364 (Expr : Node_Id;
4365 Param_Mode : Formal_Kind;
4366 Subp : Entity_Id;
4367 Global_Var : Boolean)
4368 is
4369 begin
4370 Setup_Parameter_Or_Global
4371 (Entity (Expr), Param_Mode, Subp, Global_Var);
4372 end Setup_Global;
4373
4374 procedure Setup_Globals_Inst is new Handle_Globals (Setup_Global);
4375
4376 -- Start of processing for Setup_Globals
4377
4378 begin
4379 Setup_Globals_Inst (Subp);
4380 end Setup_Globals;
4381
4382 -------------------------------
4383 -- Setup_Parameter_Or_Global --
4384 -------------------------------
4385
4386 procedure Setup_Parameter_Or_Global
4387 (Id : Entity_Id;
4388 Param_Mode : Formal_Kind;
4389 Subp : Entity_Id;
4390 Global_Var : Boolean)
4391 is
4392 Typ : constant Entity_Id := Underlying_Type (Etype (Id));
4393 Perm : Perm_Kind_Option;
4394
4395 begin
4396 case Param_Mode is
4397 when E_In_Parameter =>
4398
4399 -- Shallow parameters and globals need not be considered
4400
4401 if not Is_Deep (Typ) then
4402 Perm := None;
4403
4404 -- Inputs of functions have R permission only
4405
4406 elsif Ekind (Subp) = E_Function then
4407 Perm := Read_Only;
4408
4409 -- Input global variables have R permission only
4410
4411 elsif Global_Var then
4412 Perm := Read_Only;
4413
4414 -- Anonymous access to constant is an observe
4415
4416 elsif Is_Anonymous_Access_Type (Typ)
4417 and then Is_Access_Constant (Typ)
4418 then
4419 Perm := Read_Only;
4420
4421 -- Other access types are a borrow
4422
4423 elsif Is_Access_Type (Typ) then
4424 Perm := Read_Write;
4425
4426 -- Deep types other than access types define an observe
4427
4428 else
4429 Perm := Read_Only;
4430 end if;
4431
4432 when E_Out_Parameter
4433 | E_In_Out_Parameter
4434 =>
4435 -- Shallow parameters and globals need not be considered
4436
4437 if not Is_Deep (Typ) then
4438 Perm := None;
4439
4440 -- Functions cannot have outputs in SPARK
4441
4442 elsif Ekind (Subp) = E_Function then
4443 if Param_Mode = E_Out_Parameter then
4444 Error_Msg_N ("function with OUT parameter is not "
4445 & "allowed in SPARK", Id);
4446 else
4447 Error_Msg_N ("function with `IN OUT` parameter is not "
4448 & "allowed in SPARK", Id);
4449 end if;
4450
4451 return;
4452
4453 -- Deep types define a borrow or a move
4454
4455 else
4456 Perm := Read_Write;
4457 end if;
4458 end case;
4459
4460 if Perm /= None then
4461 declare
4462 Tree : constant Perm_Tree_Access :=
4463 new Perm_Tree_Wrapper'
4464 (Tree =>
4465 (Kind => Entire_Object,
4466 Is_Node_Deep => Is_Deep (Etype (Id)),
4467 Permission => Perm,
4468 Children_Permission => Perm));
4469 begin
4470 Set (Current_Perm_Env, Id, Tree);
4471 end;
4472 end if;
4473 end Setup_Parameter_Or_Global;
4474
4475 ----------------------
4476 -- Setup_Parameters --
4477 ----------------------
4478
4479 procedure Setup_Parameters (Subp : Entity_Id) is
4480 Formal : Entity_Id;
4481 begin
4482 Formal := First_Formal (Subp);
4483 while Present (Formal) loop
4484 Setup_Parameter_Or_Global
4485 (Formal, Ekind (Formal), Subp, Global_Var => False);
4486 Next_Formal (Formal);
4487 end loop;
4488 end Setup_Parameters;
4489
4490 end Sem_SPARK;