Remove obsolete ECOFF support.
[official-gcc.git] / gcc / ada / sem_spark.adb
blob42517ea0829be760bdf4ead98bb89cd4052eafad
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, 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. After moving a path, its permission is set
558 -- to No_Access, as well as the permission of its extensions and the
559 -- permission of its prefixes up to the first Reference node.
561 Borrow_Out,
562 -- Used for actual OUT parameters. Checks that paths have Write_Perm
563 -- permission. After checking a path, its permission is set to Read_Only
564 -- when of a by-copy type, to No_Access otherwise. After the call, its
565 -- permission is set to Read_Write.
567 Observe
568 -- Used for actual IN parameters of a scalar type. Checks that paths
569 -- have Read_Perm permission. After checking a path, its permission
570 -- is set to Read_Only.
572 -- Also used for formal IN parameters
575 type Result_Kind is (Folded, Unfolded, Function_Call);
576 -- The type declaration to discriminate in the Perm_Or_Tree type
578 -- The result type of the function Get_Perm_Or_Tree. This returns either a
579 -- tree when it found the appropriate tree, or a permission when the search
580 -- finds a leaf and the subtree we are looking for is folded. In the last
581 -- case, we return instead the Children_Permission field of the leaf.
583 type Perm_Or_Tree (R : Result_Kind) is record
584 case R is
585 when Folded => Found_Permission : Perm_Kind;
586 when Unfolded => Tree_Access : Perm_Tree_Access;
587 when Function_Call => null;
588 end case;
589 end record;
591 -----------------------
592 -- Local subprograms --
593 -----------------------
595 function "<=" (P1, P2 : Perm_Kind) return Boolean;
596 function ">=" (P1, P2 : Perm_Kind) return Boolean;
597 function Glb (P1, P2 : Perm_Kind) return Perm_Kind;
598 function Lub (P1, P2 : Perm_Kind) return Perm_Kind;
600 -- Checking proceduress for safe pointer usage. These procedures traverse
601 -- the AST, check nodes for correct permissions according to SPARK RM
602 -- 6.4.2, and update permissions depending on the node kind.
604 procedure Check_Call_Statement (Call : Node_Id);
606 procedure Check_Callable_Body (Body_N : Node_Id);
607 -- We are not in End_Of_Callee mode, hence we will save the environment
608 -- and start from a new one. We will add in the environment all formal
609 -- parameters as well as global used during the subprogram, with the
610 -- appropriate permissions (write-only for out, read-only for observed,
611 -- read-write for others).
613 -- After that we analyze the body of the function, and finaly, we check
614 -- that each borrowed parameter and global has read-write permission. We
615 -- then clean up the environment and put back the saved environment.
617 procedure Check_Declaration (Decl : Node_Id);
619 procedure Check_Expression (Expr : Node_Id);
621 procedure Check_Globals (N : Node_Id; Check_Mode : Checking_Mode);
622 -- This procedure takes a global pragma and checks depending on mode:
623 -- Mode Read: every in global is readable
624 -- Mode Observe: same as Check_Param_Observes but on globals
625 -- Mode Borrow_Out: Check_Param_Outs for globals
626 -- Mode Move: Check_Param for globals with mode Read
627 -- Mode Assign: Check_Param for globals with mode Assign
629 procedure Check_List (L : List_Id);
630 -- Calls Check_Node on each element of the list
632 procedure Check_Loop_Statement (Loop_N : Node_Id);
634 procedure Check_Node (N : Node_Id);
635 -- Main traversal procedure to check safe pointer usage. This procedure is
636 -- mutually recursive with the specialized procedures that follow.
638 procedure Check_Package_Body (Pack : Node_Id);
640 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id);
641 -- This procedure takes a formal and an actual parameter and calls the
642 -- analyze node if the parameter is borrowed with mode in out, with the
643 -- appropriate Checking_Mode (Move).
645 procedure Check_Param_Observes (Formal : Entity_Id; Actual : Node_Id);
646 -- This procedure takes a formal and an actual parameter and calls
647 -- the analyze node if the parameter is observed, with the appropriate
648 -- Checking_Mode.
650 procedure Check_Param_Outs (Formal : Entity_Id; Actual : Node_Id);
651 -- This procedure takes a formal and an actual parameter and calls the
652 -- analyze node if the parameter is of mode out, with the appropriate
653 -- Checking_Mode.
655 procedure Check_Param_Read (Formal : Entity_Id; Actual : Node_Id);
656 -- This procedure takes a formal and an actual parameter and checks the
657 -- readability of every in-mode parameter. This includes observed in, and
658 -- also borrowed in, that are then checked afterwards.
660 procedure Check_Statement (Stmt : Node_Id);
662 function Get_Perm (N : Node_Id) return Perm_Kind;
663 -- The function that takes a name as input and returns a permission
664 -- associated to it.
666 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree;
667 -- This function gets a Node_Id and looks recursively to find the
668 -- appropriate subtree for that Node_Id. If the tree is folded on
669 -- that node, then it returns the permission given at the right level.
671 function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access;
672 -- This function gets a Node_Id and looks recursively to find the
673 -- appropriate subtree for that Node_Id. If the tree is folded, then
674 -- it unrolls the tree up to the appropriate level.
676 function Has_Alias
677 (N : Node_Id)
678 return Boolean;
679 -- Function that returns whether the path given as parameter contains an
680 -- extension that is declared as aliased.
682 function Has_Array_Component (N : Node_Id) return Boolean;
683 -- This function gets a Node_Id and looks recursively to find if the given
684 -- path has any array component.
686 function Has_Function_Component (N : Node_Id) return Boolean;
687 -- This function gets a Node_Id and looks recursively to find if the given
688 -- path has any function component.
690 procedure Hp (P : Perm_Env);
691 -- A procedure that outputs the hash table. This function is used only in
692 -- the debugger to look into a hash table.
693 pragma Unreferenced (Hp);
695 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id);
696 pragma No_Return (Illegal_Global_Usage);
697 -- A procedure that is called when deep globals or aliased globals are used
698 -- without any global aspect.
700 function Is_Borrowed_In (E : Entity_Id) return Boolean;
701 -- Function that tells if the given entity is a borrowed in a formal
702 -- parameter, that is, if it is an access-to-variable type.
704 function Is_Deep (E : Entity_Id) return Boolean;
705 -- A function that can tell if a type is deep or not. Returns true if the
706 -- type passed as argument is deep.
708 function Is_Shallow (E : Entity_Id) return Boolean;
709 -- A function that can tell if a type is shallow or not. Returns true if
710 -- the type passed as argument is shallow.
712 function Loop_Of_Exit (N : Node_Id) return Entity_Id;
713 -- A function that takes an exit statement node and returns the entity of
714 -- the loop that this statement is exiting from.
716 procedure Merge_Envs (Target : in out Perm_Env; Source : in out Perm_Env);
717 -- Merge Target and Source into Target, and then deallocate the Source
719 procedure Perm_Error
720 (N : Node_Id;
721 Perm : Perm_Kind;
722 Found_Perm : Perm_Kind);
723 -- A procedure that is called when the permissions found contradict the
724 -- rules established by the RM. This function is called with the node, its
725 -- entity and the permission that was expected, and adds an error message
726 -- with the appropriate values.
728 procedure Perm_Error_Subprogram_End
729 (E : Entity_Id;
730 Subp : Entity_Id;
731 Perm : Perm_Kind;
732 Found_Perm : Perm_Kind);
733 -- A procedure that is called when the permissions found contradict the
734 -- rules established by the RM at the end of subprograms. This function
735 -- is called with the node, its entity, the node of the returning function
736 -- and the permission that was expected, and adds an error message with the
737 -- appropriate values.
739 procedure Process_Path (N : Node_Id);
741 procedure Return_Declarations (L : List_Id);
742 -- Check correct permissions on every declared object at the end of a
743 -- callee. Used at the end of the body of a callable entity. Checks that
744 -- paths of all borrowed formal parameters and global have Read_Write
745 -- permission.
747 procedure Return_Globals (Subp : Entity_Id);
748 -- Takes a subprogram as input, and checks that all borrowed global items
749 -- of the subprogram indeed have RW permission at the end of the subprogram
750 -- execution.
752 procedure Return_Parameter_Or_Global
753 (Id : Entity_Id;
754 Mode : Formal_Kind;
755 Subp : Entity_Id);
756 -- Auxiliary procedure to Return_Parameters and Return_Globals
758 procedure Return_Parameters (Subp : Entity_Id);
759 -- Takes a subprogram as input, and checks that all borrowed parameters of
760 -- the subprogram indeed have RW permission at the end of the subprogram
761 -- execution.
763 procedure Set_Perm_Extensions (T : Perm_Tree_Access; P : Perm_Kind);
764 -- This procedure takes an access to a permission tree and modifies the
765 -- tree so that any strict extensions of the given tree become of the
766 -- access specified by parameter P.
768 procedure Set_Perm_Extensions_Move (T : Perm_Tree_Access; E : Entity_Id);
769 -- Set permissions to
770 -- No for any extension with more .all
771 -- W for any deep extension with same number of .all
772 -- RW for any shallow extension with same number of .all
774 function Set_Perm_Prefixes_Assign (N : Node_Id) return Perm_Tree_Access;
775 -- This function takes a name as an input and sets in the permission
776 -- tree the given permission to the given name. The general rule here is
777 -- that everybody updates the permission of the subtree it is returning.
778 -- The permission of the assigned path has been set to RW by the caller.
780 -- Case where we have to normalize a tree after the correct permissions
781 -- have been assigned already. We look for the right subtree at the given
782 -- path, actualize its permissions, and then call the normalization on its
783 -- parent.
785 -- Example: We assign x.y and x.z then during Set_Perm_Prefixes_Move will
786 -- change the permission of x to RW because all of its components have
787 -- permission have permission RW.
789 function Set_Perm_Prefixes_Borrow_Out (N : Node_Id) return Perm_Tree_Access;
790 -- This function modifies the permissions of a given node_id in the
791 -- permission environment as well as in all the prefixes of the path,
792 -- given that the path is borrowed with mode out.
794 function Set_Perm_Prefixes_Move
795 (N : Node_Id; Mode : Checking_Mode)
796 return Perm_Tree_Access;
797 pragma Precondition (Mode = Move or Mode = Super_Move);
798 -- Given a node and a mode (that can be either Move or Super_Move), this
799 -- function modifies the permissions of a given node_id in the permission
800 -- environment as well as all the prefixes of the path, given that the path
801 -- is moved with or without 'Access. The general rule here is everybody
802 -- updates the permission of the subtree they are returning.
804 -- This case describes a move either under 'Access or without 'Access.
806 function Set_Perm_Prefixes_Observe (N : Node_Id) return Perm_Tree_Access;
807 -- This function modifies the permissions of a given node_id in the
808 -- permission environment as well as all the prefixes of the path,
809 -- given that the path is observed.
811 procedure Setup_Globals (Subp : Entity_Id);
812 -- Takes a subprogram as input, and sets up the environment by adding
813 -- global items with appropriate permissions.
815 procedure Setup_Parameter_Or_Global
816 (Id : Entity_Id;
817 Mode : Formal_Kind);
818 -- Auxiliary procedure to Setup_Parameters and Setup_Globals
820 procedure Setup_Parameters (Subp : Entity_Id);
821 -- Takes a subprogram as input, and sets up the environment by adding
822 -- formal parameters with appropriate permissions.
824 ----------------------
825 -- Global Variables --
826 ----------------------
828 Current_Perm_Env : Perm_Env;
829 -- The permission environment that is used for the analysis. This
830 -- environment can be saved, modified, reinitialized, but should be the
831 -- only one valid from which to extract the permissions of the paths in
832 -- scope. The analysis ensures at each point that this variables contains
833 -- a valid permission environment with all bindings in scope.
835 Current_Checking_Mode : Checking_Mode := Read;
836 -- The current analysis mode. This global variable indicates at each point
837 -- of the analysis whether the node being analyzed is moved, borrowed,
838 -- assigned, read, ... The full list of possible values can be found in
839 -- the declaration of type Checking_Mode.
841 Current_Loops_Envs : Env_Backups;
842 -- This variable contains saves of permission environments at each loop the
843 -- analysis entered. Each saved environment can be reached with the label
844 -- of the loop.
846 Current_Loops_Accumulators : Env_Backups;
847 -- This variable contains the environments used as accumulators for loops,
848 -- that consist of the merge of all environments at each exit point of
849 -- the loop (which can also be the entry point of the loop in the case of
850 -- non-infinite loops), each of them reachable from the label of the loop.
851 -- We require that the environment stored in the accumulator be less
852 -- restrictive than the saved environment at the beginning of the loop, and
853 -- the permission environment after the loop is equal to the accumulator.
855 Current_Initialization_Map : Initialization_Map;
856 -- This variable contains a map that binds each variable of the analyzed
857 -- source code to a boolean that becomes true whenever the variable is used
858 -- after declaration. Hence we can exclude from analysis variables that
859 -- are just declared and never accessed, typically at package declaration.
861 ----------
862 -- "<=" --
863 ----------
865 function "<=" (P1, P2 : Perm_Kind) return Boolean
867 begin
868 return P2 >= P1;
869 end "<=";
871 ----------
872 -- ">=" --
873 ----------
875 function ">=" (P1, P2 : Perm_Kind) return Boolean
877 begin
878 case P2 is
879 when No_Access => return True;
880 when Read_Only => return P1 in Read_Perm;
881 when Write_Only => return P1 in Write_Perm;
882 when Read_Write => return P1 = Read_Write;
883 end case;
884 end ">=";
886 --------------------------
887 -- Check_Call_Statement --
888 --------------------------
890 procedure Check_Call_Statement (Call : Node_Id) is
891 Saved_Env : Perm_Env;
893 procedure Iterate_Call is new
894 Iterate_Call_Parameters (Check_Param);
895 procedure Iterate_Call_Observes is new
896 Iterate_Call_Parameters (Check_Param_Observes);
897 procedure Iterate_Call_Outs is new
898 Iterate_Call_Parameters (Check_Param_Outs);
899 procedure Iterate_Call_Read is new
900 Iterate_Call_Parameters (Check_Param_Read);
902 begin
903 -- Save environment, so that the modifications done by analyzing the
904 -- parameters are not kept at the end of the call.
905 Copy_Env (Current_Perm_Env,
906 Saved_Env);
908 -- We first check the Read access on every in parameter
910 Current_Checking_Mode := Read;
911 Iterate_Call_Read (Call);
912 Check_Globals (Get_Pragma
913 (Get_Called_Entity (Call), Pragma_Global), Read);
915 -- We first observe, then borrow with mode out, and then with other
916 -- modes. This ensures that we do not have to check for by-copy types
917 -- specially, because we read them before borrowing them.
919 Iterate_Call_Observes (Call);
920 Check_Globals (Get_Pragma
921 (Get_Called_Entity (Call), Pragma_Global),
922 Observe);
924 Iterate_Call_Outs (Call);
925 Check_Globals (Get_Pragma
926 (Get_Called_Entity (Call), Pragma_Global),
927 Borrow_Out);
929 Iterate_Call (Call);
930 Check_Globals (Get_Pragma
931 (Get_Called_Entity (Call), Pragma_Global), Move);
933 -- Restore environment, because after borrowing/observing actual
934 -- parameters, they get their permission reverted to the ones before
935 -- the call.
937 Free_Env (Current_Perm_Env);
939 Copy_Env (Saved_Env,
940 Current_Perm_Env);
942 Free_Env (Saved_Env);
944 -- We assign the out parameters (necessarily borrowed per RM)
945 Current_Checking_Mode := Assign;
946 Iterate_Call (Call);
947 Check_Globals (Get_Pragma
948 (Get_Called_Entity (Call), Pragma_Global),
949 Assign);
951 end Check_Call_Statement;
953 -------------------------
954 -- Check_Callable_Body --
955 -------------------------
957 procedure Check_Callable_Body (Body_N : Node_Id) is
959 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
961 Saved_Env : Perm_Env;
962 Saved_Init_Map : Initialization_Map;
964 New_Env : Perm_Env;
966 Body_Id : constant Entity_Id := Defining_Entity (Body_N);
967 Spec_Id : constant Entity_Id := Unique_Entity (Body_Id);
969 begin
970 -- Check if SPARK pragma is not set to Off
972 if Present (SPARK_Pragma (Defining_Entity (Body_N))) then
973 if Get_SPARK_Mode_From_Annotation
974 (SPARK_Pragma (Defining_Entity (Body_N, False))) /= Opt.On
975 then
976 return;
977 end if;
978 else
979 return;
980 end if;
982 -- Save environment and put a new one in place
984 Copy_Env (Current_Perm_Env, Saved_Env);
986 -- Save initialization map
988 Copy_Init_Map (Current_Initialization_Map, Saved_Init_Map);
990 Current_Checking_Mode := Read;
991 Current_Perm_Env := New_Env;
993 -- Add formals and globals to the environment with adequate permissions
995 if Is_Subprogram_Or_Entry (Spec_Id) then
996 Setup_Parameters (Spec_Id);
997 Setup_Globals (Spec_Id);
998 end if;
1000 -- Analyze the body of the function
1002 Check_List (Declarations (Body_N));
1003 Check_Node (Handled_Statement_Sequence (Body_N));
1005 -- Check the read-write permissions of borrowed parameters/globals
1007 if Ekind_In (Spec_Id, E_Procedure, E_Entry)
1008 and then not No_Return (Spec_Id)
1009 then
1010 Return_Parameters (Spec_Id);
1011 Return_Globals (Spec_Id);
1012 end if;
1014 -- Free the environments
1016 Free_Env (Current_Perm_Env);
1018 Copy_Env (Saved_Env,
1019 Current_Perm_Env);
1021 Free_Env (Saved_Env);
1023 -- Restore initialization map
1025 Copy_Init_Map (Saved_Init_Map, Current_Initialization_Map);
1027 Reset (Saved_Init_Map);
1029 -- The assignment of all out parameters will be done by caller
1031 Current_Checking_Mode := Mode_Before;
1032 end Check_Callable_Body;
1034 -----------------------
1035 -- Check_Declaration --
1036 -----------------------
1038 procedure Check_Declaration (Decl : Node_Id) is
1039 begin
1040 case N_Declaration'(Nkind (Decl)) is
1041 when N_Full_Type_Declaration =>
1042 -- Nothing to do here ??? NOT TRUE IF CONSTRAINT ON TYPE
1043 null;
1045 when N_Object_Declaration =>
1046 -- First move the right-hand side
1047 Current_Checking_Mode := Move;
1048 Check_Node (Expression (Decl));
1050 declare
1051 Elem : Perm_Tree_Access;
1053 begin
1054 Elem := new Perm_Tree_Wrapper'
1055 (Tree =>
1056 (Kind => Entire_Object,
1057 Is_Node_Deep =>
1058 Is_Deep (Etype (Defining_Identifier (Decl))),
1059 Permission => Read_Write,
1060 Children_Permission => Read_Write));
1062 -- If unitialized declaration, then set to Write_Only. If a
1063 -- pointer declaration, it has a null default initialization.
1064 if Nkind (Expression (Decl)) = N_Empty
1065 and then not Has_Full_Default_Initialization
1066 (Etype (Defining_Identifier (Decl)))
1067 and then not Is_Access_Type
1068 (Etype (Defining_Identifier (Decl)))
1069 then
1070 Elem.all.Tree.Permission := Write_Only;
1071 Elem.all.Tree.Children_Permission := Write_Only;
1072 end if;
1074 -- Create new tree for defining identifier
1076 Set (Current_Perm_Env,
1077 Unique_Entity (Defining_Identifier (Decl)),
1078 Elem);
1080 pragma Assert (Get_First (Current_Perm_Env)
1081 /= null);
1083 end;
1085 when N_Subtype_Declaration =>
1086 Check_Node (Subtype_Indication (Decl));
1088 when N_Iterator_Specification =>
1089 pragma Assert (Is_Shallow (Etype (Defining_Identifier (Decl))));
1090 null;
1092 when N_Loop_Parameter_Specification =>
1093 pragma Assert (Is_Shallow (Etype (Defining_Identifier (Decl))));
1094 null;
1096 -- Checking should not be called directly on these nodes
1098 when N_Component_Declaration
1099 | N_Function_Specification
1100 | N_Entry_Declaration
1101 | N_Procedure_Specification
1103 raise Program_Error;
1105 -- Ignored constructs for pointer checking
1107 when N_Formal_Object_Declaration
1108 | N_Formal_Type_Declaration
1109 | N_Incomplete_Type_Declaration
1110 | N_Private_Extension_Declaration
1111 | N_Private_Type_Declaration
1112 | N_Protected_Type_Declaration
1114 null;
1116 -- The following nodes are rewritten by semantic analysis
1118 when N_Expression_Function =>
1119 raise Program_Error;
1120 end case;
1121 end Check_Declaration;
1123 ----------------------
1124 -- Check_Expression --
1125 ----------------------
1127 procedure Check_Expression (Expr : Node_Id) is
1128 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
1129 begin
1130 case N_Subexpr'(Nkind (Expr)) is
1131 when N_Procedure_Call_Statement =>
1132 Check_Call_Statement (Expr);
1134 when N_Identifier
1135 | N_Expanded_Name
1137 -- Check if identifier is pointing to nothing (On/Off/...)
1138 if not Present (Entity (Expr)) then
1139 return;
1140 end if;
1142 -- Do not analyze things that are not of object Kind
1143 if Ekind (Entity (Expr)) not in Object_Kind then
1144 return;
1145 end if;
1147 -- Consider as ident
1148 Process_Path (Expr);
1150 -- Switch to read mode and then check the readability of each operand
1152 when N_Binary_Op =>
1154 Current_Checking_Mode := Read;
1155 Check_Node (Left_Opnd (Expr));
1156 Check_Node (Right_Opnd (Expr));
1158 -- Switch to read mode and then check the readability of each operand
1160 when N_Op_Abs
1161 | N_Op_Minus
1162 | N_Op_Not
1163 | N_Op_Plus
1165 pragma Assert (Is_Shallow (Etype (Expr)));
1166 Current_Checking_Mode := Read;
1167 Check_Node (Right_Opnd (Expr));
1169 -- Forbid all deep expressions for Attribute ???
1171 when N_Attribute_Reference =>
1172 case Attribute_Name (Expr) is
1173 when Name_Access =>
1174 case Current_Checking_Mode is
1175 when Read =>
1176 Check_Node (Prefix (Expr));
1178 when Move =>
1179 Current_Checking_Mode := Super_Move;
1180 Check_Node (Prefix (Expr));
1182 -- Only assign names, not expressions
1184 when Assign =>
1185 raise Program_Error;
1187 -- Prefix in Super_Move should be a name, error here
1189 when Super_Move =>
1190 raise Program_Error;
1192 -- Could only borrow names of mode out, not n'Access
1194 when Borrow_Out =>
1195 raise Program_Error;
1197 when Observe =>
1198 Check_Node (Prefix (Expr));
1199 end case;
1201 when Name_Last
1202 | Name_First
1204 Current_Checking_Mode := Read;
1205 Check_Node (Prefix (Expr));
1207 when Name_Min =>
1208 Current_Checking_Mode := Read;
1209 Check_Node (Prefix (Expr));
1211 when Name_Image =>
1212 Check_Node (Prefix (Expr));
1214 when Name_SPARK_Mode =>
1215 null;
1217 when Name_Value =>
1218 Current_Checking_Mode := Read;
1219 Check_Node (Prefix (Expr));
1221 when Name_Update =>
1222 Check_List (Expressions (Expr));
1223 Check_Node (Prefix (Expr));
1225 when Name_Pred
1226 | Name_Succ
1228 Check_List (Expressions (Expr));
1229 Check_Node (Prefix (Expr));
1231 when Name_Length =>
1232 Current_Checking_Mode := Read;
1233 Check_Node (Prefix (Expr));
1235 -- Any Attribute referring to the underlying memory is ignored
1236 -- in the analysis. This means that taking the address of a
1237 -- variable makes a silent alias that is not rejected by the
1238 -- analysis.
1240 when Name_Address
1241 | Name_Alignment
1242 | Name_Component_Size
1243 | Name_First_Bit
1244 | Name_Last_Bit
1245 | Name_Size
1246 | Name_Position
1248 null;
1250 -- Attributes referring to types (get values from types), hence
1251 -- no need to check either for borrows or any loans.
1253 when Name_Base
1254 | Name_Val
1256 null;
1258 -- Other attributes that fall out of the scope of the analysis
1260 when others =>
1261 null;
1262 end case;
1264 when N_In =>
1265 Current_Checking_Mode := Read;
1266 Check_Node (Left_Opnd (Expr));
1267 Check_Node (Right_Opnd (Expr));
1269 when N_Not_In =>
1270 Current_Checking_Mode := Read;
1271 Check_Node (Left_Opnd (Expr));
1272 Check_Node (Right_Opnd (Expr));
1274 -- Switch to read mode and then check the readability of each operand
1276 when N_And_Then
1277 | N_Or_Else
1279 pragma Assert (Is_Shallow (Etype (Expr)));
1280 Current_Checking_Mode := Read;
1281 Check_Node (Left_Opnd (Expr));
1282 Check_Node (Right_Opnd (Expr));
1284 -- Check the arguments of the call
1286 when N_Function_Call =>
1287 Current_Checking_Mode := Read;
1288 Check_List (Parameter_Associations (Expr));
1290 when N_Explicit_Dereference =>
1291 Process_Path (Expr);
1293 -- Copy environment, run on each branch, and then merge
1295 when N_If_Expression =>
1296 declare
1297 Saved_Env : Perm_Env;
1299 -- Accumulator for the different branches
1301 New_Env : Perm_Env;
1303 Elmt : Node_Id := First (Expressions (Expr));
1305 begin
1306 Current_Checking_Mode := Read;
1308 Check_Node (Elmt);
1310 Current_Checking_Mode := Mode_Before;
1312 -- Save environment
1314 Copy_Env (Current_Perm_Env,
1315 Saved_Env);
1317 -- Here we have the original env in saved, current with a fresh
1318 -- copy, and new aliased.
1320 -- THEN PART
1322 Next (Elmt);
1323 Check_Node (Elmt);
1325 -- Here the new_environment contains curr env after then block
1327 -- ELSE part
1329 -- Restore environment before if
1330 Copy_Env (Current_Perm_Env,
1331 New_Env);
1333 Free_Env (Current_Perm_Env);
1335 Copy_Env (Saved_Env,
1336 Current_Perm_Env);
1338 -- Here new environment contains the environment after then and
1339 -- current the fresh copy of old one.
1341 Next (Elmt);
1342 Check_Node (Elmt);
1344 Merge_Envs (New_Env,
1345 Current_Perm_Env);
1347 -- CLEANUP
1349 Copy_Env (New_Env,
1350 Current_Perm_Env);
1352 Free_Env (New_Env);
1353 Free_Env (Saved_Env);
1354 end;
1356 when N_Indexed_Component =>
1357 Process_Path (Expr);
1359 -- Analyze the expression that is getting qualified
1361 when N_Qualified_Expression =>
1362 Check_Node (Expression (Expr));
1364 when N_Quantified_Expression =>
1365 declare
1366 Saved_Env : Perm_Env;
1367 begin
1368 Copy_Env (Current_Perm_Env, Saved_Env);
1369 Current_Checking_Mode := Read;
1370 Check_Node (Iterator_Specification (Expr));
1371 Check_Node (Loop_Parameter_Specification (Expr));
1373 Check_Node (Condition (Expr));
1374 Free_Env (Current_Perm_Env);
1375 Copy_Env (Saved_Env, Current_Perm_Env);
1376 Free_Env (Saved_Env);
1377 end;
1379 -- Analyze the list of associations in the aggregate
1381 when N_Aggregate =>
1382 Check_List (Expressions (Expr));
1383 Check_List (Component_Associations (Expr));
1385 when N_Allocator =>
1386 Check_Node (Expression (Expr));
1388 when N_Case_Expression =>
1389 declare
1390 Saved_Env : Perm_Env;
1392 -- Accumulator for the different branches
1394 New_Env : Perm_Env;
1396 Elmt : Node_Id := First (Alternatives (Expr));
1398 begin
1399 Current_Checking_Mode := Read;
1400 Check_Node (Expression (Expr));
1402 Current_Checking_Mode := Mode_Before;
1404 -- Save environment
1406 Copy_Env (Current_Perm_Env,
1407 Saved_Env);
1409 -- Here we have the original env in saved, current with a fresh
1410 -- copy, and new aliased.
1412 -- First alternative
1414 Check_Node (Elmt);
1415 Next (Elmt);
1417 Copy_Env (Current_Perm_Env,
1418 New_Env);
1420 Free_Env (Current_Perm_Env);
1422 -- Other alternatives
1424 while Present (Elmt) loop
1425 -- Restore environment
1427 Copy_Env (Saved_Env,
1428 Current_Perm_Env);
1430 Check_Node (Elmt);
1432 -- Merge Current_Perm_Env into New_Env
1434 Merge_Envs (New_Env,
1435 Current_Perm_Env);
1437 Next (Elmt);
1438 end loop;
1440 -- CLEANUP
1441 Copy_Env (New_Env,
1442 Current_Perm_Env);
1444 Free_Env (New_Env);
1445 Free_Env (Saved_Env);
1446 end;
1448 -- Analyze the list of associates in the aggregate as well as the
1449 -- ancestor part.
1451 when N_Extension_Aggregate =>
1453 Check_Node (Ancestor_Part (Expr));
1454 Check_List (Expressions (Expr));
1456 when N_Range =>
1457 Check_Node (Low_Bound (Expr));
1458 Check_Node (High_Bound (Expr));
1460 -- We arrived at a path. Process it.
1462 when N_Selected_Component =>
1463 Process_Path (Expr);
1465 when N_Slice =>
1466 Process_Path (Expr);
1468 when N_Type_Conversion =>
1469 Check_Node (Expression (Expr));
1471 when N_Unchecked_Type_Conversion =>
1472 Check_Node (Expression (Expr));
1474 -- Checking should not be called directly on these nodes
1476 when N_Target_Name =>
1477 raise Program_Error;
1479 -- Unsupported constructs in SPARK
1481 when N_Delta_Aggregate =>
1482 Error_Msg_N ("unsupported construct in SPARK", Expr);
1484 -- Ignored constructs for pointer checking
1486 when N_Character_Literal
1487 | N_Null
1488 | N_Numeric_Or_String_Literal
1489 | N_Operator_Symbol
1490 | N_Raise_Expression
1491 | N_Raise_xxx_Error
1493 null;
1495 -- The following nodes are never generated in GNATprove mode
1497 when N_Expression_With_Actions
1498 | N_Reference
1499 | N_Unchecked_Expression
1501 raise Program_Error;
1503 end case;
1504 end Check_Expression;
1506 -------------------
1507 -- Check_Globals --
1508 -------------------
1510 procedure Check_Globals (N : Node_Id; Check_Mode : Checking_Mode) is
1511 begin
1512 if Nkind (N) = N_Empty then
1513 return;
1514 end if;
1516 declare
1517 pragma Assert
1518 (List_Length (Pragma_Argument_Associations (N)) = 1);
1520 PAA : constant Node_Id :=
1521 First (Pragma_Argument_Associations (N));
1522 pragma Assert (Nkind (PAA) = N_Pragma_Argument_Association);
1524 Row : Node_Id;
1525 The_Mode : Name_Id;
1526 RHS : Node_Id;
1528 procedure Process (Mode : Name_Id;
1529 The_Global : Entity_Id);
1531 procedure Process (Mode : Name_Id;
1532 The_Global : Node_Id)
1534 Ident_Elt : constant Entity_Id :=
1535 Unique_Entity (Entity (The_Global));
1537 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
1539 begin
1540 if Ekind (Ident_Elt) = E_Abstract_State then
1541 return;
1542 end if;
1544 case Check_Mode is
1545 when Read =>
1546 case Mode is
1547 when Name_Input
1548 | Name_Proof_In
1550 Check_Node (The_Global);
1552 when Name_Output
1553 | Name_In_Out
1555 null;
1557 when others =>
1558 raise Program_Error;
1560 end case;
1562 when Observe =>
1563 case Mode is
1564 when Name_Input
1565 | Name_Proof_In
1567 if not Is_Borrowed_In (Ident_Elt) then
1568 -- Observed in
1570 Current_Checking_Mode := Observe;
1571 Check_Node (The_Global);
1572 end if;
1574 when others =>
1575 null;
1577 end case;
1579 when Borrow_Out =>
1581 case Mode is
1582 when Name_Output =>
1583 -- Borrowed out
1584 Current_Checking_Mode := Borrow_Out;
1585 Check_Node (The_Global);
1587 when others =>
1588 null;
1590 end case;
1592 when Move =>
1593 case Mode is
1594 when Name_Input
1595 | Name_Proof_In
1597 if Is_Borrowed_In (Ident_Elt) then
1598 -- Borrowed in
1600 Current_Checking_Mode := Move;
1601 else
1602 -- Observed
1604 return;
1605 end if;
1607 when Name_Output =>
1608 return;
1610 when Name_In_Out =>
1611 -- Borrowed in out
1613 Current_Checking_Mode := Move;
1615 when others =>
1616 raise Program_Error;
1617 end case;
1619 Check_Node (The_Global);
1620 when Assign =>
1621 case Mode is
1622 when Name_Input
1623 | Name_Proof_In
1625 null;
1627 when Name_Output
1628 | Name_In_Out
1630 -- Borrowed out or in out
1632 Process_Path (The_Global);
1634 when others =>
1635 raise Program_Error;
1636 end case;
1638 when others =>
1639 raise Program_Error;
1640 end case;
1642 Current_Checking_Mode := Mode_Before;
1643 end Process;
1645 begin
1646 if Nkind (Expression (PAA)) = N_Null then
1647 -- global => null
1648 -- No globals, nothing to do
1649 return;
1651 elsif Nkind_In (Expression (PAA), N_Identifier, N_Expanded_Name) then
1652 -- global => foo
1653 -- A single input
1654 Process (Name_Input, Expression (PAA));
1656 elsif Nkind (Expression (PAA)) = N_Aggregate
1657 and then Expressions (Expression (PAA)) /= No_List
1658 then
1659 -- global => (foo, bar)
1660 -- Inputs
1661 RHS := First (Expressions (Expression (PAA)));
1662 while Present (RHS) loop
1663 case Nkind (RHS) is
1664 when N_Identifier
1665 | N_Expanded_Name
1667 Process (Name_Input, RHS);
1669 when N_Numeric_Or_String_Literal =>
1670 Process (Name_Input, Original_Node (RHS));
1672 when others =>
1673 raise Program_Error;
1675 end case;
1676 RHS := Next (RHS);
1677 end loop;
1679 elsif Nkind (Expression (PAA)) = N_Aggregate
1680 and then Component_Associations (Expression (PAA)) /= No_List
1681 then
1682 -- global => (mode => foo,
1683 -- mode => (bar, baz))
1684 -- A mixture of things
1686 declare
1687 CA : constant List_Id :=
1688 Component_Associations (Expression (PAA));
1689 begin
1690 Row := First (CA);
1691 while Present (Row) loop
1692 pragma Assert (List_Length (Choices (Row)) = 1);
1693 The_Mode := Chars (First (Choices (Row)));
1695 RHS := Expression (Row);
1696 case Nkind (RHS) is
1697 when N_Aggregate =>
1698 RHS := First (Expressions (RHS));
1699 while Present (RHS) loop
1700 case Nkind (RHS) is
1701 when N_Numeric_Or_String_Literal =>
1702 Process (The_Mode, Original_Node (RHS));
1704 when others =>
1705 Process (The_Mode, RHS);
1707 end case;
1708 RHS := Next (RHS);
1709 end loop;
1711 when N_Identifier
1712 | N_Expanded_Name
1714 Process (The_Mode, RHS);
1716 when N_Null =>
1717 null;
1719 when N_Numeric_Or_String_Literal =>
1720 Process (The_Mode, Original_Node (RHS));
1722 when others =>
1723 raise Program_Error;
1725 end case;
1727 Row := Next (Row);
1728 end loop;
1729 end;
1731 else
1732 raise Program_Error;
1733 end if;
1734 end;
1735 end Check_Globals;
1737 ----------------
1738 -- Check_List --
1739 ----------------
1741 procedure Check_List (L : List_Id) is
1742 N : Node_Id;
1743 begin
1744 N := First (L);
1745 while Present (N) loop
1746 Check_Node (N);
1747 Next (N);
1748 end loop;
1749 end Check_List;
1751 --------------------------
1752 -- Check_Loop_Statement --
1753 --------------------------
1755 procedure Check_Loop_Statement (Loop_N : Node_Id) is
1757 -- Local Subprograms
1759 procedure Check_Is_Less_Restrictive_Env
1760 (Exiting_Env : Perm_Env;
1761 Entry_Env : Perm_Env);
1762 -- This procedure checks that the Exiting_Env environment is less
1763 -- restrictive than the Entry_Env environment.
1765 procedure Check_Is_Less_Restrictive_Tree
1766 (New_Tree : Perm_Tree_Access;
1767 Orig_Tree : Perm_Tree_Access;
1768 E : Entity_Id);
1769 -- Auxiliary procedure to check that the tree New_Tree is less
1770 -- restrictive than the tree Orig_Tree for the entity E.
1772 procedure Perm_Error_Loop_Exit
1773 (E : Entity_Id;
1774 Loop_Id : Node_Id;
1775 Perm : Perm_Kind;
1776 Found_Perm : Perm_Kind);
1777 -- A procedure that is called when the permissions found contradict
1778 -- the rules established by the RM at the exit of loops. This function
1779 -- is called with the entity, the node of the enclosing loop, the
1780 -- permission that was expected and the permission found, and issues
1781 -- an appropriate error message.
1783 -----------------------------------
1784 -- Check_Is_Less_Restrictive_Env --
1785 -----------------------------------
1787 procedure Check_Is_Less_Restrictive_Env
1788 (Exiting_Env : Perm_Env;
1789 Entry_Env : Perm_Env)
1791 Comp_Entry : Perm_Tree_Maps.Key_Option;
1792 Iter_Entry, Iter_Exit : Perm_Tree_Access;
1794 begin
1795 Comp_Entry := Get_First_Key (Entry_Env);
1796 while Comp_Entry.Present loop
1797 Iter_Entry := Get (Entry_Env, Comp_Entry.K);
1798 pragma Assert (Iter_Entry /= null);
1799 Iter_Exit := Get (Exiting_Env, Comp_Entry.K);
1800 pragma Assert (Iter_Exit /= null);
1801 Check_Is_Less_Restrictive_Tree
1802 (New_Tree => Iter_Exit,
1803 Orig_Tree => Iter_Entry,
1804 E => Comp_Entry.K);
1805 Comp_Entry := Get_Next_Key (Entry_Env);
1806 end loop;
1807 end Check_Is_Less_Restrictive_Env;
1809 ------------------------------------
1810 -- Check_Is_Less_Restrictive_Tree --
1811 ------------------------------------
1813 procedure Check_Is_Less_Restrictive_Tree
1814 (New_Tree : Perm_Tree_Access;
1815 Orig_Tree : Perm_Tree_Access;
1816 E : Entity_Id)
1818 -----------------------
1819 -- Local Subprograms --
1820 -----------------------
1822 procedure Check_Is_Less_Restrictive_Tree_Than
1823 (Tree : Perm_Tree_Access;
1824 Perm : Perm_Kind;
1825 E : Entity_Id);
1826 -- Auxiliary procedure to check that the tree N is less restrictive
1827 -- than the given permission P.
1829 procedure Check_Is_More_Restrictive_Tree_Than
1830 (Tree : Perm_Tree_Access;
1831 Perm : Perm_Kind;
1832 E : Entity_Id);
1833 -- Auxiliary procedure to check that the tree N is more restrictive
1834 -- than the given permission P.
1836 -----------------------------------------
1837 -- Check_Is_Less_Restrictive_Tree_Than --
1838 -----------------------------------------
1840 procedure Check_Is_Less_Restrictive_Tree_Than
1841 (Tree : Perm_Tree_Access;
1842 Perm : Perm_Kind;
1843 E : Entity_Id)
1845 begin
1846 if not (Permission (Tree) >= Perm) then
1847 Perm_Error_Loop_Exit
1848 (E, Loop_N, Permission (Tree), Perm);
1849 end if;
1851 case Kind (Tree) is
1852 when Entire_Object =>
1853 if not (Children_Permission (Tree) >= Perm) then
1854 Perm_Error_Loop_Exit
1855 (E, Loop_N, Children_Permission (Tree), Perm);
1857 end if;
1859 when Reference =>
1860 Check_Is_Less_Restrictive_Tree_Than
1861 (Get_All (Tree), Perm, E);
1863 when Array_Component =>
1864 Check_Is_Less_Restrictive_Tree_Than
1865 (Get_Elem (Tree), Perm, E);
1867 when Record_Component =>
1868 declare
1869 Comp : Perm_Tree_Access;
1870 begin
1871 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1872 while Comp /= null loop
1873 Check_Is_Less_Restrictive_Tree_Than (Comp, Perm, E);
1874 Comp :=
1875 Perm_Tree_Maps.Get_Next (Component (Tree));
1876 end loop;
1878 Check_Is_Less_Restrictive_Tree_Than
1879 (Other_Components (Tree), Perm, E);
1880 end;
1881 end case;
1882 end Check_Is_Less_Restrictive_Tree_Than;
1884 -----------------------------------------
1885 -- Check_Is_More_Restrictive_Tree_Than --
1886 -----------------------------------------
1888 procedure Check_Is_More_Restrictive_Tree_Than
1889 (Tree : Perm_Tree_Access;
1890 Perm : Perm_Kind;
1891 E : Entity_Id)
1893 begin
1894 if not (Perm >= Permission (Tree)) then
1895 Perm_Error_Loop_Exit
1896 (E, Loop_N, Permission (Tree), Perm);
1897 end if;
1899 case Kind (Tree) is
1900 when Entire_Object =>
1901 if not (Perm >= Children_Permission (Tree)) then
1902 Perm_Error_Loop_Exit
1903 (E, Loop_N, Children_Permission (Tree), Perm);
1904 end if;
1906 when Reference =>
1907 Check_Is_More_Restrictive_Tree_Than
1908 (Get_All (Tree), Perm, E);
1910 when Array_Component =>
1911 Check_Is_More_Restrictive_Tree_Than
1912 (Get_Elem (Tree), Perm, E);
1914 when Record_Component =>
1915 declare
1916 Comp : Perm_Tree_Access;
1917 begin
1918 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1919 while Comp /= null loop
1920 Check_Is_More_Restrictive_Tree_Than (Comp, Perm, E);
1921 Comp :=
1922 Perm_Tree_Maps.Get_Next (Component (Tree));
1923 end loop;
1925 Check_Is_More_Restrictive_Tree_Than
1926 (Other_Components (Tree), Perm, E);
1927 end;
1928 end case;
1929 end Check_Is_More_Restrictive_Tree_Than;
1931 -- Start of processing for Check_Is_Less_Restrictive_Tree
1933 begin
1934 if not (Permission (New_Tree) <= Permission (Orig_Tree)) then
1935 Perm_Error_Loop_Exit
1936 (E => E,
1937 Loop_Id => Loop_N,
1938 Perm => Permission (New_Tree),
1939 Found_Perm => Permission (Orig_Tree));
1940 end if;
1942 case Kind (New_Tree) is
1944 -- Potentially folded tree. We check the other tree Orig_Tree to
1945 -- check whether it is folded or not. If folded we just compare
1946 -- their Permission and Children_Permission, if not, then we
1947 -- look at the Children_Permission of the folded tree against
1948 -- the unfolded tree Orig_Tree.
1950 when Entire_Object =>
1951 case Kind (Orig_Tree) is
1952 when Entire_Object =>
1953 if not (Children_Permission (New_Tree) <=
1954 Children_Permission (Orig_Tree))
1955 then
1956 Perm_Error_Loop_Exit
1957 (E, Loop_N,
1958 Children_Permission (New_Tree),
1959 Children_Permission (Orig_Tree));
1960 end if;
1962 when Reference =>
1963 Check_Is_More_Restrictive_Tree_Than
1964 (Get_All (Orig_Tree), Children_Permission (New_Tree), E);
1966 when Array_Component =>
1967 Check_Is_More_Restrictive_Tree_Than
1968 (Get_Elem (Orig_Tree), Children_Permission (New_Tree), E);
1970 when Record_Component =>
1971 declare
1972 Comp : Perm_Tree_Access;
1973 begin
1974 Comp := Perm_Tree_Maps.Get_First
1975 (Component (Orig_Tree));
1976 while Comp /= null loop
1977 Check_Is_More_Restrictive_Tree_Than
1978 (Comp, Children_Permission (New_Tree), E);
1979 Comp := Perm_Tree_Maps.Get_Next
1980 (Component (Orig_Tree));
1981 end loop;
1983 Check_Is_More_Restrictive_Tree_Than
1984 (Other_Components (Orig_Tree),
1985 Children_Permission (New_Tree), E);
1986 end;
1987 end case;
1989 when Reference =>
1990 case Kind (Orig_Tree) is
1991 when Entire_Object =>
1992 Check_Is_Less_Restrictive_Tree_Than
1993 (Get_All (New_Tree), Children_Permission (Orig_Tree), E);
1995 when Reference =>
1996 Check_Is_Less_Restrictive_Tree
1997 (Get_All (New_Tree), Get_All (Orig_Tree), E);
1999 when others =>
2000 raise Program_Error;
2001 end case;
2003 when Array_Component =>
2004 case Kind (Orig_Tree) is
2005 when Entire_Object =>
2006 Check_Is_Less_Restrictive_Tree_Than
2007 (Get_Elem (New_Tree), Children_Permission (Orig_Tree), E);
2009 when Array_Component =>
2010 Check_Is_Less_Restrictive_Tree
2011 (Get_Elem (New_Tree), Get_Elem (Orig_Tree), E);
2013 when others =>
2014 raise Program_Error;
2015 end case;
2017 when Record_Component =>
2018 declare
2019 CompN : Perm_Tree_Access;
2020 begin
2021 CompN :=
2022 Perm_Tree_Maps.Get_First (Component (New_Tree));
2023 case Kind (Orig_Tree) is
2024 when Entire_Object =>
2025 while CompN /= null loop
2026 Check_Is_Less_Restrictive_Tree_Than
2027 (CompN, Children_Permission (Orig_Tree), E);
2029 CompN :=
2030 Perm_Tree_Maps.Get_Next (Component (New_Tree));
2031 end loop;
2033 Check_Is_Less_Restrictive_Tree_Than
2034 (Other_Components (New_Tree),
2035 Children_Permission (Orig_Tree),
2038 when Record_Component =>
2039 declare
2041 KeyO : Perm_Tree_Maps.Key_Option;
2042 CompO : Perm_Tree_Access;
2043 begin
2044 KeyO := Perm_Tree_Maps.Get_First_Key
2045 (Component (Orig_Tree));
2046 while KeyO.Present loop
2047 pragma Assert (CompO /= null);
2049 Check_Is_Less_Restrictive_Tree (CompN, CompO, E);
2051 KeyO := Perm_Tree_Maps.Get_Next_Key
2052 (Component (Orig_Tree));
2053 CompN := Perm_Tree_Maps.Get
2054 (Component (New_Tree), KeyO.K);
2055 CompO := Perm_Tree_Maps.Get
2056 (Component (Orig_Tree), KeyO.K);
2057 end loop;
2059 Check_Is_Less_Restrictive_Tree
2060 (Other_Components (New_Tree),
2061 Other_Components (Orig_Tree),
2063 end;
2065 when others =>
2066 raise Program_Error;
2067 end case;
2068 end;
2069 end case;
2070 end Check_Is_Less_Restrictive_Tree;
2072 --------------------------
2073 -- Perm_Error_Loop_Exit --
2074 --------------------------
2076 procedure Perm_Error_Loop_Exit
2077 (E : Entity_Id;
2078 Loop_Id : Node_Id;
2079 Perm : Perm_Kind;
2080 Found_Perm : Perm_Kind)
2082 begin
2083 Error_Msg_Node_2 := Loop_Id;
2084 Error_Msg_N ("insufficient permission for & when exiting loop &", E);
2085 Perm_Mismatch (Exp_Perm => Perm,
2086 Act_Perm => Found_Perm,
2087 N => Loop_Id);
2088 end Perm_Error_Loop_Exit;
2090 -- Local variables
2092 Loop_Name : constant Entity_Id := Entity (Identifier (Loop_N));
2093 Loop_Env : constant Perm_Env_Access := new Perm_Env;
2095 begin
2096 -- Save environment prior to the loop
2098 Copy_Env (From => Current_Perm_Env, To => Loop_Env.all);
2100 -- Add saved environment to loop environment
2102 Set (Current_Loops_Envs, Loop_Name, Loop_Env);
2104 -- If the loop is not a plain-loop, then it may either never be entered,
2105 -- or it may be exited after a number of iterations. Hence add the
2106 -- current permission environment as the initial loop exit environment.
2107 -- Otherwise, the loop exit environment remains empty until it is
2108 -- populated by analyzing exit statements.
2110 if Present (Iteration_Scheme (Loop_N)) then
2111 declare
2112 Exit_Env : constant Perm_Env_Access := new Perm_Env;
2113 begin
2114 Copy_Env (From => Current_Perm_Env, To => Exit_Env.all);
2115 Set (Current_Loops_Accumulators, Loop_Name, Exit_Env);
2116 end;
2117 end if;
2119 -- Analyze loop
2121 Check_Node (Iteration_Scheme (Loop_N));
2122 Check_List (Statements (Loop_N));
2124 -- Check that environment gets less restrictive at end of loop
2126 Check_Is_Less_Restrictive_Env
2127 (Exiting_Env => Current_Perm_Env,
2128 Entry_Env => Loop_Env.all);
2130 -- Set environment to the one for exiting the loop
2132 declare
2133 Exit_Env : constant Perm_Env_Access :=
2134 Get (Current_Loops_Accumulators, Loop_Name);
2135 begin
2136 Free_Env (Current_Perm_Env);
2138 -- In the normal case, Exit_Env is not null and we use it. In the
2139 -- degraded case of a plain-loop without exit statements, Exit_Env is
2140 -- null, and we use the initial permission environment at the start
2141 -- of the loop to continue analysis. Any environment would be fine
2142 -- here, since the code after the loop is dead code, but this way we
2143 -- avoid spurious errors by having at least variables in scope inside
2144 -- the environment.
2146 if Exit_Env /= null then
2147 Copy_Env (From => Exit_Env.all, To => Current_Perm_Env);
2148 else
2149 Copy_Env (From => Loop_Env.all, To => Current_Perm_Env);
2150 end if;
2152 Free_Env (Loop_Env.all);
2153 Free_Env (Exit_Env.all);
2154 end;
2155 end Check_Loop_Statement;
2157 ----------------
2158 -- Check_Node --
2159 ----------------
2161 procedure Check_Node (N : Node_Id) is
2162 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2163 begin
2164 case Nkind (N) is
2165 when N_Declaration =>
2166 Check_Declaration (N);
2168 when N_Subexpr =>
2169 Check_Expression (N);
2171 when N_Subtype_Indication =>
2172 Check_Node (Constraint (N));
2174 when N_Body_Stub =>
2175 Check_Node (Get_Body_From_Stub (N));
2177 when N_Statement_Other_Than_Procedure_Call =>
2178 Check_Statement (N);
2180 when N_Package_Body =>
2181 Check_Package_Body (N);
2183 when N_Subprogram_Body
2184 | N_Entry_Body
2185 | N_Task_Body
2187 Check_Callable_Body (N);
2189 when N_Protected_Body =>
2190 Check_List (Declarations (N));
2192 when N_Package_Declaration =>
2193 declare
2194 Spec : constant Node_Id := Specification (N);
2195 begin
2196 Current_Checking_Mode := Read;
2197 Check_List (Visible_Declarations (Spec));
2198 Check_List (Private_Declarations (Spec));
2200 Return_Declarations (Visible_Declarations (Spec));
2201 Return_Declarations (Private_Declarations (Spec));
2202 end;
2204 when N_Iteration_Scheme =>
2205 Current_Checking_Mode := Read;
2206 Check_Node (Condition (N));
2207 Check_Node (Iterator_Specification (N));
2208 Check_Node (Loop_Parameter_Specification (N));
2210 when N_Case_Expression_Alternative =>
2211 Current_Checking_Mode := Read;
2212 Check_List (Discrete_Choices (N));
2213 Current_Checking_Mode := Mode_Before;
2214 Check_Node (Expression (N));
2216 when N_Case_Statement_Alternative =>
2217 Current_Checking_Mode := Read;
2218 Check_List (Discrete_Choices (N));
2219 Current_Checking_Mode := Mode_Before;
2220 Check_List (Statements (N));
2222 when N_Component_Association =>
2223 Check_Node (Expression (N));
2225 when N_Handled_Sequence_Of_Statements =>
2226 Check_List (Statements (N));
2228 when N_Parameter_Association =>
2229 Check_Node (Explicit_Actual_Parameter (N));
2231 when N_Range_Constraint =>
2232 Check_Node (Range_Expression (N));
2234 when N_Index_Or_Discriminant_Constraint =>
2235 Check_List (Constraints (N));
2237 -- Checking should not be called directly on these nodes
2239 when N_Abortable_Part
2240 | N_Accept_Alternative
2241 | N_Access_Definition
2242 | N_Access_Function_Definition
2243 | N_Access_Procedure_Definition
2244 | N_Access_To_Object_Definition
2245 | N_Aspect_Specification
2246 | N_Compilation_Unit
2247 | N_Compilation_Unit_Aux
2248 | N_Component_Clause
2249 | N_Component_Definition
2250 | N_Component_List
2251 | N_Constrained_Array_Definition
2252 | N_Contract
2253 | N_Decimal_Fixed_Point_Definition
2254 | N_Defining_Character_Literal
2255 | N_Defining_Identifier
2256 | N_Defining_Operator_Symbol
2257 | N_Defining_Program_Unit_Name
2258 | N_Delay_Alternative
2259 | N_Derived_Type_Definition
2260 | N_Designator
2261 | N_Discriminant_Association
2262 | N_Discriminant_Specification
2263 | N_Elsif_Part
2264 | N_Entry_Body_Formal_Part
2265 | N_Enumeration_Type_Definition
2266 | N_Entry_Call_Alternative
2267 | N_Entry_Index_Specification
2268 | N_Error
2269 | N_Exception_Handler
2270 | N_Floating_Point_Definition
2271 | N_Formal_Decimal_Fixed_Point_Definition
2272 | N_Formal_Derived_Type_Definition
2273 | N_Formal_Discrete_Type_Definition
2274 | N_Formal_Floating_Point_Definition
2275 | N_Formal_Incomplete_Type_Definition
2276 | N_Formal_Modular_Type_Definition
2277 | N_Formal_Ordinary_Fixed_Point_Definition
2278 | N_Formal_Private_Type_Definition
2279 | N_Formal_Signed_Integer_Type_Definition
2280 | N_Generic_Association
2281 | N_Mod_Clause
2282 | N_Modular_Type_Definition
2283 | N_Ordinary_Fixed_Point_Definition
2284 | N_Package_Specification
2285 | N_Parameter_Specification
2286 | N_Pragma_Argument_Association
2287 | N_Protected_Definition
2288 | N_Push_Pop_xxx_Label
2289 | N_Real_Range_Specification
2290 | N_Record_Definition
2291 | N_SCIL_Dispatch_Table_Tag_Init
2292 | N_SCIL_Dispatching_Call
2293 | N_SCIL_Membership_Test
2294 | N_Signed_Integer_Type_Definition
2295 | N_Subunit
2296 | N_Task_Definition
2297 | N_Terminate_Alternative
2298 | N_Triggering_Alternative
2299 | N_Unconstrained_Array_Definition
2300 | N_Unused_At_Start
2301 | N_Unused_At_End
2302 | N_Variant
2303 | N_Variant_Part
2305 raise Program_Error;
2307 -- Unsupported constructs in SPARK
2309 when N_Iterated_Component_Association =>
2310 Error_Msg_N ("unsupported construct in SPARK", N);
2312 -- Ignored constructs for pointer checking
2314 when N_Abstract_Subprogram_Declaration
2315 | N_At_Clause
2316 | N_Attribute_Definition_Clause
2317 | N_Call_Marker
2318 | N_Delta_Constraint
2319 | N_Digits_Constraint
2320 | N_Empty
2321 | N_Enumeration_Representation_Clause
2322 | N_Exception_Declaration
2323 | N_Exception_Renaming_Declaration
2324 | N_Formal_Package_Declaration
2325 | N_Formal_Subprogram_Declaration
2326 | N_Freeze_Entity
2327 | N_Freeze_Generic_Entity
2328 | N_Function_Instantiation
2329 | N_Generic_Function_Renaming_Declaration
2330 | N_Generic_Package_Declaration
2331 | N_Generic_Package_Renaming_Declaration
2332 | N_Generic_Procedure_Renaming_Declaration
2333 | N_Generic_Subprogram_Declaration
2334 | N_Implicit_Label_Declaration
2335 | N_Itype_Reference
2336 | N_Label
2337 | N_Number_Declaration
2338 | N_Object_Renaming_Declaration
2339 | N_Others_Choice
2340 | N_Package_Instantiation
2341 | N_Package_Renaming_Declaration
2342 | N_Pragma
2343 | N_Procedure_Instantiation
2344 | N_Record_Representation_Clause
2345 | N_Subprogram_Declaration
2346 | N_Subprogram_Renaming_Declaration
2347 | N_Task_Type_Declaration
2348 | N_Use_Package_Clause
2349 | N_With_Clause
2350 | N_Use_Type_Clause
2351 | N_Validate_Unchecked_Conversion
2352 | N_Variable_Reference_Marker
2354 null;
2356 -- The following nodes are rewritten by semantic analysis
2358 when N_Single_Protected_Declaration
2359 | N_Single_Task_Declaration
2361 raise Program_Error;
2362 end case;
2364 Current_Checking_Mode := Mode_Before;
2365 end Check_Node;
2367 ------------------------
2368 -- Check_Package_Body --
2369 ------------------------
2371 procedure Check_Package_Body (Pack : Node_Id) is
2372 Saved_Env : Perm_Env;
2373 CorSp : Node_Id;
2375 begin
2376 if Present (SPARK_Pragma (Defining_Entity (Pack, False))) then
2377 if Get_SPARK_Mode_From_Annotation
2378 (SPARK_Pragma (Defining_Entity (Pack))) /= Opt.On
2379 then
2380 return;
2381 end if;
2382 else
2383 return;
2384 end if;
2386 CorSp := Parent (Corresponding_Spec (Pack));
2387 while Nkind (CorSp) /= N_Package_Specification loop
2388 CorSp := Parent (CorSp);
2389 end loop;
2391 Check_List (Visible_Declarations (CorSp));
2393 -- Save environment
2395 Copy_Env (Current_Perm_Env,
2396 Saved_Env);
2398 Check_List (Private_Declarations (CorSp));
2400 -- Set mode to Read, and then analyze declarations and statements
2402 Current_Checking_Mode := Read;
2404 Check_List (Declarations (Pack));
2405 Check_Node (Handled_Statement_Sequence (Pack));
2407 -- Check RW for every stateful variable (i.e. in declarations)
2409 Return_Declarations (Private_Declarations (CorSp));
2410 Return_Declarations (Visible_Declarations (CorSp));
2411 Return_Declarations (Declarations (Pack));
2413 -- Restore previous environment (i.e. delete every nonvisible
2414 -- declaration) from environment.
2416 Free_Env (Current_Perm_Env);
2417 Copy_Env (Saved_Env,
2418 Current_Perm_Env);
2419 end Check_Package_Body;
2421 -----------------
2422 -- Check_Param --
2423 -----------------
2425 procedure Check_Param (Formal : Entity_Id; Actual : Node_Id) is
2426 Mode : constant Entity_Kind := Ekind (Formal);
2427 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2429 begin
2430 case Current_Checking_Mode is
2431 when Read =>
2432 case Formal_Kind'(Mode) is
2433 when E_In_Parameter =>
2434 if Is_Borrowed_In (Formal) then
2435 -- Borrowed in
2437 Current_Checking_Mode := Move;
2438 else
2439 -- Observed
2441 return;
2442 end if;
2444 when E_Out_Parameter =>
2445 return;
2447 when E_In_Out_Parameter =>
2448 -- Borrowed in out
2450 Current_Checking_Mode := Move;
2452 end case;
2454 Check_Node (Actual);
2456 when Assign =>
2457 case Formal_Kind'(Mode) is
2458 when E_In_Parameter =>
2459 null;
2461 when E_Out_Parameter
2462 | E_In_Out_Parameter
2464 -- Borrowed out or in out
2466 Process_Path (Actual);
2468 end case;
2470 when others =>
2471 raise Program_Error;
2473 end case;
2474 Current_Checking_Mode := Mode_Before;
2475 end Check_Param;
2477 --------------------------
2478 -- Check_Param_Observes --
2479 --------------------------
2481 procedure Check_Param_Observes (Formal : Entity_Id; Actual : Node_Id) is
2482 Mode : constant Entity_Kind := Ekind (Formal);
2483 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2485 begin
2486 case Mode is
2487 when E_In_Parameter =>
2488 if not Is_Borrowed_In (Formal) then
2489 -- Observed in
2491 Current_Checking_Mode := Observe;
2492 Check_Node (Actual);
2493 end if;
2495 when others =>
2496 null;
2498 end case;
2500 Current_Checking_Mode := Mode_Before;
2501 end Check_Param_Observes;
2503 ----------------------
2504 -- Check_Param_Outs --
2505 ----------------------
2507 procedure Check_Param_Outs (Formal : Entity_Id; Actual : Node_Id) is
2508 Mode : constant Entity_Kind := Ekind (Formal);
2509 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2511 begin
2513 case Mode is
2514 when E_Out_Parameter =>
2515 -- Borrowed out
2516 Current_Checking_Mode := Borrow_Out;
2517 Check_Node (Actual);
2519 when others =>
2520 null;
2522 end case;
2524 Current_Checking_Mode := Mode_Before;
2525 end Check_Param_Outs;
2527 ----------------------
2528 -- Check_Param_Read --
2529 ----------------------
2531 procedure Check_Param_Read (Formal : Entity_Id; Actual : Node_Id) is
2532 Mode : constant Entity_Kind := Ekind (Formal);
2534 begin
2535 pragma Assert (Current_Checking_Mode = Read);
2537 case Formal_Kind'(Mode) is
2538 when E_In_Parameter =>
2539 Check_Node (Actual);
2541 when E_Out_Parameter
2542 | E_In_Out_Parameter
2544 null;
2546 end case;
2547 end Check_Param_Read;
2549 -------------------------
2550 -- Check_Safe_Pointers --
2551 -------------------------
2553 procedure Check_Safe_Pointers (N : Node_Id) is
2555 -- Local subprograms
2557 procedure Check_List (L : List_Id);
2558 -- Call the main analysis procedure on each element of the list
2560 procedure Initialize;
2561 -- Initialize global variables before starting the analysis of a body
2563 ----------------
2564 -- Check_List --
2565 ----------------
2567 procedure Check_List (L : List_Id) is
2568 N : Node_Id;
2569 begin
2570 N := First (L);
2571 while Present (N) loop
2572 Check_Safe_Pointers (N);
2573 Next (N);
2574 end loop;
2575 end Check_List;
2577 ----------------
2578 -- Initialize --
2579 ----------------
2581 procedure Initialize is
2582 begin
2583 Reset (Current_Loops_Envs);
2584 Reset (Current_Loops_Accumulators);
2585 Reset (Current_Perm_Env);
2586 Reset (Current_Initialization_Map);
2587 end Initialize;
2589 -- Local variables
2591 Prag : Node_Id;
2592 -- SPARK_Mode pragma in application
2594 -- Start of processing for Check_Safe_Pointers
2596 begin
2597 Initialize;
2599 case Nkind (N) is
2600 when N_Compilation_Unit =>
2601 Check_Safe_Pointers (Unit (N));
2603 when N_Package_Body
2604 | N_Package_Declaration
2605 | N_Subprogram_Body
2607 Prag := SPARK_Pragma (Defining_Entity (N));
2608 if Present (Prag) then
2609 if Get_SPARK_Mode_From_Annotation (Prag) = Opt.Off then
2610 return;
2611 else
2612 Check_Node (N);
2613 end if;
2615 elsif Nkind (N) = N_Package_Body then
2616 Check_List (Declarations (N));
2618 elsif Nkind (N) = N_Package_Declaration then
2619 Check_List (Private_Declarations (Specification (N)));
2620 Check_List (Visible_Declarations (Specification (N)));
2621 end if;
2623 when others =>
2624 null;
2625 end case;
2626 end Check_Safe_Pointers;
2628 ---------------------
2629 -- Check_Statement --
2630 ---------------------
2632 procedure Check_Statement (Stmt : Node_Id) is
2633 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2634 begin
2635 case N_Statement_Other_Than_Procedure_Call'(Nkind (Stmt)) is
2636 when N_Entry_Call_Statement =>
2637 Check_Call_Statement (Stmt);
2639 -- Move right-hand side first, and then assign left-hand side
2641 when N_Assignment_Statement =>
2642 if Is_Deep (Etype (Expression (Stmt))) then
2643 Current_Checking_Mode := Move;
2644 else
2645 Current_Checking_Mode := Read;
2646 end if;
2648 Check_Node (Expression (Stmt));
2649 Current_Checking_Mode := Assign;
2650 Check_Node (Name (Stmt));
2652 when N_Block_Statement =>
2653 declare
2654 Saved_Env : Perm_Env;
2656 begin
2657 -- Save environment
2659 Copy_Env (Current_Perm_Env,
2660 Saved_Env);
2662 -- Analyze declarations and Handled_Statement_Sequences
2664 Current_Checking_Mode := Read;
2665 Check_List (Declarations (Stmt));
2666 Check_Node (Handled_Statement_Sequence (Stmt));
2668 -- Restore environment
2670 Free_Env (Current_Perm_Env);
2671 Copy_Env (Saved_Env,
2672 Current_Perm_Env);
2673 end;
2675 when N_Case_Statement =>
2676 declare
2677 Saved_Env : Perm_Env;
2679 -- Accumulator for the different branches
2681 New_Env : Perm_Env;
2683 Elmt : Node_Id := First (Alternatives (Stmt));
2685 begin
2686 Current_Checking_Mode := Read;
2687 Check_Node (Expression (Stmt));
2688 Current_Checking_Mode := Mode_Before;
2690 -- Save environment
2692 Copy_Env (Current_Perm_Env,
2693 Saved_Env);
2695 -- Here we have the original env in saved, current with a fresh
2696 -- copy, and new aliased.
2698 -- First alternative
2700 Check_Node (Elmt);
2701 Next (Elmt);
2703 Copy_Env (Current_Perm_Env,
2704 New_Env);
2705 Free_Env (Current_Perm_Env);
2707 -- Other alternatives
2709 while Present (Elmt) loop
2710 -- Restore environment
2712 Copy_Env (Saved_Env,
2713 Current_Perm_Env);
2715 Check_Node (Elmt);
2717 -- Merge Current_Perm_Env into New_Env
2719 Merge_Envs (New_Env,
2720 Current_Perm_Env);
2722 Next (Elmt);
2723 end loop;
2725 -- CLEANUP
2726 Copy_Env (New_Env,
2727 Current_Perm_Env);
2729 Free_Env (New_Env);
2730 Free_Env (Saved_Env);
2731 end;
2733 when N_Delay_Relative_Statement =>
2734 Check_Node (Expression (Stmt));
2736 when N_Delay_Until_Statement =>
2737 Check_Node (Expression (Stmt));
2739 when N_Loop_Statement =>
2740 Check_Loop_Statement (Stmt);
2742 -- If deep type expression, then move, else read
2744 when N_Simple_Return_Statement =>
2745 case Nkind (Expression (Stmt)) is
2746 when N_Empty =>
2747 declare
2748 -- ??? This does not take into account the fact that
2749 -- a simple return inside an extended return statement
2750 -- applies to the extended return statement.
2751 Subp : constant Entity_Id :=
2752 Return_Applies_To (Return_Statement_Entity (Stmt));
2753 begin
2754 Return_Parameters (Subp);
2755 Return_Globals (Subp);
2756 end;
2758 when others =>
2759 if Is_Deep (Etype (Expression (Stmt))) then
2760 Current_Checking_Mode := Move;
2761 elsif Is_Shallow (Etype (Expression (Stmt))) then
2762 Current_Checking_Mode := Read;
2763 else
2764 raise Program_Error;
2765 end if;
2767 Check_Node (Expression (Stmt));
2768 end case;
2770 when N_Extended_Return_Statement =>
2771 Check_List (Return_Object_Declarations (Stmt));
2772 Check_Node (Handled_Statement_Sequence (Stmt));
2774 Return_Declarations (Return_Object_Declarations (Stmt));
2776 declare
2777 -- ??? This does not take into account the fact that a simple
2778 -- return inside an extended return statement applies to the
2779 -- extended return statement.
2780 Subp : constant Entity_Id :=
2781 Return_Applies_To (Return_Statement_Entity (Stmt));
2782 begin
2783 Return_Parameters (Subp);
2784 Return_Globals (Subp);
2785 end;
2787 -- Merge the current_Perm_Env with the accumulator for the given loop
2789 when N_Exit_Statement =>
2790 declare
2791 Loop_Name : constant Entity_Id := Loop_Of_Exit (Stmt);
2793 Saved_Accumulator : constant Perm_Env_Access :=
2794 Get (Current_Loops_Accumulators, Loop_Name);
2796 Environment_Copy : constant Perm_Env_Access :=
2797 new Perm_Env;
2798 begin
2800 Copy_Env (Current_Perm_Env,
2801 Environment_Copy.all);
2803 if Saved_Accumulator = null then
2804 Set (Current_Loops_Accumulators,
2805 Loop_Name, Environment_Copy);
2806 else
2807 Merge_Envs (Saved_Accumulator.all,
2808 Environment_Copy.all);
2809 end if;
2810 end;
2812 -- Copy environment, run on each branch, and then merge
2814 when N_If_Statement =>
2815 declare
2816 Saved_Env : Perm_Env;
2818 -- Accumulator for the different branches
2820 New_Env : Perm_Env;
2822 begin
2824 Check_Node (Condition (Stmt));
2826 -- Save environment
2828 Copy_Env (Current_Perm_Env,
2829 Saved_Env);
2831 -- Here we have the original env in saved, current with a fresh
2832 -- copy.
2834 -- THEN PART
2836 Check_List (Then_Statements (Stmt));
2838 Copy_Env (Current_Perm_Env,
2839 New_Env);
2841 Free_Env (Current_Perm_Env);
2843 -- Here the new_environment contains curr env after then block
2845 -- ELSIF part
2846 declare
2847 Elmt : Node_Id;
2849 begin
2850 Elmt := First (Elsif_Parts (Stmt));
2851 while Present (Elmt) loop
2852 -- Transfer into accumulator, and restore from save
2854 Copy_Env (Saved_Env,
2855 Current_Perm_Env);
2857 Check_Node (Condition (Elmt));
2858 Check_List (Then_Statements (Stmt));
2860 -- Merge Current_Perm_Env into New_Env
2862 Merge_Envs (New_Env,
2863 Current_Perm_Env);
2865 Next (Elmt);
2866 end loop;
2867 end;
2869 -- ELSE part
2871 -- Restore environment before if
2873 Copy_Env (Saved_Env,
2874 Current_Perm_Env);
2876 -- Here new environment contains the environment after then and
2877 -- current the fresh copy of old one.
2879 Check_List (Else_Statements (Stmt));
2881 Merge_Envs (New_Env,
2882 Current_Perm_Env);
2884 -- CLEANUP
2886 Copy_Env (New_Env,
2887 Current_Perm_Env);
2889 Free_Env (New_Env);
2890 Free_Env (Saved_Env);
2891 end;
2893 -- Unsupported constructs in SPARK
2895 when N_Abort_Statement
2896 | N_Accept_Statement
2897 | N_Asynchronous_Select
2898 | N_Code_Statement
2899 | N_Conditional_Entry_Call
2900 | N_Goto_Statement
2901 | N_Requeue_Statement
2902 | N_Selective_Accept
2903 | N_Timed_Entry_Call
2905 Error_Msg_N ("unsupported construct in SPARK", Stmt);
2907 -- Ignored constructs for pointer checking
2909 when N_Null_Statement
2910 | N_Raise_Statement
2912 null;
2914 -- The following nodes are never generated in GNATprove mode
2916 when N_Compound_Statement
2917 | N_Free_Statement
2919 raise Program_Error;
2920 end case;
2921 end Check_Statement;
2923 --------------
2924 -- Get_Perm --
2925 --------------
2927 function Get_Perm (N : Node_Id) return Perm_Kind is
2928 Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N);
2930 begin
2931 case Tree_Or_Perm.R is
2932 when Folded =>
2933 return Tree_Or_Perm.Found_Permission;
2935 when Unfolded =>
2936 pragma Assert (Tree_Or_Perm.Tree_Access /= null);
2937 return Permission (Tree_Or_Perm.Tree_Access);
2939 -- We encoutered a function call, hence the memory area is fresh,
2940 -- which means that the association permission is RW.
2942 when Function_Call =>
2943 return Read_Write;
2945 end case;
2946 end Get_Perm;
2948 ----------------------
2949 -- Get_Perm_Or_Tree --
2950 ----------------------
2952 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree is
2953 begin
2954 case Nkind (N) is
2956 -- Base identifier. Normally those are the roots of the trees stored
2957 -- in the permission environment.
2959 when N_Defining_Identifier =>
2960 raise Program_Error;
2962 when N_Identifier
2963 | N_Expanded_Name
2965 declare
2966 P : constant Entity_Id := Entity (N);
2968 C : constant Perm_Tree_Access :=
2969 Get (Current_Perm_Env, Unique_Entity (P));
2971 begin
2972 -- Setting the initialization map to True, so that this
2973 -- variable cannot be ignored anymore when looking at end
2974 -- of elaboration of package.
2976 Set (Current_Initialization_Map, Unique_Entity (P), True);
2978 if C = null then
2979 -- No null possible here, there are no parents for the path.
2980 -- This means we are using a global variable without adding
2981 -- it in environment with a global aspect.
2983 Illegal_Global_Usage (N);
2984 else
2985 return (R => Unfolded, Tree_Access => C);
2986 end if;
2987 end;
2989 when N_Type_Conversion
2990 | N_Unchecked_Type_Conversion
2991 | N_Qualified_Expression
2993 return Get_Perm_Or_Tree (Expression (N));
2995 -- Happening when we try to get the permission of a variable that
2996 -- is a formal parameter. We get instead the defining identifier
2997 -- associated with the parameter (which is the one that has been
2998 -- stored for indexing).
3000 when N_Parameter_Specification =>
3001 return Get_Perm_Or_Tree (Defining_Identifier (N));
3003 -- We get the permission tree of its prefix, and then get either the
3004 -- subtree associated with that specific selection, or if we have a
3005 -- leaf that folds its children, we take the children's permission
3006 -- and return it using the discriminant Folded.
3008 when N_Selected_Component =>
3009 declare
3010 C : constant Perm_Or_Tree :=
3011 Get_Perm_Or_Tree (Prefix (N));
3013 begin
3014 case C.R is
3015 when Folded
3016 | Function_Call
3018 return C;
3020 when Unfolded =>
3021 pragma Assert (C.Tree_Access /= null);
3023 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3024 or else
3025 Kind (C.Tree_Access) = Record_Component);
3027 if Kind (C.Tree_Access) = Record_Component then
3028 declare
3029 Selected_Component : constant Entity_Id :=
3030 Entity (Selector_Name (N));
3032 Selected_C : constant Perm_Tree_Access :=
3033 Perm_Tree_Maps.Get
3034 (Component (C.Tree_Access), Selected_Component);
3036 begin
3037 if Selected_C = null then
3038 return (R => Unfolded,
3039 Tree_Access =>
3040 Other_Components (C.Tree_Access));
3041 else
3042 return (R => Unfolded,
3043 Tree_Access => Selected_C);
3044 end if;
3045 end;
3046 elsif Kind (C.Tree_Access) = Entire_Object then
3047 return (R => Folded, Found_Permission =>
3048 Children_Permission (C.Tree_Access));
3049 else
3050 raise Program_Error;
3051 end if;
3052 end case;
3053 end;
3055 -- We get the permission tree of its prefix, and then get either the
3056 -- subtree associated with that specific selection, or if we have a
3057 -- leaf that folds its children, we take the children's permission
3058 -- and return it using the discriminant Folded.
3060 when N_Indexed_Component
3061 | N_Slice
3063 declare
3064 C : constant Perm_Or_Tree :=
3065 Get_Perm_Or_Tree (Prefix (N));
3067 begin
3068 case C.R is
3069 when Folded
3070 | Function_Call
3072 return C;
3074 when Unfolded =>
3075 pragma Assert (C.Tree_Access /= null);
3077 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3078 or else
3079 Kind (C.Tree_Access) = Array_Component);
3081 if Kind (C.Tree_Access) = Array_Component then
3082 pragma Assert (Get_Elem (C.Tree_Access) /= null);
3084 return (R => Unfolded,
3085 Tree_Access => Get_Elem (C.Tree_Access));
3086 elsif Kind (C.Tree_Access) = Entire_Object then
3087 return (R => Folded, Found_Permission =>
3088 Children_Permission (C.Tree_Access));
3089 else
3090 raise Program_Error;
3091 end if;
3092 end case;
3093 end;
3095 -- We get the permission tree of its prefix, and then get either the
3096 -- subtree associated with that specific selection, or if we have a
3097 -- leaf that folds its children, we take the children's permission
3098 -- and return it using the discriminant Folded.
3100 when N_Explicit_Dereference =>
3101 declare
3102 C : constant Perm_Or_Tree :=
3103 Get_Perm_Or_Tree (Prefix (N));
3105 begin
3106 case C.R is
3107 when Folded
3108 | Function_Call
3110 return C;
3112 when Unfolded =>
3113 pragma Assert (C.Tree_Access /= null);
3115 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3116 or else
3117 Kind (C.Tree_Access) = Reference);
3119 if Kind (C.Tree_Access) = Reference then
3120 if Get_All (C.Tree_Access) = null then
3121 -- Hash_Table_Error
3122 raise Program_Error;
3123 else
3124 return
3125 (R => Unfolded,
3126 Tree_Access => Get_All (C.Tree_Access));
3127 end if;
3128 elsif Kind (C.Tree_Access) = Entire_Object then
3129 return (R => Folded, Found_Permission =>
3130 Children_Permission (C.Tree_Access));
3131 else
3132 raise Program_Error;
3133 end if;
3134 end case;
3135 end;
3137 -- The name contains a function call, hence the given path is always
3138 -- new. We do not have to check for anything.
3140 when N_Function_Call =>
3141 return (R => Function_Call);
3143 when others =>
3144 raise Program_Error;
3145 end case;
3146 end Get_Perm_Or_Tree;
3148 -------------------
3149 -- Get_Perm_Tree --
3150 -------------------
3152 function Get_Perm_Tree
3153 (N : Node_Id)
3154 return Perm_Tree_Access
3156 begin
3157 case Nkind (N) is
3159 -- Base identifier. Normally those are the roots of the trees stored
3160 -- in the permission environment.
3162 when N_Defining_Identifier =>
3163 raise Program_Error;
3165 when N_Identifier
3166 | N_Expanded_Name
3168 declare
3169 P : constant Node_Id := Entity (N);
3171 C : constant Perm_Tree_Access :=
3172 Get (Current_Perm_Env, Unique_Entity (P));
3174 begin
3175 -- Setting the initialization map to True, so that this
3176 -- variable cannot be ignored anymore when looking at end
3177 -- of elaboration of package.
3179 Set (Current_Initialization_Map, Unique_Entity (P), True);
3181 if C = null then
3182 -- No null possible here, there are no parents for the path.
3183 -- This means we are using a global variable without adding
3184 -- it in environment with a global aspect.
3186 Illegal_Global_Usage (N);
3187 else
3188 return C;
3189 end if;
3190 end;
3192 when N_Type_Conversion
3193 | N_Unchecked_Type_Conversion
3194 | N_Qualified_Expression
3196 return Get_Perm_Tree (Expression (N));
3198 when N_Parameter_Specification =>
3199 return Get_Perm_Tree (Defining_Identifier (N));
3201 -- We get the permission tree of its prefix, and then get either the
3202 -- subtree associated with that specific selection, or if we have a
3203 -- leaf that folds its children, we unroll it in one step.
3205 when N_Selected_Component =>
3206 declare
3207 C : constant Perm_Tree_Access :=
3208 Get_Perm_Tree (Prefix (N));
3210 begin
3211 if C = null then
3212 -- If null then it means we went through a function call
3214 return null;
3215 end if;
3217 pragma Assert (Kind (C) = Entire_Object
3218 or else Kind (C) = Record_Component);
3220 if Kind (C) = Record_Component then
3221 -- The tree is unfolded. We just return the subtree.
3223 declare
3224 Selected_Component : constant Entity_Id :=
3225 Entity (Selector_Name (N));
3226 Selected_C : constant Perm_Tree_Access :=
3227 Perm_Tree_Maps.Get
3228 (Component (C), Selected_Component);
3230 begin
3231 if Selected_C = null then
3232 return Other_Components (C);
3233 end if;
3235 return Selected_C;
3236 end;
3237 elsif Kind (C) = Entire_Object then
3238 declare
3239 -- Expand the tree. Replace the node with
3240 -- Record_Component.
3242 Elem : Node_Id;
3244 -- Create the unrolled nodes
3246 Son : Perm_Tree_Access;
3248 Child_Perm : constant Perm_Kind :=
3249 Children_Permission (C);
3251 begin
3253 -- We change the current node from Entire_Object to
3254 -- Record_Component with same permission and an empty
3255 -- hash table as component list.
3257 C.all.Tree :=
3258 (Kind => Record_Component,
3259 Is_Node_Deep => Is_Node_Deep (C),
3260 Permission => Permission (C),
3261 Component => Perm_Tree_Maps.Nil,
3262 Other_Components =>
3263 new Perm_Tree_Wrapper'
3264 (Tree =>
3265 (Kind => Entire_Object,
3266 -- Is_Node_Deep is true, to be conservative
3267 Is_Node_Deep => True,
3268 Permission => Child_Perm,
3269 Children_Permission => Child_Perm)
3273 -- We fill the hash table with all sons of the record,
3274 -- with basic Entire_Objects nodes.
3275 Elem := First_Component_Or_Discriminant
3276 (Etype (Prefix (N)));
3278 while Present (Elem) loop
3279 Son := new Perm_Tree_Wrapper'
3280 (Tree =>
3281 (Kind => Entire_Object,
3282 Is_Node_Deep => Is_Deep (Etype (Elem)),
3283 Permission => Child_Perm,
3284 Children_Permission => Child_Perm));
3286 Perm_Tree_Maps.Set
3287 (C.all.Tree.Component, Elem, Son);
3289 Next_Component_Or_Discriminant (Elem);
3290 end loop;
3292 -- we return the tree to the sons, so that the recursion
3293 -- can continue.
3295 declare
3296 Selected_Component : constant Entity_Id :=
3297 Entity (Selector_Name (N));
3299 Selected_C : constant Perm_Tree_Access :=
3300 Perm_Tree_Maps.Get
3301 (Component (C), Selected_Component);
3303 begin
3304 pragma Assert (Selected_C /= null);
3306 return Selected_C;
3307 end;
3309 end;
3310 else
3311 raise Program_Error;
3312 end if;
3313 end;
3315 -- We set the permission tree of its prefix, and then we extract from
3316 -- the returned pointer the subtree. If folded, we unroll the tree at
3317 -- one step.
3319 when N_Indexed_Component
3320 | N_Slice
3322 declare
3323 C : constant Perm_Tree_Access :=
3324 Get_Perm_Tree (Prefix (N));
3326 begin
3327 if C = null then
3328 -- If null then we went through a function call
3330 return null;
3331 end if;
3333 pragma Assert (Kind (C) = Entire_Object
3334 or else Kind (C) = Array_Component);
3336 if Kind (C) = Array_Component then
3337 -- The tree is unfolded. We just return the elem subtree
3339 pragma Assert (Get_Elem (C) = null);
3341 return Get_Elem (C);
3342 elsif Kind (C) = Entire_Object then
3343 declare
3344 -- Expand the tree. Replace node with Array_Component.
3346 Son : Perm_Tree_Access;
3348 begin
3349 Son := new Perm_Tree_Wrapper'
3350 (Tree =>
3351 (Kind => Entire_Object,
3352 Is_Node_Deep => Is_Node_Deep (C),
3353 Permission => Children_Permission (C),
3354 Children_Permission => Children_Permission (C)));
3356 -- We change the current node from Entire_Object
3357 -- to Array_Component with same permission and the
3358 -- previously defined son.
3360 C.all.Tree := (Kind => Array_Component,
3361 Is_Node_Deep => Is_Node_Deep (C),
3362 Permission => Permission (C),
3363 Get_Elem => Son);
3365 return Get_Elem (C);
3366 end;
3367 else
3368 raise Program_Error;
3369 end if;
3370 end;
3372 -- We get the permission tree of its prefix, and then get either the
3373 -- subtree associated with that specific selection, or if we have a
3374 -- leaf that folds its children, we unroll the tree.
3376 when N_Explicit_Dereference =>
3377 declare
3378 C : Perm_Tree_Access;
3380 begin
3381 C := Get_Perm_Tree (Prefix (N));
3383 if C = null then
3384 -- If null, we went through a function call
3386 return null;
3387 end if;
3389 pragma Assert (Kind (C) = Entire_Object
3390 or else Kind (C) = Reference);
3392 if Kind (C) = Reference then
3393 -- The tree is unfolded. We return the elem subtree
3395 if Get_All (C) = null then
3396 -- Hash_Table_Error
3397 raise Program_Error;
3398 end if;
3400 return Get_All (C);
3401 elsif Kind (C) = Entire_Object then
3402 declare
3403 -- Expand the tree. Replace the node with Reference.
3405 Son : Perm_Tree_Access;
3407 begin
3408 Son := new Perm_Tree_Wrapper'
3409 (Tree =>
3410 (Kind => Entire_Object,
3411 Is_Node_Deep => Is_Deep (Etype (N)),
3412 Permission => Children_Permission (C),
3413 Children_Permission => Children_Permission (C)));
3415 -- We change the current node from Entire_Object to
3416 -- Reference with same permission and the previous son.
3418 pragma Assert (Is_Node_Deep (C));
3420 C.all.Tree := (Kind => Reference,
3421 Is_Node_Deep => Is_Node_Deep (C),
3422 Permission => Permission (C),
3423 Get_All => Son);
3425 return Get_All (C);
3426 end;
3427 else
3428 raise Program_Error;
3429 end if;
3430 end;
3432 -- No permission tree for function calls
3434 when N_Function_Call =>
3435 return null;
3437 when others =>
3438 raise Program_Error;
3439 end case;
3440 end Get_Perm_Tree;
3442 ---------
3443 -- Glb --
3444 ---------
3446 function Glb (P1, P2 : Perm_Kind) return Perm_Kind
3448 begin
3449 case P1 is
3450 when No_Access =>
3451 return No_Access;
3453 when Read_Only =>
3454 case P2 is
3455 when No_Access
3456 | Write_Only
3458 return No_Access;
3460 when Read_Perm =>
3461 return Read_Only;
3462 end case;
3464 when Write_Only =>
3465 case P2 is
3466 when No_Access
3467 | Read_Only
3469 return No_Access;
3471 when Write_Perm =>
3472 return Write_Only;
3473 end case;
3475 when Read_Write =>
3476 return P2;
3477 end case;
3478 end Glb;
3480 ---------------
3481 -- Has_Alias --
3482 ---------------
3484 function Has_Alias
3485 (N : Node_Id)
3486 return Boolean
3488 function Has_Alias_Deep (Typ : Entity_Id) return Boolean;
3489 function Has_Alias_Deep (Typ : Entity_Id) return Boolean
3491 Comp : Node_Id;
3492 begin
3494 if Is_Array_Type (Typ)
3495 and then Has_Aliased_Components (Typ)
3496 then
3497 return True;
3499 -- Note: Has_Aliased_Components applies only to arrays
3501 elsif Is_Record_Type (Typ) then
3502 -- It is possible to have an aliased discriminant, so they must be
3503 -- checked along with normal components.
3505 Comp := First_Component_Or_Discriminant (Typ);
3506 while Present (Comp) loop
3507 if Is_Aliased (Comp)
3508 or else Is_Aliased (Etype (Comp))
3509 then
3510 return True;
3511 end if;
3513 if Has_Alias_Deep (Etype (Comp)) then
3514 return True;
3515 end if;
3517 Next_Component_Or_Discriminant (Comp);
3518 end loop;
3519 return False;
3520 else
3521 return Is_Aliased (Typ);
3522 end if;
3523 end Has_Alias_Deep;
3525 begin
3526 case Nkind (N) is
3528 when N_Identifier
3529 | N_Expanded_Name
3531 return Has_Alias_Deep (Etype (N));
3533 when N_Defining_Identifier =>
3534 return Has_Alias_Deep (Etype (N));
3536 when N_Type_Conversion
3537 | N_Unchecked_Type_Conversion
3538 | N_Qualified_Expression
3540 return Has_Alias (Expression (N));
3542 when N_Parameter_Specification =>
3543 return Has_Alias (Defining_Identifier (N));
3545 when N_Selected_Component =>
3546 case Nkind (Selector_Name (N)) is
3547 when N_Identifier =>
3548 if Is_Aliased (Entity (Selector_Name (N))) then
3549 return True;
3550 end if;
3552 when others => null;
3554 end case;
3556 return Has_Alias (Prefix (N));
3558 when N_Indexed_Component
3559 | N_Slice
3561 return Has_Alias (Prefix (N));
3563 when N_Explicit_Dereference =>
3564 return True;
3566 when N_Function_Call =>
3567 return False;
3569 when N_Attribute_Reference =>
3570 if Is_Deep (Etype (Prefix (N))) then
3571 raise Program_Error;
3572 end if;
3573 return False;
3575 when others =>
3576 return False;
3577 end case;
3578 end Has_Alias;
3580 -------------------------
3581 -- Has_Array_Component --
3582 -------------------------
3584 function Has_Array_Component (N : Node_Id) return Boolean is
3585 begin
3586 case Nkind (N) is
3587 -- Base identifier. There is no array component here.
3589 when N_Identifier
3590 | N_Expanded_Name
3591 | N_Defining_Identifier
3593 return False;
3595 -- We check if the expression inside the conversion has an array
3596 -- component.
3598 when N_Type_Conversion
3599 | N_Unchecked_Type_Conversion
3600 | N_Qualified_Expression
3602 return Has_Array_Component (Expression (N));
3604 -- We check if the prefix has an array component
3606 when N_Selected_Component =>
3607 return Has_Array_Component (Prefix (N));
3609 -- We found the array component, return True
3611 when N_Indexed_Component
3612 | N_Slice
3614 return True;
3616 -- We check if the prefix has an array component
3618 when N_Explicit_Dereference =>
3619 return Has_Array_Component (Prefix (N));
3621 when N_Function_Call =>
3622 return False;
3624 when others =>
3625 raise Program_Error;
3626 end case;
3627 end Has_Array_Component;
3629 ----------------------------
3630 -- Has_Function_Component --
3631 ----------------------------
3633 function Has_Function_Component (N : Node_Id) return Boolean is
3634 begin
3635 case Nkind (N) is
3636 -- Base identifier. There is no function component here.
3638 when N_Identifier
3639 | N_Expanded_Name
3640 | N_Defining_Identifier
3642 return False;
3644 -- We check if the expression inside the conversion has a function
3645 -- component.
3647 when N_Type_Conversion
3648 | N_Unchecked_Type_Conversion
3649 | N_Qualified_Expression
3651 return Has_Function_Component (Expression (N));
3653 -- We check if the prefix has a function component
3655 when N_Selected_Component =>
3656 return Has_Function_Component (Prefix (N));
3658 -- We check if the prefix has a function component
3660 when N_Indexed_Component
3661 | N_Slice
3663 return Has_Function_Component (Prefix (N));
3665 -- We check if the prefix has a function component
3667 when N_Explicit_Dereference =>
3668 return Has_Function_Component (Prefix (N));
3670 -- We found the function component, return True
3672 when N_Function_Call =>
3673 return True;
3675 when others =>
3676 raise Program_Error;
3678 end case;
3679 end Has_Function_Component;
3681 --------
3682 -- Hp --
3683 --------
3685 procedure Hp (P : Perm_Env) is
3686 Elem : Perm_Tree_Maps.Key_Option;
3688 begin
3689 Elem := Get_First_Key (P);
3690 while Elem.Present loop
3691 Print_Node_Briefly (Elem.K);
3692 Elem := Get_Next_Key (P);
3693 end loop;
3694 end Hp;
3696 --------------------------
3697 -- Illegal_Global_Usage --
3698 --------------------------
3700 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id) is
3701 begin
3702 Error_Msg_NE ("cannot use global variable & of deep type", N, N);
3703 Error_Msg_N ("\without prior declaration in a Global aspect", N);
3705 Errout.Finalize (Last_Call => True);
3706 Errout.Output_Messages;
3707 Exit_Program (E_Errors);
3708 end Illegal_Global_Usage;
3710 --------------------
3711 -- Is_Borrowed_In --
3712 --------------------
3714 function Is_Borrowed_In (E : Entity_Id) return Boolean is
3715 begin
3716 return Is_Access_Type (Etype (E))
3717 and then not Is_Access_Constant (Etype (E));
3718 end Is_Borrowed_In;
3720 -------------
3721 -- Is_Deep --
3722 -------------
3724 function Is_Deep (E : Entity_Id) return Boolean is
3725 function Is_Private_Entity_Mode_Off (E : Entity_Id) return Boolean;
3727 function Is_Private_Entity_Mode_Off (E : Entity_Id) return Boolean is
3728 Decl : Node_Id;
3729 Pack_Decl : Node_Id;
3731 begin
3732 if Is_Itype (E) then
3733 Decl := Associated_Node_For_Itype (E);
3734 else
3735 Decl := Parent (E);
3736 end if;
3738 Pack_Decl := Parent (Parent (Decl));
3740 if Nkind (Pack_Decl) /= N_Package_Declaration then
3741 return False;
3742 end if;
3744 return
3745 Present (SPARK_Aux_Pragma (Defining_Entity (Pack_Decl)))
3746 and then Get_SPARK_Mode_From_Annotation
3747 (SPARK_Aux_Pragma (Defining_Entity (Pack_Decl))) = Off;
3748 end Is_Private_Entity_Mode_Off;
3749 begin
3750 pragma Assert (Is_Type (E));
3752 case Ekind (E) is
3753 when Scalar_Kind =>
3754 return False;
3756 when Access_Kind =>
3757 return True;
3759 -- Just check the depth of its component type
3761 when E_Array_Type
3762 | E_Array_Subtype
3764 return Is_Deep (Component_Type (E));
3766 when E_String_Literal_Subtype =>
3767 return False;
3769 -- Per RM 8.11 for class-wide types
3771 when E_Class_Wide_Subtype
3772 | E_Class_Wide_Type
3774 return True;
3776 -- ??? What about hidden components
3778 when E_Record_Type
3779 | E_Record_Subtype
3781 declare
3782 Elmt : Entity_Id;
3784 begin
3785 Elmt := First_Component_Or_Discriminant (E);
3786 while Present (Elmt) loop
3787 if Is_Deep (Etype (Elmt)) then
3788 return True;
3789 else
3790 Next_Component_Or_Discriminant (Elmt);
3791 end if;
3792 end loop;
3794 return False;
3795 end;
3797 when Private_Kind =>
3798 if Is_Private_Entity_Mode_Off (E) then
3799 return False;
3800 else
3801 if Present (Full_View (E)) then
3802 return Is_Deep (Full_View (E));
3803 else
3804 return True;
3805 end if;
3806 end if;
3808 when E_Incomplete_Type =>
3809 return True;
3811 when E_Incomplete_Subtype =>
3812 return True;
3814 -- No problem with synchronized types
3816 when E_Protected_Type
3817 | E_Protected_Subtype
3818 | E_Task_Subtype
3819 | E_Task_Type
3821 return False;
3823 when E_Exception_Type =>
3824 return False;
3826 when others =>
3827 raise Program_Error;
3828 end case;
3829 end Is_Deep;
3831 ----------------
3832 -- Is_Shallow --
3833 ----------------
3835 function Is_Shallow (E : Entity_Id) return Boolean is
3836 begin
3837 pragma Assert (Is_Type (E));
3838 return not Is_Deep (E);
3839 end Is_Shallow;
3841 ------------------
3842 -- Loop_Of_Exit --
3843 ------------------
3845 function Loop_Of_Exit (N : Node_Id) return Entity_Id is
3846 Nam : Node_Id := Name (N);
3847 Stmt : Node_Id := N;
3848 begin
3849 if No (Nam) then
3850 while Present (Stmt) loop
3851 Stmt := Parent (Stmt);
3852 if Nkind (Stmt) = N_Loop_Statement then
3853 Nam := Identifier (Stmt);
3854 exit;
3855 end if;
3856 end loop;
3857 end if;
3858 return Entity (Nam);
3859 end Loop_Of_Exit;
3860 ---------
3861 -- Lub --
3862 ---------
3864 function Lub (P1, P2 : Perm_Kind) return Perm_Kind
3866 begin
3867 case P1 is
3868 when No_Access =>
3869 return P2;
3871 when Read_Only =>
3872 case P2 is
3873 when No_Access
3874 | Read_Only
3876 return Read_Only;
3878 when Write_Perm =>
3879 return Read_Write;
3880 end case;
3882 when Write_Only =>
3883 case P2 is
3884 when No_Access
3885 | Write_Only
3887 return Write_Only;
3889 when Read_Perm =>
3890 return Read_Write;
3891 end case;
3893 when Read_Write =>
3894 return Read_Write;
3895 end case;
3896 end Lub;
3898 ----------------
3899 -- Merge_Envs --
3900 ----------------
3902 procedure Merge_Envs
3903 (Target : in out Perm_Env;
3904 Source : in out Perm_Env)
3906 procedure Merge_Trees
3907 (Target : Perm_Tree_Access;
3908 Source : Perm_Tree_Access);
3910 procedure Merge_Trees
3911 (Target : Perm_Tree_Access;
3912 Source : Perm_Tree_Access)
3914 procedure Apply_Glb_Tree
3915 (A : Perm_Tree_Access;
3916 P : Perm_Kind);
3918 procedure Apply_Glb_Tree
3919 (A : Perm_Tree_Access;
3920 P : Perm_Kind)
3922 begin
3923 A.all.Tree.Permission := Glb (Permission (A), P);
3925 case Kind (A) is
3926 when Entire_Object =>
3927 A.all.Tree.Children_Permission :=
3928 Glb (Children_Permission (A), P);
3930 when Reference =>
3931 Apply_Glb_Tree (Get_All (A), P);
3933 when Array_Component =>
3934 Apply_Glb_Tree (Get_Elem (A), P);
3936 when Record_Component =>
3937 declare
3938 Comp : Perm_Tree_Access;
3939 begin
3940 Comp := Perm_Tree_Maps.Get_First (Component (A));
3941 while Comp /= null loop
3942 Apply_Glb_Tree (Comp, P);
3943 Comp := Perm_Tree_Maps.Get_Next (Component (A));
3944 end loop;
3946 Apply_Glb_Tree (Other_Components (A), P);
3947 end;
3948 end case;
3949 end Apply_Glb_Tree;
3951 Perm : constant Perm_Kind :=
3952 Glb (Permission (Target), Permission (Source));
3954 begin
3955 pragma Assert (Is_Node_Deep (Target) = Is_Node_Deep (Source));
3956 Target.all.Tree.Permission := Perm;
3958 case Kind (Target) is
3959 when Entire_Object =>
3960 declare
3961 Child_Perm : constant Perm_Kind :=
3962 Children_Permission (Target);
3964 begin
3965 case Kind (Source) is
3966 when Entire_Object =>
3967 Target.all.Tree.Children_Permission :=
3968 Glb (Child_Perm, Children_Permission (Source));
3970 when Reference =>
3971 Copy_Tree (Source, Target);
3972 Target.all.Tree.Permission := Perm;
3973 Apply_Glb_Tree (Get_All (Target), Child_Perm);
3975 when Array_Component =>
3976 Copy_Tree (Source, Target);
3977 Target.all.Tree.Permission := Perm;
3978 Apply_Glb_Tree (Get_Elem (Target), Child_Perm);
3980 when Record_Component =>
3981 Copy_Tree (Source, Target);
3982 Target.all.Tree.Permission := Perm;
3983 declare
3984 Comp : Perm_Tree_Access;
3986 begin
3987 Comp :=
3988 Perm_Tree_Maps.Get_First (Component (Target));
3989 while Comp /= null loop
3990 -- Apply glb tree on every component subtree
3992 Apply_Glb_Tree (Comp, Child_Perm);
3993 Comp := Perm_Tree_Maps.Get_Next
3994 (Component (Target));
3995 end loop;
3996 end;
3997 Apply_Glb_Tree (Other_Components (Target), Child_Perm);
3999 end case;
4000 end;
4001 when Reference =>
4002 case Kind (Source) is
4003 when Entire_Object =>
4004 Apply_Glb_Tree (Get_All (Target),
4005 Children_Permission (Source));
4007 when Reference =>
4008 Merge_Trees (Get_All (Target), Get_All (Source));
4010 when others =>
4011 raise Program_Error;
4013 end case;
4015 when Array_Component =>
4016 case Kind (Source) is
4017 when Entire_Object =>
4018 Apply_Glb_Tree (Get_Elem (Target),
4019 Children_Permission (Source));
4021 when Array_Component =>
4022 Merge_Trees (Get_Elem (Target), Get_Elem (Source));
4024 when others =>
4025 raise Program_Error;
4027 end case;
4029 when Record_Component =>
4030 case Kind (Source) is
4031 when Entire_Object =>
4032 declare
4033 Child_Perm : constant Perm_Kind :=
4034 Children_Permission (Source);
4036 Comp : Perm_Tree_Access;
4038 begin
4039 Comp := Perm_Tree_Maps.Get_First
4040 (Component (Target));
4041 while Comp /= null loop
4042 -- Apply glb tree on every component subtree
4044 Apply_Glb_Tree (Comp, Child_Perm);
4045 Comp :=
4046 Perm_Tree_Maps.Get_Next (Component (Target));
4047 end loop;
4048 Apply_Glb_Tree (Other_Components (Target), Child_Perm);
4049 end;
4051 when Record_Component =>
4052 declare
4053 Key_Source : Perm_Tree_Maps.Key_Option;
4054 CompTarget : Perm_Tree_Access;
4055 CompSource : Perm_Tree_Access;
4057 begin
4058 Key_Source := Perm_Tree_Maps.Get_First_Key
4059 (Component (Source));
4061 while Key_Source.Present loop
4062 CompSource := Perm_Tree_Maps.Get
4063 (Component (Source), Key_Source.K);
4064 CompTarget := Perm_Tree_Maps.Get
4065 (Component (Target), Key_Source.K);
4067 pragma Assert (CompSource /= null);
4068 Merge_Trees (CompTarget, CompSource);
4070 Key_Source := Perm_Tree_Maps.Get_Next_Key
4071 (Component (Source));
4072 end loop;
4074 Merge_Trees (Other_Components (Target),
4075 Other_Components (Source));
4076 end;
4078 when others =>
4079 raise Program_Error;
4081 end case;
4082 end case;
4083 end Merge_Trees;
4085 CompTarget : Perm_Tree_Access;
4086 CompSource : Perm_Tree_Access;
4087 KeyTarget : Perm_Tree_Maps.Key_Option;
4089 begin
4090 KeyTarget := Get_First_Key (Target);
4091 -- Iterate over every tree of the environment in the target, and merge
4092 -- it with the source if there is such a similar one that exists. If
4093 -- there is none, then skip.
4094 while KeyTarget.Present loop
4096 CompSource := Get (Source, KeyTarget.K);
4097 CompTarget := Get (Target, KeyTarget.K);
4099 pragma Assert (CompTarget /= null);
4101 if CompSource /= null then
4102 Merge_Trees (CompTarget, CompSource);
4103 Remove (Source, KeyTarget.K);
4104 end if;
4106 KeyTarget := Get_Next_Key (Target);
4107 end loop;
4109 -- Iterate over every tree of the environment of the source. And merge
4110 -- again. If there is not any tree of the target then just copy the tree
4111 -- from source to target.
4112 declare
4113 KeySource : Perm_Tree_Maps.Key_Option;
4114 begin
4115 KeySource := Get_First_Key (Source);
4116 while KeySource.Present loop
4118 CompSource := Get (Source, KeySource.K);
4119 CompTarget := Get (Target, KeySource.K);
4121 if CompTarget = null then
4122 CompTarget := new Perm_Tree_Wrapper'(CompSource.all);
4123 Copy_Tree (CompSource, CompTarget);
4124 Set (Target, KeySource.K, CompTarget);
4125 else
4126 Merge_Trees (CompTarget, CompSource);
4127 end if;
4129 KeySource := Get_Next_Key (Source);
4130 end loop;
4131 end;
4133 Free_Env (Source);
4134 end Merge_Envs;
4136 ----------------
4137 -- Perm_Error --
4138 ----------------
4140 procedure Perm_Error
4141 (N : Node_Id;
4142 Perm : Perm_Kind;
4143 Found_Perm : Perm_Kind)
4145 procedure Set_Root_Object
4146 (Path : Node_Id;
4147 Obj : out Entity_Id;
4148 Deref : out Boolean);
4149 -- Set the root object Obj, and whether the path contains a dereference,
4150 -- from a path Path.
4152 ---------------------
4153 -- Set_Root_Object --
4154 ---------------------
4156 procedure Set_Root_Object
4157 (Path : Node_Id;
4158 Obj : out Entity_Id;
4159 Deref : out Boolean)
4161 begin
4162 case Nkind (Path) is
4163 when N_Identifier
4164 | N_Expanded_Name
4166 Obj := Entity (Path);
4167 Deref := False;
4169 when N_Type_Conversion
4170 | N_Unchecked_Type_Conversion
4171 | N_Qualified_Expression
4173 Set_Root_Object (Expression (Path), Obj, Deref);
4175 when N_Indexed_Component
4176 | N_Selected_Component
4177 | N_Slice
4179 Set_Root_Object (Prefix (Path), Obj, Deref);
4181 when N_Explicit_Dereference =>
4182 Set_Root_Object (Prefix (Path), Obj, Deref);
4183 Deref := True;
4185 when others =>
4186 raise Program_Error;
4187 end case;
4188 end Set_Root_Object;
4190 -- Local variables
4192 Root : Entity_Id;
4193 Is_Deref : Boolean;
4195 -- Start of processing for Perm_Error
4197 begin
4198 Set_Root_Object (N, Root, Is_Deref);
4200 if Is_Deref then
4201 Error_Msg_NE
4202 ("insufficient permission on dereference from &", N, Root);
4203 else
4204 Error_Msg_NE ("insufficient permission for &", N, Root);
4205 end if;
4207 Perm_Mismatch (Perm, Found_Perm, N);
4208 end Perm_Error;
4210 -------------------------------
4211 -- Perm_Error_Subprogram_End --
4212 -------------------------------
4214 procedure Perm_Error_Subprogram_End
4215 (E : Entity_Id;
4216 Subp : Entity_Id;
4217 Perm : Perm_Kind;
4218 Found_Perm : Perm_Kind)
4220 begin
4221 Error_Msg_Node_2 := Subp;
4222 Error_Msg_NE ("insufficient permission for & when returning from &",
4223 Subp, E);
4224 Perm_Mismatch (Perm, Found_Perm, Subp);
4225 end Perm_Error_Subprogram_End;
4227 ------------------
4228 -- Process_Path --
4229 ------------------
4231 procedure Process_Path (N : Node_Id) is
4232 Root : constant Entity_Id := Get_Enclosing_Object (N);
4233 begin
4234 -- We ignore if yielding to synchronized
4236 if Present (Root)
4237 and then Is_Synchronized_Object (Root)
4238 then
4239 return;
4240 end if;
4242 -- We ignore shallow unaliased. They are checked in flow analysis,
4243 -- allowing backward compatibility.
4245 if not Has_Alias (N)
4246 and then Is_Shallow (Etype (N))
4247 then
4248 return;
4249 end if;
4251 declare
4252 Perm_N : constant Perm_Kind := Get_Perm (N);
4254 begin
4256 case Current_Checking_Mode is
4257 -- Check permission R, do nothing
4259 when Read =>
4260 if Perm_N not in Read_Perm then
4261 Perm_Error (N, Read_Only, Perm_N);
4262 end if;
4264 -- If shallow type no need for RW, only R
4266 when Move =>
4267 if Is_Shallow (Etype (N)) then
4268 if Perm_N not in Read_Perm then
4269 Perm_Error (N, Read_Only, Perm_N);
4270 end if;
4271 else
4272 -- Check permission RW if deep
4274 if Perm_N /= Read_Write then
4275 Perm_Error (N, Read_Write, Perm_N);
4276 end if;
4278 declare
4279 -- Set permission to W to the path and any of its prefix
4281 Tree : constant Perm_Tree_Access :=
4282 Set_Perm_Prefixes_Move (N, Move);
4284 begin
4285 if Tree = null then
4286 -- We went through a function call, no permission to
4287 -- modify.
4289 return;
4290 end if;
4292 -- Set permissions to
4293 -- No for any extension with more .all
4294 -- W for any deep extension with same number of .all
4295 -- RW for any shallow extension with same number of .all
4297 Set_Perm_Extensions_Move (Tree, Etype (N));
4298 end;
4299 end if;
4301 -- Check permission RW
4303 when Super_Move =>
4304 if Perm_N /= Read_Write then
4305 Perm_Error (N, Read_Write, Perm_N);
4306 end if;
4308 declare
4309 -- Set permission to No to the path and any of its prefix up
4310 -- to the first .all and then W.
4312 Tree : constant Perm_Tree_Access :=
4313 Set_Perm_Prefixes_Move (N, Super_Move);
4315 begin
4316 if Tree = null then
4317 -- We went through a function call, no permission to
4318 -- modify.
4320 return;
4321 end if;
4323 -- Set permissions to No on any strict extension of the path
4325 Set_Perm_Extensions (Tree, No_Access);
4326 end;
4328 -- Check permission W
4330 when Assign =>
4331 if Perm_N not in Write_Perm then
4332 Perm_Error (N, Write_Only, Perm_N);
4333 end if;
4335 -- If the tree has an array component, then the permissions do
4336 -- not get modified by the assignment.
4338 if Has_Array_Component (N) then
4339 return;
4340 end if;
4342 -- Same if has function component
4344 if Has_Function_Component (N) then
4345 return;
4346 end if;
4348 declare
4349 -- Get the permission tree for the path
4351 Tree : constant Perm_Tree_Access :=
4352 Get_Perm_Tree (N);
4354 Dummy : Perm_Tree_Access;
4356 begin
4357 if Tree = null then
4358 -- We went through a function call, no permission to
4359 -- modify.
4361 return;
4362 end if;
4364 -- Set permission RW for it and all of its extensions
4366 Tree.all.Tree.Permission := Read_Write;
4368 Set_Perm_Extensions (Tree, Read_Write);
4370 -- Normalize the permission tree
4372 Dummy := Set_Perm_Prefixes_Assign (N);
4373 end;
4375 -- Check permission W
4377 when Borrow_Out =>
4378 if Perm_N not in Write_Perm then
4379 Perm_Error (N, Write_Only, Perm_N);
4380 end if;
4382 declare
4383 -- Set permission to No to the path and any of its prefixes
4385 Tree : constant Perm_Tree_Access :=
4386 Set_Perm_Prefixes_Borrow_Out (N);
4388 begin
4389 if Tree = null then
4390 -- We went through a function call, no permission to
4391 -- modify.
4393 return;
4394 end if;
4396 -- Set permissions to No on any strict extension of the path
4398 Set_Perm_Extensions (Tree, No_Access);
4399 end;
4401 when Observe =>
4402 if Perm_N not in Read_Perm then
4403 Perm_Error (N, Read_Only, Perm_N);
4404 end if;
4406 if Is_By_Copy_Type (Etype (N)) then
4407 return;
4408 end if;
4410 declare
4411 -- Set permission to No on the path and any of its prefixes
4413 Tree : constant Perm_Tree_Access :=
4414 Set_Perm_Prefixes_Observe (N);
4416 begin
4417 if Tree = null then
4418 -- We went through a function call, no permission to
4419 -- modify.
4421 return;
4422 end if;
4424 -- Set permissions to No on any strict extension of the path
4426 Set_Perm_Extensions (Tree, Read_Only);
4427 end;
4428 end case;
4429 end;
4430 end Process_Path;
4432 -------------------------
4433 -- Return_Declarations --
4434 -------------------------
4436 procedure Return_Declarations (L : List_Id) is
4438 procedure Return_Declaration (Decl : Node_Id);
4439 -- Check correct permissions for every declared object
4441 ------------------------
4442 -- Return_Declaration --
4443 ------------------------
4445 procedure Return_Declaration (Decl : Node_Id) is
4446 begin
4447 if Nkind (Decl) = N_Object_Declaration then
4448 -- Check RW for object declared, unless the object has never been
4449 -- initialized.
4451 if Get (Current_Initialization_Map,
4452 Unique_Entity (Defining_Identifier (Decl))) = False
4453 then
4454 return;
4455 end if;
4457 -- We ignore shallow unaliased. They are checked in flow analysis,
4458 -- allowing backward compatibility.
4460 if not Has_Alias (Defining_Identifier (Decl))
4461 and then Is_Shallow (Etype (Defining_Identifier (Decl)))
4462 then
4463 return;
4464 end if;
4466 declare
4467 Elem : constant Perm_Tree_Access :=
4468 Get (Current_Perm_Env,
4469 Unique_Entity (Defining_Identifier (Decl)));
4471 begin
4472 if Elem = null then
4473 -- Here we are on a declaration. Hence it should have been
4474 -- added in the environment when analyzing this node with
4475 -- mode Read. Hence it is not possible to find a null
4476 -- pointer here.
4478 -- Hash_Table_Error
4479 raise Program_Error;
4480 end if;
4482 if Permission (Elem) /= Read_Write then
4483 Perm_Error (Decl, Read_Write, Permission (Elem));
4484 end if;
4485 end;
4486 end if;
4487 end Return_Declaration;
4489 -- Local Variables
4491 N : Node_Id;
4493 -- Start of processing for Return_Declarations
4495 begin
4496 N := First (L);
4497 while Present (N) loop
4498 Return_Declaration (N);
4499 Next (N);
4500 end loop;
4501 end Return_Declarations;
4503 --------------------
4504 -- Return_Globals --
4505 --------------------
4507 procedure Return_Globals (Subp : Entity_Id) is
4509 procedure Return_Globals_From_List
4510 (First_Item : Node_Id;
4511 Kind : Formal_Kind);
4512 -- Return global items from the list starting at Item
4514 procedure Return_Globals_Of_Mode (Global_Mode : Name_Id);
4515 -- Return global items for the mode Global_Mode
4517 ------------------------------
4518 -- Return_Globals_From_List --
4519 ------------------------------
4521 procedure Return_Globals_From_List
4522 (First_Item : Node_Id;
4523 Kind : Formal_Kind)
4525 Item : Node_Id := First_Item;
4526 E : Entity_Id;
4528 begin
4529 while Present (Item) loop
4530 E := Entity (Item);
4532 -- Ignore abstract states, which play no role in pointer aliasing
4534 if Ekind (E) = E_Abstract_State then
4535 null;
4536 else
4537 Return_Parameter_Or_Global (E, Kind, Subp);
4538 end if;
4539 Next_Global (Item);
4540 end loop;
4541 end Return_Globals_From_List;
4543 ----------------------------
4544 -- Return_Globals_Of_Mode --
4545 ----------------------------
4547 procedure Return_Globals_Of_Mode (Global_Mode : Name_Id) is
4548 Kind : Formal_Kind;
4550 begin
4551 case Global_Mode is
4552 when Name_Input | Name_Proof_In =>
4553 Kind := E_In_Parameter;
4554 when Name_Output =>
4555 Kind := E_Out_Parameter;
4556 when Name_In_Out =>
4557 Kind := E_In_Out_Parameter;
4558 when others =>
4559 raise Program_Error;
4560 end case;
4562 -- Return both global items from Global and Refined_Global pragmas
4564 Return_Globals_From_List (First_Global (Subp, Global_Mode), Kind);
4565 Return_Globals_From_List
4566 (First_Global (Subp, Global_Mode, Refined => True), Kind);
4567 end Return_Globals_Of_Mode;
4569 -- Start of processing for Return_Globals
4571 begin
4572 Return_Globals_Of_Mode (Name_Proof_In);
4573 Return_Globals_Of_Mode (Name_Input);
4574 Return_Globals_Of_Mode (Name_Output);
4575 Return_Globals_Of_Mode (Name_In_Out);
4576 end Return_Globals;
4578 --------------------------------
4579 -- Return_Parameter_Or_Global --
4580 --------------------------------
4582 procedure Return_Parameter_Or_Global
4583 (Id : Entity_Id;
4584 Mode : Formal_Kind;
4585 Subp : Entity_Id)
4587 Elem : constant Perm_Tree_Access := Get (Current_Perm_Env, Id);
4588 pragma Assert (Elem /= null);
4590 begin
4591 -- Shallow unaliased parameters and globals cannot introduce pointer
4592 -- aliasing.
4594 if not Has_Alias (Id) and then Is_Shallow (Etype (Id)) then
4595 null;
4597 -- Observed IN parameters and globals need not return a permission to
4598 -- the caller.
4600 elsif Mode = E_In_Parameter and then not Is_Borrowed_In (Id) then
4601 null;
4603 -- All other parameters and globals should return with mode RW to the
4604 -- caller.
4606 else
4607 if Permission (Elem) /= Read_Write then
4608 Perm_Error_Subprogram_End
4609 (E => Id,
4610 Subp => Subp,
4611 Perm => Read_Write,
4612 Found_Perm => Permission (Elem));
4613 end if;
4614 end if;
4615 end Return_Parameter_Or_Global;
4617 -----------------------
4618 -- Return_Parameters --
4619 -----------------------
4621 procedure Return_Parameters (Subp : Entity_Id) is
4622 Formal : Entity_Id;
4624 begin
4625 Formal := First_Formal (Subp);
4626 while Present (Formal) loop
4627 Return_Parameter_Or_Global (Formal, Ekind (Formal), Subp);
4628 Next_Formal (Formal);
4629 end loop;
4630 end Return_Parameters;
4632 -------------------------
4633 -- Set_Perm_Extensions --
4634 -------------------------
4636 procedure Set_Perm_Extensions
4637 (T : Perm_Tree_Access;
4638 P : Perm_Kind)
4640 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access);
4642 procedure Free_Perm_Tree_Children (T : Perm_Tree_Access)
4644 begin
4645 case Kind (T) is
4646 when Entire_Object =>
4647 null;
4649 when Reference =>
4650 Free_Perm_Tree (T.all.Tree.Get_All);
4652 when Array_Component =>
4653 Free_Perm_Tree (T.all.Tree.Get_Elem);
4655 -- Free every Component subtree
4657 when Record_Component =>
4658 declare
4659 Comp : Perm_Tree_Access;
4661 begin
4662 Comp := Perm_Tree_Maps.Get_First (Component (T));
4663 while Comp /= null loop
4664 Free_Perm_Tree (Comp);
4665 Comp := Perm_Tree_Maps.Get_Next (Component (T));
4666 end loop;
4668 Free_Perm_Tree (T.all.Tree.Other_Components);
4669 end;
4670 end case;
4671 end Free_Perm_Tree_Children;
4673 Son : constant Perm_Tree :=
4674 Perm_Tree'
4675 (Kind => Entire_Object,
4676 Is_Node_Deep => Is_Node_Deep (T),
4677 Permission => Permission (T),
4678 Children_Permission => P);
4680 begin
4681 Free_Perm_Tree_Children (T);
4682 T.all.Tree := Son;
4683 end Set_Perm_Extensions;
4685 ------------------------------
4686 -- Set_Perm_Extensions_Move --
4687 ------------------------------
4689 procedure Set_Perm_Extensions_Move
4690 (T : Perm_Tree_Access;
4691 E : Entity_Id)
4693 begin
4694 if not Is_Node_Deep (T) then
4695 -- We are a shallow extension with same number of .all
4697 Set_Perm_Extensions (T, Read_Write);
4698 return;
4699 end if;
4701 -- We are a deep extension here (or the moved deep path)
4703 T.all.Tree.Permission := Write_Only;
4705 case T.all.Tree.Kind is
4706 -- Unroll the tree depending on the type
4708 when Entire_Object =>
4709 case Ekind (E) is
4710 when Scalar_Kind
4711 | E_String_Literal_Subtype
4713 Set_Perm_Extensions (T, No_Access);
4715 -- No need to unroll here, directly put sons to No_Access
4717 when Access_Kind =>
4718 if Ekind (E) in Access_Subprogram_Kind then
4719 null;
4720 else
4721 Set_Perm_Extensions (T, No_Access);
4722 end if;
4724 -- No unrolling done, too complicated
4726 when E_Class_Wide_Subtype
4727 | E_Class_Wide_Type
4728 | E_Incomplete_Type
4729 | E_Incomplete_Subtype
4730 | E_Exception_Type
4731 | E_Task_Type
4732 | E_Task_Subtype
4734 Set_Perm_Extensions (T, No_Access);
4736 -- Expand the tree. Replace the node with Array component.
4738 when E_Array_Type
4739 | E_Array_Subtype =>
4740 declare
4741 Son : Perm_Tree_Access;
4743 begin
4744 Son := new Perm_Tree_Wrapper'
4745 (Tree =>
4746 (Kind => Entire_Object,
4747 Is_Node_Deep => Is_Node_Deep (T),
4748 Permission => Read_Write,
4749 Children_Permission => Read_Write));
4751 Set_Perm_Extensions_Move (Son, Component_Type (E));
4753 -- We change the current node from Entire_Object to
4754 -- Reference with Write_Only and the previous son.
4756 pragma Assert (Is_Node_Deep (T));
4758 T.all.Tree := (Kind => Array_Component,
4759 Is_Node_Deep => Is_Node_Deep (T),
4760 Permission => Write_Only,
4761 Get_Elem => Son);
4762 end;
4764 -- Unroll, and set permission extensions with component type
4766 when E_Record_Type
4767 | E_Record_Subtype
4768 | E_Record_Type_With_Private
4769 | E_Record_Subtype_With_Private
4770 | E_Protected_Type
4771 | E_Protected_Subtype
4773 declare
4774 -- Expand the tree. Replace the node with
4775 -- Record_Component.
4777 Elem : Node_Id;
4779 Son : Perm_Tree_Access;
4781 begin
4782 -- We change the current node from Entire_Object to
4783 -- Record_Component with same permission and an empty
4784 -- hash table as component list.
4786 pragma Assert (Is_Node_Deep (T));
4788 T.all.Tree :=
4789 (Kind => Record_Component,
4790 Is_Node_Deep => Is_Node_Deep (T),
4791 Permission => Write_Only,
4792 Component => Perm_Tree_Maps.Nil,
4793 Other_Components =>
4794 new Perm_Tree_Wrapper'
4795 (Tree =>
4796 (Kind => Entire_Object,
4797 Is_Node_Deep => True,
4798 Permission => Read_Write,
4799 Children_Permission => Read_Write)
4803 -- We fill the hash table with all sons of the record,
4804 -- with basic Entire_Objects nodes.
4805 Elem := First_Component_Or_Discriminant (E);
4806 while Present (Elem) loop
4807 Son := new Perm_Tree_Wrapper'
4808 (Tree =>
4809 (Kind => Entire_Object,
4810 Is_Node_Deep => Is_Deep (Etype (Elem)),
4811 Permission => Read_Write,
4812 Children_Permission => Read_Write));
4814 Set_Perm_Extensions_Move (Son, Etype (Elem));
4816 Perm_Tree_Maps.Set
4817 (T.all.Tree.Component, Elem, Son);
4819 Next_Component_Or_Discriminant (Elem);
4820 end loop;
4821 end;
4823 when E_Private_Type
4824 | E_Private_Subtype
4825 | E_Limited_Private_Type
4826 | E_Limited_Private_Subtype
4828 Set_Perm_Extensions_Move (T, Underlying_Type (E));
4830 when others =>
4831 raise Program_Error;
4832 end case;
4834 when Reference =>
4835 -- Now the son does not have the same number of .all
4836 Set_Perm_Extensions (T, No_Access);
4838 when Array_Component =>
4839 Set_Perm_Extensions_Move (Get_Elem (T), Component_Type (E));
4841 when Record_Component =>
4842 declare
4843 Comp : Perm_Tree_Access;
4844 It : Node_Id;
4846 begin
4847 It := First_Component_Or_Discriminant (E);
4848 while It /= Empty loop
4849 Comp := Perm_Tree_Maps.Get (Component (T), It);
4850 pragma Assert (Comp /= null);
4851 Set_Perm_Extensions_Move (Comp, It);
4852 It := Next_Component_Or_Discriminant (E);
4853 end loop;
4855 Set_Perm_Extensions (Other_Components (T), No_Access);
4856 end;
4857 end case;
4858 end Set_Perm_Extensions_Move;
4860 ------------------------------
4861 -- Set_Perm_Prefixes_Assign --
4862 ------------------------------
4864 function Set_Perm_Prefixes_Assign
4865 (N : Node_Id)
4866 return Perm_Tree_Access
4868 C : constant Perm_Tree_Access := Get_Perm_Tree (N);
4870 begin
4871 pragma Assert (Current_Checking_Mode = Assign);
4873 -- The function should not be called if has_function_component
4875 pragma Assert (C /= null);
4877 case Kind (C) is
4878 when Entire_Object =>
4879 pragma Assert (Children_Permission (C) = Read_Write);
4880 C.all.Tree.Permission := Read_Write;
4882 when Reference =>
4883 pragma Assert (Get_All (C) /= null);
4885 C.all.Tree.Permission :=
4886 Lub (Permission (C), Permission (Get_All (C)));
4888 when Array_Component =>
4889 pragma Assert (C.all.Tree.Get_Elem /= null);
4891 -- Given that it is not possible to know which element has been
4892 -- assigned, then the permissions do not get changed in case of
4893 -- Array_Component.
4895 null;
4897 when Record_Component =>
4898 declare
4899 Perm : Perm_Kind := Read_Write;
4901 Comp : Perm_Tree_Access;
4903 begin
4904 -- We take the Glb of all the descendants, and then update the
4905 -- permission of the node with it.
4906 Comp := Perm_Tree_Maps.Get_First (Component (C));
4907 while Comp /= null loop
4908 Perm := Glb (Perm, Permission (Comp));
4909 Comp := Perm_Tree_Maps.Get_Next (Component (C));
4910 end loop;
4912 Perm := Glb (Perm, Permission (Other_Components (C)));
4914 C.all.Tree.Permission := Lub (Permission (C), Perm);
4915 end;
4916 end case;
4918 case Nkind (N) is
4919 -- Base identifier. End recursion here.
4921 when N_Identifier
4922 | N_Expanded_Name
4923 | N_Defining_Identifier
4925 return null;
4927 when N_Type_Conversion
4928 | N_Unchecked_Type_Conversion
4929 | N_Qualified_Expression
4931 return Set_Perm_Prefixes_Assign (Expression (N));
4933 when N_Parameter_Specification =>
4934 raise Program_Error;
4936 -- Continue recursion on prefix
4938 when N_Selected_Component =>
4939 return Set_Perm_Prefixes_Assign (Prefix (N));
4941 -- Continue recursion on prefix
4943 when N_Indexed_Component
4944 | N_Slice
4946 return Set_Perm_Prefixes_Assign (Prefix (N));
4948 -- Continue recursion on prefix
4950 when N_Explicit_Dereference =>
4951 return Set_Perm_Prefixes_Assign (Prefix (N));
4953 when N_Function_Call =>
4954 raise Program_Error;
4956 when others =>
4957 raise Program_Error;
4959 end case;
4960 end Set_Perm_Prefixes_Assign;
4962 ----------------------------------
4963 -- Set_Perm_Prefixes_Borrow_Out --
4964 ----------------------------------
4966 function Set_Perm_Prefixes_Borrow_Out
4967 (N : Node_Id)
4968 return Perm_Tree_Access
4970 begin
4971 pragma Assert (Current_Checking_Mode = Borrow_Out);
4973 case Nkind (N) is
4974 -- Base identifier. Set permission to No.
4976 when N_Identifier
4977 | N_Expanded_Name
4979 declare
4980 P : constant Node_Id := Entity (N);
4982 C : constant Perm_Tree_Access :=
4983 Get (Current_Perm_Env, Unique_Entity (P));
4985 pragma Assert (C /= null);
4987 begin
4988 -- Setting the initialization map to True, so that this
4989 -- variable cannot be ignored anymore when looking at end
4990 -- of elaboration of package.
4992 Set (Current_Initialization_Map, Unique_Entity (P), True);
4994 C.all.Tree.Permission := No_Access;
4995 return C;
4996 end;
4998 when N_Type_Conversion
4999 | N_Unchecked_Type_Conversion
5000 | N_Qualified_Expression
5002 return Set_Perm_Prefixes_Borrow_Out (Expression (N));
5004 when N_Parameter_Specification
5005 | N_Defining_Identifier
5007 raise Program_Error;
5009 -- We set the permission tree of its prefix, and then we extract
5010 -- our subtree from the returned pointer and assign an adequate
5011 -- permission to it, if unfolded. If folded, we unroll the tree
5012 -- in one step.
5014 when N_Selected_Component =>
5015 declare
5016 C : constant Perm_Tree_Access :=
5017 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5019 begin
5020 if C = null then
5021 -- We went through a function call, do nothing
5023 return null;
5024 end if;
5026 -- The permission of the returned node should be No
5028 pragma Assert (Permission (C) = No_Access);
5030 pragma Assert (Kind (C) = Entire_Object
5031 or else Kind (C) = Record_Component);
5033 if Kind (C) = Record_Component then
5034 -- The tree is unfolded. We just modify the permission and
5035 -- return the record subtree.
5037 declare
5038 Selected_Component : constant Entity_Id :=
5039 Entity (Selector_Name (N));
5041 Selected_C : Perm_Tree_Access :=
5042 Perm_Tree_Maps.Get
5043 (Component (C), Selected_Component);
5045 begin
5046 if Selected_C = null then
5047 Selected_C := Other_Components (C);
5048 end if;
5050 pragma Assert (Selected_C /= null);
5052 Selected_C.all.Tree.Permission := No_Access;
5054 return Selected_C;
5055 end;
5056 elsif Kind (C) = Entire_Object then
5057 declare
5058 -- Expand the tree. Replace the node with
5059 -- Record_Component.
5061 Elem : Node_Id;
5063 -- Create an empty hash table
5065 Hashtbl : Perm_Tree_Maps.Instance;
5067 -- We create the unrolled nodes, that will all have same
5068 -- permission than parent.
5070 Son : Perm_Tree_Access;
5072 ChildrenPerm : constant Perm_Kind :=
5073 Children_Permission (C);
5075 begin
5076 -- We change the current node from Entire_Object to
5077 -- Record_Component with same permission and an empty
5078 -- hash table as component list.
5080 C.all.Tree :=
5081 (Kind => Record_Component,
5082 Is_Node_Deep => Is_Node_Deep (C),
5083 Permission => Permission (C),
5084 Component => Hashtbl,
5085 Other_Components =>
5086 new Perm_Tree_Wrapper'
5087 (Tree =>
5088 (Kind => Entire_Object,
5089 Is_Node_Deep => True,
5090 Permission => ChildrenPerm,
5091 Children_Permission => ChildrenPerm)
5094 -- We fill the hash table with all sons of the record,
5095 -- with basic Entire_Objects nodes.
5096 Elem := First_Component_Or_Discriminant
5097 (Etype (Prefix (N)));
5099 while Present (Elem) loop
5100 Son := new Perm_Tree_Wrapper'
5101 (Tree =>
5102 (Kind => Entire_Object,
5103 Is_Node_Deep => Is_Deep (Etype (Elem)),
5104 Permission => ChildrenPerm,
5105 Children_Permission => ChildrenPerm));
5107 Perm_Tree_Maps.Set
5108 (C.all.Tree.Component, Elem, Son);
5110 Next_Component_Or_Discriminant (Elem);
5111 end loop;
5113 -- Now we set the right field to No_Access, and then we
5114 -- return the tree to the sons, so that the recursion can
5115 -- continue.
5117 declare
5118 Selected_Component : constant Entity_Id :=
5119 Entity (Selector_Name (N));
5121 Selected_C : Perm_Tree_Access :=
5122 Perm_Tree_Maps.Get
5123 (Component (C), Selected_Component);
5125 begin
5126 if Selected_C = null then
5127 Selected_C := Other_Components (C);
5128 end if;
5130 pragma Assert (Selected_C /= null);
5132 Selected_C.all.Tree.Permission := No_Access;
5134 return Selected_C;
5135 end;
5136 end;
5137 else
5138 raise Program_Error;
5139 end if;
5140 end;
5142 -- We set the permission tree of its prefix, and then we extract
5143 -- from the returned pointer the subtree and assign an adequate
5144 -- permission to it, if unfolded. If folded, we unroll the tree in
5145 -- one step.
5147 when N_Indexed_Component
5148 | N_Slice
5150 declare
5151 C : constant Perm_Tree_Access :=
5152 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5154 begin
5155 if C = null then
5156 -- We went through a function call, do nothing
5158 return null;
5159 end if;
5161 -- The permission of the returned node should be either W
5162 -- (because the recursive call sets <= Write_Only) or No
5163 -- (if another path has been moved with 'Access).
5165 pragma Assert (Permission (C) = No_Access);
5167 pragma Assert (Kind (C) = Entire_Object
5168 or else Kind (C) = Array_Component);
5170 if Kind (C) = Array_Component then
5171 -- The tree is unfolded. We just modify the permission and
5172 -- return the elem subtree.
5174 pragma Assert (Get_Elem (C) /= null);
5176 C.all.Tree.Get_Elem.all.Tree.Permission := No_Access;
5178 return Get_Elem (C);
5179 elsif Kind (C) = Entire_Object then
5180 declare
5181 -- Expand the tree. Replace node with Array_Component.
5183 Son : Perm_Tree_Access;
5185 begin
5186 Son := new Perm_Tree_Wrapper'
5187 (Tree =>
5188 (Kind => Entire_Object,
5189 Is_Node_Deep => Is_Node_Deep (C),
5190 Permission => No_Access,
5191 Children_Permission => Children_Permission (C)));
5193 -- We change the current node from Entire_Object
5194 -- to Array_Component with same permission and the
5195 -- previously defined son.
5197 C.all.Tree := (Kind => Array_Component,
5198 Is_Node_Deep => Is_Node_Deep (C),
5199 Permission => No_Access,
5200 Get_Elem => Son);
5202 return Get_Elem (C);
5203 end;
5204 else
5205 raise Program_Error;
5206 end if;
5207 end;
5209 -- We set the permission tree of its prefix, and then we extract
5210 -- from the returned pointer the subtree and assign an adequate
5211 -- permission to it, if unfolded. If folded, we unroll the tree
5212 -- at one step.
5214 when N_Explicit_Dereference =>
5215 declare
5216 C : constant Perm_Tree_Access :=
5217 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5219 begin
5220 if C = null then
5221 -- We went through a function call. Do nothing.
5223 return null;
5224 end if;
5226 -- The permission of the returned node should be No
5228 pragma Assert (Permission (C) = No_Access);
5229 pragma Assert (Kind (C) = Entire_Object
5230 or else Kind (C) = Reference);
5232 if Kind (C) = Reference then
5233 -- The tree is unfolded. We just modify the permission and
5234 -- return the elem subtree.
5236 pragma Assert (Get_All (C) /= null);
5238 C.all.Tree.Get_All.all.Tree.Permission := No_Access;
5240 return Get_All (C);
5241 elsif Kind (C) = Entire_Object then
5242 declare
5243 -- Expand the tree. Replace the node with Reference.
5245 Son : Perm_Tree_Access;
5247 begin
5248 Son := new Perm_Tree_Wrapper'
5249 (Tree =>
5250 (Kind => Entire_Object,
5251 Is_Node_Deep => Is_Deep (Etype (N)),
5252 Permission => No_Access,
5253 Children_Permission => Children_Permission (C)));
5255 -- We change the current node from Entire_Object to
5256 -- Reference with No_Access and the previous son.
5258 pragma Assert (Is_Node_Deep (C));
5260 C.all.Tree := (Kind => Reference,
5261 Is_Node_Deep => Is_Node_Deep (C),
5262 Permission => No_Access,
5263 Get_All => Son);
5265 return Get_All (C);
5266 end;
5267 else
5268 raise Program_Error;
5269 end if;
5270 end;
5272 when N_Function_Call =>
5273 return null;
5275 when others =>
5276 raise Program_Error;
5277 end case;
5278 end Set_Perm_Prefixes_Borrow_Out;
5280 ----------------------------
5281 -- Set_Perm_Prefixes_Move --
5282 ----------------------------
5284 function Set_Perm_Prefixes_Move
5285 (N : Node_Id; Mode : Checking_Mode)
5286 return Perm_Tree_Access
5288 begin
5289 case Nkind (N) is
5291 -- Base identifier. Set permission to W or No depending on Mode.
5293 when N_Identifier
5294 | N_Expanded_Name
5296 declare
5297 P : constant Node_Id := Entity (N);
5298 C : constant Perm_Tree_Access :=
5299 Get (Current_Perm_Env, Unique_Entity (P));
5301 begin
5302 -- The base tree can be RW (first move from this base path) or
5303 -- W (already some extensions values moved), or even No_Access
5304 -- (extensions moved with 'Access). But it cannot be Read_Only
5305 -- (we get an error).
5307 if Permission (C) = Read_Only then
5308 raise Unrecoverable_Error;
5309 end if;
5311 -- Setting the initialization map to True, so that this
5312 -- variable cannot be ignored anymore when looking at end
5313 -- of elaboration of package.
5315 Set (Current_Initialization_Map, Unique_Entity (P), True);
5317 if C = null then
5318 -- No null possible here, there are no parents for the path.
5319 -- This means we are using a global variable without adding
5320 -- it in environment with a global aspect.
5322 Illegal_Global_Usage (N);
5323 end if;
5325 if Mode = Super_Move then
5326 C.all.Tree.Permission := No_Access;
5327 else
5328 C.all.Tree.Permission := Glb (Write_Only, Permission (C));
5329 end if;
5331 return C;
5332 end;
5334 when N_Type_Conversion
5335 | N_Unchecked_Type_Conversion
5336 | N_Qualified_Expression
5338 return Set_Perm_Prefixes_Move (Expression (N), Mode);
5340 when N_Parameter_Specification
5341 | N_Defining_Identifier
5343 raise Program_Error;
5345 -- We set the permission tree of its prefix, and then we extract
5346 -- from the returned pointer our subtree and assign an adequate
5347 -- permission to it, if unfolded. If folded, we unroll the tree
5348 -- at one step.
5350 when N_Selected_Component =>
5351 declare
5352 C : constant Perm_Tree_Access :=
5353 Set_Perm_Prefixes_Move (Prefix (N), Mode);
5355 begin
5356 if C = null then
5357 -- We went through a function call, do nothing
5359 return null;
5360 end if;
5362 -- The permission of the returned node should be either W
5363 -- (because the recursive call sets <= Write_Only) or No
5364 -- (if another path has been moved with 'Access).
5366 pragma Assert (Permission (C) = No_Access
5367 or else Permission (C) = Write_Only);
5369 if Mode = Super_Move then
5370 -- The permission of the returned node should be No (thanks
5371 -- to the recursion).
5373 pragma Assert (Permission (C) = No_Access);
5374 null;
5375 end if;
5377 pragma Assert (Kind (C) = Entire_Object
5378 or else Kind (C) = Record_Component);
5380 if Kind (C) = Record_Component then
5381 -- The tree is unfolded. We just modify the permission and
5382 -- return the record subtree.
5384 declare
5385 Selected_Component : constant Entity_Id :=
5386 Entity (Selector_Name (N));
5388 Selected_C : Perm_Tree_Access :=
5389 Perm_Tree_Maps.Get
5390 (Component (C), Selected_Component);
5392 begin
5393 if Selected_C = null then
5394 -- If the hash table returns no element, then we fall
5395 -- into the part of Other_Components.
5396 pragma Assert (Is_Tagged_Type (Etype (Prefix (N))));
5398 Selected_C := Other_Components (C);
5399 end if;
5401 pragma Assert (Selected_C /= null);
5403 -- The Selected_C can have permissions:
5404 -- RW : first move in this path
5405 -- W : Already other moves in this path
5406 -- No : Already other moves with 'Access
5408 pragma Assert (Permission (Selected_C) /= Read_Only);
5409 if Mode = Super_Move then
5410 Selected_C.all.Tree.Permission := No_Access;
5411 else
5412 Selected_C.all.Tree.Permission :=
5413 Glb (Write_Only, Permission (Selected_C));
5415 end if;
5417 return Selected_C;
5418 end;
5419 elsif Kind (C) = Entire_Object then
5420 declare
5421 -- Expand the tree. Replace the node with
5422 -- Record_Component.
5424 Elem : Node_Id;
5426 -- Create an empty hash table
5428 Hashtbl : Perm_Tree_Maps.Instance;
5430 -- We are in Move or Super_Move mode, hence we can assume
5431 -- that the Children_permission is RW, given that there
5432 -- are no other paths that could have been moved.
5434 pragma Assert (Children_Permission (C) = Read_Write);
5436 -- We create the unrolled nodes, that will all have RW
5437 -- permission given that we are in move mode. We will
5438 -- then set the right node to W.
5440 Son : Perm_Tree_Access;
5442 begin
5443 -- We change the current node from Entire_Object to
5444 -- Record_Component with same permission and an empty
5445 -- hash table as component list.
5447 C.all.Tree :=
5448 (Kind => Record_Component,
5449 Is_Node_Deep => Is_Node_Deep (C),
5450 Permission => Permission (C),
5451 Component => Hashtbl,
5452 Other_Components =>
5453 new Perm_Tree_Wrapper'
5454 (Tree =>
5455 (Kind => Entire_Object,
5456 Is_Node_Deep => True,
5457 Permission => Read_Write,
5458 Children_Permission => Read_Write)
5461 -- We fill the hash table with all sons of the record,
5462 -- with basic Entire_Objects nodes.
5463 Elem := First_Component_Or_Discriminant
5464 (Etype (Prefix (N)));
5466 while Present (Elem) loop
5467 Son := new Perm_Tree_Wrapper'
5468 (Tree =>
5469 (Kind => Entire_Object,
5470 Is_Node_Deep => Is_Deep (Etype (Elem)),
5471 Permission => Read_Write,
5472 Children_Permission => Read_Write));
5474 Perm_Tree_Maps.Set
5475 (C.all.Tree.Component, Elem, Son);
5477 Next_Component_Or_Discriminant (Elem);
5478 end loop;
5480 -- Now we set the right field to Write_Only or No_Access
5481 -- depending on mode, and then we return the tree to the
5482 -- sons, so that the recursion can continue.
5484 declare
5485 Selected_Component : constant Entity_Id :=
5486 Entity (Selector_Name (N));
5488 Selected_C : Perm_Tree_Access :=
5489 Perm_Tree_Maps.Get
5490 (Component (C), Selected_Component);
5492 begin
5493 if Selected_C = null then
5494 Selected_C := Other_Components (C);
5495 end if;
5497 pragma Assert (Selected_C /= null);
5499 -- Given that this is a newly created Select_C, we can
5500 -- safely assume that its permission is Read_Write.
5502 pragma Assert (Permission (Selected_C) =
5503 Read_Write);
5505 if Mode = Super_Move then
5506 Selected_C.all.Tree.Permission := No_Access;
5507 else
5508 Selected_C.all.Tree.Permission := Write_Only;
5509 end if;
5511 return Selected_C;
5512 end;
5513 end;
5514 else
5515 raise Program_Error;
5516 end if;
5517 end;
5519 -- We set the permission tree of its prefix, and then we extract
5520 -- from the returned pointer the subtree and assign an adequate
5521 -- permission to it, if unfolded. If folded, we unroll the tree
5522 -- at one step.
5524 when N_Indexed_Component
5525 | N_Slice
5527 declare
5528 C : constant Perm_Tree_Access :=
5529 Set_Perm_Prefixes_Move (Prefix (N), Mode);
5531 begin
5532 if C = null then
5533 -- We went through a function call, do nothing
5535 return null;
5536 end if;
5538 -- The permission of the returned node should be either
5539 -- W (because the recursive call sets <= Write_Only)
5540 -- or No (if another path has been moved with 'Access)
5542 if Mode = Super_Move then
5543 pragma Assert (Permission (C) = No_Access);
5544 null;
5545 else
5546 pragma Assert (Permission (C) = Write_Only
5547 or else Permission (C) = No_Access);
5548 null;
5549 end if;
5551 pragma Assert (Kind (C) = Entire_Object
5552 or else Kind (C) = Array_Component);
5554 if Kind (C) = Array_Component then
5555 -- The tree is unfolded. We just modify the permission and
5556 -- return the elem subtree.
5558 if Get_Elem (C) = null then
5559 -- Hash_Table_Error
5560 raise Program_Error;
5561 end if;
5563 -- The Get_Elem can have permissions :
5564 -- RW : first move in this path
5565 -- W : Already other moves in this path
5566 -- No : Already other moves with 'Access
5568 pragma Assert (Permission (Get_Elem (C)) /= Read_Only);
5570 if Mode = Super_Move then
5571 C.all.Tree.Get_Elem.all.Tree.Permission := No_Access;
5572 else
5573 C.all.Tree.Get_Elem.all.Tree.Permission :=
5574 Glb (Write_Only, Permission (Get_Elem (C)));
5575 end if;
5577 return Get_Elem (C);
5578 elsif Kind (C) = Entire_Object then
5579 declare
5580 -- Expand the tree. Replace node with Array_Component.
5582 -- We are in move mode, hence we can assume that the
5583 -- Children_permission is RW.
5585 pragma Assert (Children_Permission (C) = Read_Write);
5587 Son : Perm_Tree_Access;
5589 begin
5590 Son := new Perm_Tree_Wrapper'
5591 (Tree =>
5592 (Kind => Entire_Object,
5593 Is_Node_Deep => Is_Node_Deep (C),
5594 Permission => Read_Write,
5595 Children_Permission => Read_Write));
5597 if Mode = Super_Move then
5598 Son.all.Tree.Permission := No_Access;
5599 else
5600 Son.all.Tree.Permission := Write_Only;
5601 end if;
5603 -- We change the current node from Entire_Object
5604 -- to Array_Component with same permission and the
5605 -- previously defined son.
5607 C.all.Tree := (Kind => Array_Component,
5608 Is_Node_Deep => Is_Node_Deep (C),
5609 Permission => Permission (C),
5610 Get_Elem => Son);
5612 return Get_Elem (C);
5613 end;
5614 else
5615 raise Program_Error;
5616 end if;
5617 end;
5619 -- We set the permission tree of its prefix, and then we extract
5620 -- from the returned pointer the subtree and assign an adequate
5621 -- permission to it, if unfolded. If folded, we unroll the tree
5622 -- at one step.
5624 when N_Explicit_Dereference =>
5625 declare
5626 C : constant Perm_Tree_Access :=
5627 Set_Perm_Prefixes_Move (Prefix (N), Move);
5629 begin
5630 if C = null then
5631 -- We went through a function call: do nothing
5633 return null;
5634 end if;
5636 -- The permission of the returned node should be only
5637 -- W (because the recursive call sets <= Write_Only)
5638 -- No is NOT POSSIBLE here
5640 pragma Assert (Permission (C) = Write_Only);
5642 pragma Assert (Kind (C) = Entire_Object
5643 or else Kind (C) = Reference);
5645 if Kind (C) = Reference then
5646 -- The tree is unfolded. We just modify the permission and
5647 -- return the elem subtree.
5649 if Get_All (C) = null then
5650 -- Hash_Table_Error
5651 raise Program_Error;
5652 end if;
5654 -- The Get_All can have permissions :
5655 -- RW : first move in this path
5656 -- W : Already other moves in this path
5657 -- No : Already other moves with 'Access
5659 pragma Assert (Permission (Get_All (C)) /= Read_Only);
5661 if Mode = Super_Move then
5662 C.all.Tree.Get_All.all.Tree.Permission := No_Access;
5663 else
5664 Get_All (C).all.Tree.Permission :=
5665 Glb (Write_Only, Permission (Get_All (C)));
5666 end if;
5667 return Get_All (C);
5668 elsif Kind (C) = Entire_Object then
5669 declare
5670 -- Expand the tree. Replace the node with Reference.
5672 -- We are in Move or Super_Move mode, hence we can assume
5673 -- that the Children_permission is RW.
5675 pragma Assert (Children_Permission (C) = Read_Write);
5677 Son : Perm_Tree_Access;
5679 begin
5680 Son := new Perm_Tree_Wrapper'
5681 (Tree =>
5682 (Kind => Entire_Object,
5683 Is_Node_Deep => Is_Deep (Etype (N)),
5684 Permission => Read_Write,
5685 Children_Permission => Read_Write));
5687 if Mode = Super_Move then
5688 Son.all.Tree.Permission := No_Access;
5689 else
5690 Son.all.Tree.Permission := Write_Only;
5691 end if;
5693 -- We change the current node from Entire_Object to
5694 -- Reference with Write_Only and the previous son.
5696 pragma Assert (Is_Node_Deep (C));
5698 C.all.Tree := (Kind => Reference,
5699 Is_Node_Deep => Is_Node_Deep (C),
5700 Permission => Write_Only,
5701 -- Write_only is equal to C.Permission
5702 Get_All => Son);
5704 return Get_All (C);
5705 end;
5706 else
5707 raise Program_Error;
5708 end if;
5709 end;
5711 when N_Function_Call =>
5712 return null;
5714 when others =>
5715 raise Program_Error;
5716 end case;
5718 end Set_Perm_Prefixes_Move;
5720 -------------------------------
5721 -- Set_Perm_Prefixes_Observe --
5722 -------------------------------
5724 function Set_Perm_Prefixes_Observe
5725 (N : Node_Id)
5726 return Perm_Tree_Access
5728 begin
5729 pragma Assert (Current_Checking_Mode = Observe);
5731 case Nkind (N) is
5732 -- Base identifier. Set permission to R.
5734 when N_Identifier
5735 | N_Expanded_Name
5736 | N_Defining_Identifier
5738 declare
5739 P : Node_Id;
5740 C : Perm_Tree_Access;
5742 begin
5743 if Nkind (N) = N_Defining_Identifier then
5744 P := N;
5745 else
5746 P := Entity (N);
5747 end if;
5749 C := Get (Current_Perm_Env, Unique_Entity (P));
5750 -- Setting the initialization map to True, so that this
5751 -- variable cannot be ignored anymore when looking at end
5752 -- of elaboration of package.
5754 Set (Current_Initialization_Map, Unique_Entity (P), True);
5756 if C = null then
5757 -- No null possible here, there are no parents for the path.
5758 -- This means we are using a global variable without adding
5759 -- it in environment with a global aspect.
5761 Illegal_Global_Usage (N);
5762 end if;
5764 C.all.Tree.Permission := Glb (Read_Only, Permission (C));
5766 return C;
5767 end;
5769 when N_Type_Conversion
5770 | N_Unchecked_Type_Conversion
5771 | N_Qualified_Expression
5773 return Set_Perm_Prefixes_Observe (Expression (N));
5775 when N_Parameter_Specification =>
5776 raise Program_Error;
5778 -- We set the permission tree of its prefix, and then we extract
5779 -- from the returned pointer our subtree and assign an adequate
5780 -- permission to it, if unfolded. If folded, we unroll the tree
5781 -- at one step.
5783 when N_Selected_Component =>
5784 declare
5785 C : constant Perm_Tree_Access :=
5786 Set_Perm_Prefixes_Observe (Prefix (N));
5788 begin
5789 if C = null then
5790 -- We went through a function call, do nothing
5792 return null;
5793 end if;
5795 pragma Assert (Kind (C) = Entire_Object
5796 or else Kind (C) = Record_Component);
5798 if Kind (C) = Record_Component then
5799 -- The tree is unfolded. We just modify the permission and
5800 -- return the record subtree. We put the permission to the
5801 -- glb of read_only and its current permission, to consider
5802 -- the case of observing x.y while x.z has been moved. Then
5803 -- x should be No_Access.
5805 declare
5806 Selected_Component : constant Entity_Id :=
5807 Entity (Selector_Name (N));
5809 Selected_C : Perm_Tree_Access :=
5810 Perm_Tree_Maps.Get
5811 (Component (C), Selected_Component);
5813 begin
5814 if Selected_C = null then
5815 Selected_C := Other_Components (C);
5816 end if;
5818 pragma Assert (Selected_C /= null);
5820 Selected_C.all.Tree.Permission :=
5821 Glb (Read_Only, Permission (Selected_C));
5823 return Selected_C;
5824 end;
5825 elsif Kind (C) = Entire_Object then
5826 declare
5827 -- Expand the tree. Replace the node with
5828 -- Record_Component.
5830 Elem : Node_Id;
5832 -- Create an empty hash table
5834 Hashtbl : Perm_Tree_Maps.Instance;
5836 -- We create the unrolled nodes, that will all have RW
5837 -- permission given that we are in move mode. We will
5838 -- then set the right node to W.
5840 Son : Perm_Tree_Access;
5842 Child_Perm : constant Perm_Kind :=
5843 Children_Permission (C);
5845 begin
5846 -- We change the current node from Entire_Object to
5847 -- Record_Component with same permission and an empty
5848 -- hash table as component list.
5850 C.all.Tree :=
5851 (Kind => Record_Component,
5852 Is_Node_Deep => Is_Node_Deep (C),
5853 Permission => Permission (C),
5854 Component => Hashtbl,
5855 Other_Components =>
5856 new Perm_Tree_Wrapper'
5857 (Tree =>
5858 (Kind => Entire_Object,
5859 Is_Node_Deep => True,
5860 Permission => Child_Perm,
5861 Children_Permission => Child_Perm)
5864 -- We fill the hash table with all sons of the record,
5865 -- with basic Entire_Objects nodes.
5866 Elem := First_Component_Or_Discriminant
5867 (Etype (Prefix (N)));
5869 while Present (Elem) loop
5870 Son := new Perm_Tree_Wrapper'
5871 (Tree =>
5872 (Kind => Entire_Object,
5873 Is_Node_Deep => Is_Deep (Etype (Elem)),
5874 Permission => Child_Perm,
5875 Children_Permission => Child_Perm));
5877 Perm_Tree_Maps.Set
5878 (C.all.Tree.Component, Elem, Son);
5880 Next_Component_Or_Discriminant (Elem);
5881 end loop;
5883 -- Now we set the right field to Read_Only. and then we
5884 -- return the tree to the sons, so that the recursion can
5885 -- continue.
5887 declare
5888 Selected_Component : constant Entity_Id :=
5889 Entity (Selector_Name (N));
5891 Selected_C : Perm_Tree_Access :=
5892 Perm_Tree_Maps.Get
5893 (Component (C), Selected_Component);
5895 begin
5896 if Selected_C = null then
5897 Selected_C := Other_Components (C);
5898 end if;
5900 pragma Assert (Selected_C /= null);
5902 Selected_C.all.Tree.Permission :=
5903 Glb (Read_Only, Child_Perm);
5905 return Selected_C;
5906 end;
5907 end;
5908 else
5909 raise Program_Error;
5910 end if;
5911 end;
5913 -- We set the permission tree of its prefix, and then we extract from
5914 -- the returned pointer the subtree and assign an adequate permission
5915 -- to it, if unfolded. If folded, we unroll the tree at one step.
5917 when N_Indexed_Component
5918 | N_Slice
5920 declare
5921 C : constant Perm_Tree_Access :=
5922 Set_Perm_Prefixes_Observe (Prefix (N));
5924 begin
5925 if C = null then
5926 -- We went through a function call, do nothing
5928 return null;
5929 end if;
5931 pragma Assert (Kind (C) = Entire_Object
5932 or else Kind (C) = Array_Component);
5934 if Kind (C) = Array_Component then
5935 -- The tree is unfolded. We just modify the permission and
5936 -- return the elem subtree.
5938 pragma Assert (Get_Elem (C) /= null);
5940 C.all.Tree.Get_Elem.all.Tree.Permission :=
5941 Glb (Read_Only, Permission (Get_Elem (C)));
5943 return Get_Elem (C);
5944 elsif Kind (C) = Entire_Object then
5945 declare
5946 -- Expand the tree. Replace node with Array_Component.
5948 Son : Perm_Tree_Access;
5950 Child_Perm : constant Perm_Kind :=
5951 Glb (Read_Only, Children_Permission (C));
5953 begin
5954 Son := new Perm_Tree_Wrapper'
5955 (Tree =>
5956 (Kind => Entire_Object,
5957 Is_Node_Deep => Is_Node_Deep (C),
5958 Permission => Child_Perm,
5959 Children_Permission => Child_Perm));
5961 -- We change the current node from Entire_Object
5962 -- to Array_Component with same permission and the
5963 -- previously defined son.
5965 C.all.Tree := (Kind => Array_Component,
5966 Is_Node_Deep => Is_Node_Deep (C),
5967 Permission => Child_Perm,
5968 Get_Elem => Son);
5970 return Get_Elem (C);
5971 end;
5973 else
5974 raise Program_Error;
5975 end if;
5976 end;
5978 -- We set the permission tree of its prefix, and then we extract from
5979 -- the returned pointer the subtree and assign an adequate permission
5980 -- to it, if unfolded. If folded, we unroll the tree at one step.
5982 when N_Explicit_Dereference =>
5983 declare
5984 C : constant Perm_Tree_Access :=
5985 Set_Perm_Prefixes_Observe (Prefix (N));
5987 begin
5988 if C = null then
5989 -- We went through a function call, do nothing
5991 return null;
5992 end if;
5994 pragma Assert (Kind (C) = Entire_Object
5995 or else Kind (C) = Reference);
5997 if Kind (C) = Reference then
5998 -- The tree is unfolded. We just modify the permission and
5999 -- return the elem subtree.
6001 pragma Assert (Get_All (C) /= null);
6003 C.all.Tree.Get_All.all.Tree.Permission :=
6004 Glb (Read_Only, Permission (Get_All (C)));
6006 return Get_All (C);
6007 elsif Kind (C) = Entire_Object then
6008 declare
6009 -- Expand the tree. Replace the node with Reference.
6011 Son : Perm_Tree_Access;
6013 Child_Perm : constant Perm_Kind :=
6014 Glb (Read_Only, Children_Permission (C));
6016 begin
6017 Son := new Perm_Tree_Wrapper'
6018 (Tree =>
6019 (Kind => Entire_Object,
6020 Is_Node_Deep => Is_Deep (Etype (N)),
6021 Permission => Child_Perm,
6022 Children_Permission => Child_Perm));
6024 -- We change the current node from Entire_Object to
6025 -- Reference with Write_Only and the previous son.
6027 pragma Assert (Is_Node_Deep (C));
6029 C.all.Tree := (Kind => Reference,
6030 Is_Node_Deep => Is_Node_Deep (C),
6031 Permission => Child_Perm,
6032 Get_All => Son);
6034 return Get_All (C);
6035 end;
6036 else
6037 raise Program_Error;
6038 end if;
6039 end;
6041 when N_Function_Call =>
6042 return null;
6044 when others =>
6045 raise Program_Error;
6047 end case;
6048 end Set_Perm_Prefixes_Observe;
6050 -------------------
6051 -- Setup_Globals --
6052 -------------------
6054 procedure Setup_Globals (Subp : Entity_Id) is
6056 procedure Setup_Globals_From_List
6057 (First_Item : Node_Id;
6058 Kind : Formal_Kind);
6059 -- Set up global items from the list starting at Item
6061 procedure Setup_Globals_Of_Mode (Global_Mode : Name_Id);
6062 -- Set up global items for the mode Global_Mode
6064 -----------------------------
6065 -- Setup_Globals_From_List --
6066 -----------------------------
6068 procedure Setup_Globals_From_List
6069 (First_Item : Node_Id;
6070 Kind : Formal_Kind)
6072 Item : Node_Id := First_Item;
6073 E : Entity_Id;
6075 begin
6076 while Present (Item) loop
6077 E := Entity (Item);
6079 -- Ignore abstract states, which play no role in pointer aliasing
6081 if Ekind (E) = E_Abstract_State then
6082 null;
6083 else
6084 Setup_Parameter_Or_Global (E, Kind);
6085 end if;
6086 Next_Global (Item);
6087 end loop;
6088 end Setup_Globals_From_List;
6090 ---------------------------
6091 -- Setup_Globals_Of_Mode --
6092 ---------------------------
6094 procedure Setup_Globals_Of_Mode (Global_Mode : Name_Id) is
6095 Kind : Formal_Kind;
6097 begin
6098 case Global_Mode is
6099 when Name_Input | Name_Proof_In =>
6100 Kind := E_In_Parameter;
6101 when Name_Output =>
6102 Kind := E_Out_Parameter;
6103 when Name_In_Out =>
6104 Kind := E_In_Out_Parameter;
6105 when others =>
6106 raise Program_Error;
6107 end case;
6109 -- Set up both global items from Global and Refined_Global pragmas
6111 Setup_Globals_From_List (First_Global (Subp, Global_Mode), Kind);
6112 Setup_Globals_From_List
6113 (First_Global (Subp, Global_Mode, Refined => True), Kind);
6114 end Setup_Globals_Of_Mode;
6116 -- Start of processing for Setup_Globals
6118 begin
6119 Setup_Globals_Of_Mode (Name_Proof_In);
6120 Setup_Globals_Of_Mode (Name_Input);
6121 Setup_Globals_Of_Mode (Name_Output);
6122 Setup_Globals_Of_Mode (Name_In_Out);
6123 end Setup_Globals;
6125 -------------------------------
6126 -- Setup_Parameter_Or_Global --
6127 -------------------------------
6129 procedure Setup_Parameter_Or_Global
6130 (Id : Entity_Id;
6131 Mode : Formal_Kind)
6133 Elem : Perm_Tree_Access;
6135 begin
6136 Elem := new Perm_Tree_Wrapper'
6137 (Tree =>
6138 (Kind => Entire_Object,
6139 Is_Node_Deep => Is_Deep (Etype (Id)),
6140 Permission => Read_Write,
6141 Children_Permission => Read_Write));
6143 case Mode is
6144 when E_In_Parameter =>
6146 -- Borrowed IN: RW for everybody
6148 if Is_Borrowed_In (Id) then
6149 Elem.all.Tree.Permission := Read_Write;
6150 Elem.all.Tree.Children_Permission := Read_Write;
6152 -- Observed IN: R for everybody
6154 else
6155 Elem.all.Tree.Permission := Read_Only;
6156 Elem.all.Tree.Children_Permission := Read_Only;
6157 end if;
6159 -- OUT: borrow, but callee has W only
6161 when E_Out_Parameter =>
6162 Elem.all.Tree.Permission := Write_Only;
6163 Elem.all.Tree.Children_Permission := Write_Only;
6165 -- IN OUT: borrow and callee has RW
6167 when E_In_Out_Parameter =>
6168 Elem.all.Tree.Permission := Read_Write;
6169 Elem.all.Tree.Children_Permission := Read_Write;
6170 end case;
6172 Set (Current_Perm_Env, Id, Elem);
6173 end Setup_Parameter_Or_Global;
6175 ----------------------
6176 -- Setup_Parameters --
6177 ----------------------
6179 procedure Setup_Parameters (Subp : Entity_Id) is
6180 Formal : Entity_Id;
6182 begin
6183 Formal := First_Formal (Subp);
6184 while Present (Formal) loop
6185 Setup_Parameter_Or_Global (Formal, Ekind (Formal));
6186 Next_Formal (Formal);
6187 end loop;
6188 end Setup_Parameters;
6190 end Sem_SPARK;