[NDS32] new attribute no_prologue and new option -mret-in-naked-func.
[official-gcc.git] / gcc / ada / sem_spark.adb
blob3abfd99ae874eef3613b3bf41b177449df624e39
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-2018, 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 ------------------------------------------------------------------------------
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;
40 with Ada.Unchecked_Deallocation;
41 with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
43 package body Sem_SPARK is
45 -------------------------------------------------
46 -- Handling of Permissions Associated to Paths --
47 -------------------------------------------------
49 package Permissions is
50 Elaboration_Context_Max : constant := 1009;
51 -- The hash range
53 type Elaboration_Context_Index is range 0 .. Elaboration_Context_Max - 1;
55 function Elaboration_Context_Hash
56 (Key : Entity_Id) return Elaboration_Context_Index;
57 -- Function to hash any node of the AST
59 type Perm_Kind is (No_Access, Read_Only, Read_Write, Write_Only);
60 -- Permission type associated with paths
62 subtype Read_Perm is Perm_Kind range Read_Only .. Read_Write;
63 subtype Write_Perm is Perm_Kind range Read_Write .. Write_Only;
65 type Perm_Tree_Wrapper;
67 type Perm_Tree_Access is access Perm_Tree_Wrapper;
68 -- A tree of permissions is defined, where the root is a whole object
69 -- and tree branches follow access paths in memory. As Perm_Tree is a
70 -- discriminated record, a wrapper type is used for the access type
71 -- designating a subtree, to make it unconstrained so that it can be
72 -- updated.
74 -- Nodes in the permission tree are of different kinds
76 type Path_Kind is
77 (Entire_Object, -- Scalar object, or folded object of any type
78 Reference, -- Unfolded object of access type
79 Array_Component, -- Unfolded object of array type
80 Record_Component -- Unfolded object of record type
83 package Perm_Tree_Maps is new Simple_HTable
84 (Header_Num => Elaboration_Context_Index,
85 Key => Node_Id,
86 Element => Perm_Tree_Access,
87 No_Element => null,
88 Hash => Elaboration_Context_Hash,
89 Equal => "=");
90 -- The instantation of a hash table, with keys being nodes and values
91 -- being pointers to trees. This is used to reference easily all
92 -- extensions of a Record_Component node (that can have name x, y, ...).
94 -- The definition of permission trees. This is a tree, which has a
95 -- permission at each node, and depending on the type of the node,
96 -- can have zero, one, or more children pointed to by an access to tree.
97 type Perm_Tree (Kind : Path_Kind := Entire_Object) is record
98 Permission : Perm_Kind;
99 -- Permission at this level in the path
101 Is_Node_Deep : Boolean;
102 -- Whether this node is of a deep type, to be used when moving the
103 -- path.
105 case Kind is
107 -- An entire object is either a leaf (an object which cannot be
108 -- extended further in a path) or a subtree in folded form (which
109 -- could later be unfolded further in another kind of node). The
110 -- field Children_Permission specifies a permission for every
111 -- extension of that node if that permission is different from
112 -- the node's permission.
114 when Entire_Object =>
115 Children_Permission : Perm_Kind;
117 -- Unfolded path of access type. The permission of the object
118 -- pointed to is given in Get_All.
120 when Reference =>
121 Get_All : Perm_Tree_Access;
123 -- Unfolded path of array type. The permission of the elements is
124 -- given in Get_Elem.
126 when Array_Component =>
127 Get_Elem : Perm_Tree_Access;
129 -- Unfolded path of record type. The permission of the regular
130 -- components is given in Component. The permission of unknown
131 -- components (for objects of tagged type) is given in
132 -- Other_Components.
134 when Record_Component =>
135 Component : Perm_Tree_Maps.Instance;
136 Other_Components : Perm_Tree_Access;
137 end case;
138 end record;
140 type Perm_Tree_Wrapper is record
141 Tree : Perm_Tree;
142 end record;
143 -- We use this wrapper in order to have unconstrained discriminants
145 type Perm_Env is new Perm_Tree_Maps.Instance;
146 -- The definition of a permission environment for the analysis. This
147 -- is just a hash table of permission trees, each of them rooted with
148 -- an Identifier/Expanded_Name.
150 type Perm_Env_Access is access Perm_Env;
151 -- Access to permission environments
153 package Env_Maps is new Simple_HTable
154 (Header_Num => Elaboration_Context_Index,
155 Key => Entity_Id,
156 Element => Perm_Env_Access,
157 No_Element => null,
158 Hash => Elaboration_Context_Hash,
159 Equal => "=");
160 -- The instantiation of a hash table whose elements are permission
161 -- environments. This hash table is used to save the environments at
162 -- the entry of each loop, with the key being the loop label.
164 type Env_Backups is new Env_Maps.Instance;
165 -- The type defining the hash table saving the environments at the entry
166 -- of each loop.
168 package Boolean_Variables_Maps is new Simple_HTable
169 (Header_Num => Elaboration_Context_Index,
170 Key => Entity_Id,
171 Element => Boolean,
172 No_Element => False,
173 Hash => Elaboration_Context_Hash,
174 Equal => "=");
175 -- These maps allow tracking the variables that have been declared but
176 -- never used anywhere in the source code. Especially, we do not raise
177 -- an error if the variable stays write-only and is declared at package
178 -- level, because there is no risk that the variable has been moved,
179 -- because it has never been used.
181 type Initialization_Map is new Boolean_Variables_Maps.Instance;
183 --------------------
184 -- Simple Getters --
185 --------------------
187 -- Simple getters to avoid having .all.Tree.Field everywhere. Of course,
188 -- that's only for the top access, as otherwise this reverses the order
189 -- in accesses visually.
191 function Children_Permission (T : Perm_Tree_Access) return Perm_Kind;
192 function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance;
193 function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access;
194 function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access;
195 function Is_Node_Deep (T : Perm_Tree_Access) return Boolean;
196 function Kind (T : Perm_Tree_Access) return Path_Kind;
197 function Other_Components (T : Perm_Tree_Access) return Perm_Tree_Access;
198 function Permission (T : Perm_Tree_Access) return Perm_Kind;
200 -----------------------
201 -- Memory Management --
202 -----------------------
204 procedure Copy_Env
205 (From : Perm_Env;
206 To : in out Perm_Env);
207 -- Procedure to copy a permission environment
209 procedure Copy_Init_Map
210 (From : Initialization_Map;
211 To : in out Initialization_Map);
212 -- Procedure to copy an initialization map
214 procedure Copy_Tree
215 (From : Perm_Tree_Access;
216 To : Perm_Tree_Access);
217 -- Procedure to copy a permission tree
219 procedure Free_Env
220 (PE : in out Perm_Env);
221 -- Procedure to free a permission environment
223 procedure Free_Perm_Tree
224 (PT : in out Perm_Tree_Access);
225 -- Procedure to free a permission tree
227 --------------------
228 -- Error Messages --
229 --------------------
231 procedure Perm_Mismatch
232 (Exp_Perm, Act_Perm : Perm_Kind;
233 N : Node_Id);
234 -- Issues a continuation error message about a mismatch between a
235 -- desired permission Exp_Perm and a permission obtained Act_Perm. N
236 -- is the node on which the error is reported.
238 end Permissions;
240 package body Permissions is
242 -------------------------
243 -- Children_Permission --
244 -------------------------
246 function Children_Permission
247 (T : Perm_Tree_Access)
248 return Perm_Kind
250 begin
251 return T.all.Tree.Children_Permission;
252 end Children_Permission;
254 ---------------
255 -- Component --
256 ---------------
258 function Component
259 (T : Perm_Tree_Access)
260 return Perm_Tree_Maps.Instance
262 begin
263 return T.all.Tree.Component;
264 end Component;
266 --------------
267 -- Copy_Env --
268 --------------
270 procedure Copy_Env
271 (From : Perm_Env;
272 To : in out Perm_Env)
274 Comp_From : Perm_Tree_Access;
275 Key_From : Perm_Tree_Maps.Key_Option;
276 Son : Perm_Tree_Access;
278 begin
279 Reset (To);
280 Key_From := Get_First_Key (From);
281 while Key_From.Present loop
282 Comp_From := Get (From, Key_From.K);
283 pragma Assert (Comp_From /= null);
285 Son := new Perm_Tree_Wrapper;
286 Copy_Tree (Comp_From, Son);
288 Set (To, Key_From.K, Son);
289 Key_From := Get_Next_Key (From);
290 end loop;
291 end Copy_Env;
293 -------------------
294 -- Copy_Init_Map --
295 -------------------
297 procedure Copy_Init_Map
298 (From : Initialization_Map;
299 To : in out Initialization_Map)
301 Comp_From : Boolean;
302 Key_From : Boolean_Variables_Maps.Key_Option;
304 begin
305 Reset (To);
306 Key_From := Get_First_Key (From);
307 while Key_From.Present loop
308 Comp_From := Get (From, Key_From.K);
309 Set (To, Key_From.K, Comp_From);
310 Key_From := Get_Next_Key (From);
311 end loop;
312 end Copy_Init_Map;
314 ---------------
315 -- Copy_Tree --
316 ---------------
318 procedure Copy_Tree
319 (From : Perm_Tree_Access;
320 To : Perm_Tree_Access)
322 begin
323 To.all := From.all;
325 case Kind (From) is
326 when Entire_Object =>
327 null;
329 when Reference =>
330 To.all.Tree.Get_All := new Perm_Tree_Wrapper;
332 Copy_Tree (Get_All (From), Get_All (To));
334 when Array_Component =>
335 To.all.Tree.Get_Elem := new Perm_Tree_Wrapper;
337 Copy_Tree (Get_Elem (From), Get_Elem (To));
339 when Record_Component =>
340 declare
341 Comp_From : Perm_Tree_Access;
342 Key_From : Perm_Tree_Maps.Key_Option;
343 Son : Perm_Tree_Access;
344 Hash_Table : Perm_Tree_Maps.Instance;
345 begin
346 -- We put a new hash table, so that it gets dealiased from the
347 -- Component (From) hash table.
348 To.all.Tree.Component := Hash_Table;
350 To.all.Tree.Other_Components :=
351 new Perm_Tree_Wrapper'(Other_Components (From).all);
353 Copy_Tree (Other_Components (From), Other_Components (To));
355 Key_From := Perm_Tree_Maps.Get_First_Key
356 (Component (From));
357 while Key_From.Present loop
358 Comp_From := Perm_Tree_Maps.Get
359 (Component (From), Key_From.K);
361 pragma Assert (Comp_From /= null);
362 Son := new Perm_Tree_Wrapper;
364 Copy_Tree (Comp_From, Son);
366 Perm_Tree_Maps.Set
367 (To.all.Tree.Component, Key_From.K, Son);
369 Key_From := Perm_Tree_Maps.Get_Next_Key
370 (Component (From));
371 end loop;
372 end;
373 end case;
374 end Copy_Tree;
376 ------------------------------
377 -- Elaboration_Context_Hash --
378 ------------------------------
380 function Elaboration_Context_Hash
381 (Key : Entity_Id) return Elaboration_Context_Index
383 begin
384 return Elaboration_Context_Index (Key mod Elaboration_Context_Max);
385 end Elaboration_Context_Hash;
387 --------------
388 -- Free_Env --
389 --------------
391 procedure Free_Env (PE : in out Perm_Env) is
392 CompO : Perm_Tree_Access;
393 begin
394 CompO := Get_First (PE);
395 while CompO /= null loop
396 Free_Perm_Tree (CompO);
397 CompO := Get_Next (PE);
398 end loop;
399 end Free_Env;
401 --------------------
402 -- Free_Perm_Tree --
403 --------------------
405 procedure Free_Perm_Tree
406 (PT : in out Perm_Tree_Access)
408 procedure Free_Perm_Tree_Dealloc is
409 new Ada.Unchecked_Deallocation
410 (Perm_Tree_Wrapper, Perm_Tree_Access);
411 -- The deallocator for permission_trees
413 begin
414 case Kind (PT) is
415 when Entire_Object =>
416 Free_Perm_Tree_Dealloc (PT);
418 when Reference =>
419 Free_Perm_Tree (PT.all.Tree.Get_All);
420 Free_Perm_Tree_Dealloc (PT);
422 when Array_Component =>
423 Free_Perm_Tree (PT.all.Tree.Get_Elem);
425 when Record_Component =>
426 declare
427 Comp : Perm_Tree_Access;
429 begin
430 Free_Perm_Tree (PT.all.Tree.Other_Components);
431 Comp := Perm_Tree_Maps.Get_First (Component (PT));
432 while Comp /= null loop
433 -- Free every Component subtree
435 Free_Perm_Tree (Comp);
436 Comp := Perm_Tree_Maps.Get_Next (Component (PT));
437 end loop;
438 end;
439 Free_Perm_Tree_Dealloc (PT);
440 end case;
441 end Free_Perm_Tree;
443 -------------
444 -- Get_All --
445 -------------
447 function Get_All
448 (T : Perm_Tree_Access)
449 return Perm_Tree_Access
451 begin
452 return T.all.Tree.Get_All;
453 end Get_All;
455 --------------
456 -- Get_Elem --
457 --------------
459 function Get_Elem
460 (T : Perm_Tree_Access)
461 return Perm_Tree_Access
463 begin
464 return T.all.Tree.Get_Elem;
465 end Get_Elem;
467 ------------------
468 -- Is_Node_Deep --
469 ------------------
471 function Is_Node_Deep
472 (T : Perm_Tree_Access)
473 return Boolean
475 begin
476 return T.all.Tree.Is_Node_Deep;
477 end Is_Node_Deep;
479 ----------
480 -- Kind --
481 ----------
483 function Kind
484 (T : Perm_Tree_Access)
485 return Path_Kind
487 begin
488 return T.all.Tree.Kind;
489 end Kind;
491 ----------------------
492 -- Other_Components --
493 ----------------------
495 function Other_Components
496 (T : Perm_Tree_Access)
497 return Perm_Tree_Access
499 begin
500 return T.all.Tree.Other_Components;
501 end Other_Components;
503 ----------------
504 -- Permission --
505 ----------------
507 function Permission
508 (T : Perm_Tree_Access)
509 return Perm_Kind
511 begin
512 return T.all.Tree.Permission;
513 end Permission;
515 -------------------
516 -- Perm_Mismatch --
517 -------------------
519 procedure Perm_Mismatch
520 (Exp_Perm, Act_Perm : Perm_Kind;
521 N : Node_Id)
523 begin
524 Error_Msg_N ("\expected at least `"
525 & Perm_Kind'Image (Exp_Perm) & "`, got `"
526 & Perm_Kind'Image (Act_Perm) & "`", N);
527 end Perm_Mismatch;
529 end Permissions;
531 use Permissions;
533 --------------------------------------
534 -- Analysis modes for AST traversal --
535 --------------------------------------
537 -- The different modes for analysis. This allows to checking whether a path
538 -- found in the code should be moved, borrowed, or observed.
540 type Checking_Mode is
542 (Read,
543 -- Default mode. Checks that paths have Read_Perm permission.
545 Move,
546 -- Regular moving semantics (not under 'Access). Checks that paths have
547 -- Read_Write permission. After moving a path, its permission is set to
548 -- Write_Only and the permission of its extensions is set to No_Access.
550 Assign,
551 -- Used for the target of an assignment, or an actual parameter with
552 -- mode OUT. Checks that paths have Write_Perm permission. After
553 -- assigning to a path, its permission is set to Read_Write.
555 Super_Move,
556 -- Enhanced moving semantics (under 'Access). Checks that paths have
557 -- Read_Write permission (shallow types may have only Write permission).
558 -- After moving a path, its permission is set to No_Access, as well as
559 -- the permission of its extensions and the permission of its prefixes
560 -- up to the first Reference node.
562 Borrow_Out,
563 -- Used for actual OUT parameters. Checks that paths have Write_Perm
564 -- permission. After checking a path, its permission is set to Read_Only
565 -- when of a by-copy type, to No_Access otherwise. After the call, its
566 -- permission is set to Read_Write.
568 Observe
569 -- Used for actual IN parameters of a scalar type. Checks that paths
570 -- have Read_Perm permission. After checking a path, its permission
571 -- is set to Read_Only.
573 -- Also used for formal IN parameters
576 type Result_Kind is (Folded, Unfolded, Function_Call);
577 -- The type declaration to discriminate in the Perm_Or_Tree type
579 -- The result type of the function Get_Perm_Or_Tree. This returns either a
580 -- tree when it found the appropriate tree, or a permission when the search
581 -- finds a leaf and the subtree we are looking for is folded. In the last
582 -- case, we return instead the Children_Permission field of the leaf.
584 type Perm_Or_Tree (R : Result_Kind) is record
585 case R is
586 when Folded => Found_Permission : Perm_Kind;
587 when Unfolded => Tree_Access : Perm_Tree_Access;
588 when Function_Call => null;
589 end case;
590 end record;
592 -----------------------
593 -- Local subprograms --
594 -----------------------
596 function "<=" (P1, P2 : Perm_Kind) return Boolean;
597 function ">=" (P1, P2 : Perm_Kind) return Boolean;
598 function Glb (P1, P2 : Perm_Kind) return Perm_Kind;
599 function Lub (P1, P2 : Perm_Kind) return Perm_Kind;
601 -- Checking proceduress for safe pointer usage. These procedures traverse
602 -- the AST, check nodes for correct permissions according to SPARK RM
603 -- 6.4.2, and update permissions depending on the node kind.
605 procedure Check_Call_Statement (Call : Node_Id);
607 procedure Check_Callable_Body (Body_N : Node_Id);
608 -- We are not in End_Of_Callee mode, hence we will save the environment
609 -- and start from a new one. We will add in the environment all formal
610 -- parameters as well as global used during the subprogram, with the
611 -- appropriate permissions (write-only for out, read-only for observed,
612 -- read-write for others).
614 -- After that we analyze the body of the function, and finaly, we check
615 -- that each borrowed parameter and global has read-write permission. We
616 -- then clean up the environment and put back the saved environment.
618 procedure Check_Declaration (Decl : Node_Id);
620 procedure Check_Expression (Expr : Node_Id);
622 procedure Check_Globals (N : Node_Id; Check_Mode : Checking_Mode);
623 -- This procedure takes a global pragma and checks depending on mode:
624 -- Mode Read: every in global is readable
625 -- Mode Observe: same as Check_Param_Observes but on globals
626 -- Mode Borrow_Out: Check_Param_Outs for globals
627 -- Mode Move: Check_Param for globals with mode Read
628 -- Mode Assign: Check_Param for globals with mode Assign
630 procedure Check_List (L : List_Id);
631 -- Calls Check_Node on each element of the list
633 procedure Check_Loop_Statement (Loop_N : Node_Id);
635 procedure Check_Node (N : Node_Id);
636 -- Main traversal procedure to check safe pointer usage. This procedure is
637 -- mutually recursive with the specialized procedures that follow.
639 procedure Check_Package_Body (Pack : Node_Id);
641 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id);
642 -- This procedure takes a formal and an actual parameter and calls the
643 -- analyze node if the parameter is borrowed with mode in out, with the
644 -- appropriate Checking_Mode (Move).
646 procedure Check_Param_Observes (Formal : Entity_Id; Actual : Node_Id);
647 -- This procedure takes a formal and an actual parameter and calls
648 -- the analyze node if the parameter is observed, with the appropriate
649 -- Checking_Mode.
651 procedure Check_Param_Outs (Formal : Entity_Id; Actual : Node_Id);
652 -- This procedure takes a formal and an actual parameter and calls the
653 -- analyze node if the parameter is of mode out, with the appropriate
654 -- Checking_Mode.
656 procedure Check_Param_Read (Formal : Entity_Id; Actual : Node_Id);
657 -- This procedure takes a formal and an actual parameter and checks the
658 -- readability of every in-mode parameter. This includes observed in, and
659 -- also borrowed in, that are then checked afterwards.
661 procedure Check_Statement (Stmt : Node_Id);
663 function Get_Perm (N : Node_Id) return Perm_Kind;
664 -- The function that takes a name as input and returns a permission
665 -- associated to it.
667 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree;
668 -- This function gets a Node_Id and looks recursively to find the
669 -- appropriate subtree for that Node_Id. If the tree is folded on
670 -- that node, then it returns the permission given at the right level.
672 function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access;
673 -- This function gets a Node_Id and looks recursively to find the
674 -- appropriate subtree for that Node_Id. If the tree is folded, then
675 -- it unrolls the tree up to the appropriate level.
677 function Has_Alias
678 (N : Node_Id)
679 return Boolean;
680 -- Function that returns whether the path given as parameter contains an
681 -- extension that is declared as aliased.
683 function Has_Array_Component (N : Node_Id) return Boolean;
684 -- This function gets a Node_Id and looks recursively to find if the given
685 -- path has any array component.
687 function Has_Function_Component (N : Node_Id) return Boolean;
688 -- This function gets a Node_Id and looks recursively to find if the given
689 -- path has any function component.
691 procedure Hp (P : Perm_Env);
692 -- A procedure that outputs the hash table. This function is used only in
693 -- the debugger to look into a hash table.
694 pragma Unreferenced (Hp);
696 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id);
697 pragma No_Return (Illegal_Global_Usage);
698 -- A procedure that is called when deep globals or aliased globals are used
699 -- without any global aspect.
701 function Is_Borrowed_In (E : Entity_Id) return Boolean;
702 -- Function that tells if the given entity is a borrowed in a formal
703 -- parameter, that is, if it is an access-to-variable type.
705 function Is_Deep (E : Entity_Id) return Boolean;
706 -- A function that can tell if a type is deep or not. Returns true if the
707 -- type passed as argument is deep.
709 function Is_Shallow (E : Entity_Id) return Boolean;
710 -- A function that can tell if a type is shallow or not. Returns true if
711 -- the type passed as argument is shallow.
713 function Loop_Of_Exit (N : Node_Id) return Entity_Id;
714 -- A function that takes an exit statement node and returns the entity of
715 -- the loop that this statement is exiting from.
717 procedure Merge_Envs (Target : in out Perm_Env; Source : in out Perm_Env);
718 -- Merge Target and Source into Target, and then deallocate the Source
720 procedure Perm_Error
721 (N : Node_Id;
722 Perm : Perm_Kind;
723 Found_Perm : Perm_Kind);
724 -- A procedure that is called when the permissions found contradict the
725 -- rules established by the RM. This function is called with the node, its
726 -- entity and the permission that was expected, and adds an error message
727 -- with the appropriate values.
729 procedure Perm_Error_Subprogram_End
730 (E : Entity_Id;
731 Subp : Entity_Id;
732 Perm : Perm_Kind;
733 Found_Perm : Perm_Kind);
734 -- A procedure that is called when the permissions found contradict the
735 -- rules established by the RM at the end of subprograms. This function
736 -- is called with the node, its entity, the node of the returning function
737 -- and the permission that was expected, and adds an error message with the
738 -- appropriate values.
740 procedure Process_Path (N : Node_Id);
742 procedure Return_Declarations (L : List_Id);
743 -- Check correct permissions on every declared object at the end of a
744 -- callee. Used at the end of the body of a callable entity. Checks that
745 -- paths of all borrowed formal parameters and global have Read_Write
746 -- permission.
748 procedure Return_Globals (Subp : Entity_Id);
749 -- Takes a subprogram as input, and checks that all borrowed global items
750 -- of the subprogram indeed have RW permission at the end of the subprogram
751 -- execution.
753 procedure Return_Parameter_Or_Global
754 (Id : Entity_Id;
755 Mode : Formal_Kind;
756 Subp : Entity_Id;
757 Global_Var : Boolean);
758 -- Auxiliary procedure to Return_Parameters and Return_Globals
760 procedure Return_Parameters (Subp : Entity_Id);
761 -- Takes a subprogram as input, and checks that all borrowed parameters of
762 -- the subprogram indeed have RW permission at the end of the subprogram
763 -- execution.
765 procedure Set_Perm_Extensions (T : Perm_Tree_Access; P : Perm_Kind);
766 -- This procedure takes an access to a permission tree and modifies the
767 -- tree so that any strict extensions of the given tree become of the
768 -- access specified by parameter P.
770 procedure Set_Perm_Extensions_Move (T : Perm_Tree_Access; E : Entity_Id);
771 -- Set permissions to
772 -- No for any extension with more .all
773 -- W for any deep extension with same number of .all
774 -- RW for any shallow extension with same number of .all
776 function Set_Perm_Prefixes_Assign (N : Node_Id) return Perm_Tree_Access;
777 -- This function takes a name as an input and sets in the permission
778 -- tree the given permission to the given name. The general rule here is
779 -- that everybody updates the permission of the subtree it is returning.
780 -- The permission of the assigned path has been set to RW by the caller.
782 -- Case where we have to normalize a tree after the correct permissions
783 -- have been assigned already. We look for the right subtree at the given
784 -- path, actualize its permissions, and then call the normalization on its
785 -- parent.
787 -- Example: We assign x.y and x.z then during Set_Perm_Prefixes_Move will
788 -- change the permission of x to RW because all of its components have
789 -- permission have permission RW.
791 function Set_Perm_Prefixes_Borrow_Out (N : Node_Id) return Perm_Tree_Access;
792 -- This function modifies the permissions of a given node_id in the
793 -- permission environment as well as in all the prefixes of the path,
794 -- given that the path is borrowed with mode out.
796 function Set_Perm_Prefixes_Move
797 (N : Node_Id; Mode : Checking_Mode)
798 return Perm_Tree_Access;
799 pragma Precondition (Mode = Move or Mode = Super_Move);
800 -- Given a node and a mode (that can be either Move or Super_Move), this
801 -- function modifies the permissions of a given node_id in the permission
802 -- environment as well as all the prefixes of the path, given that the path
803 -- is moved with or without 'Access. The general rule here is everybody
804 -- updates the permission of the subtree they are returning.
806 -- This case describes a move either under 'Access or without 'Access.
808 function Set_Perm_Prefixes_Observe (N : Node_Id) return Perm_Tree_Access;
809 -- This function modifies the permissions of a given node_id in the
810 -- permission environment as well as all the prefixes of the path,
811 -- given that the path is observed.
813 procedure Setup_Globals (Subp : Entity_Id);
814 -- Takes a subprogram as input, and sets up the environment by adding
815 -- global items with appropriate permissions.
817 procedure Setup_Parameter_Or_Global
818 (Id : Entity_Id;
819 Mode : Formal_Kind;
820 Global_Var : Boolean);
821 -- Auxiliary procedure to Setup_Parameters and Setup_Globals
823 procedure Setup_Parameters (Subp : Entity_Id);
824 -- Takes a subprogram as input, and sets up the environment by adding
825 -- formal parameters with appropriate permissions.
827 ----------------------
828 -- Global Variables --
829 ----------------------
831 Current_Perm_Env : Perm_Env;
832 -- The permission environment that is used for the analysis. This
833 -- environment can be saved, modified, reinitialized, but should be the
834 -- only one valid from which to extract the permissions of the paths in
835 -- scope. The analysis ensures at each point that this variables contains
836 -- a valid permission environment with all bindings in scope.
838 Current_Checking_Mode : Checking_Mode := Read;
839 -- The current analysis mode. This global variable indicates at each point
840 -- of the analysis whether the node being analyzed is moved, borrowed,
841 -- assigned, read, ... The full list of possible values can be found in
842 -- the declaration of type Checking_Mode.
844 Current_Loops_Envs : Env_Backups;
845 -- This variable contains saves of permission environments at each loop the
846 -- analysis entered. Each saved environment can be reached with the label
847 -- of the loop.
849 Current_Loops_Accumulators : Env_Backups;
850 -- This variable contains the environments used as accumulators for loops,
851 -- that consist of the merge of all environments at each exit point of
852 -- the loop (which can also be the entry point of the loop in the case of
853 -- non-infinite loops), each of them reachable from the label of the loop.
854 -- We require that the environment stored in the accumulator be less
855 -- restrictive than the saved environment at the beginning of the loop, and
856 -- the permission environment after the loop is equal to the accumulator.
858 Current_Initialization_Map : Initialization_Map;
859 -- This variable contains a map that binds each variable of the analyzed
860 -- source code to a boolean that becomes true whenever the variable is used
861 -- after declaration. Hence we can exclude from analysis variables that
862 -- are just declared and never accessed, typically at package declaration.
864 ----------
865 -- "<=" --
866 ----------
868 function "<=" (P1, P2 : Perm_Kind) return Boolean
870 begin
871 return P2 >= P1;
872 end "<=";
874 ----------
875 -- ">=" --
876 ----------
878 function ">=" (P1, P2 : Perm_Kind) return Boolean
880 begin
881 case P2 is
882 when No_Access => return True;
883 when Read_Only => return P1 in Read_Perm;
884 when Write_Only => return P1 in Write_Perm;
885 when Read_Write => return P1 = Read_Write;
886 end case;
887 end ">=";
889 --------------------------
890 -- Check_Call_Statement --
891 --------------------------
893 procedure Check_Call_Statement (Call : Node_Id) is
894 Saved_Env : Perm_Env;
896 procedure Iterate_Call is new
897 Iterate_Call_Parameters (Check_Param);
898 procedure Iterate_Call_Observes is new
899 Iterate_Call_Parameters (Check_Param_Observes);
900 procedure Iterate_Call_Outs is new
901 Iterate_Call_Parameters (Check_Param_Outs);
902 procedure Iterate_Call_Read is new
903 Iterate_Call_Parameters (Check_Param_Read);
905 begin
906 -- Save environment, so that the modifications done by analyzing the
907 -- parameters are not kept at the end of the call.
908 Copy_Env (Current_Perm_Env,
909 Saved_Env);
911 -- We first check the Read access on every in parameter
913 Current_Checking_Mode := Read;
914 Iterate_Call_Read (Call);
915 Check_Globals (Get_Pragma
916 (Get_Called_Entity (Call), Pragma_Global), Read);
918 -- We first observe, then borrow with mode out, and then with other
919 -- modes. This ensures that we do not have to check for by-copy types
920 -- specially, because we read them before borrowing them.
922 Iterate_Call_Observes (Call);
923 Check_Globals (Get_Pragma
924 (Get_Called_Entity (Call), Pragma_Global),
925 Observe);
927 Iterate_Call_Outs (Call);
928 Check_Globals (Get_Pragma
929 (Get_Called_Entity (Call), Pragma_Global),
930 Borrow_Out);
932 Iterate_Call (Call);
933 Check_Globals (Get_Pragma
934 (Get_Called_Entity (Call), Pragma_Global), Move);
936 -- Restore environment, because after borrowing/observing actual
937 -- parameters, they get their permission reverted to the ones before
938 -- the call.
940 Free_Env (Current_Perm_Env);
942 Copy_Env (Saved_Env,
943 Current_Perm_Env);
945 Free_Env (Saved_Env);
947 -- We assign the out parameters (necessarily borrowed per RM)
948 Current_Checking_Mode := Assign;
949 Iterate_Call (Call);
950 Check_Globals (Get_Pragma
951 (Get_Called_Entity (Call), Pragma_Global),
952 Assign);
954 end Check_Call_Statement;
956 -------------------------
957 -- Check_Callable_Body --
958 -------------------------
960 procedure Check_Callable_Body (Body_N : Node_Id) is
962 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
964 Saved_Env : Perm_Env;
965 Saved_Init_Map : Initialization_Map;
967 New_Env : Perm_Env;
969 Body_Id : constant Entity_Id := Defining_Entity (Body_N);
970 Spec_Id : constant Entity_Id := Unique_Entity (Body_Id);
972 begin
973 -- Check if SPARK pragma is not set to Off
975 if Present (SPARK_Pragma (Defining_Entity (Body_N))) then
976 if Get_SPARK_Mode_From_Annotation
977 (SPARK_Pragma (Defining_Entity (Body_N, False))) /= Opt.On
978 then
979 return;
980 end if;
981 else
982 return;
983 end if;
985 -- Save environment and put a new one in place
987 Copy_Env (Current_Perm_Env, Saved_Env);
989 -- Save initialization map
991 Copy_Init_Map (Current_Initialization_Map, Saved_Init_Map);
993 Current_Checking_Mode := Read;
994 Current_Perm_Env := New_Env;
996 -- Add formals and globals to the environment with adequate permissions
998 if Is_Subprogram_Or_Entry (Spec_Id) then
999 Setup_Parameters (Spec_Id);
1000 Setup_Globals (Spec_Id);
1001 end if;
1003 -- Analyze the body of the function
1005 Check_List (Declarations (Body_N));
1006 Check_Node (Handled_Statement_Sequence (Body_N));
1008 -- Check the read-write permissions of borrowed parameters/globals
1010 if Ekind_In (Spec_Id, E_Procedure, E_Entry)
1011 and then not No_Return (Spec_Id)
1012 then
1013 Return_Parameters (Spec_Id);
1014 Return_Globals (Spec_Id);
1015 end if;
1017 -- Free the environments
1019 Free_Env (Current_Perm_Env);
1021 Copy_Env (Saved_Env,
1022 Current_Perm_Env);
1024 Free_Env (Saved_Env);
1026 -- Restore initialization map
1028 Copy_Init_Map (Saved_Init_Map, Current_Initialization_Map);
1030 Reset (Saved_Init_Map);
1032 -- The assignment of all out parameters will be done by caller
1034 Current_Checking_Mode := Mode_Before;
1035 end Check_Callable_Body;
1037 -----------------------
1038 -- Check_Declaration --
1039 -----------------------
1041 procedure Check_Declaration (Decl : Node_Id) is
1042 begin
1043 case N_Declaration'(Nkind (Decl)) is
1044 when N_Full_Type_Declaration =>
1046 -- Nothing to do here ??? NOT TRUE IF CONSTRAINT ON TYPE
1048 null;
1050 when N_Object_Declaration =>
1052 -- First move the right-hand side
1054 Current_Checking_Mode := Move;
1055 Check_Node (Expression (Decl));
1057 declare
1058 Deep : constant Boolean :=
1059 Is_Deep (Etype (Defining_Identifier (Decl)));
1060 Elem : Perm_Tree_Access;
1062 begin
1063 Elem := new Perm_Tree_Wrapper'
1064 (Tree =>
1065 (Kind => Entire_Object,
1066 Is_Node_Deep => Deep,
1067 Permission => Read_Write,
1068 Children_Permission => Read_Write));
1070 -- If unitialized declaration, then set to Write_Only. If a
1071 -- pointer declaration, it has a null default initialization.
1073 if No (Expression (Decl))
1074 and then not Has_Full_Default_Initialization
1075 (Etype (Defining_Identifier (Decl)))
1076 and then not Is_Access_Type
1077 (Etype (Defining_Identifier (Decl)))
1079 -- Objects of shallow types are considered as always
1080 -- initialized, leaving the checking of initialization to
1081 -- flow analysis.
1083 and then Deep
1084 then
1085 Elem.all.Tree.Permission := Write_Only;
1086 Elem.all.Tree.Children_Permission := Write_Only;
1087 end if;
1089 -- Create new tree for defining identifier
1091 Set (Current_Perm_Env,
1092 Unique_Entity (Defining_Identifier (Decl)),
1093 Elem);
1095 pragma Assert (Get_First (Current_Perm_Env) /= null);
1096 end;
1098 when N_Subtype_Declaration =>
1099 Check_Node (Subtype_Indication (Decl));
1101 when N_Iterator_Specification =>
1102 pragma Assert (Is_Shallow (Etype (Defining_Identifier (Decl))));
1103 null;
1105 when N_Loop_Parameter_Specification =>
1106 pragma Assert (Is_Shallow (Etype (Defining_Identifier (Decl))));
1107 null;
1109 -- Checking should not be called directly on these nodes
1111 when N_Component_Declaration
1112 | N_Function_Specification
1113 | N_Entry_Declaration
1114 | N_Procedure_Specification
1116 raise Program_Error;
1118 -- Ignored constructs for pointer checking
1120 when N_Formal_Object_Declaration
1121 | N_Formal_Type_Declaration
1122 | N_Incomplete_Type_Declaration
1123 | N_Private_Extension_Declaration
1124 | N_Private_Type_Declaration
1125 | N_Protected_Type_Declaration
1127 null;
1129 -- The following nodes are rewritten by semantic analysis
1131 when N_Expression_Function =>
1132 raise Program_Error;
1133 end case;
1134 end Check_Declaration;
1136 ----------------------
1137 -- Check_Expression --
1138 ----------------------
1140 procedure Check_Expression (Expr : Node_Id) is
1141 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
1142 begin
1143 case N_Subexpr'(Nkind (Expr)) is
1144 when N_Procedure_Call_Statement =>
1145 Check_Call_Statement (Expr);
1147 when N_Identifier
1148 | N_Expanded_Name
1150 -- Check if identifier is pointing to nothing (On/Off/...)
1151 if not Present (Entity (Expr)) then
1152 return;
1153 end if;
1155 -- Do not analyze things that are not of object Kind
1156 if Ekind (Entity (Expr)) not in Object_Kind then
1157 return;
1158 end if;
1160 -- Consider as ident
1161 Process_Path (Expr);
1163 -- Switch to read mode and then check the readability of each operand
1165 when N_Binary_Op =>
1167 Current_Checking_Mode := Read;
1168 Check_Node (Left_Opnd (Expr));
1169 Check_Node (Right_Opnd (Expr));
1171 -- Switch to read mode and then check the readability of each operand
1173 when N_Op_Abs
1174 | N_Op_Minus
1175 | N_Op_Not
1176 | N_Op_Plus
1178 pragma Assert (Is_Shallow (Etype (Expr)));
1179 Current_Checking_Mode := Read;
1180 Check_Node (Right_Opnd (Expr));
1182 -- Forbid all deep expressions for Attribute ???
1184 when N_Attribute_Reference =>
1185 case Attribute_Name (Expr) is
1186 when Name_Access =>
1187 case Current_Checking_Mode is
1188 when Read =>
1189 Check_Node (Prefix (Expr));
1191 when Move =>
1192 Current_Checking_Mode := Super_Move;
1193 Check_Node (Prefix (Expr));
1195 -- Only assign names, not expressions
1197 when Assign =>
1198 raise Program_Error;
1200 -- Prefix in Super_Move should be a name, error here
1202 when Super_Move =>
1203 raise Program_Error;
1205 -- Could only borrow names of mode out, not n'Access
1207 when Borrow_Out =>
1208 raise Program_Error;
1210 when Observe =>
1211 Check_Node (Prefix (Expr));
1212 end case;
1214 when Name_Last
1215 | Name_First
1217 Current_Checking_Mode := Read;
1218 Check_Node (Prefix (Expr));
1220 when Name_Min =>
1221 Current_Checking_Mode := Read;
1222 Check_Node (Prefix (Expr));
1224 when Name_Image =>
1225 Check_List (Expressions (Expr));
1227 when Name_Img =>
1228 Check_Node (Prefix (Expr));
1230 when Name_SPARK_Mode =>
1231 null;
1233 when Name_Value =>
1234 Current_Checking_Mode := Read;
1235 Check_Node (Prefix (Expr));
1237 when Name_Update =>
1238 Check_List (Expressions (Expr));
1239 Check_Node (Prefix (Expr));
1241 when Name_Pred
1242 | Name_Succ
1244 Check_List (Expressions (Expr));
1245 Check_Node (Prefix (Expr));
1247 when Name_Length =>
1248 Current_Checking_Mode := Read;
1249 Check_Node (Prefix (Expr));
1251 -- Any Attribute referring to the underlying memory is ignored
1252 -- in the analysis. This means that taking the address of a
1253 -- variable makes a silent alias that is not rejected by the
1254 -- analysis.
1256 when Name_Address
1257 | Name_Alignment
1258 | Name_Component_Size
1259 | Name_First_Bit
1260 | Name_Last_Bit
1261 | Name_Size
1262 | Name_Position
1264 null;
1266 -- Attributes referring to types (get values from types), hence
1267 -- no need to check either for borrows or any loans.
1269 when Name_Base
1270 | Name_Val
1272 null;
1274 -- Other attributes that fall out of the scope of the analysis
1276 when others =>
1277 null;
1278 end case;
1280 when N_In =>
1281 Current_Checking_Mode := Read;
1282 Check_Node (Left_Opnd (Expr));
1283 Check_Node (Right_Opnd (Expr));
1285 when N_Not_In =>
1286 Current_Checking_Mode := Read;
1287 Check_Node (Left_Opnd (Expr));
1288 Check_Node (Right_Opnd (Expr));
1290 -- Switch to read mode and then check the readability of each operand
1292 when N_And_Then
1293 | N_Or_Else
1295 pragma Assert (Is_Shallow (Etype (Expr)));
1296 Current_Checking_Mode := Read;
1297 Check_Node (Left_Opnd (Expr));
1298 Check_Node (Right_Opnd (Expr));
1300 -- Check the arguments of the call
1302 when N_Function_Call =>
1303 Current_Checking_Mode := Read;
1304 Check_List (Parameter_Associations (Expr));
1306 when N_Explicit_Dereference =>
1307 Process_Path (Expr);
1309 -- Copy environment, run on each branch, and then merge
1311 when N_If_Expression =>
1312 declare
1313 Saved_Env : Perm_Env;
1315 -- Accumulator for the different branches
1317 New_Env : Perm_Env;
1319 Elmt : Node_Id := First (Expressions (Expr));
1321 begin
1322 Current_Checking_Mode := Read;
1324 Check_Node (Elmt);
1326 Current_Checking_Mode := Mode_Before;
1328 -- Save environment
1330 Copy_Env (Current_Perm_Env,
1331 Saved_Env);
1333 -- Here we have the original env in saved, current with a fresh
1334 -- copy, and new aliased.
1336 -- THEN PART
1338 Next (Elmt);
1339 Check_Node (Elmt);
1341 -- Here the new_environment contains curr env after then block
1343 -- ELSE part
1345 -- Restore environment before if
1346 Copy_Env (Current_Perm_Env,
1347 New_Env);
1349 Free_Env (Current_Perm_Env);
1351 Copy_Env (Saved_Env,
1352 Current_Perm_Env);
1354 -- Here new environment contains the environment after then and
1355 -- current the fresh copy of old one.
1357 Next (Elmt);
1358 Check_Node (Elmt);
1360 Merge_Envs (New_Env,
1361 Current_Perm_Env);
1363 -- CLEANUP
1365 Copy_Env (New_Env,
1366 Current_Perm_Env);
1368 Free_Env (New_Env);
1369 Free_Env (Saved_Env);
1370 end;
1372 when N_Indexed_Component =>
1373 Process_Path (Expr);
1375 -- Analyze the expression that is getting qualified
1377 when N_Qualified_Expression =>
1378 Check_Node (Expression (Expr));
1380 when N_Quantified_Expression =>
1381 declare
1382 Saved_Env : Perm_Env;
1383 begin
1384 Copy_Env (Current_Perm_Env, Saved_Env);
1385 Current_Checking_Mode := Read;
1386 Check_Node (Iterator_Specification (Expr));
1387 Check_Node (Loop_Parameter_Specification (Expr));
1389 Check_Node (Condition (Expr));
1390 Free_Env (Current_Perm_Env);
1391 Copy_Env (Saved_Env, Current_Perm_Env);
1392 Free_Env (Saved_Env);
1393 end;
1395 -- Analyze the list of associations in the aggregate
1397 when N_Aggregate =>
1398 Check_List (Expressions (Expr));
1399 Check_List (Component_Associations (Expr));
1401 when N_Allocator =>
1402 Check_Node (Expression (Expr));
1404 when N_Case_Expression =>
1405 declare
1406 Saved_Env : Perm_Env;
1408 -- Accumulator for the different branches
1410 New_Env : Perm_Env;
1412 Elmt : Node_Id := First (Alternatives (Expr));
1414 begin
1415 Current_Checking_Mode := Read;
1416 Check_Node (Expression (Expr));
1418 Current_Checking_Mode := Mode_Before;
1420 -- Save environment
1422 Copy_Env (Current_Perm_Env,
1423 Saved_Env);
1425 -- Here we have the original env in saved, current with a fresh
1426 -- copy, and new aliased.
1428 -- First alternative
1430 Check_Node (Elmt);
1431 Next (Elmt);
1433 Copy_Env (Current_Perm_Env,
1434 New_Env);
1436 Free_Env (Current_Perm_Env);
1438 -- Other alternatives
1440 while Present (Elmt) loop
1441 -- Restore environment
1443 Copy_Env (Saved_Env,
1444 Current_Perm_Env);
1446 Check_Node (Elmt);
1448 -- Merge Current_Perm_Env into New_Env
1450 Merge_Envs (New_Env,
1451 Current_Perm_Env);
1453 Next (Elmt);
1454 end loop;
1456 -- CLEANUP
1457 Copy_Env (New_Env,
1458 Current_Perm_Env);
1460 Free_Env (New_Env);
1461 Free_Env (Saved_Env);
1462 end;
1464 -- Analyze the list of associates in the aggregate as well as the
1465 -- ancestor part.
1467 when N_Extension_Aggregate =>
1469 Check_Node (Ancestor_Part (Expr));
1470 Check_List (Expressions (Expr));
1472 when N_Range =>
1473 Check_Node (Low_Bound (Expr));
1474 Check_Node (High_Bound (Expr));
1476 -- We arrived at a path. Process it.
1478 when N_Selected_Component =>
1479 Process_Path (Expr);
1481 when N_Slice =>
1482 Process_Path (Expr);
1484 when N_Type_Conversion =>
1485 Check_Node (Expression (Expr));
1487 when N_Unchecked_Type_Conversion =>
1488 Check_Node (Expression (Expr));
1490 -- Checking should not be called directly on these nodes
1492 when N_Target_Name =>
1493 raise Program_Error;
1495 -- Unsupported constructs in SPARK
1497 when N_Delta_Aggregate =>
1498 Error_Msg_N ("unsupported construct in SPARK", Expr);
1500 -- Ignored constructs for pointer checking
1502 when N_Character_Literal
1503 | N_Null
1504 | N_Numeric_Or_String_Literal
1505 | N_Operator_Symbol
1506 | N_Raise_Expression
1507 | N_Raise_xxx_Error
1509 null;
1511 -- The following nodes are never generated in GNATprove mode
1513 when N_Expression_With_Actions
1514 | N_Reference
1515 | N_Unchecked_Expression
1517 raise Program_Error;
1519 end case;
1520 end Check_Expression;
1522 -------------------
1523 -- Check_Globals --
1524 -------------------
1526 procedure Check_Globals (N : Node_Id; Check_Mode : Checking_Mode) is
1527 begin
1528 if Nkind (N) = N_Empty then
1529 return;
1530 end if;
1532 declare
1533 pragma Assert
1534 (List_Length (Pragma_Argument_Associations (N)) = 1);
1536 PAA : constant Node_Id :=
1537 First (Pragma_Argument_Associations (N));
1538 pragma Assert (Nkind (PAA) = N_Pragma_Argument_Association);
1540 Row : Node_Id;
1541 The_Mode : Name_Id;
1542 RHS : Node_Id;
1544 procedure Process (Mode : Name_Id;
1545 The_Global : Entity_Id);
1547 procedure Process (Mode : Name_Id;
1548 The_Global : Node_Id)
1550 Ident_Elt : constant Entity_Id :=
1551 Unique_Entity (Entity (The_Global));
1553 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
1555 begin
1556 if Ekind (Ident_Elt) = E_Abstract_State then
1557 return;
1558 end if;
1560 case Check_Mode is
1561 when Read =>
1562 case Mode is
1563 when Name_Input
1564 | Name_Proof_In
1566 Check_Node (The_Global);
1568 when Name_Output
1569 | Name_In_Out
1571 null;
1573 when others =>
1574 raise Program_Error;
1576 end case;
1578 when Observe =>
1579 case Mode is
1580 when Name_Input
1581 | Name_Proof_In
1583 if not Is_Borrowed_In (Ident_Elt) then
1584 -- Observed in
1586 Current_Checking_Mode := Observe;
1587 Check_Node (The_Global);
1588 end if;
1590 when others =>
1591 null;
1593 end case;
1595 when Borrow_Out =>
1597 case Mode is
1598 when Name_Output =>
1599 -- Borrowed out
1600 Current_Checking_Mode := Borrow_Out;
1601 Check_Node (The_Global);
1603 when others =>
1604 null;
1606 end case;
1608 when Move =>
1609 case Mode is
1610 when Name_Input
1611 | Name_Proof_In
1613 if Is_Borrowed_In (Ident_Elt) then
1614 -- Borrowed in
1616 Current_Checking_Mode := Move;
1617 else
1618 -- Observed
1620 return;
1621 end if;
1623 when Name_Output =>
1624 return;
1626 when Name_In_Out =>
1627 -- Borrowed in out
1629 Current_Checking_Mode := Move;
1631 when others =>
1632 raise Program_Error;
1633 end case;
1635 Check_Node (The_Global);
1636 when Assign =>
1637 case Mode is
1638 when Name_Input
1639 | Name_Proof_In
1641 null;
1643 when Name_Output
1644 | Name_In_Out
1646 -- Borrowed out or in out
1648 Process_Path (The_Global);
1650 when others =>
1651 raise Program_Error;
1652 end case;
1654 when others =>
1655 raise Program_Error;
1656 end case;
1658 Current_Checking_Mode := Mode_Before;
1659 end Process;
1661 begin
1662 if Nkind (Expression (PAA)) = N_Null then
1663 -- global => null
1664 -- No globals, nothing to do
1665 return;
1667 elsif Nkind_In (Expression (PAA), N_Identifier, N_Expanded_Name) then
1668 -- global => foo
1669 -- A single input
1670 Process (Name_Input, Expression (PAA));
1672 elsif Nkind (Expression (PAA)) = N_Aggregate
1673 and then Expressions (Expression (PAA)) /= No_List
1674 then
1675 -- global => (foo, bar)
1676 -- Inputs
1677 RHS := First (Expressions (Expression (PAA)));
1678 while Present (RHS) loop
1679 case Nkind (RHS) is
1680 when N_Identifier
1681 | N_Expanded_Name
1683 Process (Name_Input, RHS);
1685 when N_Numeric_Or_String_Literal =>
1686 Process (Name_Input, Original_Node (RHS));
1688 when others =>
1689 raise Program_Error;
1691 end case;
1692 RHS := Next (RHS);
1693 end loop;
1695 elsif Nkind (Expression (PAA)) = N_Aggregate
1696 and then Component_Associations (Expression (PAA)) /= No_List
1697 then
1698 -- global => (mode => foo,
1699 -- mode => (bar, baz))
1700 -- A mixture of things
1702 declare
1703 CA : constant List_Id :=
1704 Component_Associations (Expression (PAA));
1705 begin
1706 Row := First (CA);
1707 while Present (Row) loop
1708 pragma Assert (List_Length (Choices (Row)) = 1);
1709 The_Mode := Chars (First (Choices (Row)));
1711 RHS := Expression (Row);
1712 case Nkind (RHS) is
1713 when N_Aggregate =>
1714 RHS := First (Expressions (RHS));
1715 while Present (RHS) loop
1716 case Nkind (RHS) is
1717 when N_Numeric_Or_String_Literal =>
1718 Process (The_Mode, Original_Node (RHS));
1720 when others =>
1721 Process (The_Mode, RHS);
1723 end case;
1724 RHS := Next (RHS);
1725 end loop;
1727 when N_Identifier
1728 | N_Expanded_Name
1730 Process (The_Mode, RHS);
1732 when N_Null =>
1733 null;
1735 when N_Numeric_Or_String_Literal =>
1736 Process (The_Mode, Original_Node (RHS));
1738 when others =>
1739 raise Program_Error;
1741 end case;
1743 Row := Next (Row);
1744 end loop;
1745 end;
1747 else
1748 raise Program_Error;
1749 end if;
1750 end;
1751 end Check_Globals;
1753 ----------------
1754 -- Check_List --
1755 ----------------
1757 procedure Check_List (L : List_Id) is
1758 N : Node_Id;
1759 begin
1760 N := First (L);
1761 while Present (N) loop
1762 Check_Node (N);
1763 Next (N);
1764 end loop;
1765 end Check_List;
1767 --------------------------
1768 -- Check_Loop_Statement --
1769 --------------------------
1771 procedure Check_Loop_Statement (Loop_N : Node_Id) is
1773 -- Local Subprograms
1775 procedure Check_Is_Less_Restrictive_Env
1776 (Exiting_Env : Perm_Env;
1777 Entry_Env : Perm_Env);
1778 -- This procedure checks that the Exiting_Env environment is less
1779 -- restrictive than the Entry_Env environment.
1781 procedure Check_Is_Less_Restrictive_Tree
1782 (New_Tree : Perm_Tree_Access;
1783 Orig_Tree : Perm_Tree_Access;
1784 E : Entity_Id);
1785 -- Auxiliary procedure to check that the tree New_Tree is less
1786 -- restrictive than the tree Orig_Tree for the entity E.
1788 procedure Perm_Error_Loop_Exit
1789 (E : Entity_Id;
1790 Loop_Id : Node_Id;
1791 Perm : Perm_Kind;
1792 Found_Perm : Perm_Kind);
1793 -- A procedure that is called when the permissions found contradict
1794 -- the rules established by the RM at the exit of loops. This function
1795 -- is called with the entity, the node of the enclosing loop, the
1796 -- permission that was expected and the permission found, and issues
1797 -- an appropriate error message.
1799 -----------------------------------
1800 -- Check_Is_Less_Restrictive_Env --
1801 -----------------------------------
1803 procedure Check_Is_Less_Restrictive_Env
1804 (Exiting_Env : Perm_Env;
1805 Entry_Env : Perm_Env)
1807 Comp_Entry : Perm_Tree_Maps.Key_Option;
1808 Iter_Entry, Iter_Exit : Perm_Tree_Access;
1810 begin
1811 Comp_Entry := Get_First_Key (Entry_Env);
1812 while Comp_Entry.Present loop
1813 Iter_Entry := Get (Entry_Env, Comp_Entry.K);
1814 pragma Assert (Iter_Entry /= null);
1815 Iter_Exit := Get (Exiting_Env, Comp_Entry.K);
1816 pragma Assert (Iter_Exit /= null);
1817 Check_Is_Less_Restrictive_Tree
1818 (New_Tree => Iter_Exit,
1819 Orig_Tree => Iter_Entry,
1820 E => Comp_Entry.K);
1821 Comp_Entry := Get_Next_Key (Entry_Env);
1822 end loop;
1823 end Check_Is_Less_Restrictive_Env;
1825 ------------------------------------
1826 -- Check_Is_Less_Restrictive_Tree --
1827 ------------------------------------
1829 procedure Check_Is_Less_Restrictive_Tree
1830 (New_Tree : Perm_Tree_Access;
1831 Orig_Tree : Perm_Tree_Access;
1832 E : Entity_Id)
1834 -----------------------
1835 -- Local Subprograms --
1836 -----------------------
1838 procedure Check_Is_Less_Restrictive_Tree_Than
1839 (Tree : Perm_Tree_Access;
1840 Perm : Perm_Kind;
1841 E : Entity_Id);
1842 -- Auxiliary procedure to check that the tree N is less restrictive
1843 -- than the given permission P.
1845 procedure Check_Is_More_Restrictive_Tree_Than
1846 (Tree : Perm_Tree_Access;
1847 Perm : Perm_Kind;
1848 E : Entity_Id);
1849 -- Auxiliary procedure to check that the tree N is more restrictive
1850 -- than the given permission P.
1852 -----------------------------------------
1853 -- Check_Is_Less_Restrictive_Tree_Than --
1854 -----------------------------------------
1856 procedure Check_Is_Less_Restrictive_Tree_Than
1857 (Tree : Perm_Tree_Access;
1858 Perm : Perm_Kind;
1859 E : Entity_Id)
1861 begin
1862 if not (Permission (Tree) >= Perm) then
1863 Perm_Error_Loop_Exit
1864 (E, Loop_N, Permission (Tree), Perm);
1865 end if;
1867 case Kind (Tree) is
1868 when Entire_Object =>
1869 if not (Children_Permission (Tree) >= Perm) then
1870 Perm_Error_Loop_Exit
1871 (E, Loop_N, Children_Permission (Tree), Perm);
1873 end if;
1875 when Reference =>
1876 Check_Is_Less_Restrictive_Tree_Than
1877 (Get_All (Tree), Perm, E);
1879 when Array_Component =>
1880 Check_Is_Less_Restrictive_Tree_Than
1881 (Get_Elem (Tree), Perm, E);
1883 when Record_Component =>
1884 declare
1885 Comp : Perm_Tree_Access;
1886 begin
1887 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1888 while Comp /= null loop
1889 Check_Is_Less_Restrictive_Tree_Than (Comp, Perm, E);
1890 Comp :=
1891 Perm_Tree_Maps.Get_Next (Component (Tree));
1892 end loop;
1894 Check_Is_Less_Restrictive_Tree_Than
1895 (Other_Components (Tree), Perm, E);
1896 end;
1897 end case;
1898 end Check_Is_Less_Restrictive_Tree_Than;
1900 -----------------------------------------
1901 -- Check_Is_More_Restrictive_Tree_Than --
1902 -----------------------------------------
1904 procedure Check_Is_More_Restrictive_Tree_Than
1905 (Tree : Perm_Tree_Access;
1906 Perm : Perm_Kind;
1907 E : Entity_Id)
1909 begin
1910 if not (Perm >= Permission (Tree)) then
1911 Perm_Error_Loop_Exit
1912 (E, Loop_N, Permission (Tree), Perm);
1913 end if;
1915 case Kind (Tree) is
1916 when Entire_Object =>
1917 if not (Perm >= Children_Permission (Tree)) then
1918 Perm_Error_Loop_Exit
1919 (E, Loop_N, Children_Permission (Tree), Perm);
1920 end if;
1922 when Reference =>
1923 Check_Is_More_Restrictive_Tree_Than
1924 (Get_All (Tree), Perm, E);
1926 when Array_Component =>
1927 Check_Is_More_Restrictive_Tree_Than
1928 (Get_Elem (Tree), Perm, E);
1930 when Record_Component =>
1931 declare
1932 Comp : Perm_Tree_Access;
1933 begin
1934 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1935 while Comp /= null loop
1936 Check_Is_More_Restrictive_Tree_Than (Comp, Perm, E);
1937 Comp :=
1938 Perm_Tree_Maps.Get_Next (Component (Tree));
1939 end loop;
1941 Check_Is_More_Restrictive_Tree_Than
1942 (Other_Components (Tree), Perm, E);
1943 end;
1944 end case;
1945 end Check_Is_More_Restrictive_Tree_Than;
1947 -- Start of processing for Check_Is_Less_Restrictive_Tree
1949 begin
1950 if not (Permission (New_Tree) <= Permission (Orig_Tree)) then
1951 Perm_Error_Loop_Exit
1952 (E => E,
1953 Loop_Id => Loop_N,
1954 Perm => Permission (New_Tree),
1955 Found_Perm => Permission (Orig_Tree));
1956 end if;
1958 case Kind (New_Tree) is
1960 -- Potentially folded tree. We check the other tree Orig_Tree to
1961 -- check whether it is folded or not. If folded we just compare
1962 -- their Permission and Children_Permission, if not, then we
1963 -- look at the Children_Permission of the folded tree against
1964 -- the unfolded tree Orig_Tree.
1966 when Entire_Object =>
1967 case Kind (Orig_Tree) is
1968 when Entire_Object =>
1969 if not (Children_Permission (New_Tree) <=
1970 Children_Permission (Orig_Tree))
1971 then
1972 Perm_Error_Loop_Exit
1973 (E, Loop_N,
1974 Children_Permission (New_Tree),
1975 Children_Permission (Orig_Tree));
1976 end if;
1978 when Reference =>
1979 Check_Is_More_Restrictive_Tree_Than
1980 (Get_All (Orig_Tree), Children_Permission (New_Tree), E);
1982 when Array_Component =>
1983 Check_Is_More_Restrictive_Tree_Than
1984 (Get_Elem (Orig_Tree), Children_Permission (New_Tree), E);
1986 when Record_Component =>
1987 declare
1988 Comp : Perm_Tree_Access;
1989 begin
1990 Comp := Perm_Tree_Maps.Get_First
1991 (Component (Orig_Tree));
1992 while Comp /= null loop
1993 Check_Is_More_Restrictive_Tree_Than
1994 (Comp, Children_Permission (New_Tree), E);
1995 Comp := Perm_Tree_Maps.Get_Next
1996 (Component (Orig_Tree));
1997 end loop;
1999 Check_Is_More_Restrictive_Tree_Than
2000 (Other_Components (Orig_Tree),
2001 Children_Permission (New_Tree), E);
2002 end;
2003 end case;
2005 when Reference =>
2006 case Kind (Orig_Tree) is
2007 when Entire_Object =>
2008 Check_Is_Less_Restrictive_Tree_Than
2009 (Get_All (New_Tree), Children_Permission (Orig_Tree), E);
2011 when Reference =>
2012 Check_Is_Less_Restrictive_Tree
2013 (Get_All (New_Tree), Get_All (Orig_Tree), E);
2015 when others =>
2016 raise Program_Error;
2017 end case;
2019 when Array_Component =>
2020 case Kind (Orig_Tree) is
2021 when Entire_Object =>
2022 Check_Is_Less_Restrictive_Tree_Than
2023 (Get_Elem (New_Tree), Children_Permission (Orig_Tree), E);
2025 when Array_Component =>
2026 Check_Is_Less_Restrictive_Tree
2027 (Get_Elem (New_Tree), Get_Elem (Orig_Tree), E);
2029 when others =>
2030 raise Program_Error;
2031 end case;
2033 when Record_Component =>
2034 declare
2035 CompN : Perm_Tree_Access;
2036 begin
2037 CompN :=
2038 Perm_Tree_Maps.Get_First (Component (New_Tree));
2039 case Kind (Orig_Tree) is
2040 when Entire_Object =>
2041 while CompN /= null loop
2042 Check_Is_Less_Restrictive_Tree_Than
2043 (CompN, Children_Permission (Orig_Tree), E);
2045 CompN :=
2046 Perm_Tree_Maps.Get_Next (Component (New_Tree));
2047 end loop;
2049 Check_Is_Less_Restrictive_Tree_Than
2050 (Other_Components (New_Tree),
2051 Children_Permission (Orig_Tree),
2054 when Record_Component =>
2055 declare
2057 KeyO : Perm_Tree_Maps.Key_Option;
2058 CompO : Perm_Tree_Access;
2059 begin
2060 KeyO := Perm_Tree_Maps.Get_First_Key
2061 (Component (Orig_Tree));
2062 while KeyO.Present loop
2063 pragma Assert (CompO /= null);
2065 Check_Is_Less_Restrictive_Tree (CompN, CompO, E);
2067 KeyO := Perm_Tree_Maps.Get_Next_Key
2068 (Component (Orig_Tree));
2069 CompN := Perm_Tree_Maps.Get
2070 (Component (New_Tree), KeyO.K);
2071 CompO := Perm_Tree_Maps.Get
2072 (Component (Orig_Tree), KeyO.K);
2073 end loop;
2075 Check_Is_Less_Restrictive_Tree
2076 (Other_Components (New_Tree),
2077 Other_Components (Orig_Tree),
2079 end;
2081 when others =>
2082 raise Program_Error;
2083 end case;
2084 end;
2085 end case;
2086 end Check_Is_Less_Restrictive_Tree;
2088 --------------------------
2089 -- Perm_Error_Loop_Exit --
2090 --------------------------
2092 procedure Perm_Error_Loop_Exit
2093 (E : Entity_Id;
2094 Loop_Id : Node_Id;
2095 Perm : Perm_Kind;
2096 Found_Perm : Perm_Kind)
2098 begin
2099 Error_Msg_Node_2 := Loop_Id;
2100 Error_Msg_N ("insufficient permission for & when exiting loop &", E);
2101 Perm_Mismatch (Exp_Perm => Perm,
2102 Act_Perm => Found_Perm,
2103 N => Loop_Id);
2104 end Perm_Error_Loop_Exit;
2106 -- Local variables
2108 Loop_Name : constant Entity_Id := Entity (Identifier (Loop_N));
2109 Loop_Env : constant Perm_Env_Access := new Perm_Env;
2111 begin
2112 -- Save environment prior to the loop
2114 Copy_Env (From => Current_Perm_Env, To => Loop_Env.all);
2116 -- Add saved environment to loop environment
2118 Set (Current_Loops_Envs, Loop_Name, Loop_Env);
2120 -- If the loop is not a plain-loop, then it may either never be entered,
2121 -- or it may be exited after a number of iterations. Hence add the
2122 -- current permission environment as the initial loop exit environment.
2123 -- Otherwise, the loop exit environment remains empty until it is
2124 -- populated by analyzing exit statements.
2126 if Present (Iteration_Scheme (Loop_N)) then
2127 declare
2128 Exit_Env : constant Perm_Env_Access := new Perm_Env;
2129 begin
2130 Copy_Env (From => Current_Perm_Env, To => Exit_Env.all);
2131 Set (Current_Loops_Accumulators, Loop_Name, Exit_Env);
2132 end;
2133 end if;
2135 -- Analyze loop
2137 Check_Node (Iteration_Scheme (Loop_N));
2138 Check_List (Statements (Loop_N));
2140 -- Check that environment gets less restrictive at end of loop
2142 Check_Is_Less_Restrictive_Env
2143 (Exiting_Env => Current_Perm_Env,
2144 Entry_Env => Loop_Env.all);
2146 -- Set environment to the one for exiting the loop
2148 declare
2149 Exit_Env : constant Perm_Env_Access :=
2150 Get (Current_Loops_Accumulators, Loop_Name);
2151 begin
2152 Free_Env (Current_Perm_Env);
2154 -- In the normal case, Exit_Env is not null and we use it. In the
2155 -- degraded case of a plain-loop without exit statements, Exit_Env is
2156 -- null, and we use the initial permission environment at the start
2157 -- of the loop to continue analysis. Any environment would be fine
2158 -- here, since the code after the loop is dead code, but this way we
2159 -- avoid spurious errors by having at least variables in scope inside
2160 -- the environment.
2162 if Exit_Env /= null then
2163 Copy_Env (From => Exit_Env.all, To => Current_Perm_Env);
2164 else
2165 Copy_Env (From => Loop_Env.all, To => Current_Perm_Env);
2166 end if;
2168 Free_Env (Loop_Env.all);
2169 Free_Env (Exit_Env.all);
2170 end;
2171 end Check_Loop_Statement;
2173 ----------------
2174 -- Check_Node --
2175 ----------------
2177 procedure Check_Node (N : Node_Id) is
2178 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2179 begin
2180 case Nkind (N) is
2181 when N_Declaration =>
2182 Check_Declaration (N);
2184 when N_Subexpr =>
2185 Check_Expression (N);
2187 when N_Subtype_Indication =>
2188 Check_Node (Constraint (N));
2190 when N_Body_Stub =>
2191 Check_Node (Get_Body_From_Stub (N));
2193 when N_Statement_Other_Than_Procedure_Call =>
2194 Check_Statement (N);
2196 when N_Package_Body =>
2197 Check_Package_Body (N);
2199 when N_Subprogram_Body
2200 | N_Entry_Body
2201 | N_Task_Body
2203 Check_Callable_Body (N);
2205 when N_Protected_Body =>
2206 Check_List (Declarations (N));
2208 when N_Package_Declaration =>
2209 declare
2210 Spec : constant Node_Id := Specification (N);
2211 begin
2212 Current_Checking_Mode := Read;
2213 Check_List (Visible_Declarations (Spec));
2214 Check_List (Private_Declarations (Spec));
2216 Return_Declarations (Visible_Declarations (Spec));
2217 Return_Declarations (Private_Declarations (Spec));
2218 end;
2220 when N_Iteration_Scheme =>
2221 Current_Checking_Mode := Read;
2222 Check_Node (Condition (N));
2223 Check_Node (Iterator_Specification (N));
2224 Check_Node (Loop_Parameter_Specification (N));
2226 when N_Case_Expression_Alternative =>
2227 Current_Checking_Mode := Read;
2228 Check_List (Discrete_Choices (N));
2229 Current_Checking_Mode := Mode_Before;
2230 Check_Node (Expression (N));
2232 when N_Case_Statement_Alternative =>
2233 Current_Checking_Mode := Read;
2234 Check_List (Discrete_Choices (N));
2235 Current_Checking_Mode := Mode_Before;
2236 Check_List (Statements (N));
2238 when N_Component_Association =>
2239 Check_Node (Expression (N));
2241 when N_Handled_Sequence_Of_Statements =>
2242 Check_List (Statements (N));
2244 when N_Parameter_Association =>
2245 Check_Node (Explicit_Actual_Parameter (N));
2247 when N_Range_Constraint =>
2248 Check_Node (Range_Expression (N));
2250 when N_Index_Or_Discriminant_Constraint =>
2251 Check_List (Constraints (N));
2253 -- Checking should not be called directly on these nodes
2255 when N_Abortable_Part
2256 | N_Accept_Alternative
2257 | N_Access_Definition
2258 | N_Access_Function_Definition
2259 | N_Access_Procedure_Definition
2260 | N_Access_To_Object_Definition
2261 | N_Aspect_Specification
2262 | N_Compilation_Unit
2263 | N_Compilation_Unit_Aux
2264 | N_Component_Clause
2265 | N_Component_Definition
2266 | N_Component_List
2267 | N_Constrained_Array_Definition
2268 | N_Contract
2269 | N_Decimal_Fixed_Point_Definition
2270 | N_Defining_Character_Literal
2271 | N_Defining_Identifier
2272 | N_Defining_Operator_Symbol
2273 | N_Defining_Program_Unit_Name
2274 | N_Delay_Alternative
2275 | N_Derived_Type_Definition
2276 | N_Designator
2277 | N_Discriminant_Association
2278 | N_Discriminant_Specification
2279 | N_Elsif_Part
2280 | N_Entry_Body_Formal_Part
2281 | N_Enumeration_Type_Definition
2282 | N_Entry_Call_Alternative
2283 | N_Entry_Index_Specification
2284 | N_Error
2285 | N_Exception_Handler
2286 | N_Floating_Point_Definition
2287 | N_Formal_Decimal_Fixed_Point_Definition
2288 | N_Formal_Derived_Type_Definition
2289 | N_Formal_Discrete_Type_Definition
2290 | N_Formal_Floating_Point_Definition
2291 | N_Formal_Incomplete_Type_Definition
2292 | N_Formal_Modular_Type_Definition
2293 | N_Formal_Ordinary_Fixed_Point_Definition
2294 | N_Formal_Private_Type_Definition
2295 | N_Formal_Signed_Integer_Type_Definition
2296 | N_Generic_Association
2297 | N_Mod_Clause
2298 | N_Modular_Type_Definition
2299 | N_Ordinary_Fixed_Point_Definition
2300 | N_Package_Specification
2301 | N_Parameter_Specification
2302 | N_Pragma_Argument_Association
2303 | N_Protected_Definition
2304 | N_Push_Pop_xxx_Label
2305 | N_Real_Range_Specification
2306 | N_Record_Definition
2307 | N_SCIL_Dispatch_Table_Tag_Init
2308 | N_SCIL_Dispatching_Call
2309 | N_SCIL_Membership_Test
2310 | N_Signed_Integer_Type_Definition
2311 | N_Subunit
2312 | N_Task_Definition
2313 | N_Terminate_Alternative
2314 | N_Triggering_Alternative
2315 | N_Unconstrained_Array_Definition
2316 | N_Unused_At_Start
2317 | N_Unused_At_End
2318 | N_Variant
2319 | N_Variant_Part
2321 raise Program_Error;
2323 -- Unsupported constructs in SPARK
2325 when N_Iterated_Component_Association =>
2326 Error_Msg_N ("unsupported construct in SPARK", N);
2328 -- Ignored constructs for pointer checking
2330 when N_Abstract_Subprogram_Declaration
2331 | N_At_Clause
2332 | N_Attribute_Definition_Clause
2333 | N_Call_Marker
2334 | N_Delta_Constraint
2335 | N_Digits_Constraint
2336 | N_Empty
2337 | N_Enumeration_Representation_Clause
2338 | N_Exception_Declaration
2339 | N_Exception_Renaming_Declaration
2340 | N_Formal_Package_Declaration
2341 | N_Formal_Subprogram_Declaration
2342 | N_Freeze_Entity
2343 | N_Freeze_Generic_Entity
2344 | N_Function_Instantiation
2345 | N_Generic_Function_Renaming_Declaration
2346 | N_Generic_Package_Declaration
2347 | N_Generic_Package_Renaming_Declaration
2348 | N_Generic_Procedure_Renaming_Declaration
2349 | N_Generic_Subprogram_Declaration
2350 | N_Implicit_Label_Declaration
2351 | N_Itype_Reference
2352 | N_Label
2353 | N_Number_Declaration
2354 | N_Object_Renaming_Declaration
2355 | N_Others_Choice
2356 | N_Package_Instantiation
2357 | N_Package_Renaming_Declaration
2358 | N_Pragma
2359 | N_Procedure_Instantiation
2360 | N_Record_Representation_Clause
2361 | N_Subprogram_Declaration
2362 | N_Subprogram_Renaming_Declaration
2363 | N_Task_Type_Declaration
2364 | N_Use_Package_Clause
2365 | N_With_Clause
2366 | N_Use_Type_Clause
2367 | N_Validate_Unchecked_Conversion
2368 | N_Variable_Reference_Marker
2370 null;
2372 -- The following nodes are rewritten by semantic analysis
2374 when N_Single_Protected_Declaration
2375 | N_Single_Task_Declaration
2377 raise Program_Error;
2378 end case;
2380 Current_Checking_Mode := Mode_Before;
2381 end Check_Node;
2383 ------------------------
2384 -- Check_Package_Body --
2385 ------------------------
2387 procedure Check_Package_Body (Pack : Node_Id) is
2388 Saved_Env : Perm_Env;
2389 CorSp : Node_Id;
2391 begin
2392 if Present (SPARK_Pragma (Defining_Entity (Pack, False))) then
2393 if Get_SPARK_Mode_From_Annotation
2394 (SPARK_Pragma (Defining_Entity (Pack))) /= Opt.On
2395 then
2396 return;
2397 end if;
2398 else
2399 return;
2400 end if;
2402 CorSp := Parent (Corresponding_Spec (Pack));
2403 while Nkind (CorSp) /= N_Package_Specification loop
2404 CorSp := Parent (CorSp);
2405 end loop;
2407 Check_List (Visible_Declarations (CorSp));
2409 -- Save environment
2411 Copy_Env (Current_Perm_Env,
2412 Saved_Env);
2414 Check_List (Private_Declarations (CorSp));
2416 -- Set mode to Read, and then analyze declarations and statements
2418 Current_Checking_Mode := Read;
2420 Check_List (Declarations (Pack));
2421 Check_Node (Handled_Statement_Sequence (Pack));
2423 -- Check RW for every stateful variable (i.e. in declarations)
2425 Return_Declarations (Private_Declarations (CorSp));
2426 Return_Declarations (Visible_Declarations (CorSp));
2427 Return_Declarations (Declarations (Pack));
2429 -- Restore previous environment (i.e. delete every nonvisible
2430 -- declaration) from environment.
2432 Free_Env (Current_Perm_Env);
2433 Copy_Env (Saved_Env,
2434 Current_Perm_Env);
2435 end Check_Package_Body;
2437 -----------------
2438 -- Check_Param --
2439 -----------------
2441 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id) is
2442 Mode : constant Entity_Kind := Ekind (Formal);
2443 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2445 begin
2446 case Current_Checking_Mode is
2447 when Read =>
2448 case Formal_Kind'(Mode) is
2449 when E_In_Parameter =>
2450 if Is_Borrowed_In (Formal) then
2451 -- Borrowed in
2453 Current_Checking_Mode := Move;
2454 else
2455 -- Observed
2457 return;
2458 end if;
2460 when E_Out_Parameter =>
2461 return;
2463 when E_In_Out_Parameter =>
2464 -- Borrowed in out
2466 Current_Checking_Mode := Move;
2468 end case;
2470 Check_Node (Actual);
2472 when Assign =>
2473 case Formal_Kind'(Mode) is
2474 when E_In_Parameter =>
2475 null;
2477 when E_Out_Parameter
2478 | E_In_Out_Parameter
2480 -- Borrowed out or in out
2482 Process_Path (Actual);
2484 end case;
2486 when others =>
2487 raise Program_Error;
2489 end case;
2490 Current_Checking_Mode := Mode_Before;
2491 end Check_Param;
2493 --------------------------
2494 -- Check_Param_Observes --
2495 --------------------------
2497 procedure Check_Param_Observes (Formal : Entity_Id; Actual : Node_Id) is
2498 Mode : constant Entity_Kind := Ekind (Formal);
2499 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2501 begin
2502 case Mode is
2503 when E_In_Parameter =>
2504 if not Is_Borrowed_In (Formal) then
2505 -- Observed in
2507 Current_Checking_Mode := Observe;
2508 Check_Node (Actual);
2509 end if;
2511 when others =>
2512 null;
2514 end case;
2516 Current_Checking_Mode := Mode_Before;
2517 end Check_Param_Observes;
2519 ----------------------
2520 -- Check_Param_Outs --
2521 ----------------------
2523 procedure Check_Param_Outs (Formal : Entity_Id; Actual : Node_Id) is
2524 Mode : constant Entity_Kind := Ekind (Formal);
2525 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2527 begin
2529 case Mode is
2530 when E_Out_Parameter =>
2531 -- Borrowed out
2532 Current_Checking_Mode := Borrow_Out;
2533 Check_Node (Actual);
2535 when others =>
2536 null;
2538 end case;
2540 Current_Checking_Mode := Mode_Before;
2541 end Check_Param_Outs;
2543 ----------------------
2544 -- Check_Param_Read --
2545 ----------------------
2547 procedure Check_Param_Read (Formal : Entity_Id; Actual : Node_Id) is
2548 Mode : constant Entity_Kind := Ekind (Formal);
2550 begin
2551 pragma Assert (Current_Checking_Mode = Read);
2553 case Formal_Kind'(Mode) is
2554 when E_In_Parameter =>
2555 Check_Node (Actual);
2557 when E_Out_Parameter
2558 | E_In_Out_Parameter
2560 null;
2562 end case;
2563 end Check_Param_Read;
2565 -------------------------
2566 -- Check_Safe_Pointers --
2567 -------------------------
2569 procedure Check_Safe_Pointers (N : Node_Id) is
2571 -- Local subprograms
2573 procedure Check_List (L : List_Id);
2574 -- Call the main analysis procedure on each element of the list
2576 procedure Initialize;
2577 -- Initialize global variables before starting the analysis of a body
2579 ----------------
2580 -- Check_List --
2581 ----------------
2583 procedure Check_List (L : List_Id) is
2584 N : Node_Id;
2585 begin
2586 N := First (L);
2587 while Present (N) loop
2588 Check_Safe_Pointers (N);
2589 Next (N);
2590 end loop;
2591 end Check_List;
2593 ----------------
2594 -- Initialize --
2595 ----------------
2597 procedure Initialize is
2598 begin
2599 Reset (Current_Loops_Envs);
2600 Reset (Current_Loops_Accumulators);
2601 Reset (Current_Perm_Env);
2602 Reset (Current_Initialization_Map);
2603 end Initialize;
2605 -- Local variables
2607 Prag : Node_Id;
2608 -- SPARK_Mode pragma in application
2610 -- Start of processing for Check_Safe_Pointers
2612 begin
2613 Initialize;
2615 case Nkind (N) is
2616 when N_Compilation_Unit =>
2617 Check_Safe_Pointers (Unit (N));
2619 when N_Package_Body
2620 | N_Package_Declaration
2621 | N_Subprogram_Body
2623 Prag := SPARK_Pragma (Defining_Entity (N));
2624 if Present (Prag) then
2625 if Get_SPARK_Mode_From_Annotation (Prag) = Opt.Off then
2626 return;
2627 else
2628 Check_Node (N);
2629 end if;
2631 elsif Nkind (N) = N_Package_Body then
2632 Check_List (Declarations (N));
2634 elsif Nkind (N) = N_Package_Declaration then
2635 Check_List (Private_Declarations (Specification (N)));
2636 Check_List (Visible_Declarations (Specification (N)));
2637 end if;
2639 when others =>
2640 null;
2641 end case;
2642 end Check_Safe_Pointers;
2644 ---------------------
2645 -- Check_Statement --
2646 ---------------------
2648 procedure Check_Statement (Stmt : Node_Id) is
2649 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2650 begin
2651 case N_Statement_Other_Than_Procedure_Call'(Nkind (Stmt)) is
2652 when N_Entry_Call_Statement =>
2653 Check_Call_Statement (Stmt);
2655 -- Move right-hand side first, and then assign left-hand side
2657 when N_Assignment_Statement =>
2658 if Is_Deep (Etype (Expression (Stmt))) then
2659 Current_Checking_Mode := Move;
2660 else
2661 Current_Checking_Mode := Read;
2662 end if;
2664 Check_Node (Expression (Stmt));
2665 Current_Checking_Mode := Assign;
2666 Check_Node (Name (Stmt));
2668 when N_Block_Statement =>
2669 declare
2670 Saved_Env : Perm_Env;
2672 begin
2673 -- Save environment
2675 Copy_Env (Current_Perm_Env,
2676 Saved_Env);
2678 -- Analyze declarations and Handled_Statement_Sequences
2680 Current_Checking_Mode := Read;
2681 Check_List (Declarations (Stmt));
2682 Check_Node (Handled_Statement_Sequence (Stmt));
2684 -- Restore environment
2686 Free_Env (Current_Perm_Env);
2687 Copy_Env (Saved_Env,
2688 Current_Perm_Env);
2689 end;
2691 when N_Case_Statement =>
2692 declare
2693 Saved_Env : Perm_Env;
2695 -- Accumulator for the different branches
2697 New_Env : Perm_Env;
2699 Elmt : Node_Id := First (Alternatives (Stmt));
2701 begin
2702 Current_Checking_Mode := Read;
2703 Check_Node (Expression (Stmt));
2704 Current_Checking_Mode := Mode_Before;
2706 -- Save environment
2708 Copy_Env (Current_Perm_Env,
2709 Saved_Env);
2711 -- Here we have the original env in saved, current with a fresh
2712 -- copy, and new aliased.
2714 -- First alternative
2716 Check_Node (Elmt);
2717 Next (Elmt);
2719 Copy_Env (Current_Perm_Env,
2720 New_Env);
2721 Free_Env (Current_Perm_Env);
2723 -- Other alternatives
2725 while Present (Elmt) loop
2726 -- Restore environment
2728 Copy_Env (Saved_Env,
2729 Current_Perm_Env);
2731 Check_Node (Elmt);
2733 -- Merge Current_Perm_Env into New_Env
2735 Merge_Envs (New_Env,
2736 Current_Perm_Env);
2738 Next (Elmt);
2739 end loop;
2741 -- CLEANUP
2742 Copy_Env (New_Env,
2743 Current_Perm_Env);
2745 Free_Env (New_Env);
2746 Free_Env (Saved_Env);
2747 end;
2749 when N_Delay_Relative_Statement =>
2750 Check_Node (Expression (Stmt));
2752 when N_Delay_Until_Statement =>
2753 Check_Node (Expression (Stmt));
2755 when N_Loop_Statement =>
2756 Check_Loop_Statement (Stmt);
2758 -- If deep type expression, then move, else read
2760 when N_Simple_Return_Statement =>
2761 case Nkind (Expression (Stmt)) is
2762 when N_Empty =>
2763 declare
2764 -- ??? This does not take into account the fact that
2765 -- a simple return inside an extended return statement
2766 -- applies to the extended return statement.
2767 Subp : constant Entity_Id :=
2768 Return_Applies_To (Return_Statement_Entity (Stmt));
2769 begin
2770 Return_Parameters (Subp);
2771 Return_Globals (Subp);
2772 end;
2774 when others =>
2775 if Is_Deep (Etype (Expression (Stmt))) then
2776 Current_Checking_Mode := Move;
2777 elsif Is_Shallow (Etype (Expression (Stmt))) then
2778 Current_Checking_Mode := Read;
2779 else
2780 raise Program_Error;
2781 end if;
2783 Check_Node (Expression (Stmt));
2784 end case;
2786 when N_Extended_Return_Statement =>
2787 Check_List (Return_Object_Declarations (Stmt));
2788 Check_Node (Handled_Statement_Sequence (Stmt));
2790 Return_Declarations (Return_Object_Declarations (Stmt));
2792 declare
2793 -- ??? This does not take into account the fact that a simple
2794 -- return inside an extended return statement applies to the
2795 -- extended return statement.
2796 Subp : constant Entity_Id :=
2797 Return_Applies_To (Return_Statement_Entity (Stmt));
2798 begin
2799 Return_Parameters (Subp);
2800 Return_Globals (Subp);
2801 end;
2803 -- Merge the current_Perm_Env with the accumulator for the given loop
2805 when N_Exit_Statement =>
2806 declare
2807 Loop_Name : constant Entity_Id := Loop_Of_Exit (Stmt);
2809 Saved_Accumulator : constant Perm_Env_Access :=
2810 Get (Current_Loops_Accumulators, Loop_Name);
2812 Environment_Copy : constant Perm_Env_Access :=
2813 new Perm_Env;
2814 begin
2816 Copy_Env (Current_Perm_Env,
2817 Environment_Copy.all);
2819 if Saved_Accumulator = null then
2820 Set (Current_Loops_Accumulators,
2821 Loop_Name, Environment_Copy);
2822 else
2823 Merge_Envs (Saved_Accumulator.all,
2824 Environment_Copy.all);
2825 end if;
2826 end;
2828 -- Copy environment, run on each branch, and then merge
2830 when N_If_Statement =>
2831 declare
2832 Saved_Env : Perm_Env;
2834 -- Accumulator for the different branches
2836 New_Env : Perm_Env;
2838 begin
2840 Check_Node (Condition (Stmt));
2842 -- Save environment
2844 Copy_Env (Current_Perm_Env,
2845 Saved_Env);
2847 -- Here we have the original env in saved, current with a fresh
2848 -- copy.
2850 -- THEN PART
2852 Check_List (Then_Statements (Stmt));
2854 Copy_Env (Current_Perm_Env,
2855 New_Env);
2857 Free_Env (Current_Perm_Env);
2859 -- Here the new_environment contains curr env after then block
2861 -- ELSIF part
2862 declare
2863 Elmt : Node_Id;
2865 begin
2866 Elmt := First (Elsif_Parts (Stmt));
2867 while Present (Elmt) loop
2868 -- Transfer into accumulator, and restore from save
2870 Copy_Env (Saved_Env,
2871 Current_Perm_Env);
2873 Check_Node (Condition (Elmt));
2874 Check_List (Then_Statements (Stmt));
2876 -- Merge Current_Perm_Env into New_Env
2878 Merge_Envs (New_Env,
2879 Current_Perm_Env);
2881 Next (Elmt);
2882 end loop;
2883 end;
2885 -- ELSE part
2887 -- Restore environment before if
2889 Copy_Env (Saved_Env,
2890 Current_Perm_Env);
2892 -- Here new environment contains the environment after then and
2893 -- current the fresh copy of old one.
2895 Check_List (Else_Statements (Stmt));
2897 Merge_Envs (New_Env,
2898 Current_Perm_Env);
2900 -- CLEANUP
2902 Copy_Env (New_Env,
2903 Current_Perm_Env);
2905 Free_Env (New_Env);
2906 Free_Env (Saved_Env);
2907 end;
2909 -- Unsupported constructs in SPARK
2911 when N_Abort_Statement
2912 | N_Accept_Statement
2913 | N_Asynchronous_Select
2914 | N_Code_Statement
2915 | N_Conditional_Entry_Call
2916 | N_Goto_Statement
2917 | N_Requeue_Statement
2918 | N_Selective_Accept
2919 | N_Timed_Entry_Call
2921 Error_Msg_N ("unsupported construct in SPARK", Stmt);
2923 -- Ignored constructs for pointer checking
2925 when N_Null_Statement
2926 | N_Raise_Statement
2928 null;
2930 -- The following nodes are never generated in GNATprove mode
2932 when N_Compound_Statement
2933 | N_Free_Statement
2935 raise Program_Error;
2936 end case;
2937 end Check_Statement;
2939 --------------
2940 -- Get_Perm --
2941 --------------
2943 function Get_Perm (N : Node_Id) return Perm_Kind is
2944 Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N);
2946 begin
2947 case Tree_Or_Perm.R is
2948 when Folded =>
2949 return Tree_Or_Perm.Found_Permission;
2951 when Unfolded =>
2952 pragma Assert (Tree_Or_Perm.Tree_Access /= null);
2953 return Permission (Tree_Or_Perm.Tree_Access);
2955 -- We encoutered a function call, hence the memory area is fresh,
2956 -- which means that the association permission is RW.
2958 when Function_Call =>
2959 return Read_Write;
2961 end case;
2962 end Get_Perm;
2964 ----------------------
2965 -- Get_Perm_Or_Tree --
2966 ----------------------
2968 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree is
2969 begin
2970 case Nkind (N) is
2972 -- Base identifier. Normally those are the roots of the trees stored
2973 -- in the permission environment.
2975 when N_Defining_Identifier =>
2976 raise Program_Error;
2978 when N_Identifier
2979 | N_Expanded_Name
2981 declare
2982 P : constant Entity_Id := Entity (N);
2984 C : constant Perm_Tree_Access :=
2985 Get (Current_Perm_Env, Unique_Entity (P));
2987 begin
2988 -- Setting the initialization map to True, so that this
2989 -- variable cannot be ignored anymore when looking at end
2990 -- of elaboration of package.
2992 Set (Current_Initialization_Map, Unique_Entity (P), True);
2994 if C = null then
2995 -- No null possible here, there are no parents for the path.
2996 -- This means we are using a global variable without adding
2997 -- it in environment with a global aspect.
2999 Illegal_Global_Usage (N);
3000 else
3001 return (R => Unfolded, Tree_Access => C);
3002 end if;
3003 end;
3005 when N_Type_Conversion
3006 | N_Unchecked_Type_Conversion
3007 | N_Qualified_Expression
3009 return Get_Perm_Or_Tree (Expression (N));
3011 -- Happening when we try to get the permission of a variable that
3012 -- is a formal parameter. We get instead the defining identifier
3013 -- associated with the parameter (which is the one that has been
3014 -- stored for indexing).
3016 when N_Parameter_Specification =>
3017 return Get_Perm_Or_Tree (Defining_Identifier (N));
3019 -- We get the permission tree of its prefix, and then get either the
3020 -- subtree associated with that specific selection, or if we have a
3021 -- leaf that folds its children, we take the children's permission
3022 -- and return it using the discriminant Folded.
3024 when N_Selected_Component =>
3025 declare
3026 C : constant Perm_Or_Tree :=
3027 Get_Perm_Or_Tree (Prefix (N));
3029 begin
3030 case C.R is
3031 when Folded
3032 | Function_Call
3034 return C;
3036 when Unfolded =>
3037 pragma Assert (C.Tree_Access /= null);
3039 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3040 or else
3041 Kind (C.Tree_Access) = Record_Component);
3043 if Kind (C.Tree_Access) = Record_Component then
3044 declare
3045 Selected_Component : constant Entity_Id :=
3046 Entity (Selector_Name (N));
3048 Selected_C : constant Perm_Tree_Access :=
3049 Perm_Tree_Maps.Get
3050 (Component (C.Tree_Access), Selected_Component);
3052 begin
3053 if Selected_C = null then
3054 return (R => Unfolded,
3055 Tree_Access =>
3056 Other_Components (C.Tree_Access));
3057 else
3058 return (R => Unfolded,
3059 Tree_Access => Selected_C);
3060 end if;
3061 end;
3062 elsif Kind (C.Tree_Access) = Entire_Object then
3063 return (R => Folded, Found_Permission =>
3064 Children_Permission (C.Tree_Access));
3065 else
3066 raise Program_Error;
3067 end if;
3068 end case;
3069 end;
3071 -- We get the permission tree of its prefix, and then get either the
3072 -- subtree associated with that specific selection, or if we have a
3073 -- leaf that folds its children, we take the children's permission
3074 -- and return it using the discriminant Folded.
3076 when N_Indexed_Component
3077 | N_Slice
3079 declare
3080 C : constant Perm_Or_Tree :=
3081 Get_Perm_Or_Tree (Prefix (N));
3083 begin
3084 case C.R is
3085 when Folded
3086 | Function_Call
3088 return C;
3090 when Unfolded =>
3091 pragma Assert (C.Tree_Access /= null);
3093 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3094 or else
3095 Kind (C.Tree_Access) = Array_Component);
3097 if Kind (C.Tree_Access) = Array_Component then
3098 pragma Assert (Get_Elem (C.Tree_Access) /= null);
3100 return (R => Unfolded,
3101 Tree_Access => Get_Elem (C.Tree_Access));
3102 elsif Kind (C.Tree_Access) = Entire_Object then
3103 return (R => Folded, Found_Permission =>
3104 Children_Permission (C.Tree_Access));
3105 else
3106 raise Program_Error;
3107 end if;
3108 end case;
3109 end;
3111 -- We get the permission tree of its prefix, and then get either the
3112 -- subtree associated with that specific selection, or if we have a
3113 -- leaf that folds its children, we take the children's permission
3114 -- and return it using the discriminant Folded.
3116 when N_Explicit_Dereference =>
3117 declare
3118 C : constant Perm_Or_Tree :=
3119 Get_Perm_Or_Tree (Prefix (N));
3121 begin
3122 case C.R is
3123 when Folded
3124 | Function_Call
3126 return C;
3128 when Unfolded =>
3129 pragma Assert (C.Tree_Access /= null);
3131 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3132 or else
3133 Kind (C.Tree_Access) = Reference);
3135 if Kind (C.Tree_Access) = Reference then
3136 if Get_All (C.Tree_Access) = null then
3137 -- Hash_Table_Error
3138 raise Program_Error;
3139 else
3140 return
3141 (R => Unfolded,
3142 Tree_Access => Get_All (C.Tree_Access));
3143 end if;
3144 elsif Kind (C.Tree_Access) = Entire_Object then
3145 return (R => Folded, Found_Permission =>
3146 Children_Permission (C.Tree_Access));
3147 else
3148 raise Program_Error;
3149 end if;
3150 end case;
3151 end;
3153 -- The name contains a function call, hence the given path is always
3154 -- new. We do not have to check for anything.
3156 when N_Function_Call =>
3157 return (R => Function_Call);
3159 when others =>
3160 raise Program_Error;
3161 end case;
3162 end Get_Perm_Or_Tree;
3164 -------------------
3165 -- Get_Perm_Tree --
3166 -------------------
3168 function Get_Perm_Tree
3169 (N : Node_Id)
3170 return Perm_Tree_Access
3172 begin
3173 case Nkind (N) is
3175 -- Base identifier. Normally those are the roots of the trees stored
3176 -- in the permission environment.
3178 when N_Defining_Identifier =>
3179 raise Program_Error;
3181 when N_Identifier
3182 | N_Expanded_Name
3184 declare
3185 P : constant Node_Id := Entity (N);
3187 C : constant Perm_Tree_Access :=
3188 Get (Current_Perm_Env, Unique_Entity (P));
3190 begin
3191 -- Setting the initialization map to True, so that this
3192 -- variable cannot be ignored anymore when looking at end
3193 -- of elaboration of package.
3195 Set (Current_Initialization_Map, Unique_Entity (P), True);
3197 if C = null then
3198 -- No null possible here, there are no parents for the path.
3199 -- This means we are using a global variable without adding
3200 -- it in environment with a global aspect.
3202 Illegal_Global_Usage (N);
3203 else
3204 return C;
3205 end if;
3206 end;
3208 when N_Type_Conversion
3209 | N_Unchecked_Type_Conversion
3210 | N_Qualified_Expression
3212 return Get_Perm_Tree (Expression (N));
3214 when N_Parameter_Specification =>
3215 return Get_Perm_Tree (Defining_Identifier (N));
3217 -- We get the permission tree of its prefix, and then get either the
3218 -- subtree associated with that specific selection, or if we have a
3219 -- leaf that folds its children, we unroll it in one step.
3221 when N_Selected_Component =>
3222 declare
3223 C : constant Perm_Tree_Access :=
3224 Get_Perm_Tree (Prefix (N));
3226 begin
3227 if C = null then
3228 -- If null then it means we went through a function call
3230 return null;
3231 end if;
3233 pragma Assert (Kind (C) = Entire_Object
3234 or else Kind (C) = Record_Component);
3236 if Kind (C) = Record_Component then
3237 -- The tree is unfolded. We just return the subtree.
3239 declare
3240 Selected_Component : constant Entity_Id :=
3241 Entity (Selector_Name (N));
3242 Selected_C : constant Perm_Tree_Access :=
3243 Perm_Tree_Maps.Get
3244 (Component (C), Selected_Component);
3246 begin
3247 if Selected_C = null then
3248 return Other_Components (C);
3249 end if;
3251 return Selected_C;
3252 end;
3253 elsif Kind (C) = Entire_Object then
3254 declare
3255 -- Expand the tree. Replace the node with
3256 -- Record_Component.
3258 Elem : Node_Id;
3260 -- Create the unrolled nodes
3262 Son : Perm_Tree_Access;
3264 Child_Perm : constant Perm_Kind :=
3265 Children_Permission (C);
3267 begin
3269 -- We change the current node from Entire_Object to
3270 -- Record_Component with same permission and an empty
3271 -- hash table as component list.
3273 C.all.Tree :=
3274 (Kind => Record_Component,
3275 Is_Node_Deep => Is_Node_Deep (C),
3276 Permission => Permission (C),
3277 Component => Perm_Tree_Maps.Nil,
3278 Other_Components =>
3279 new Perm_Tree_Wrapper'
3280 (Tree =>
3281 (Kind => Entire_Object,
3282 -- Is_Node_Deep is true, to be conservative
3283 Is_Node_Deep => True,
3284 Permission => Child_Perm,
3285 Children_Permission => Child_Perm)
3289 -- We fill the hash table with all sons of the record,
3290 -- with basic Entire_Objects nodes.
3291 Elem := First_Component_Or_Discriminant
3292 (Etype (Prefix (N)));
3294 while Present (Elem) loop
3295 Son := new Perm_Tree_Wrapper'
3296 (Tree =>
3297 (Kind => Entire_Object,
3298 Is_Node_Deep => Is_Deep (Etype (Elem)),
3299 Permission => Child_Perm,
3300 Children_Permission => Child_Perm));
3302 Perm_Tree_Maps.Set
3303 (C.all.Tree.Component, Elem, Son);
3305 Next_Component_Or_Discriminant (Elem);
3306 end loop;
3308 -- we return the tree to the sons, so that the recursion
3309 -- can continue.
3311 declare
3312 Selected_Component : constant Entity_Id :=
3313 Entity (Selector_Name (N));
3315 Selected_C : constant Perm_Tree_Access :=
3316 Perm_Tree_Maps.Get
3317 (Component (C), Selected_Component);
3319 begin
3320 pragma Assert (Selected_C /= null);
3322 return Selected_C;
3323 end;
3325 end;
3326 else
3327 raise Program_Error;
3328 end if;
3329 end;
3331 -- We set the permission tree of its prefix, and then we extract from
3332 -- the returned pointer the subtree. If folded, we unroll the tree at
3333 -- one step.
3335 when N_Indexed_Component
3336 | N_Slice
3338 declare
3339 C : constant Perm_Tree_Access :=
3340 Get_Perm_Tree (Prefix (N));
3342 begin
3343 if C = null then
3344 -- If null then we went through a function call
3346 return null;
3347 end if;
3349 pragma Assert (Kind (C) = Entire_Object
3350 or else Kind (C) = Array_Component);
3352 if Kind (C) = Array_Component then
3353 -- The tree is unfolded. We just return the elem subtree
3355 pragma Assert (Get_Elem (C) = null);
3357 return Get_Elem (C);
3358 elsif Kind (C) = Entire_Object then
3359 declare
3360 -- Expand the tree. Replace node with Array_Component.
3362 Son : Perm_Tree_Access;
3364 begin
3365 Son := new Perm_Tree_Wrapper'
3366 (Tree =>
3367 (Kind => Entire_Object,
3368 Is_Node_Deep => Is_Node_Deep (C),
3369 Permission => Children_Permission (C),
3370 Children_Permission => Children_Permission (C)));
3372 -- We change the current node from Entire_Object
3373 -- to Array_Component with same permission and the
3374 -- previously defined son.
3376 C.all.Tree := (Kind => Array_Component,
3377 Is_Node_Deep => Is_Node_Deep (C),
3378 Permission => Permission (C),
3379 Get_Elem => Son);
3381 return Get_Elem (C);
3382 end;
3383 else
3384 raise Program_Error;
3385 end if;
3386 end;
3388 -- We get the permission tree of its prefix, and then get either the
3389 -- subtree associated with that specific selection, or if we have a
3390 -- leaf that folds its children, we unroll the tree.
3392 when N_Explicit_Dereference =>
3393 declare
3394 C : Perm_Tree_Access;
3396 begin
3397 C := Get_Perm_Tree (Prefix (N));
3399 if C = null then
3400 -- If null, we went through a function call
3402 return null;
3403 end if;
3405 pragma Assert (Kind (C) = Entire_Object
3406 or else Kind (C) = Reference);
3408 if Kind (C) = Reference then
3409 -- The tree is unfolded. We return the elem subtree
3411 if Get_All (C) = null then
3412 -- Hash_Table_Error
3413 raise Program_Error;
3414 end if;
3416 return Get_All (C);
3417 elsif Kind (C) = Entire_Object then
3418 declare
3419 -- Expand the tree. Replace the node with Reference.
3421 Son : Perm_Tree_Access;
3423 begin
3424 Son := new Perm_Tree_Wrapper'
3425 (Tree =>
3426 (Kind => Entire_Object,
3427 Is_Node_Deep => Is_Deep (Etype (N)),
3428 Permission => Children_Permission (C),
3429 Children_Permission => Children_Permission (C)));
3431 -- We change the current node from Entire_Object to
3432 -- Reference with same permission and the previous son.
3434 pragma Assert (Is_Node_Deep (C));
3436 C.all.Tree := (Kind => Reference,
3437 Is_Node_Deep => Is_Node_Deep (C),
3438 Permission => Permission (C),
3439 Get_All => Son);
3441 return Get_All (C);
3442 end;
3443 else
3444 raise Program_Error;
3445 end if;
3446 end;
3448 -- No permission tree for function calls
3450 when N_Function_Call =>
3451 return null;
3453 when others =>
3454 raise Program_Error;
3455 end case;
3456 end Get_Perm_Tree;
3458 ---------
3459 -- Glb --
3460 ---------
3462 function Glb (P1, P2 : Perm_Kind) return Perm_Kind
3464 begin
3465 case P1 is
3466 when No_Access =>
3467 return No_Access;
3469 when Read_Only =>
3470 case P2 is
3471 when No_Access
3472 | Write_Only
3474 return No_Access;
3476 when Read_Perm =>
3477 return Read_Only;
3478 end case;
3480 when Write_Only =>
3481 case P2 is
3482 when No_Access
3483 | Read_Only
3485 return No_Access;
3487 when Write_Perm =>
3488 return Write_Only;
3489 end case;
3491 when Read_Write =>
3492 return P2;
3493 end case;
3494 end Glb;
3496 ---------------
3497 -- Has_Alias --
3498 ---------------
3500 function Has_Alias
3501 (N : Node_Id)
3502 return Boolean
3504 function Has_Alias_Deep (Typ : Entity_Id) return Boolean;
3505 function Has_Alias_Deep (Typ : Entity_Id) return Boolean
3507 Comp : Node_Id;
3508 begin
3510 if Is_Array_Type (Typ)
3511 and then Has_Aliased_Components (Typ)
3512 then
3513 return True;
3515 -- Note: Has_Aliased_Components applies only to arrays
3517 elsif Is_Record_Type (Typ) then
3518 -- It is possible to have an aliased discriminant, so they must be
3519 -- checked along with normal components.
3521 Comp := First_Component_Or_Discriminant (Typ);
3522 while Present (Comp) loop
3523 if Is_Aliased (Comp)
3524 or else Is_Aliased (Etype (Comp))
3525 then
3526 return True;
3527 end if;
3529 if Has_Alias_Deep (Etype (Comp)) then
3530 return True;
3531 end if;
3533 Next_Component_Or_Discriminant (Comp);
3534 end loop;
3535 return False;
3536 else
3537 return Is_Aliased (Typ);
3538 end if;
3539 end Has_Alias_Deep;
3541 begin
3542 case Nkind (N) is
3544 when N_Identifier
3545 | N_Expanded_Name
3547 return Is_Aliased (Entity (N)) or else Has_Alias_Deep (Etype (N));
3549 when N_Defining_Identifier =>
3550 return Is_Aliased (N) or else Has_Alias_Deep (Etype (N));
3552 when N_Type_Conversion
3553 | N_Unchecked_Type_Conversion
3554 | N_Qualified_Expression
3556 return Has_Alias (Expression (N));
3558 when N_Parameter_Specification =>
3559 return Has_Alias (Defining_Identifier (N));
3561 when N_Selected_Component =>
3562 case Nkind (Selector_Name (N)) is
3563 when N_Identifier =>
3564 if Is_Aliased (Entity (Selector_Name (N))) then
3565 return True;
3566 end if;
3568 when others => null;
3570 end case;
3572 return Has_Alias (Prefix (N));
3574 when N_Indexed_Component
3575 | N_Slice
3577 return Has_Alias (Prefix (N));
3579 when N_Explicit_Dereference =>
3580 return True;
3582 when N_Function_Call =>
3583 return False;
3585 when N_Attribute_Reference =>
3586 if Is_Deep (Etype (Prefix (N))) then
3587 raise Program_Error;
3588 end if;
3589 return False;
3591 when others =>
3592 return False;
3593 end case;
3594 end Has_Alias;
3596 -------------------------
3597 -- Has_Array_Component --
3598 -------------------------
3600 function Has_Array_Component (N : Node_Id) return Boolean is
3601 begin
3602 case Nkind (N) is
3603 -- Base identifier. There is no array component here.
3605 when N_Identifier
3606 | N_Expanded_Name
3607 | N_Defining_Identifier
3609 return False;
3611 -- We check if the expression inside the conversion has an array
3612 -- component.
3614 when N_Type_Conversion
3615 | N_Unchecked_Type_Conversion
3616 | N_Qualified_Expression
3618 return Has_Array_Component (Expression (N));
3620 -- We check if the prefix has an array component
3622 when N_Selected_Component =>
3623 return Has_Array_Component (Prefix (N));
3625 -- We found the array component, return True
3627 when N_Indexed_Component
3628 | N_Slice
3630 return True;
3632 -- We check if the prefix has an array component
3634 when N_Explicit_Dereference =>
3635 return Has_Array_Component (Prefix (N));
3637 when N_Function_Call =>
3638 return False;
3640 when others =>
3641 raise Program_Error;
3642 end case;
3643 end Has_Array_Component;
3645 ----------------------------
3646 -- Has_Function_Component --
3647 ----------------------------
3649 function Has_Function_Component (N : Node_Id) return Boolean is
3650 begin
3651 case Nkind (N) is
3652 -- Base identifier. There is no function component here.
3654 when N_Identifier
3655 | N_Expanded_Name
3656 | N_Defining_Identifier
3658 return False;
3660 -- We check if the expression inside the conversion has a function
3661 -- component.
3663 when N_Type_Conversion
3664 | N_Unchecked_Type_Conversion
3665 | N_Qualified_Expression
3667 return Has_Function_Component (Expression (N));
3669 -- We check if the prefix has a function component
3671 when N_Selected_Component =>
3672 return Has_Function_Component (Prefix (N));
3674 -- We check if the prefix has a function component
3676 when N_Indexed_Component
3677 | N_Slice
3679 return Has_Function_Component (Prefix (N));
3681 -- We check if the prefix has a function component
3683 when N_Explicit_Dereference =>
3684 return Has_Function_Component (Prefix (N));
3686 -- We found the function component, return True
3688 when N_Function_Call =>
3689 return True;
3691 when others =>
3692 raise Program_Error;
3694 end case;
3695 end Has_Function_Component;
3697 --------
3698 -- Hp --
3699 --------
3701 procedure Hp (P : Perm_Env) is
3702 Elem : Perm_Tree_Maps.Key_Option;
3704 begin
3705 Elem := Get_First_Key (P);
3706 while Elem.Present loop
3707 Print_Node_Briefly (Elem.K);
3708 Elem := Get_Next_Key (P);
3709 end loop;
3710 end Hp;
3712 --------------------------
3713 -- Illegal_Global_Usage --
3714 --------------------------
3716 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id) is
3717 begin
3718 Error_Msg_NE ("cannot use global variable & of deep type", N, N);
3719 Error_Msg_N ("\without prior declaration in a Global aspect", N);
3721 Errout.Finalize (Last_Call => True);
3722 Errout.Output_Messages;
3723 Exit_Program (E_Errors);
3724 end Illegal_Global_Usage;
3726 --------------------
3727 -- Is_Borrowed_In --
3728 --------------------
3730 function Is_Borrowed_In (E : Entity_Id) return Boolean is
3731 begin
3732 return Is_Access_Type (Etype (E))
3733 and then not Is_Access_Constant (Etype (E));
3734 end Is_Borrowed_In;
3736 -------------
3737 -- Is_Deep --
3738 -------------
3740 function Is_Deep (E : Entity_Id) return Boolean is
3741 function Is_Private_Entity_Mode_Off (E : Entity_Id) return Boolean;
3743 function Is_Private_Entity_Mode_Off (E : Entity_Id) return Boolean is
3744 Decl : Node_Id;
3745 Pack_Decl : Node_Id;
3747 begin
3748 if Is_Itype (E) then
3749 Decl := Associated_Node_For_Itype (E);
3750 else
3751 Decl := Parent (E);
3752 end if;
3754 Pack_Decl := Parent (Parent (Decl));
3756 if Nkind (Pack_Decl) /= N_Package_Declaration then
3757 return False;
3758 end if;
3760 return
3761 Present (SPARK_Aux_Pragma (Defining_Entity (Pack_Decl)))
3762 and then Get_SPARK_Mode_From_Annotation
3763 (SPARK_Aux_Pragma (Defining_Entity (Pack_Decl))) = Off;
3764 end Is_Private_Entity_Mode_Off;
3765 begin
3766 pragma Assert (Is_Type (E));
3768 case Ekind (E) is
3769 when Scalar_Kind =>
3770 return False;
3772 when Access_Kind =>
3773 return True;
3775 -- Just check the depth of its component type
3777 when E_Array_Type
3778 | E_Array_Subtype
3780 return Is_Deep (Component_Type (E));
3782 when E_String_Literal_Subtype =>
3783 return False;
3785 -- Per RM 8.11 for class-wide types
3787 when E_Class_Wide_Subtype
3788 | E_Class_Wide_Type
3790 return True;
3792 -- ??? What about hidden components
3794 when E_Record_Type
3795 | E_Record_Subtype
3797 declare
3798 Elmt : Entity_Id;
3800 begin
3801 Elmt := First_Component_Or_Discriminant (E);
3802 while Present (Elmt) loop
3803 if Is_Deep (Etype (Elmt)) then
3804 return True;
3805 else
3806 Next_Component_Or_Discriminant (Elmt);
3807 end if;
3808 end loop;
3810 return False;
3811 end;
3813 when Private_Kind =>
3814 if Is_Private_Entity_Mode_Off (E) then
3815 return False;
3816 else
3817 if Present (Full_View (E)) then
3818 return Is_Deep (Full_View (E));
3819 else
3820 return True;
3821 end if;
3822 end if;
3824 when E_Incomplete_Type =>
3825 return True;
3827 when E_Incomplete_Subtype =>
3828 return True;
3830 -- No problem with synchronized types
3832 when E_Protected_Type
3833 | E_Protected_Subtype
3834 | E_Task_Subtype
3835 | E_Task_Type
3837 return False;
3839 when E_Exception_Type =>
3840 return False;
3842 when others =>
3843 raise Program_Error;
3844 end case;
3845 end Is_Deep;
3847 ----------------
3848 -- Is_Shallow --
3849 ----------------
3851 function Is_Shallow (E : Entity_Id) return Boolean is
3852 begin
3853 pragma Assert (Is_Type (E));
3854 return not Is_Deep (E);
3855 end Is_Shallow;
3857 ------------------
3858 -- Loop_Of_Exit --
3859 ------------------
3861 function Loop_Of_Exit (N : Node_Id) return Entity_Id is
3862 Nam : Node_Id := Name (N);
3863 Stmt : Node_Id := N;
3864 begin
3865 if No (Nam) then
3866 while Present (Stmt) loop
3867 Stmt := Parent (Stmt);
3868 if Nkind (Stmt) = N_Loop_Statement then
3869 Nam := Identifier (Stmt);
3870 exit;
3871 end if;
3872 end loop;
3873 end if;
3874 return Entity (Nam);
3875 end Loop_Of_Exit;
3876 ---------
3877 -- Lub --
3878 ---------
3880 function Lub (P1, P2 : Perm_Kind) return Perm_Kind
3882 begin
3883 case P1 is
3884 when No_Access =>
3885 return P2;
3887 when Read_Only =>
3888 case P2 is
3889 when No_Access
3890 | Read_Only
3892 return Read_Only;
3894 when Write_Perm =>
3895 return Read_Write;
3896 end case;
3898 when Write_Only =>
3899 case P2 is
3900 when No_Access
3901 | Write_Only
3903 return Write_Only;
3905 when Read_Perm =>
3906 return Read_Write;
3907 end case;
3909 when Read_Write =>
3910 return Read_Write;
3911 end case;
3912 end Lub;
3914 ----------------
3915 -- Merge_Envs --
3916 ----------------
3918 procedure Merge_Envs
3919 (Target : in out Perm_Env;
3920 Source : in out Perm_Env)
3922 procedure Merge_Trees
3923 (Target : Perm_Tree_Access;
3924 Source : Perm_Tree_Access);
3926 procedure Merge_Trees
3927 (Target : Perm_Tree_Access;
3928 Source : Perm_Tree_Access)
3930 procedure Apply_Glb_Tree
3931 (A : Perm_Tree_Access;
3932 P : Perm_Kind);
3934 procedure Apply_Glb_Tree
3935 (A : Perm_Tree_Access;
3936 P : Perm_Kind)
3938 begin
3939 A.all.Tree.Permission := Glb (Permission (A), P);
3941 case Kind (A) is
3942 when Entire_Object =>
3943 A.all.Tree.Children_Permission :=
3944 Glb (Children_Permission (A), P);
3946 when Reference =>
3947 Apply_Glb_Tree (Get_All (A), P);
3949 when Array_Component =>
3950 Apply_Glb_Tree (Get_Elem (A), P);
3952 when Record_Component =>
3953 declare
3954 Comp : Perm_Tree_Access;
3955 begin
3956 Comp := Perm_Tree_Maps.Get_First (Component (A));
3957 while Comp /= null loop
3958 Apply_Glb_Tree (Comp, P);
3959 Comp := Perm_Tree_Maps.Get_Next (Component (A));
3960 end loop;
3962 Apply_Glb_Tree (Other_Components (A), P);
3963 end;
3964 end case;
3965 end Apply_Glb_Tree;
3967 Perm : constant Perm_Kind :=
3968 Glb (Permission (Target), Permission (Source));
3970 begin
3971 pragma Assert (Is_Node_Deep (Target) = Is_Node_Deep (Source));
3972 Target.all.Tree.Permission := Perm;
3974 case Kind (Target) is
3975 when Entire_Object =>
3976 declare
3977 Child_Perm : constant Perm_Kind :=
3978 Children_Permission (Target);
3980 begin
3981 case Kind (Source) is
3982 when Entire_Object =>
3983 Target.all.Tree.Children_Permission :=
3984 Glb (Child_Perm, Children_Permission (Source));
3986 when Reference =>
3987 Copy_Tree (Source, Target);
3988 Target.all.Tree.Permission := Perm;
3989 Apply_Glb_Tree (Get_All (Target), Child_Perm);
3991 when Array_Component =>
3992 Copy_Tree (Source, Target);
3993 Target.all.Tree.Permission := Perm;
3994 Apply_Glb_Tree (Get_Elem (Target), Child_Perm);
3996 when Record_Component =>
3997 Copy_Tree (Source, Target);
3998 Target.all.Tree.Permission := Perm;
3999 declare
4000 Comp : Perm_Tree_Access;
4002 begin
4003 Comp :=
4004 Perm_Tree_Maps.Get_First (Component (Target));
4005 while Comp /= null loop
4006 -- Apply glb tree on every component subtree
4008 Apply_Glb_Tree (Comp, Child_Perm);
4009 Comp := Perm_Tree_Maps.Get_Next
4010 (Component (Target));
4011 end loop;
4012 end;
4013 Apply_Glb_Tree (Other_Components (Target), Child_Perm);
4015 end case;
4016 end;
4017 when Reference =>
4018 case Kind (Source) is
4019 when Entire_Object =>
4020 Apply_Glb_Tree (Get_All (Target),
4021 Children_Permission (Source));
4023 when Reference =>
4024 Merge_Trees (Get_All (Target), Get_All (Source));
4026 when others =>
4027 raise Program_Error;
4029 end case;
4031 when Array_Component =>
4032 case Kind (Source) is
4033 when Entire_Object =>
4034 Apply_Glb_Tree (Get_Elem (Target),
4035 Children_Permission (Source));
4037 when Array_Component =>
4038 Merge_Trees (Get_Elem (Target), Get_Elem (Source));
4040 when others =>
4041 raise Program_Error;
4043 end case;
4045 when Record_Component =>
4046 case Kind (Source) is
4047 when Entire_Object =>
4048 declare
4049 Child_Perm : constant Perm_Kind :=
4050 Children_Permission (Source);
4052 Comp : Perm_Tree_Access;
4054 begin
4055 Comp := Perm_Tree_Maps.Get_First
4056 (Component (Target));
4057 while Comp /= null loop
4058 -- Apply glb tree on every component subtree
4060 Apply_Glb_Tree (Comp, Child_Perm);
4061 Comp :=
4062 Perm_Tree_Maps.Get_Next (Component (Target));
4063 end loop;
4064 Apply_Glb_Tree (Other_Components (Target), Child_Perm);
4065 end;
4067 when Record_Component =>
4068 declare
4069 Key_Source : Perm_Tree_Maps.Key_Option;
4070 CompTarget : Perm_Tree_Access;
4071 CompSource : Perm_Tree_Access;
4073 begin
4074 Key_Source := Perm_Tree_Maps.Get_First_Key
4075 (Component (Source));
4077 while Key_Source.Present loop
4078 CompSource := Perm_Tree_Maps.Get
4079 (Component (Source), Key_Source.K);
4080 CompTarget := Perm_Tree_Maps.Get
4081 (Component (Target), Key_Source.K);
4083 pragma Assert (CompSource /= null);
4084 Merge_Trees (CompTarget, CompSource);
4086 Key_Source := Perm_Tree_Maps.Get_Next_Key
4087 (Component (Source));
4088 end loop;
4090 Merge_Trees (Other_Components (Target),
4091 Other_Components (Source));
4092 end;
4094 when others =>
4095 raise Program_Error;
4097 end case;
4098 end case;
4099 end Merge_Trees;
4101 CompTarget : Perm_Tree_Access;
4102 CompSource : Perm_Tree_Access;
4103 KeyTarget : Perm_Tree_Maps.Key_Option;
4105 begin
4106 KeyTarget := Get_First_Key (Target);
4107 -- Iterate over every tree of the environment in the target, and merge
4108 -- it with the source if there is such a similar one that exists. If
4109 -- there is none, then skip.
4110 while KeyTarget.Present loop
4112 CompSource := Get (Source, KeyTarget.K);
4113 CompTarget := Get (Target, KeyTarget.K);
4115 pragma Assert (CompTarget /= null);
4117 if CompSource /= null then
4118 Merge_Trees (CompTarget, CompSource);
4119 Remove (Source, KeyTarget.K);
4120 end if;
4122 KeyTarget := Get_Next_Key (Target);
4123 end loop;
4125 -- Iterate over every tree of the environment of the source. And merge
4126 -- again. If there is not any tree of the target then just copy the tree
4127 -- from source to target.
4128 declare
4129 KeySource : Perm_Tree_Maps.Key_Option;
4130 begin
4131 KeySource := Get_First_Key (Source);
4132 while KeySource.Present loop
4134 CompSource := Get (Source, KeySource.K);
4135 CompTarget := Get (Target, KeySource.K);
4137 if CompTarget = null then
4138 CompTarget := new Perm_Tree_Wrapper'(CompSource.all);
4139 Copy_Tree (CompSource, CompTarget);
4140 Set (Target, KeySource.K, CompTarget);
4141 else
4142 Merge_Trees (CompTarget, CompSource);
4143 end if;
4145 KeySource := Get_Next_Key (Source);
4146 end loop;
4147 end;
4149 Free_Env (Source);
4150 end Merge_Envs;
4152 ----------------
4153 -- Perm_Error --
4154 ----------------
4156 procedure Perm_Error
4157 (N : Node_Id;
4158 Perm : Perm_Kind;
4159 Found_Perm : Perm_Kind)
4161 procedure Set_Root_Object
4162 (Path : Node_Id;
4163 Obj : out Entity_Id;
4164 Deref : out Boolean);
4165 -- Set the root object Obj, and whether the path contains a dereference,
4166 -- from a path Path.
4168 ---------------------
4169 -- Set_Root_Object --
4170 ---------------------
4172 procedure Set_Root_Object
4173 (Path : Node_Id;
4174 Obj : out Entity_Id;
4175 Deref : out Boolean)
4177 begin
4178 case Nkind (Path) is
4179 when N_Identifier
4180 | N_Expanded_Name
4182 Obj := Entity (Path);
4183 Deref := False;
4185 when N_Type_Conversion
4186 | N_Unchecked_Type_Conversion
4187 | N_Qualified_Expression
4189 Set_Root_Object (Expression (Path), Obj, Deref);
4191 when N_Indexed_Component
4192 | N_Selected_Component
4193 | N_Slice
4195 Set_Root_Object (Prefix (Path), Obj, Deref);
4197 when N_Explicit_Dereference =>
4198 Set_Root_Object (Prefix (Path), Obj, Deref);
4199 Deref := True;
4201 when others =>
4202 raise Program_Error;
4203 end case;
4204 end Set_Root_Object;
4206 -- Local variables
4208 Root : Entity_Id;
4209 Is_Deref : Boolean;
4211 -- Start of processing for Perm_Error
4213 begin
4214 Set_Root_Object (N, Root, Is_Deref);
4216 if Is_Deref then
4217 Error_Msg_NE
4218 ("insufficient permission on dereference from &", N, Root);
4219 else
4220 Error_Msg_NE ("insufficient permission for &", N, Root);
4221 end if;
4223 Perm_Mismatch (Perm, Found_Perm, N);
4224 end Perm_Error;
4226 -------------------------------
4227 -- Perm_Error_Subprogram_End --
4228 -------------------------------
4230 procedure Perm_Error_Subprogram_End
4231 (E : Entity_Id;
4232 Subp : Entity_Id;
4233 Perm : Perm_Kind;
4234 Found_Perm : Perm_Kind)
4236 begin
4237 Error_Msg_Node_2 := Subp;
4238 Error_Msg_NE ("insufficient permission for & when returning from &",
4239 Subp, E);
4240 Perm_Mismatch (Perm, Found_Perm, Subp);
4241 end Perm_Error_Subprogram_End;
4243 ------------------
4244 -- Process_Path --
4245 ------------------
4247 procedure Process_Path (N : Node_Id) is
4248 Root : constant Entity_Id := Get_Enclosing_Object (N);
4250 begin
4251 -- We ignore if yielding to synchronized
4253 if Present (Root)
4254 and then Is_Synchronized_Object (Root)
4255 then
4256 return;
4257 end if;
4259 -- We ignore shallow unaliased. They are checked in flow analysis,
4260 -- allowing backward compatibility.
4262 if Current_Checking_Mode /= Super_Move
4263 and then not Has_Alias (N)
4264 and then Is_Shallow (Etype (N))
4265 then
4266 return;
4267 end if;
4269 declare
4270 Perm_N : constant Perm_Kind := Get_Perm (N);
4272 begin
4274 case Current_Checking_Mode is
4275 -- Check permission R, do nothing
4277 when Read =>
4278 if Perm_N not in Read_Perm then
4279 Perm_Error (N, Read_Only, Perm_N);
4280 return;
4281 end if;
4283 -- If shallow type no need for RW, only R
4285 when Move =>
4286 if Is_Shallow (Etype (N)) then
4287 if Perm_N not in Read_Perm then
4288 Perm_Error (N, Read_Only, Perm_N);
4289 return;
4290 end if;
4291 else
4292 -- Check permission RW if deep
4294 if Perm_N /= Read_Write then
4295 Perm_Error (N, Read_Write, Perm_N);
4296 return;
4297 end if;
4299 declare
4300 -- Set permission to W to the path and any of its prefix
4302 Tree : constant Perm_Tree_Access :=
4303 Set_Perm_Prefixes_Move (N, Move);
4305 begin
4306 if Tree = null then
4307 -- We went through a function call, no permission to
4308 -- modify.
4310 return;
4311 end if;
4313 -- Set permissions to
4314 -- No for any extension with more .all
4315 -- W for any deep extension with same number of .all
4316 -- RW for any shallow extension with same number of .all
4318 Set_Perm_Extensions_Move (Tree, Etype (N));
4319 end;
4320 end if;
4322 -- Check permission RW
4324 when Super_Move =>
4325 if Perm_N /= Read_Write then
4326 Perm_Error (N, Read_Write, Perm_N);
4327 return;
4328 end if;
4330 declare
4331 -- Set permission to No to the path and any of its prefix up
4332 -- to the first .all and then W.
4334 Tree : constant Perm_Tree_Access :=
4335 Set_Perm_Prefixes_Move (N, Super_Move);
4337 begin
4338 if Tree = null then
4339 -- We went through a function call, no permission to
4340 -- modify.
4342 return;
4343 end if;
4345 -- Set permissions to No on any strict extension of the path
4347 Set_Perm_Extensions (Tree, No_Access);
4348 end;
4350 -- Check permission W
4352 when Assign =>
4353 if Perm_N not in Write_Perm then
4354 Perm_Error (N, Write_Only, Perm_N);
4355 return;
4356 end if;
4358 -- If the tree has an array component, then the permissions do
4359 -- not get modified by the assignment.
4361 if Has_Array_Component (N) then
4362 return;
4363 end if;
4365 -- Same if has function component
4367 if Has_Function_Component (N) then -- Dead code?
4368 return;
4369 end if;
4371 declare
4372 -- Get the permission tree for the path
4374 Tree : constant Perm_Tree_Access :=
4375 Get_Perm_Tree (N);
4377 Dummy : Perm_Tree_Access;
4379 begin
4380 if Tree = null then
4381 -- We went through a function call, no permission to
4382 -- modify.
4384 return;
4385 end if;
4387 -- Set permission RW for it and all of its extensions
4389 Tree.all.Tree.Permission := Read_Write;
4391 Set_Perm_Extensions (Tree, Read_Write);
4393 -- Normalize the permission tree
4395 Dummy := Set_Perm_Prefixes_Assign (N);
4396 end;
4398 -- Check permission W
4400 when Borrow_Out =>
4401 if Perm_N not in Write_Perm then
4402 Perm_Error (N, Write_Only, Perm_N);
4403 end if;
4405 declare
4406 -- Set permission to No to the path and any of its prefixes
4408 Tree : constant Perm_Tree_Access :=
4409 Set_Perm_Prefixes_Borrow_Out (N);
4411 begin
4412 if Tree = null then
4413 -- We went through a function call, no permission to
4414 -- modify.
4416 return;
4417 end if;
4419 -- Set permissions to No on any strict extension of the path
4421 Set_Perm_Extensions (Tree, No_Access);
4422 end;
4424 when Observe =>
4425 if Perm_N not in Read_Perm then
4426 Perm_Error (N, Read_Only, Perm_N);
4427 end if;
4429 if Is_By_Copy_Type (Etype (N)) then
4430 return;
4431 end if;
4433 declare
4434 -- Set permission to No on the path and any of its prefixes
4436 Tree : constant Perm_Tree_Access :=
4437 Set_Perm_Prefixes_Observe (N);
4439 begin
4440 if Tree = null then
4441 -- We went through a function call, no permission to
4442 -- modify.
4444 return;
4445 end if;
4447 -- Set permissions to No on any strict extension of the path
4449 Set_Perm_Extensions (Tree, Read_Only);
4450 end;
4451 end case;
4452 end;
4453 end Process_Path;
4455 -------------------------
4456 -- Return_Declarations --
4457 -------------------------
4459 procedure Return_Declarations (L : List_Id) is
4461 procedure Return_Declaration (Decl : Node_Id);
4462 -- Check correct permissions for every declared object
4464 ------------------------
4465 -- Return_Declaration --
4466 ------------------------
4468 procedure Return_Declaration (Decl : Node_Id) is
4469 begin
4470 if Nkind (Decl) = N_Object_Declaration then
4471 -- Check RW for object declared, unless the object has never been
4472 -- initialized.
4474 if Get (Current_Initialization_Map,
4475 Unique_Entity (Defining_Identifier (Decl))) = False
4476 then
4477 return;
4478 end if;
4480 -- We ignore shallow unaliased. They are checked in flow analysis,
4481 -- allowing backward compatibility.
4483 if not Has_Alias (Defining_Identifier (Decl))
4484 and then Is_Shallow (Etype (Defining_Identifier (Decl)))
4485 then
4486 return;
4487 end if;
4489 declare
4490 Elem : constant Perm_Tree_Access :=
4491 Get (Current_Perm_Env,
4492 Unique_Entity (Defining_Identifier (Decl)));
4494 begin
4495 if Elem = null then
4496 -- Here we are on a declaration. Hence it should have been
4497 -- added in the environment when analyzing this node with
4498 -- mode Read. Hence it is not possible to find a null
4499 -- pointer here.
4501 -- Hash_Table_Error
4502 raise Program_Error;
4503 end if;
4505 if Permission (Elem) /= Read_Write then
4506 Perm_Error (Decl, Read_Write, Permission (Elem));
4507 end if;
4508 end;
4509 end if;
4510 end Return_Declaration;
4512 -- Local Variables
4514 N : Node_Id;
4516 -- Start of processing for Return_Declarations
4518 begin
4519 N := First (L);
4520 while Present (N) loop
4521 Return_Declaration (N);
4522 Next (N);
4523 end loop;
4524 end Return_Declarations;
4526 --------------------
4527 -- Return_Globals --
4528 --------------------
4530 procedure Return_Globals (Subp : Entity_Id) is
4532 procedure Return_Globals_From_List
4533 (First_Item : Node_Id;
4534 Kind : Formal_Kind);
4535 -- Return global items from the list starting at Item
4537 procedure Return_Globals_Of_Mode (Global_Mode : Name_Id);
4538 -- Return global items for the mode Global_Mode
4540 ------------------------------
4541 -- Return_Globals_From_List --
4542 ------------------------------
4544 procedure Return_Globals_From_List
4545 (First_Item : Node_Id;
4546 Kind : Formal_Kind)
4548 Item : Node_Id := First_Item;
4549 E : Entity_Id;
4551 begin
4552 while Present (Item) loop
4553 E := Entity (Item);
4555 -- Ignore abstract states, which play no role in pointer aliasing
4557 if Ekind (E) = E_Abstract_State then
4558 null;
4559 else
4560 Return_Parameter_Or_Global (E, Kind, Subp, Global_Var => True);
4561 end if;
4562 Next_Global (Item);
4563 end loop;
4564 end Return_Globals_From_List;
4566 ----------------------------
4567 -- Return_Globals_Of_Mode --
4568 ----------------------------
4570 procedure Return_Globals_Of_Mode (Global_Mode : Name_Id) is
4571 Kind : Formal_Kind;
4573 begin
4574 case Global_Mode is
4575 when Name_Input | Name_Proof_In =>
4576 Kind := E_In_Parameter;
4577 when Name_Output =>
4578 Kind := E_Out_Parameter;
4579 when Name_In_Out =>
4580 Kind := E_In_Out_Parameter;
4581 when others =>
4582 raise Program_Error;
4583 end case;
4585 -- Return both global items from Global and Refined_Global pragmas
4587 Return_Globals_From_List (First_Global (Subp, Global_Mode), Kind);
4588 Return_Globals_From_List
4589 (First_Global (Subp, Global_Mode, Refined => True), Kind);
4590 end Return_Globals_Of_Mode;
4592 -- Start of processing for Return_Globals
4594 begin
4595 Return_Globals_Of_Mode (Name_Proof_In);
4596 Return_Globals_Of_Mode (Name_Input);
4597 Return_Globals_Of_Mode (Name_Output);
4598 Return_Globals_Of_Mode (Name_In_Out);
4599 end Return_Globals;
4601 --------------------------------
4602 -- Return_Parameter_Or_Global --
4603 --------------------------------
4605 procedure Return_Parameter_Or_Global
4606 (Id : Entity_Id;
4607 Mode : Formal_Kind;
4608 Subp : Entity_Id;
4609 Global_Var : Boolean)
4611 Elem : constant Perm_Tree_Access := Get (Current_Perm_Env, Id);
4612 pragma Assert (Elem /= null);
4614 begin
4615 -- Shallow unaliased parameters and globals cannot introduce pointer
4616 -- aliasing.
4618 if not Has_Alias (Id) and then Is_Shallow (Etype (Id)) then
4619 null;
4621 -- Observed IN parameters and globals need not return a permission to
4622 -- the caller.
4624 elsif Mode = E_In_Parameter
4625 and then (not Is_Borrowed_In (Id) or else Global_Var)
4626 then
4627 null;
4629 -- All other parameters and globals should return with mode RW to the
4630 -- caller.
4632 else
4633 if Permission (Elem) /= Read_Write then
4634 Perm_Error_Subprogram_End
4635 (E => Id,
4636 Subp => Subp,
4637 Perm => Read_Write,
4638 Found_Perm => Permission (Elem));
4639 end if;
4640 end if;
4641 end Return_Parameter_Or_Global;
4643 -----------------------
4644 -- Return_Parameters --
4645 -----------------------
4647 procedure Return_Parameters (Subp : Entity_Id) is
4648 Formal : Entity_Id;
4650 begin
4651 Formal := First_Formal (Subp);
4652 while Present (Formal) loop
4653 Return_Parameter_Or_Global (Formal, Ekind (Formal), Subp, False);
4654 Next_Formal (Formal);
4655 end loop;
4656 end Return_Parameters;
4658 -------------------------
4659 -- Set_Perm_Extensions --
4660 -------------------------
4662 procedure Set_Perm_Extensions
4663 (T : Perm_Tree_Access;
4664 P : Perm_Kind)
4666 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access);
4668 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access)
4670 begin
4671 case Kind (T) is
4672 when Entire_Object =>
4673 null;
4675 when Reference =>
4676 Free_Perm_Tree (T.all.Tree.Get_All);
4678 when Array_Component =>
4679 Free_Perm_Tree (T.all.Tree.Get_Elem);
4681 -- Free every Component subtree
4683 when Record_Component =>
4684 declare
4685 Comp : Perm_Tree_Access;
4687 begin
4688 Comp := Perm_Tree_Maps.Get_First (Component (T));
4689 while Comp /= null loop
4690 Free_Perm_Tree (Comp);
4691 Comp := Perm_Tree_Maps.Get_Next (Component (T));
4692 end loop;
4694 Free_Perm_Tree (T.all.Tree.Other_Components);
4695 end;
4696 end case;
4697 end Free_Perm_Tree_Children;
4699 Son : constant Perm_Tree :=
4700 Perm_Tree'
4701 (Kind => Entire_Object,
4702 Is_Node_Deep => Is_Node_Deep (T),
4703 Permission => Permission (T),
4704 Children_Permission => P);
4706 begin
4707 Free_Perm_Tree_Children (T);
4708 T.all.Tree := Son;
4709 end Set_Perm_Extensions;
4711 ------------------------------
4712 -- Set_Perm_Extensions_Move --
4713 ------------------------------
4715 procedure Set_Perm_Extensions_Move
4716 (T : Perm_Tree_Access;
4717 E : Entity_Id)
4719 begin
4720 if not Is_Node_Deep (T) then
4721 -- We are a shallow extension with same number of .all
4723 Set_Perm_Extensions (T, Read_Write);
4724 return;
4725 end if;
4727 -- We are a deep extension here (or the moved deep path)
4729 T.all.Tree.Permission := Write_Only;
4731 case T.all.Tree.Kind is
4732 -- Unroll the tree depending on the type
4734 when Entire_Object =>
4735 case Ekind (E) is
4736 when Scalar_Kind
4737 | E_String_Literal_Subtype
4739 Set_Perm_Extensions (T, No_Access);
4741 -- No need to unroll here, directly put sons to No_Access
4743 when Access_Kind =>
4744 if Ekind (E) in Access_Subprogram_Kind then
4745 null;
4746 else
4747 Set_Perm_Extensions (T, No_Access);
4748 end if;
4750 -- No unrolling done, too complicated
4752 when E_Class_Wide_Subtype
4753 | E_Class_Wide_Type
4754 | E_Incomplete_Type
4755 | E_Incomplete_Subtype
4756 | E_Exception_Type
4757 | E_Task_Type
4758 | E_Task_Subtype
4760 Set_Perm_Extensions (T, No_Access);
4762 -- Expand the tree. Replace the node with Array component.
4764 when E_Array_Type
4765 | E_Array_Subtype =>
4766 declare
4767 Son : Perm_Tree_Access;
4769 begin
4770 Son := new Perm_Tree_Wrapper'
4771 (Tree =>
4772 (Kind => Entire_Object,
4773 Is_Node_Deep => Is_Node_Deep (T),
4774 Permission => Read_Write,
4775 Children_Permission => Read_Write));
4777 Set_Perm_Extensions_Move (Son, Component_Type (E));
4779 -- We change the current node from Entire_Object to
4780 -- Reference with Write_Only and the previous son.
4782 pragma Assert (Is_Node_Deep (T));
4784 T.all.Tree := (Kind => Array_Component,
4785 Is_Node_Deep => Is_Node_Deep (T),
4786 Permission => Write_Only,
4787 Get_Elem => Son);
4788 end;
4790 -- Unroll, and set permission extensions with component type
4792 when E_Record_Type
4793 | E_Record_Subtype
4794 | E_Record_Type_With_Private
4795 | E_Record_Subtype_With_Private
4796 | E_Protected_Type
4797 | E_Protected_Subtype
4799 declare
4800 -- Expand the tree. Replace the node with
4801 -- Record_Component.
4803 Elem : Node_Id;
4805 Son : Perm_Tree_Access;
4807 begin
4808 -- We change the current node from Entire_Object to
4809 -- Record_Component with same permission and an empty
4810 -- hash table as component list.
4812 pragma Assert (Is_Node_Deep (T));
4814 T.all.Tree :=
4815 (Kind => Record_Component,
4816 Is_Node_Deep => Is_Node_Deep (T),
4817 Permission => Write_Only,
4818 Component => Perm_Tree_Maps.Nil,
4819 Other_Components =>
4820 new Perm_Tree_Wrapper'
4821 (Tree =>
4822 (Kind => Entire_Object,
4823 Is_Node_Deep => True,
4824 Permission => Read_Write,
4825 Children_Permission => Read_Write)
4829 -- We fill the hash table with all sons of the record,
4830 -- with basic Entire_Objects nodes.
4831 Elem := First_Component_Or_Discriminant (E);
4832 while Present (Elem) loop
4833 Son := new Perm_Tree_Wrapper'
4834 (Tree =>
4835 (Kind => Entire_Object,
4836 Is_Node_Deep => Is_Deep (Etype (Elem)),
4837 Permission => Read_Write,
4838 Children_Permission => Read_Write));
4840 Set_Perm_Extensions_Move (Son, Etype (Elem));
4842 Perm_Tree_Maps.Set
4843 (T.all.Tree.Component, Elem, Son);
4845 Next_Component_Or_Discriminant (Elem);
4846 end loop;
4847 end;
4849 when E_Private_Type
4850 | E_Private_Subtype
4851 | E_Limited_Private_Type
4852 | E_Limited_Private_Subtype
4854 Set_Perm_Extensions_Move (T, Underlying_Type (E));
4856 when others =>
4857 raise Program_Error;
4858 end case;
4860 when Reference =>
4861 -- Now the son does not have the same number of .all
4862 Set_Perm_Extensions (T, No_Access);
4864 when Array_Component =>
4865 Set_Perm_Extensions_Move (Get_Elem (T), Component_Type (E));
4867 when Record_Component =>
4868 declare
4869 Comp : Perm_Tree_Access;
4870 It : Node_Id;
4872 begin
4873 It := First_Component_Or_Discriminant (E);
4874 while It /= Empty loop
4875 Comp := Perm_Tree_Maps.Get (Component (T), It);
4876 pragma Assert (Comp /= null);
4877 Set_Perm_Extensions_Move (Comp, It);
4878 It := Next_Component_Or_Discriminant (E);
4879 end loop;
4881 Set_Perm_Extensions (Other_Components (T), No_Access);
4882 end;
4883 end case;
4884 end Set_Perm_Extensions_Move;
4886 ------------------------------
4887 -- Set_Perm_Prefixes_Assign --
4888 ------------------------------
4890 function Set_Perm_Prefixes_Assign (N : Node_Id) return Perm_Tree_Access is
4891 C : constant Perm_Tree_Access := Get_Perm_Tree (N);
4893 begin
4894 pragma Assert (Current_Checking_Mode = Assign);
4896 -- The function should not be called if has_function_component
4898 pragma Assert (C /= null);
4900 case Kind (C) is
4901 when Entire_Object =>
4902 pragma Assert (Children_Permission (C) = Read_Write);
4904 -- Maroua: Children could have read_only perm. Why Read_Write?
4906 C.all.Tree.Permission := Read_Write;
4908 when Reference =>
4909 pragma Assert (Get_All (C) /= null);
4911 C.all.Tree.Permission :=
4912 Lub (Permission (C), Permission (Get_All (C)));
4914 when Array_Component =>
4915 pragma Assert (C.all.Tree.Get_Elem /= null);
4917 -- Given that it is not possible to know which element has been
4918 -- assigned, then the permissions do not get changed in case of
4919 -- Array_Component.
4921 null;
4923 when Record_Component =>
4924 declare
4925 Comp : Perm_Tree_Access;
4926 Perm : Perm_Kind := Read_Write;
4928 begin
4929 -- We take the Glb of all the descendants, and then update the
4930 -- permission of the node with it.
4932 Comp := Perm_Tree_Maps.Get_First (Component (C));
4933 while Comp /= null loop
4934 Perm := Glb (Perm, Permission (Comp));
4935 Comp := Perm_Tree_Maps.Get_Next (Component (C));
4936 end loop;
4938 Perm := Glb (Perm, Permission (Other_Components (C)));
4940 C.all.Tree.Permission := Lub (Permission (C), Perm);
4941 end;
4942 end case;
4944 case Nkind (N) is
4946 -- Base identifier. End recursion here.
4948 when N_Identifier
4949 | N_Expanded_Name
4950 | N_Defining_Identifier
4952 return null;
4954 when N_Type_Conversion
4955 | N_Unchecked_Type_Conversion
4956 | N_Qualified_Expression
4958 return Set_Perm_Prefixes_Assign (Expression (N));
4960 when N_Parameter_Specification =>
4961 raise Program_Error;
4963 -- Continue recursion on prefix
4965 when N_Selected_Component =>
4966 return Set_Perm_Prefixes_Assign (Prefix (N));
4968 -- Continue recursion on prefix
4970 when N_Indexed_Component
4971 | N_Slice
4973 return Set_Perm_Prefixes_Assign (Prefix (N));
4975 -- Continue recursion on prefix
4977 when N_Explicit_Dereference =>
4978 return Set_Perm_Prefixes_Assign (Prefix (N));
4980 when N_Function_Call =>
4981 raise Program_Error;
4983 when others =>
4984 raise Program_Error;
4986 end case;
4987 end Set_Perm_Prefixes_Assign;
4989 ----------------------------------
4990 -- Set_Perm_Prefixes_Borrow_Out --
4991 ----------------------------------
4993 function Set_Perm_Prefixes_Borrow_Out
4994 (N : Node_Id)
4995 return Perm_Tree_Access
4997 begin
4998 pragma Assert (Current_Checking_Mode = Borrow_Out);
5000 case Nkind (N) is
5001 -- Base identifier. Set permission to No.
5003 when N_Identifier
5004 | N_Expanded_Name
5006 declare
5007 P : constant Node_Id := Entity (N);
5009 C : constant Perm_Tree_Access :=
5010 Get (Current_Perm_Env, Unique_Entity (P));
5012 pragma Assert (C /= null);
5014 begin
5015 -- Setting the initialization map to True, so that this
5016 -- variable cannot be ignored anymore when looking at end
5017 -- of elaboration of package.
5019 Set (Current_Initialization_Map, Unique_Entity (P), True);
5021 C.all.Tree.Permission := No_Access;
5022 return C;
5023 end;
5025 when N_Type_Conversion
5026 | N_Unchecked_Type_Conversion
5027 | N_Qualified_Expression
5029 return Set_Perm_Prefixes_Borrow_Out (Expression (N));
5031 when N_Parameter_Specification
5032 | N_Defining_Identifier
5034 raise Program_Error;
5036 -- We set the permission tree of its prefix, and then we extract
5037 -- our subtree from the returned pointer and assign an adequate
5038 -- permission to it, if unfolded. If folded, we unroll the tree
5039 -- in one step.
5041 when N_Selected_Component =>
5042 declare
5043 C : constant Perm_Tree_Access :=
5044 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5046 begin
5047 if C = null then
5048 -- We went through a function call, do nothing
5050 return null;
5051 end if;
5053 -- The permission of the returned node should be No
5055 pragma Assert (Permission (C) = No_Access);
5057 pragma Assert (Kind (C) = Entire_Object
5058 or else Kind (C) = Record_Component);
5060 if Kind (C) = Record_Component then
5061 -- The tree is unfolded. We just modify the permission and
5062 -- return the record subtree.
5064 declare
5065 Selected_Component : constant Entity_Id :=
5066 Entity (Selector_Name (N));
5068 Selected_C : Perm_Tree_Access :=
5069 Perm_Tree_Maps.Get
5070 (Component (C), Selected_Component);
5072 begin
5073 if Selected_C = null then
5074 Selected_C := Other_Components (C);
5075 end if;
5077 pragma Assert (Selected_C /= null);
5079 Selected_C.all.Tree.Permission := No_Access;
5081 return Selected_C;
5082 end;
5083 elsif Kind (C) = Entire_Object then
5084 declare
5085 -- Expand the tree. Replace the node with
5086 -- Record_Component.
5088 Elem : Node_Id;
5090 -- Create an empty hash table
5092 Hashtbl : Perm_Tree_Maps.Instance;
5094 -- We create the unrolled nodes, that will all have same
5095 -- permission than parent.
5097 Son : Perm_Tree_Access;
5099 ChildrenPerm : constant Perm_Kind :=
5100 Children_Permission (C);
5102 begin
5103 -- We change the current node from Entire_Object to
5104 -- Record_Component with same permission and an empty
5105 -- hash table as component list.
5107 C.all.Tree :=
5108 (Kind => Record_Component,
5109 Is_Node_Deep => Is_Node_Deep (C),
5110 Permission => Permission (C),
5111 Component => Hashtbl,
5112 Other_Components =>
5113 new Perm_Tree_Wrapper'
5114 (Tree =>
5115 (Kind => Entire_Object,
5116 Is_Node_Deep => True,
5117 Permission => ChildrenPerm,
5118 Children_Permission => ChildrenPerm)
5121 -- We fill the hash table with all sons of the record,
5122 -- with basic Entire_Objects nodes.
5123 Elem := First_Component_Or_Discriminant
5124 (Etype (Prefix (N)));
5126 while Present (Elem) loop
5127 Son := new Perm_Tree_Wrapper'
5128 (Tree =>
5129 (Kind => Entire_Object,
5130 Is_Node_Deep => Is_Deep (Etype (Elem)),
5131 Permission => ChildrenPerm,
5132 Children_Permission => ChildrenPerm));
5134 Perm_Tree_Maps.Set
5135 (C.all.Tree.Component, Elem, Son);
5137 Next_Component_Or_Discriminant (Elem);
5138 end loop;
5140 -- Now we set the right field to No_Access, and then we
5141 -- return the tree to the sons, so that the recursion can
5142 -- continue.
5144 declare
5145 Selected_Component : constant Entity_Id :=
5146 Entity (Selector_Name (N));
5148 Selected_C : Perm_Tree_Access :=
5149 Perm_Tree_Maps.Get
5150 (Component (C), Selected_Component);
5152 begin
5153 if Selected_C = null then
5154 Selected_C := Other_Components (C);
5155 end if;
5157 pragma Assert (Selected_C /= null);
5159 Selected_C.all.Tree.Permission := No_Access;
5161 return Selected_C;
5162 end;
5163 end;
5164 else
5165 raise Program_Error;
5166 end if;
5167 end;
5169 -- We set the permission tree of its prefix, and then we extract
5170 -- from the returned pointer the subtree and assign an adequate
5171 -- permission to it, if unfolded. If folded, we unroll the tree in
5172 -- one step.
5174 when N_Indexed_Component
5175 | N_Slice
5177 declare
5178 C : constant Perm_Tree_Access :=
5179 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5181 begin
5182 if C = null then
5183 -- We went through a function call, do nothing
5185 return null;
5186 end if;
5188 -- The permission of the returned node should be either W
5189 -- (because the recursive call sets <= Write_Only) or No
5190 -- (if another path has been moved with 'Access).
5192 pragma Assert (Permission (C) = No_Access);
5194 pragma Assert (Kind (C) = Entire_Object
5195 or else Kind (C) = Array_Component);
5197 if Kind (C) = Array_Component then
5198 -- The tree is unfolded. We just modify the permission and
5199 -- return the elem subtree.
5201 pragma Assert (Get_Elem (C) /= null);
5203 C.all.Tree.Get_Elem.all.Tree.Permission := No_Access;
5205 return Get_Elem (C);
5206 elsif Kind (C) = Entire_Object then
5207 declare
5208 -- Expand the tree. Replace node with Array_Component.
5210 Son : Perm_Tree_Access;
5212 begin
5213 Son := new Perm_Tree_Wrapper'
5214 (Tree =>
5215 (Kind => Entire_Object,
5216 Is_Node_Deep => Is_Node_Deep (C),
5217 Permission => No_Access,
5218 Children_Permission => Children_Permission (C)));
5220 -- We change the current node from Entire_Object
5221 -- to Array_Component with same permission and the
5222 -- previously defined son.
5224 C.all.Tree := (Kind => Array_Component,
5225 Is_Node_Deep => Is_Node_Deep (C),
5226 Permission => No_Access,
5227 Get_Elem => Son);
5229 return Get_Elem (C);
5230 end;
5231 else
5232 raise Program_Error;
5233 end if;
5234 end;
5236 -- We set the permission tree of its prefix, and then we extract
5237 -- from the returned pointer the subtree and assign an adequate
5238 -- permission to it, if unfolded. If folded, we unroll the tree
5239 -- at one step.
5241 when N_Explicit_Dereference =>
5242 declare
5243 C : constant Perm_Tree_Access :=
5244 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5246 begin
5247 if C = null then
5248 -- We went through a function call. Do nothing.
5250 return null;
5251 end if;
5253 -- The permission of the returned node should be No
5255 pragma Assert (Permission (C) = No_Access);
5256 pragma Assert (Kind (C) = Entire_Object
5257 or else Kind (C) = Reference);
5259 if Kind (C) = Reference then
5260 -- The tree is unfolded. We just modify the permission and
5261 -- return the elem subtree.
5263 pragma Assert (Get_All (C) /= null);
5265 C.all.Tree.Get_All.all.Tree.Permission := No_Access;
5267 return Get_All (C);
5268 elsif Kind (C) = Entire_Object then
5269 declare
5270 -- Expand the tree. Replace the node with Reference.
5272 Son : Perm_Tree_Access;
5274 begin
5275 Son := new Perm_Tree_Wrapper'
5276 (Tree =>
5277 (Kind => Entire_Object,
5278 Is_Node_Deep => Is_Deep (Etype (N)),
5279 Permission => No_Access,
5280 Children_Permission => Children_Permission (C)));
5282 -- We change the current node from Entire_Object to
5283 -- Reference with No_Access and the previous son.
5285 pragma Assert (Is_Node_Deep (C));
5287 C.all.Tree := (Kind => Reference,
5288 Is_Node_Deep => Is_Node_Deep (C),
5289 Permission => No_Access,
5290 Get_All => Son);
5292 return Get_All (C);
5293 end;
5294 else
5295 raise Program_Error;
5296 end if;
5297 end;
5299 when N_Function_Call =>
5300 return null;
5302 when others =>
5303 raise Program_Error;
5304 end case;
5305 end Set_Perm_Prefixes_Borrow_Out;
5307 ----------------------------
5308 -- Set_Perm_Prefixes_Move --
5309 ----------------------------
5311 function Set_Perm_Prefixes_Move
5312 (N : Node_Id; Mode : Checking_Mode)
5313 return Perm_Tree_Access
5315 begin
5316 case Nkind (N) is
5318 -- Base identifier. Set permission to W or No depending on Mode.
5320 when N_Identifier
5321 | N_Expanded_Name
5323 declare
5324 P : constant Node_Id := Entity (N);
5325 C : constant Perm_Tree_Access :=
5326 Get (Current_Perm_Env, Unique_Entity (P));
5328 begin
5329 -- The base tree can be RW (first move from this base path) or
5330 -- W (already some extensions values moved), or even No_Access
5331 -- (extensions moved with 'Access). But it cannot be Read_Only
5332 -- (we get an error).
5334 if Permission (C) = Read_Only then
5335 raise Unrecoverable_Error;
5336 end if;
5338 -- Setting the initialization map to True, so that this
5339 -- variable cannot be ignored anymore when looking at end
5340 -- of elaboration of package.
5342 Set (Current_Initialization_Map, Unique_Entity (P), True);
5344 if C = null then
5345 -- No null possible here, there are no parents for the path.
5346 -- This means we are using a global variable without adding
5347 -- it in environment with a global aspect.
5349 Illegal_Global_Usage (N);
5350 end if;
5352 if Mode = Super_Move then
5353 C.all.Tree.Permission := No_Access;
5354 else
5355 C.all.Tree.Permission := Glb (Write_Only, Permission (C));
5356 end if;
5358 return C;
5359 end;
5361 when N_Type_Conversion
5362 | N_Unchecked_Type_Conversion
5363 | N_Qualified_Expression
5365 return Set_Perm_Prefixes_Move (Expression (N), Mode);
5367 when N_Parameter_Specification
5368 | N_Defining_Identifier
5370 raise Program_Error;
5372 -- We set the permission tree of its prefix, and then we extract
5373 -- from the returned pointer our subtree and assign an adequate
5374 -- permission to it, if unfolded. If folded, we unroll the tree
5375 -- at one step.
5377 when N_Selected_Component =>
5378 declare
5379 C : constant Perm_Tree_Access :=
5380 Set_Perm_Prefixes_Move (Prefix (N), Mode);
5382 begin
5383 if C = null then
5384 -- We went through a function call, do nothing
5386 return null;
5387 end if;
5389 -- The permission of the returned node should be either W
5390 -- (because the recursive call sets <= Write_Only) or No
5391 -- (if another path has been moved with 'Access).
5393 pragma Assert (Permission (C) = No_Access
5394 or else Permission (C) = Write_Only);
5396 if Mode = Super_Move then
5397 -- The permission of the returned node should be No (thanks
5398 -- to the recursion).
5400 pragma Assert (Permission (C) = No_Access);
5401 null;
5402 end if;
5404 pragma Assert (Kind (C) = Entire_Object
5405 or else Kind (C) = Record_Component);
5407 if Kind (C) = Record_Component then
5408 -- The tree is unfolded. We just modify the permission and
5409 -- return the record subtree.
5411 declare
5412 Selected_Component : constant Entity_Id :=
5413 Entity (Selector_Name (N));
5415 Selected_C : Perm_Tree_Access :=
5416 Perm_Tree_Maps.Get
5417 (Component (C), Selected_Component);
5419 begin
5420 if Selected_C = null then
5421 -- If the hash table returns no element, then we fall
5422 -- into the part of Other_Components.
5423 pragma Assert (Is_Tagged_Type (Etype (Prefix (N))));
5425 Selected_C := Other_Components (C);
5426 end if;
5428 pragma Assert (Selected_C /= null);
5430 -- The Selected_C can have permissions:
5431 -- RW : first move in this path
5432 -- W : Already other moves in this path
5433 -- No : Already other moves with 'Access
5435 pragma Assert (Permission (Selected_C) /= Read_Only);
5436 if Mode = Super_Move then
5437 Selected_C.all.Tree.Permission := No_Access;
5438 else
5439 Selected_C.all.Tree.Permission :=
5440 Glb (Write_Only, Permission (Selected_C));
5442 end if;
5444 return Selected_C;
5445 end;
5446 elsif Kind (C) = Entire_Object then
5447 declare
5448 -- Expand the tree. Replace the node with
5449 -- Record_Component.
5451 Elem : Node_Id;
5453 -- Create an empty hash table
5455 Hashtbl : Perm_Tree_Maps.Instance;
5457 -- We are in Move or Super_Move mode, hence we can assume
5458 -- that the Children_permission is RW, given that there
5459 -- are no other paths that could have been moved.
5461 pragma Assert (Children_Permission (C) = Read_Write);
5463 -- We create the unrolled nodes, that will all have RW
5464 -- permission given that we are in move mode. We will
5465 -- then set the right node to W.
5467 Son : Perm_Tree_Access;
5469 begin
5470 -- We change the current node from Entire_Object to
5471 -- Record_Component with same permission and an empty
5472 -- hash table as component list.
5474 C.all.Tree :=
5475 (Kind => Record_Component,
5476 Is_Node_Deep => Is_Node_Deep (C),
5477 Permission => Permission (C),
5478 Component => Hashtbl,
5479 Other_Components =>
5480 new Perm_Tree_Wrapper'
5481 (Tree =>
5482 (Kind => Entire_Object,
5483 Is_Node_Deep => True,
5484 Permission => Read_Write,
5485 Children_Permission => Read_Write)
5488 -- We fill the hash table with all sons of the record,
5489 -- with basic Entire_Objects nodes.
5490 Elem := First_Component_Or_Discriminant
5491 (Etype (Prefix (N)));
5493 while Present (Elem) loop
5494 Son := new Perm_Tree_Wrapper'
5495 (Tree =>
5496 (Kind => Entire_Object,
5497 Is_Node_Deep => Is_Deep (Etype (Elem)),
5498 Permission => Read_Write,
5499 Children_Permission => Read_Write));
5501 Perm_Tree_Maps.Set
5502 (C.all.Tree.Component, Elem, Son);
5504 Next_Component_Or_Discriminant (Elem);
5505 end loop;
5507 -- Now we set the right field to Write_Only or No_Access
5508 -- depending on mode, and then we return the tree to the
5509 -- sons, so that the recursion can continue.
5511 declare
5512 Selected_Component : constant Entity_Id :=
5513 Entity (Selector_Name (N));
5515 Selected_C : Perm_Tree_Access :=
5516 Perm_Tree_Maps.Get
5517 (Component (C), Selected_Component);
5519 begin
5520 if Selected_C = null then
5521 Selected_C := Other_Components (C);
5522 end if;
5524 pragma Assert (Selected_C /= null);
5526 -- Given that this is a newly created Select_C, we can
5527 -- safely assume that its permission is Read_Write.
5529 pragma Assert (Permission (Selected_C) =
5530 Read_Write);
5532 if Mode = Super_Move then
5533 Selected_C.all.Tree.Permission := No_Access;
5534 else
5535 Selected_C.all.Tree.Permission := Write_Only;
5536 end if;
5538 return Selected_C;
5539 end;
5540 end;
5541 else
5542 raise Program_Error;
5543 end if;
5544 end;
5546 -- We set the permission tree of its prefix, and then we extract
5547 -- from the returned pointer the subtree and assign an adequate
5548 -- permission to it, if unfolded. If folded, we unroll the tree
5549 -- at one step.
5551 when N_Indexed_Component
5552 | N_Slice
5554 declare
5555 C : constant Perm_Tree_Access :=
5556 Set_Perm_Prefixes_Move (Prefix (N), Mode);
5558 begin
5559 if C = null then
5560 -- We went through a function call, do nothing
5562 return null;
5563 end if;
5565 -- The permission of the returned node should be either
5566 -- W (because the recursive call sets <= Write_Only)
5567 -- or No (if another path has been moved with 'Access)
5569 if Mode = Super_Move then
5570 pragma Assert (Permission (C) = No_Access);
5571 null;
5572 else
5573 pragma Assert (Permission (C) = Write_Only
5574 or else Permission (C) = No_Access);
5575 null;
5576 end if;
5578 pragma Assert (Kind (C) = Entire_Object
5579 or else Kind (C) = Array_Component);
5581 if Kind (C) = Array_Component then
5582 -- The tree is unfolded. We just modify the permission and
5583 -- return the elem subtree.
5585 if Get_Elem (C) = null then
5586 -- Hash_Table_Error
5587 raise Program_Error;
5588 end if;
5590 -- The Get_Elem can have permissions :
5591 -- RW : first move in this path
5592 -- W : Already other moves in this path
5593 -- No : Already other moves with 'Access
5595 pragma Assert (Permission (Get_Elem (C)) /= Read_Only);
5597 if Mode = Super_Move then
5598 C.all.Tree.Get_Elem.all.Tree.Permission := No_Access;
5599 else
5600 C.all.Tree.Get_Elem.all.Tree.Permission :=
5601 Glb (Write_Only, Permission (Get_Elem (C)));
5602 end if;
5604 return Get_Elem (C);
5605 elsif Kind (C) = Entire_Object then
5606 declare
5607 -- Expand the tree. Replace node with Array_Component.
5609 -- We are in move mode, hence we can assume that the
5610 -- Children_permission is RW.
5612 pragma Assert (Children_Permission (C) = Read_Write);
5614 Son : Perm_Tree_Access;
5616 begin
5617 Son := new Perm_Tree_Wrapper'
5618 (Tree =>
5619 (Kind => Entire_Object,
5620 Is_Node_Deep => Is_Node_Deep (C),
5621 Permission => Read_Write,
5622 Children_Permission => Read_Write));
5624 if Mode = Super_Move then
5625 Son.all.Tree.Permission := No_Access;
5626 else
5627 Son.all.Tree.Permission := Write_Only;
5628 end if;
5630 -- We change the current node from Entire_Object
5631 -- to Array_Component with same permission and the
5632 -- previously defined son.
5634 C.all.Tree := (Kind => Array_Component,
5635 Is_Node_Deep => Is_Node_Deep (C),
5636 Permission => Permission (C),
5637 Get_Elem => Son);
5639 return Get_Elem (C);
5640 end;
5641 else
5642 raise Program_Error;
5643 end if;
5644 end;
5646 -- We set the permission tree of its prefix, and then we extract
5647 -- from the returned pointer the subtree and assign an adequate
5648 -- permission to it, if unfolded. If folded, we unroll the tree
5649 -- at one step.
5651 when N_Explicit_Dereference =>
5652 declare
5653 C : constant Perm_Tree_Access :=
5654 Set_Perm_Prefixes_Move (Prefix (N), Move);
5656 begin
5657 if C = null then
5658 -- We went through a function call: do nothing
5660 return null;
5661 end if;
5663 -- The permission of the returned node should be only
5664 -- W (because the recursive call sets <= Write_Only)
5665 -- No is NOT POSSIBLE here
5667 pragma Assert (Permission (C) = Write_Only);
5669 pragma Assert (Kind (C) = Entire_Object
5670 or else Kind (C) = Reference);
5672 if Kind (C) = Reference then
5673 -- The tree is unfolded. We just modify the permission and
5674 -- return the elem subtree.
5676 if Get_All (C) = null then
5677 -- Hash_Table_Error
5678 raise Program_Error;
5679 end if;
5681 -- The Get_All can have permissions :
5682 -- RW : first move in this path
5683 -- W : Already other moves in this path
5684 -- No : Already other moves with 'Access
5686 pragma Assert (Permission (Get_All (C)) /= Read_Only);
5688 if Mode = Super_Move then
5689 C.all.Tree.Get_All.all.Tree.Permission := No_Access;
5690 else
5691 Get_All (C).all.Tree.Permission :=
5692 Glb (Write_Only, Permission (Get_All (C)));
5693 end if;
5694 return Get_All (C);
5695 elsif Kind (C) = Entire_Object then
5696 declare
5697 -- Expand the tree. Replace the node with Reference.
5699 -- We are in Move or Super_Move mode, hence we can assume
5700 -- that the Children_permission is RW.
5702 pragma Assert (Children_Permission (C) = Read_Write);
5704 Son : Perm_Tree_Access;
5706 begin
5707 Son := new Perm_Tree_Wrapper'
5708 (Tree =>
5709 (Kind => Entire_Object,
5710 Is_Node_Deep => Is_Deep (Etype (N)),
5711 Permission => Read_Write,
5712 Children_Permission => Read_Write));
5714 if Mode = Super_Move then
5715 Son.all.Tree.Permission := No_Access;
5716 else
5717 Son.all.Tree.Permission := Write_Only;
5718 end if;
5720 -- We change the current node from Entire_Object to
5721 -- Reference with Write_Only and the previous son.
5723 pragma Assert (Is_Node_Deep (C));
5725 C.all.Tree := (Kind => Reference,
5726 Is_Node_Deep => Is_Node_Deep (C),
5727 Permission => Write_Only,
5728 -- Write_only is equal to C.Permission
5729 Get_All => Son);
5731 return Get_All (C);
5732 end;
5733 else
5734 raise Program_Error;
5735 end if;
5736 end;
5738 when N_Function_Call =>
5739 return null;
5741 when others =>
5742 raise Program_Error;
5743 end case;
5745 end Set_Perm_Prefixes_Move;
5747 -------------------------------
5748 -- Set_Perm_Prefixes_Observe --
5749 -------------------------------
5751 function Set_Perm_Prefixes_Observe
5752 (N : Node_Id)
5753 return Perm_Tree_Access
5755 begin
5756 pragma Assert (Current_Checking_Mode = Observe);
5758 case Nkind (N) is
5759 -- Base identifier. Set permission to R.
5761 when N_Identifier
5762 | N_Expanded_Name
5763 | N_Defining_Identifier
5765 declare
5766 P : Node_Id;
5767 C : Perm_Tree_Access;
5769 begin
5770 if Nkind (N) = N_Defining_Identifier then
5771 P := N;
5772 else
5773 P := Entity (N);
5774 end if;
5776 C := Get (Current_Perm_Env, Unique_Entity (P));
5777 -- Setting the initialization map to True, so that this
5778 -- variable cannot be ignored anymore when looking at end
5779 -- of elaboration of package.
5781 Set (Current_Initialization_Map, Unique_Entity (P), True);
5783 if C = null then
5784 -- No null possible here, there are no parents for the path.
5785 -- This means we are using a global variable without adding
5786 -- it in environment with a global aspect.
5788 Illegal_Global_Usage (N);
5789 end if;
5791 C.all.Tree.Permission := Glb (Read_Only, Permission (C));
5793 return C;
5794 end;
5796 when N_Type_Conversion
5797 | N_Unchecked_Type_Conversion
5798 | N_Qualified_Expression
5800 return Set_Perm_Prefixes_Observe (Expression (N));
5802 when N_Parameter_Specification =>
5803 raise Program_Error;
5805 -- We set the permission tree of its prefix, and then we extract
5806 -- from the returned pointer our subtree and assign an adequate
5807 -- permission to it, if unfolded. If folded, we unroll the tree
5808 -- at one step.
5810 when N_Selected_Component =>
5811 declare
5812 C : constant Perm_Tree_Access :=
5813 Set_Perm_Prefixes_Observe (Prefix (N));
5815 begin
5816 if C = null then
5817 -- We went through a function call, do nothing
5819 return null;
5820 end if;
5822 pragma Assert (Kind (C) = Entire_Object
5823 or else Kind (C) = Record_Component);
5825 if Kind (C) = Record_Component then
5826 -- The tree is unfolded. We just modify the permission and
5827 -- return the record subtree. We put the permission to the
5828 -- glb of read_only and its current permission, to consider
5829 -- the case of observing x.y while x.z has been moved. Then
5830 -- x should be No_Access.
5832 declare
5833 Selected_Component : constant Entity_Id :=
5834 Entity (Selector_Name (N));
5836 Selected_C : Perm_Tree_Access :=
5837 Perm_Tree_Maps.Get
5838 (Component (C), Selected_Component);
5840 begin
5841 if Selected_C = null then
5842 Selected_C := Other_Components (C);
5843 end if;
5845 pragma Assert (Selected_C /= null);
5847 Selected_C.all.Tree.Permission :=
5848 Glb (Read_Only, Permission (Selected_C));
5850 return Selected_C;
5851 end;
5852 elsif Kind (C) = Entire_Object then
5853 declare
5854 -- Expand the tree. Replace the node with
5855 -- Record_Component.
5857 Elem : Node_Id;
5859 -- Create an empty hash table
5861 Hashtbl : Perm_Tree_Maps.Instance;
5863 -- We create the unrolled nodes, that will all have RW
5864 -- permission given that we are in move mode. We will
5865 -- then set the right node to W.
5867 Son : Perm_Tree_Access;
5869 Child_Perm : constant Perm_Kind :=
5870 Children_Permission (C);
5872 begin
5873 -- We change the current node from Entire_Object to
5874 -- Record_Component with same permission and an empty
5875 -- hash table as component list.
5877 C.all.Tree :=
5878 (Kind => Record_Component,
5879 Is_Node_Deep => Is_Node_Deep (C),
5880 Permission => Permission (C),
5881 Component => Hashtbl,
5882 Other_Components =>
5883 new Perm_Tree_Wrapper'
5884 (Tree =>
5885 (Kind => Entire_Object,
5886 Is_Node_Deep => True,
5887 Permission => Child_Perm,
5888 Children_Permission => Child_Perm)
5891 -- We fill the hash table with all sons of the record,
5892 -- with basic Entire_Objects nodes.
5893 Elem := First_Component_Or_Discriminant
5894 (Etype (Prefix (N)));
5896 while Present (Elem) loop
5897 Son := new Perm_Tree_Wrapper'
5898 (Tree =>
5899 (Kind => Entire_Object,
5900 Is_Node_Deep => Is_Deep (Etype (Elem)),
5901 Permission => Child_Perm,
5902 Children_Permission => Child_Perm));
5904 Perm_Tree_Maps.Set
5905 (C.all.Tree.Component, Elem, Son);
5907 Next_Component_Or_Discriminant (Elem);
5908 end loop;
5910 -- Now we set the right field to Read_Only. and then we
5911 -- return the tree to the sons, so that the recursion can
5912 -- continue.
5914 declare
5915 Selected_Component : constant Entity_Id :=
5916 Entity (Selector_Name (N));
5918 Selected_C : Perm_Tree_Access :=
5919 Perm_Tree_Maps.Get
5920 (Component (C), Selected_Component);
5922 begin
5923 if Selected_C = null then
5924 Selected_C := Other_Components (C);
5925 end if;
5927 pragma Assert (Selected_C /= null);
5929 Selected_C.all.Tree.Permission :=
5930 Glb (Read_Only, Child_Perm);
5932 return Selected_C;
5933 end;
5934 end;
5935 else
5936 raise Program_Error;
5937 end if;
5938 end;
5940 -- We set the permission tree of its prefix, and then we extract from
5941 -- the returned pointer the subtree and assign an adequate permission
5942 -- to it, if unfolded. If folded, we unroll the tree at one step.
5944 when N_Indexed_Component
5945 | N_Slice
5947 declare
5948 C : constant Perm_Tree_Access :=
5949 Set_Perm_Prefixes_Observe (Prefix (N));
5951 begin
5952 if C = null then
5953 -- We went through a function call, do nothing
5955 return null;
5956 end if;
5958 pragma Assert (Kind (C) = Entire_Object
5959 or else Kind (C) = Array_Component);
5961 if Kind (C) = Array_Component then
5962 -- The tree is unfolded. We just modify the permission and
5963 -- return the elem subtree.
5965 pragma Assert (Get_Elem (C) /= null);
5967 C.all.Tree.Get_Elem.all.Tree.Permission :=
5968 Glb (Read_Only, Permission (Get_Elem (C)));
5970 return Get_Elem (C);
5971 elsif Kind (C) = Entire_Object then
5972 declare
5973 -- Expand the tree. Replace node with Array_Component.
5975 Son : Perm_Tree_Access;
5977 Child_Perm : constant Perm_Kind :=
5978 Glb (Read_Only, Children_Permission (C));
5980 begin
5981 Son := new Perm_Tree_Wrapper'
5982 (Tree =>
5983 (Kind => Entire_Object,
5984 Is_Node_Deep => Is_Node_Deep (C),
5985 Permission => Child_Perm,
5986 Children_Permission => Child_Perm));
5988 -- We change the current node from Entire_Object
5989 -- to Array_Component with same permission and the
5990 -- previously defined son.
5992 C.all.Tree := (Kind => Array_Component,
5993 Is_Node_Deep => Is_Node_Deep (C),
5994 Permission => Child_Perm,
5995 Get_Elem => Son);
5997 return Get_Elem (C);
5998 end;
6000 else
6001 raise Program_Error;
6002 end if;
6003 end;
6005 -- We set the permission tree of its prefix, and then we extract from
6006 -- the returned pointer the subtree and assign an adequate permission
6007 -- to it, if unfolded. If folded, we unroll the tree at one step.
6009 when N_Explicit_Dereference =>
6010 declare
6011 C : constant Perm_Tree_Access :=
6012 Set_Perm_Prefixes_Observe (Prefix (N));
6014 begin
6015 if C = null then
6016 -- We went through a function call, do nothing
6018 return null;
6019 end if;
6021 pragma Assert (Kind (C) = Entire_Object
6022 or else Kind (C) = Reference);
6024 if Kind (C) = Reference then
6025 -- The tree is unfolded. We just modify the permission and
6026 -- return the elem subtree.
6028 pragma Assert (Get_All (C) /= null);
6030 C.all.Tree.Get_All.all.Tree.Permission :=
6031 Glb (Read_Only, Permission (Get_All (C)));
6033 return Get_All (C);
6034 elsif Kind (C) = Entire_Object then
6035 declare
6036 -- Expand the tree. Replace the node with Reference.
6038 Son : Perm_Tree_Access;
6040 Child_Perm : constant Perm_Kind :=
6041 Glb (Read_Only, Children_Permission (C));
6043 begin
6044 Son := new Perm_Tree_Wrapper'
6045 (Tree =>
6046 (Kind => Entire_Object,
6047 Is_Node_Deep => Is_Deep (Etype (N)),
6048 Permission => Child_Perm,
6049 Children_Permission => Child_Perm));
6051 -- We change the current node from Entire_Object to
6052 -- Reference with Write_Only and the previous son.
6054 pragma Assert (Is_Node_Deep (C));
6056 C.all.Tree := (Kind => Reference,
6057 Is_Node_Deep => Is_Node_Deep (C),
6058 Permission => Child_Perm,
6059 Get_All => Son);
6061 return Get_All (C);
6062 end;
6063 else
6064 raise Program_Error;
6065 end if;
6066 end;
6068 when N_Function_Call =>
6069 return null;
6071 when others =>
6072 raise Program_Error;
6074 end case;
6075 end Set_Perm_Prefixes_Observe;
6077 -------------------
6078 -- Setup_Globals --
6079 -------------------
6081 procedure Setup_Globals (Subp : Entity_Id) is
6083 procedure Setup_Globals_From_List
6084 (First_Item : Node_Id;
6085 Kind : Formal_Kind);
6086 -- Set up global items from the list starting at Item
6088 procedure Setup_Globals_Of_Mode (Global_Mode : Name_Id);
6089 -- Set up global items for the mode Global_Mode
6091 -----------------------------
6092 -- Setup_Globals_From_List --
6093 -----------------------------
6095 procedure Setup_Globals_From_List
6096 (First_Item : Node_Id;
6097 Kind : Formal_Kind)
6099 Item : Node_Id := First_Item;
6100 E : Entity_Id;
6102 begin
6103 while Present (Item) loop
6104 E := Entity (Item);
6106 -- Ignore abstract states, which play no role in pointer aliasing
6108 if Ekind (E) = E_Abstract_State then
6109 null;
6110 else
6111 Setup_Parameter_Or_Global (E, Kind, Global_Var => True);
6112 end if;
6113 Next_Global (Item);
6114 end loop;
6115 end Setup_Globals_From_List;
6117 ---------------------------
6118 -- Setup_Globals_Of_Mode --
6119 ---------------------------
6121 procedure Setup_Globals_Of_Mode (Global_Mode : Name_Id) is
6122 Kind : Formal_Kind;
6124 begin
6125 case Global_Mode is
6126 when Name_Input | Name_Proof_In =>
6127 Kind := E_In_Parameter;
6128 when Name_Output =>
6129 Kind := E_Out_Parameter;
6130 when Name_In_Out =>
6131 Kind := E_In_Out_Parameter;
6132 when others =>
6133 raise Program_Error;
6134 end case;
6136 -- Set up both global items from Global and Refined_Global pragmas
6138 Setup_Globals_From_List (First_Global (Subp, Global_Mode), Kind);
6139 Setup_Globals_From_List
6140 (First_Global (Subp, Global_Mode, Refined => True), Kind);
6141 end Setup_Globals_Of_Mode;
6143 -- Start of processing for Setup_Globals
6145 begin
6146 Setup_Globals_Of_Mode (Name_Proof_In);
6147 Setup_Globals_Of_Mode (Name_Input);
6148 Setup_Globals_Of_Mode (Name_Output);
6149 Setup_Globals_Of_Mode (Name_In_Out);
6150 end Setup_Globals;
6152 -------------------------------
6153 -- Setup_Parameter_Or_Global --
6154 -------------------------------
6156 procedure Setup_Parameter_Or_Global
6157 (Id : Entity_Id;
6158 Mode : Formal_Kind;
6159 Global_Var : Boolean)
6161 Elem : Perm_Tree_Access;
6163 begin
6164 Elem := new Perm_Tree_Wrapper'
6165 (Tree =>
6166 (Kind => Entire_Object,
6167 Is_Node_Deep => Is_Deep (Etype (Id)),
6168 Permission => Read_Write,
6169 Children_Permission => Read_Write));
6171 case Mode is
6172 when E_In_Parameter =>
6174 -- Borrowed IN: RW for everybody
6176 if Is_Borrowed_In (Id) and not Global_Var then
6177 Elem.all.Tree.Permission := Read_Write;
6178 Elem.all.Tree.Children_Permission := Read_Write;
6180 -- Observed IN: R for everybody
6182 else
6183 Elem.all.Tree.Permission := Read_Only;
6184 Elem.all.Tree.Children_Permission := Read_Only;
6185 end if;
6187 -- OUT: borrow, but callee has W only
6189 when E_Out_Parameter =>
6190 Elem.all.Tree.Permission := Write_Only;
6191 Elem.all.Tree.Children_Permission := Write_Only;
6193 -- IN OUT: borrow and callee has RW
6195 when E_In_Out_Parameter =>
6196 Elem.all.Tree.Permission := Read_Write;
6197 Elem.all.Tree.Children_Permission := Read_Write;
6198 end case;
6200 Set (Current_Perm_Env, Id, Elem);
6201 end Setup_Parameter_Or_Global;
6203 ----------------------
6204 -- Setup_Parameters --
6205 ----------------------
6207 procedure Setup_Parameters (Subp : Entity_Id) is
6208 Formal : Entity_Id;
6210 begin
6211 Formal := First_Formal (Subp);
6212 while Present (Formal) loop
6213 Setup_Parameter_Or_Global
6214 (Formal, Ekind (Formal), Global_Var => False);
6215 Next_Formal (Formal);
6216 end loop;
6217 end Setup_Parameters;
6219 end Sem_SPARK;