1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S E M _ S P A R K --
9 -- Copyright (C) 2017, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
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
;
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;
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
74 -- Nodes in the permission tree are of different kinds
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
,
86 Element
=> Perm_Tree_Access
,
88 Hash
=> Elaboration_Context_Hash
,
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
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.
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
134 when Record_Component
=>
135 Component
: Perm_Tree_Maps
.Instance
;
136 Other_Components
: Perm_Tree_Access
;
140 type Perm_Tree_Wrapper
is 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
,
156 Element
=> Perm_Env_Access
,
158 Hash
=> Elaboration_Context_Hash
,
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
168 package Boolean_Variables_Maps
is new Simple_HTable
169 (Header_Num
=> Elaboration_Context_Index
,
173 Hash
=> Elaboration_Context_Hash
,
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
;
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 -----------------------
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
215 (From
: Perm_Tree_Access
;
216 To
: Perm_Tree_Access
);
217 -- Procedure to copy a permission tree
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
231 procedure Perm_Mismatch
232 (Exp_Perm
, Act_Perm
: Perm_Kind
;
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.
240 package body Permissions
is
242 -------------------------
243 -- Children_Permission --
244 -------------------------
246 function Children_Permission
247 (T
: Perm_Tree_Access
)
251 return T
.all.Tree
.Children_Permission
;
252 end Children_Permission
;
259 (T
: Perm_Tree_Access
)
260 return Perm_Tree_Maps
.Instance
263 return T
.all.Tree
.Component
;
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
;
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
);
297 procedure Copy_Init_Map
298 (From
: Initialization_Map
;
299 To
: in out Initialization_Map
)
302 Key_From
: Boolean_Variables_Maps
.Key_Option
;
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
);
319 (From
: Perm_Tree_Access
;
320 To
: Perm_Tree_Access
)
326 when Entire_Object
=>
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
=>
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
;
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
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);
367 (To.all.Tree.Component, Key_From.K, Son);
369 Key_From := Perm_Tree_Maps.Get_Next_Key
376 ------------------------------
377 -- Elaboration_Context_Hash --
378 ------------------------------
380 function Elaboration_Context_Hash
381 (Key : Entity_Id) return Elaboration_Context_Index
384 return Elaboration_Context_Index (Key mod Elaboration_Context_Max);
385 end Elaboration_Context_Hash;
391 procedure Free_Env (PE : in out Perm_Env) is
392 CompO : Perm_Tree_Access;
394 CompO := Get_First (PE);
395 while CompO /= null loop
396 Free_Perm_Tree (CompO);
397 CompO := Get_Next (PE);
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
415 when Entire_Object =>
416 Free_Perm_Tree_Dealloc (PT);
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 =>
427 Comp : Perm_Tree_Access;
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));
439 Free_Perm_Tree_Dealloc (PT);
448 (T : Perm_Tree_Access)
449 return Perm_Tree_Access
452 return T.all.Tree.Get_All;
460 (T : Perm_Tree_Access)
461 return Perm_Tree_Access
464 return T.all.Tree.Get_Elem;
471 function Is_Node_Deep
472 (T : Perm_Tree_Access)
476 return T.all.Tree.Is_Node_Deep;
484 (T : Perm_Tree_Access)
488 return T.all.Tree.Kind;
491 ----------------------
492 -- Other_Components --
493 ----------------------
495 function Other_Components
496 (T : Perm_Tree_Access)
497 return Perm_Tree_Access
500 return T.all.Tree.Other_Components;
501 end Other_Components;
508 (T : Perm_Tree_Access)
512 return T.all.Tree.Permission;
519 procedure Perm_Mismatch
520 (Exp_Perm, Act_Perm : Perm_Kind;
524 Error_Msg_N ("\expected at least `"
525 & Perm_Kind'Image (Exp_Perm) & "`, got `"
526 & Perm_Kind'Image (Act_Perm) & "`", N);
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
543 -- Default mode. Checks that paths have Read_Perm permission.
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.
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.
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.
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.
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
585 when Folded
=> Found_Permission
: Perm_Kind
;
586 when Unfolded
=> Tree_Access
: Perm_Tree_Access
;
587 when Function_Call
=> null;
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
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
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
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.
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
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
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
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
752 procedure Return_Parameter_Or_Global
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
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
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
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
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.
865 function "<=" (P1
, P2
: Perm_Kind
) return Boolean
875 function ">=" (P1
, P2
: Perm_Kind
) return Boolean
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
;
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
);
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
,
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
),
924 Iterate_Call_Outs
(Call
);
925 Check_Globals
(Get_Pragma
926 (Get_Called_Entity
(Call
), Pragma_Global
),
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
937 Free_Env
(Current_Perm_Env
);
942 Free_Env
(Saved_Env
);
944 -- We assign the out parameters (necessarily borrowed per RM)
945 Current_Checking_Mode
:= Assign
;
947 Check_Globals
(Get_Pragma
948 (Get_Called_Entity
(Call
), Pragma_Global
),
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
;
966 Body_Id
: constant Entity_Id
:= Defining_Entity
(Body_N
);
967 Spec_Id
: constant Entity_Id
:= Unique_Entity
(Body_Id
);
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
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
);
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
)
1010 Return_Parameters
(Spec_Id
);
1011 Return_Globals
(Spec_Id
);
1014 -- Free the environments
1016 Free_Env
(Current_Perm_Env
);
1018 Copy_Env
(Saved_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
1040 case N_Declaration
'(Nkind (Decl)) is
1041 when N_Full_Type_Declaration =>
1042 -- Nothing to do here ??? NOT TRUE IF CONSTRAINT ON TYPE
1045 when N_Object_Declaration =>
1046 -- First move the right-hand side
1047 Current_Checking_Mode := Move;
1048 Check_Node (Expression (Decl));
1051 Elem : Perm_Tree_Access;
1054 Elem := new Perm_Tree_Wrapper'
1056 (Kind
=> Entire_Object
,
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
)))
1070 Elem
.all.Tree
.Permission
:= Write_Only
;
1071 Elem
.all.Tree
.Children_Permission
:= Write_Only
;
1074 -- Create new tree for defining identifier
1076 Set
(Current_Perm_Env
,
1077 Unique_Entity
(Defining_Identifier
(Decl
)),
1080 pragma Assert
(Get_First
(Current_Perm_Env
)
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
))));
1092 when N_Loop_Parameter_Specification
=>
1093 pragma Assert
(Is_Shallow
(Etype
(Defining_Identifier
(Decl
))));
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
1116 -- The following nodes are rewritten by semantic analysis
1118 when N_Expression_Function
=>
1119 raise Program_Error
;
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
;
1130 case N_Subexpr
'(Nkind (Expr)) is
1131 when N_Procedure_Call_Statement =>
1132 Check_Call_Statement (Expr);
1137 -- Check if identifier is pointing to nothing (On/Off/...)
1138 if not Present (Entity (Expr)) then
1142 -- Do not analyze things that are not of object Kind
1143 if Ekind (Entity (Expr)) not in Object_Kind then
1147 -- Consider as ident
1148 Process_Path (Expr);
1150 -- Switch to read mode and then check the readability of each operand
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
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
1174 case Current_Checking_Mode is
1176 Check_Node (Prefix (Expr));
1179 Current_Checking_Mode := Super_Move;
1180 Check_Node (Prefix (Expr));
1182 -- Only assign names, not expressions
1185 raise Program_Error;
1187 -- Prefix in Super_Move should be a name, error here
1190 raise Program_Error;
1192 -- Could only borrow names of mode out, not n'Access
1195 raise Program_Error;
1198 Check_Node (Prefix (Expr));
1204 Current_Checking_Mode := Read;
1205 Check_Node (Prefix (Expr));
1208 Current_Checking_Mode := Read;
1209 Check_Node (Prefix (Expr));
1212 Check_Node (Prefix (Expr));
1214 when Name_SPARK_Mode =>
1218 Current_Checking_Mode := Read;
1219 Check_Node (Prefix (Expr));
1222 Check_List (Expressions (Expr));
1223 Check_Node (Prefix (Expr));
1228 Check_List (Expressions (Expr));
1229 Check_Node (Prefix (Expr));
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
1242 | Name_Component_Size
1250 -- Attributes referring to types (get values from types), hence
1251 -- no need to check either for borrows or any loans.
1258 -- Other attributes that fall out of the scope of the analysis
1265 Current_Checking_Mode := Read;
1266 Check_Node (Left_Opnd (Expr));
1267 Check_Node (Right_Opnd (Expr));
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
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 =>
1297 Saved_Env : Perm_Env;
1299 -- Accumulator for the different branches
1303 Elmt : Node_Id := First (Expressions (Expr));
1306 Current_Checking_Mode := Read;
1310 Current_Checking_Mode := Mode_Before;
1314 Copy_Env (Current_Perm_Env,
1317 -- Here we have the original env in saved, current with a fresh
1318 -- copy, and new aliased.
1325 -- Here the new_environment contains curr env after then block
1329 -- Restore environment before if
1330 Copy_Env (Current_Perm_Env,
1333 Free_Env (Current_Perm_Env);
1335 Copy_Env (Saved_Env,
1338 -- Here new environment contains the environment after then and
1339 -- current the fresh copy of old one.
1344 Merge_Envs (New_Env,
1353 Free_Env (Saved_Env);
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 =>
1366 Saved_Env : Perm_Env;
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);
1379 -- Analyze the list of associations in the aggregate
1382 Check_List (Expressions (Expr));
1383 Check_List (Component_Associations (Expr));
1386 Check_Node (Expression (Expr));
1388 when N_Case_Expression =>
1390 Saved_Env : Perm_Env;
1392 -- Accumulator for the different branches
1396 Elmt : Node_Id := First (Alternatives (Expr));
1399 Current_Checking_Mode := Read;
1400 Check_Node (Expression (Expr));
1402 Current_Checking_Mode := Mode_Before;
1406 Copy_Env (Current_Perm_Env,
1409 -- Here we have the original env in saved, current with a fresh
1410 -- copy, and new aliased.
1412 -- First alternative
1417 Copy_Env (Current_Perm_Env,
1420 Free_Env (Current_Perm_Env);
1422 -- Other alternatives
1424 while Present (Elmt) loop
1425 -- Restore environment
1427 Copy_Env (Saved_Env,
1432 -- Merge Current_Perm_Env into New_Env
1434 Merge_Envs (New_Env,
1445 Free_Env (Saved_Env);
1448 -- Analyze the list of associates in the aggregate as well as the
1451 when N_Extension_Aggregate =>
1453 Check_Node (Ancestor_Part (Expr));
1454 Check_List (Expressions (Expr));
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);
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
1488 | N_Numeric_Or_String_Literal
1490 | N_Raise_Expression
1495 -- The following nodes are never generated in GNATprove mode
1497 when N_Expression_With_Actions
1499 | N_Unchecked_Expression
1501 raise Program_Error;
1504 end Check_Expression;
1510 procedure Check_Globals (N : Node_Id; Check_Mode : Checking_Mode) is
1512 if Nkind (N) = N_Empty then
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);
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;
1540 if Ekind (Ident_Elt) = E_Abstract_State then
1550 Check_Node (The_Global);
1558 raise Program_Error;
1567 if not Is_Borrowed_In (Ident_Elt) then
1570 Current_Checking_Mode := Observe;
1571 Check_Node (The_Global);
1584 Current_Checking_Mode := Borrow_Out;
1585 Check_Node (The_Global);
1597 if Is_Borrowed_In (Ident_Elt) then
1600 Current_Checking_Mode := Move;
1613 Current_Checking_Mode := Move;
1616 raise Program_Error;
1619 Check_Node (The_Global);
1630 -- Borrowed out or in out
1632 Process_Path (The_Global);
1635 raise Program_Error;
1639 raise Program_Error;
1642 Current_Checking_Mode := Mode_Before;
1646 if Nkind (Expression (PAA)) = N_Null then
1648 -- No globals, nothing to do
1651 elsif Nkind_In (Expression (PAA), N_Identifier, N_Expanded_Name) then
1654 Process (Name_Input, Expression (PAA));
1656 elsif Nkind (Expression (PAA)) = N_Aggregate
1657 and then Expressions (Expression (PAA)) /= No_List
1659 -- global => (foo, bar)
1661 RHS := First (Expressions (Expression (PAA)));
1662 while Present (RHS) loop
1667 Process (Name_Input, RHS);
1669 when N_Numeric_Or_String_Literal =>
1670 Process (Name_Input, Original_Node (RHS));
1673 raise Program_Error;
1679 elsif Nkind (Expression (PAA)) = N_Aggregate
1680 and then Component_Associations (Expression (PAA)) /= No_List
1682 -- global => (mode => foo,
1683 -- mode => (bar, baz))
1684 -- A mixture of things
1687 CA : constant List_Id :=
1688 Component_Associations (Expression (PAA));
1691 while Present (Row) loop
1692 pragma Assert (List_Length (Choices (Row)) = 1);
1693 The_Mode := Chars (First (Choices (Row)));
1695 RHS := Expression (Row);
1698 RHS := First (Expressions (RHS));
1699 while Present (RHS) loop
1701 when N_Numeric_Or_String_Literal =>
1702 Process (The_Mode, Original_Node (RHS));
1705 Process (The_Mode, RHS);
1714 Process (The_Mode, RHS);
1719 when N_Numeric_Or_String_Literal =>
1720 Process (The_Mode, Original_Node (RHS));
1723 raise Program_Error;
1732 raise Program_Error;
1741 procedure Check_List (L : List_Id) is
1745 while Present (N) loop
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;
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
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;
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,
1805 Comp_Entry := Get_Next_Key (Entry_Env);
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;
1818 -----------------------
1819 -- Local Subprograms --
1820 -----------------------
1822 procedure Check_Is_Less_Restrictive_Tree_Than
1823 (Tree : Perm_Tree_Access;
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;
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;
1846 if not (Permission (Tree) >= Perm) then
1847 Perm_Error_Loop_Exit
1848 (E, Loop_N, Permission (Tree), Perm);
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);
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 =>
1869 Comp : Perm_Tree_Access;
1871 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1872 while Comp /= null loop
1873 Check_Is_Less_Restrictive_Tree_Than (Comp, Perm, E);
1875 Perm_Tree_Maps.Get_Next (Component (Tree));
1878 Check_Is_Less_Restrictive_Tree_Than
1879 (Other_Components (Tree), Perm, E);
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;
1894 if not (Perm >= Permission (Tree)) then
1895 Perm_Error_Loop_Exit
1896 (E, Loop_N, Permission (Tree), Perm);
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);
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 =>
1916 Comp : Perm_Tree_Access;
1918 Comp := Perm_Tree_Maps.Get_First (Component (Tree));
1919 while Comp /= null loop
1920 Check_Is_More_Restrictive_Tree_Than (Comp, Perm, E);
1922 Perm_Tree_Maps.Get_Next (Component (Tree));
1925 Check_Is_More_Restrictive_Tree_Than
1926 (Other_Components (Tree), Perm, E);
1929 end Check_Is_More_Restrictive_Tree_Than;
1931 -- Start of processing for Check_Is_Less_Restrictive_Tree
1934 if not (Permission (New_Tree) <= Permission (Orig_Tree)) then
1935 Perm_Error_Loop_Exit
1938 Perm => Permission (New_Tree),
1939 Found_Perm => Permission (Orig_Tree));
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))
1956 Perm_Error_Loop_Exit
1958 Children_Permission (New_Tree),
1959 Children_Permission (Orig_Tree));
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 =>
1972 Comp : Perm_Tree_Access;
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));
1983 Check_Is_More_Restrictive_Tree_Than
1984 (Other_Components (Orig_Tree),
1985 Children_Permission (New_Tree), E);
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);
1996 Check_Is_Less_Restrictive_Tree
1997 (Get_All (New_Tree), Get_All (Orig_Tree), E);
2000 raise Program_Error;
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);
2014 raise Program_Error;
2017 when Record_Component =>
2019 CompN : Perm_Tree_Access;
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);
2030 Perm_Tree_Maps.Get_Next (Component (New_Tree));
2033 Check_Is_Less_Restrictive_Tree_Than
2034 (Other_Components (New_Tree),
2035 Children_Permission (Orig_Tree),
2038 when Record_Component =>
2041 KeyO : Perm_Tree_Maps.Key_Option;
2042 CompO : Perm_Tree_Access;
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);
2059 Check_Is_Less_Restrictive_Tree
2060 (Other_Components (New_Tree),
2061 Other_Components (Orig_Tree),
2066 raise Program_Error;
2070 end Check_Is_Less_Restrictive_Tree;
2072 --------------------------
2073 -- Perm_Error_Loop_Exit --
2074 --------------------------
2076 procedure Perm_Error_Loop_Exit
2080 Found_Perm : Perm_Kind)
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,
2088 end Perm_Error_Loop_Exit;
2092 Loop_Name : constant Entity_Id := Entity (Identifier (Loop_N));
2093 Loop_Env : constant Perm_Env_Access := new Perm_Env;
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
2112 Exit_Env : constant Perm_Env_Access := new Perm_Env;
2114 Copy_Env (From => Current_Perm_Env, To => Exit_Env.all);
2115 Set (Current_Loops_Accumulators, Loop_Name, Exit_Env);
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
2133 Exit_Env : constant Perm_Env_Access :=
2134 Get (Current_Loops_Accumulators, Loop_Name);
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
2146 if Exit_Env /= null then
2147 Copy_Env (From => Exit_Env.all, To => Current_Perm_Env);
2149 Copy_Env (From => Loop_Env.all, To => Current_Perm_Env);
2152 Free_Env (Loop_Env.all);
2153 Free_Env (Exit_Env.all);
2155 end Check_Loop_Statement;
2161 procedure Check_Node (N : Node_Id) is
2162 Mode_Before : constant Checking_Mode := Current_Checking_Mode;
2165 when N_Declaration =>
2166 Check_Declaration (N);
2169 Check_Expression (N);
2171 when N_Subtype_Indication =>
2172 Check_Node (Constraint (N));
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
2187 Check_Callable_Body (N);
2189 when N_Protected_Body =>
2190 Check_List (Declarations (N));
2192 when N_Package_Declaration =>
2194 Spec : constant Node_Id := Specification (N);
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));
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
2251 | N_Constrained_Array_Definition
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
2261 | N_Discriminant_Association
2262 | N_Discriminant_Specification
2264 | N_Entry_Body_Formal_Part
2265 | N_Enumeration_Type_Definition
2266 | N_Entry_Call_Alternative
2267 | N_Entry_Index_Specification
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
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
2297 | N_Terminate_Alternative
2298 | N_Triggering_Alternative
2299 | N_Unconstrained_Array_Definition
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
2316 | N_Attribute_Definition_Clause
2318 | N_Delta_Constraint
2319 | N_Digits_Constraint
2321 | N_Enumeration_Representation_Clause
2322 | N_Exception_Declaration
2323 | N_Exception_Renaming_Declaration
2324 | N_Formal_Package_Declaration
2325 | N_Formal_Subprogram_Declaration
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
2337 | N_Number_Declaration
2338 | N_Object_Renaming_Declaration
2340 | N_Package_Instantiation
2341 | N_Package_Renaming_Declaration
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
2351 | N_Validate_Unchecked_Conversion
2352 | N_Variable_Reference_Marker
2356 -- The following nodes are rewritten by semantic analysis
2358 when N_Single_Protected_Declaration
2359 | N_Single_Task_Declaration
2361 raise Program_Error;
2364 Current_Checking_Mode := Mode_Before;
2367 ------------------------
2368 -- Check_Package_Body --
2369 ------------------------
2371 procedure Check_Package_Body (Pack : Node_Id) is
2372 Saved_Env : Perm_Env;
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
2386 CorSp := Parent (Corresponding_Spec (Pack));
2387 while Nkind (CorSp) /= N_Package_Specification loop
2388 CorSp := Parent (CorSp);
2391 Check_List (Visible_Declarations (CorSp));
2395 Copy_Env (Current_Perm_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,
2419 end Check_Package_Body;
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;
2430 case Current_Checking_Mode is
2432 case Formal_Kind'(Mode
) is
2433 when E_In_Parameter
=>
2434 if Is_Borrowed_In
(Formal
) then
2437 Current_Checking_Mode
:= Move
;
2444 when E_Out_Parameter
=>
2447 when E_In_Out_Parameter
=>
2450 Current_Checking_Mode
:= Move
;
2454 Check_Node
(Actual
);
2457 case Formal_Kind
'(Mode) is
2458 when E_In_Parameter =>
2461 when E_Out_Parameter
2462 | E_In_Out_Parameter
2464 -- Borrowed out or in out
2466 Process_Path (Actual);
2471 raise Program_Error;
2474 Current_Checking_Mode := Mode_Before;
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;
2487 when E_In_Parameter =>
2488 if not Is_Borrowed_In (Formal) then
2491 Current_Checking_Mode := Observe;
2492 Check_Node (Actual);
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;
2514 when E_Out_Parameter =>
2516 Current_Checking_Mode := Borrow_Out;
2517 Check_Node (Actual);
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);
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
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
2567 procedure Check_List
(L
: List_Id
) is
2571 while Present
(N
) loop
2572 Check_Safe_Pointers
(N
);
2581 procedure Initialize
is
2583 Reset
(Current_Loops_Envs
);
2584 Reset
(Current_Loops_Accumulators
);
2585 Reset
(Current_Perm_Env
);
2586 Reset
(Current_Initialization_Map
);
2592 -- SPARK_Mode pragma in application
2594 -- Start of processing for Check_Safe_Pointers
2600 when N_Compilation_Unit
=>
2601 Check_Safe_Pointers
(Unit
(N
));
2604 | N_Package_Declaration
2607 Prag
:= SPARK_Pragma
(Defining_Entity
(N
));
2608 if Present
(Prag
) then
2609 if Get_SPARK_Mode_From_Annotation
(Prag
) = Opt
.Off
then
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
)));
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
;
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;
2645 Current_Checking_Mode := Read;
2648 Check_Node (Expression (Stmt));
2649 Current_Checking_Mode := Assign;
2650 Check_Node (Name (Stmt));
2652 when N_Block_Statement =>
2654 Saved_Env : Perm_Env;
2659 Copy_Env (Current_Perm_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,
2675 when N_Case_Statement =>
2677 Saved_Env : Perm_Env;
2679 -- Accumulator for the different branches
2683 Elmt : Node_Id := First (Alternatives (Stmt));
2686 Current_Checking_Mode := Read;
2687 Check_Node (Expression (Stmt));
2688 Current_Checking_Mode := Mode_Before;
2692 Copy_Env (Current_Perm_Env,
2695 -- Here we have the original env in saved, current with a fresh
2696 -- copy, and new aliased.
2698 -- First alternative
2703 Copy_Env (Current_Perm_Env,
2705 Free_Env (Current_Perm_Env);
2707 -- Other alternatives
2709 while Present (Elmt) loop
2710 -- Restore environment
2712 Copy_Env (Saved_Env,
2717 -- Merge Current_Perm_Env into New_Env
2719 Merge_Envs (New_Env,
2730 Free_Env (Saved_Env);
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
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));
2754 Return_Parameters (Subp);
2755 Return_Globals (Subp);
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;
2764 raise Program_Error;
2767 Check_Node (Expression (Stmt));
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));
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));
2783 Return_Parameters (Subp);
2784 Return_Globals (Subp);
2787 -- Merge the current_Perm_Env with the accumulator for the given loop
2789 when N_Exit_Statement =>
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 :=
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);
2807 Merge_Envs (Saved_Accumulator.all,
2808 Environment_Copy.all);
2812 -- Copy environment, run on each branch, and then merge
2814 when N_If_Statement =>
2816 Saved_Env : Perm_Env;
2818 -- Accumulator for the different branches
2824 Check_Node (Condition (Stmt));
2828 Copy_Env (Current_Perm_Env,
2831 -- Here we have the original env in saved, current with a fresh
2836 Check_List (Then_Statements (Stmt));
2838 Copy_Env (Current_Perm_Env,
2841 Free_Env (Current_Perm_Env);
2843 -- Here the new_environment contains curr env after then block
2850 Elmt := First (Elsif_Parts (Stmt));
2851 while Present (Elmt) loop
2852 -- Transfer into accumulator, and restore from save
2854 Copy_Env (Saved_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,
2871 -- Restore environment before if
2873 Copy_Env (Saved_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,
2890 Free_Env (Saved_Env);
2893 -- Unsupported constructs in SPARK
2895 when N_Abort_Statement
2896 | N_Accept_Statement
2897 | N_Asynchronous_Select
2899 | N_Conditional_Entry_Call
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
2914 -- The following nodes are never generated in GNATprove mode
2916 when N_Compound_Statement
2919 raise Program_Error;
2921 end Check_Statement;
2927 function Get_Perm (N : Node_Id) return Perm_Kind is
2928 Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N);
2931 case Tree_Or_Perm.R is
2933 return Tree_Or_Perm.Found_Permission;
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 =>
2948 ----------------------
2949 -- Get_Perm_Or_Tree --
2950 ----------------------
2952 function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree 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;
2966 P : constant Entity_Id := Entity (N);
2968 C : constant Perm_Tree_Access :=
2969 Get (Current_Perm_Env, Unique_Entity (P));
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);
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);
2985 return (R => Unfolded, Tree_Access => C);
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 =>
3010 C : constant Perm_Or_Tree :=
3011 Get_Perm_Or_Tree (Prefix (N));
3021 pragma Assert (C.Tree_Access /= null);
3023 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3025 Kind (C.Tree_Access) = Record_Component);
3027 if Kind (C.Tree_Access) = Record_Component then
3029 Selected_Component : constant Entity_Id :=
3030 Entity (Selector_Name (N));
3032 Selected_C : constant Perm_Tree_Access :=
3034 (Component (C.Tree_Access), Selected_Component);
3037 if Selected_C = null then
3038 return (R => Unfolded,
3040 Other_Components (C.Tree_Access));
3042 return (R => Unfolded,
3043 Tree_Access => Selected_C);
3046 elsif Kind (C.Tree_Access) = Entire_Object then
3047 return (R => Folded, Found_Permission =>
3048 Children_Permission (C.Tree_Access));
3050 raise Program_Error;
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
3064 C : constant Perm_Or_Tree :=
3065 Get_Perm_Or_Tree (Prefix (N));
3075 pragma Assert (C.Tree_Access /= null);
3077 pragma Assert (Kind (C.Tree_Access) = Entire_Object
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));
3090 raise Program_Error;
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 =>
3102 C : constant Perm_Or_Tree :=
3103 Get_Perm_Or_Tree (Prefix (N));
3113 pragma Assert (C.Tree_Access /= null);
3115 pragma Assert (Kind (C.Tree_Access) = Entire_Object
3117 Kind (C.Tree_Access) = Reference);
3119 if Kind (C.Tree_Access) = Reference then
3120 if Get_All (C.Tree_Access) = null then
3122 raise Program_Error;
3126 Tree_Access => Get_All (C.Tree_Access));
3128 elsif Kind (C.Tree_Access) = Entire_Object then
3129 return (R => Folded, Found_Permission =>
3130 Children_Permission (C.Tree_Access));
3132 raise Program_Error;
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);
3144 raise Program_Error;
3146 end Get_Perm_Or_Tree;
3152 function Get_Perm_Tree
3154 return Perm_Tree_Access
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;
3169 P : constant Node_Id := Entity (N);
3171 C : constant Perm_Tree_Access :=
3172 Get (Current_Perm_Env, Unique_Entity (P));
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);
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);
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 =>
3207 C : constant Perm_Tree_Access :=
3208 Get_Perm_Tree (Prefix (N));
3212 -- If null then it means we went through a function call
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.
3224 Selected_Component : constant Entity_Id :=
3225 Entity (Selector_Name (N));
3226 Selected_C : constant Perm_Tree_Access :=
3228 (Component (C), Selected_Component);
3231 if Selected_C = null then
3232 return Other_Components (C);
3237 elsif Kind (C) = Entire_Object then
3239 -- Expand the tree. Replace the node with
3240 -- Record_Component.
3244 -- Create the unrolled nodes
3246 Son : Perm_Tree_Access;
3248 Child_Perm : constant Perm_Kind :=
3249 Children_Permission (C);
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.
3258 (Kind => Record_Component,
3259 Is_Node_Deep => Is_Node_Deep (C),
3260 Permission => Permission (C),
3261 Component => Perm_Tree_Maps.Nil,
3263 new Perm_Tree_Wrapper'
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
'
3281 (Kind => Entire_Object,
3282 Is_Node_Deep => Is_Deep (Etype (Elem)),
3283 Permission => Child_Perm,
3284 Children_Permission => Child_Perm));
3287 (C.all.Tree.Component, Elem, Son);
3289 Next_Component_Or_Discriminant (Elem);
3292 -- we return the tree to the sons, so that the recursion
3296 Selected_Component : constant Entity_Id :=
3297 Entity (Selector_Name (N));
3299 Selected_C : constant Perm_Tree_Access :=
3301 (Component (C), Selected_Component);
3304 pragma Assert (Selected_C /= null);
3311 raise Program_Error;
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
3319 when N_Indexed_Component
3323 C : constant Perm_Tree_Access :=
3324 Get_Perm_Tree (Prefix (N));
3328 -- If null then we went through a function call
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
3344 -- Expand the tree. Replace node with Array_Component.
3346 Son : Perm_Tree_Access;
3349 Son := new Perm_Tree_Wrapper'
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
),
3365 return Get_Elem
(C
);
3368 raise Program_Error
;
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
=>
3378 C
: Perm_Tree_Access
;
3381 C
:= Get_Perm_Tree
(Prefix
(N
));
3384 -- If null, we went through a function call
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
3397 raise Program_Error
;
3401 elsif Kind
(C
) = Entire_Object
then
3403 -- Expand the tree. Replace the node with Reference.
3405 Son
: Perm_Tree_Access
;
3408 Son
:= new Perm_Tree_Wrapper
'
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),
3428 raise Program_Error;
3432 -- No permission tree for function calls
3434 when N_Function_Call =>
3438 raise Program_Error;
3446 function Glb (P1, P2 : Perm_Kind) return Perm_Kind
3488 function Has_Alias_Deep (Typ : Entity_Id) return Boolean;
3489 function Has_Alias_Deep (Typ : Entity_Id) return Boolean
3494 if Is_Array_Type (Typ)
3495 and then Has_Aliased_Components (Typ)
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))
3513 if Has_Alias_Deep (Etype (Comp)) then
3517 Next_Component_Or_Discriminant (Comp);
3521 return Is_Aliased (Typ);
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
3552 when others => null;
3556 return Has_Alias (Prefix (N));
3558 when N_Indexed_Component
3561 return Has_Alias (Prefix (N));
3563 when N_Explicit_Dereference =>
3566 when N_Function_Call =>
3569 when N_Attribute_Reference =>
3570 if Is_Deep (Etype (Prefix (N))) then
3571 raise Program_Error;
3580 -------------------------
3581 -- Has_Array_Component --
3582 -------------------------
3584 function Has_Array_Component (N : Node_Id) return Boolean is
3587 -- Base identifier. There is no array component here.
3591 | N_Defining_Identifier
3595 -- We check if the expression inside the conversion has an array
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
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 =>
3625 raise Program_Error;
3627 end Has_Array_Component;
3629 ----------------------------
3630 -- Has_Function_Component --
3631 ----------------------------
3633 function Has_Function_Component (N : Node_Id) return Boolean is
3636 -- Base identifier. There is no function component here.
3640 | N_Defining_Identifier
3644 -- We check if the expression inside the conversion has a function
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
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 =>
3676 raise Program_Error;
3679 end Has_Function_Component;
3685 procedure Hp (P : Perm_Env) is
3686 Elem : Perm_Tree_Maps.Key_Option;
3689 Elem := Get_First_Key (P);
3690 while Elem.Present loop
3691 Print_Node_Briefly (Elem.K);
3692 Elem := Get_Next_Key (P);
3696 --------------------------
3697 -- Illegal_Global_Usage --
3698 --------------------------
3700 procedure Illegal_Global_Usage (N : Node_Or_Entity_Id) is
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
3716 return Is_Access_Type (Etype (E))
3717 and then not Is_Access_Constant (Etype (E));
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
3729 Pack_Decl : Node_Id;
3732 if Is_Itype (E) then
3733 Decl := Associated_Node_For_Itype (E);
3738 Pack_Decl := Parent (Parent (Decl));
3740 if Nkind (Pack_Decl) /= N_Package_Declaration then
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;
3750 pragma Assert (Is_Type (E));
3759 -- Just check the depth of its component type
3764 return Is_Deep (Component_Type (E));
3766 when E_String_Literal_Subtype =>
3769 -- Per RM 8.11 for class-wide types
3771 when E_Class_Wide_Subtype
3776 -- ??? What about hidden components
3785 Elmt := First_Component_Or_Discriminant (E);
3786 while Present (Elmt) loop
3787 if Is_Deep (Etype (Elmt)) then
3790 Next_Component_Or_Discriminant (Elmt);
3797 when Private_Kind =>
3798 if Is_Private_Entity_Mode_Off (E) then
3801 if Present (Full_View (E)) then
3802 return Is_Deep (Full_View (E));
3808 when E_Incomplete_Type =>
3811 when E_Incomplete_Subtype =>
3814 -- No problem with synchronized types
3816 when E_Protected_Type
3817 | E_Protected_Subtype
3823 when E_Exception_Type =>
3827 raise Program_Error;
3835 function Is_Shallow (E : Entity_Id) return Boolean is
3837 pragma Assert (Is_Type (E));
3838 return not Is_Deep (E);
3845 function Loop_Of_Exit (N : Node_Id) return Entity_Id is
3846 Nam : Node_Id := Name (N);
3847 Stmt : Node_Id := N;
3850 while Present (Stmt) loop
3851 Stmt := Parent (Stmt);
3852 if Nkind (Stmt) = N_Loop_Statement then
3853 Nam := Identifier (Stmt);
3858 return Entity (Nam);
3864 function Lub (P1, P2 : Perm_Kind) return Perm_Kind
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;
3918 procedure Apply_Glb_Tree
3919 (A : Perm_Tree_Access;
3923 A.all.Tree.Permission := Glb (Permission (A), P);
3926 when Entire_Object =>
3927 A.all.Tree.Children_Permission :=
3928 Glb (Children_Permission (A), P);
3931 Apply_Glb_Tree (Get_All (A), P);
3933 when Array_Component =>
3934 Apply_Glb_Tree (Get_Elem (A), P);
3936 when Record_Component =>
3938 Comp : Perm_Tree_Access;
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));
3946 Apply_Glb_Tree (Other_Components (A), P);
3951 Perm : constant Perm_Kind :=
3952 Glb (Permission (Target), Permission (Source));
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 =>
3961 Child_Perm : constant Perm_Kind :=
3962 Children_Permission (Target);
3965 case Kind (Source) is
3966 when Entire_Object =>
3967 Target.all.Tree.Children_Permission :=
3968 Glb (Child_Perm, Children_Permission (Source));
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;
3984 Comp : Perm_Tree_Access;
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));
3997 Apply_Glb_Tree (Other_Components (Target), Child_Perm);
4002 case Kind (Source) is
4003 when Entire_Object =>
4004 Apply_Glb_Tree (Get_All (Target),
4005 Children_Permission (Source));
4008 Merge_Trees (Get_All (Target), Get_All (Source));
4011 raise Program_Error;
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));
4025 raise Program_Error;
4029 when Record_Component =>
4030 case Kind (Source) is
4031 when Entire_Object =>
4033 Child_Perm : constant Perm_Kind :=
4034 Children_Permission (Source);
4036 Comp : Perm_Tree_Access;
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);
4046 Perm_Tree_Maps.Get_Next (Component (Target));
4048 Apply_Glb_Tree (Other_Components (Target), Child_Perm);
4051 when Record_Component =>
4053 Key_Source : Perm_Tree_Maps.Key_Option;
4054 CompTarget : Perm_Tree_Access;
4055 CompSource : Perm_Tree_Access;
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));
4074 Merge_Trees (Other_Components (Target),
4075 Other_Components (Source));
4079 raise Program_Error;
4085 CompTarget : Perm_Tree_Access;
4086 CompSource : Perm_Tree_Access;
4087 KeyTarget : Perm_Tree_Maps.Key_Option;
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);
4106 KeyTarget := Get_Next_Key (Target);
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.
4113 KeySource : Perm_Tree_Maps.Key_Option;
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
);
4126 Merge_Trees
(CompTarget
, CompSource
);
4129 KeySource
:= Get_Next_Key
(Source
);
4140 procedure Perm_Error
4143 Found_Perm
: Perm_Kind
)
4145 procedure Set_Root_Object
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
4158 Obj
: out Entity_Id
;
4159 Deref
: out Boolean)
4162 case Nkind
(Path
) is
4166 Obj
:= Entity
(Path
);
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
4179 Set_Root_Object
(Prefix
(Path
), Obj
, Deref
);
4181 when N_Explicit_Dereference
=>
4182 Set_Root_Object
(Prefix
(Path
), Obj
, Deref
);
4186 raise Program_Error
;
4188 end Set_Root_Object
;
4195 -- Start of processing for Perm_Error
4198 Set_Root_Object
(N
, Root
, Is_Deref
);
4202 ("insufficient permission on dereference from &", N
, Root
);
4204 Error_Msg_NE
("insufficient permission for &", N
, Root
);
4207 Perm_Mismatch
(Perm
, Found_Perm
, N
);
4210 -------------------------------
4211 -- Perm_Error_Subprogram_End --
4212 -------------------------------
4214 procedure Perm_Error_Subprogram_End
4218 Found_Perm
: Perm_Kind
)
4221 Error_Msg_Node_2
:= Subp
;
4222 Error_Msg_NE
("insufficient permission for & when returning from &",
4224 Perm_Mismatch
(Perm
, Found_Perm
, Subp
);
4225 end Perm_Error_Subprogram_End
;
4231 procedure Process_Path
(N
: Node_Id
) is
4232 Root
: constant Entity_Id
:= Get_Enclosing_Object
(N
);
4234 -- We ignore if yielding to synchronized
4237 and then Is_Synchronized_Object
(Root
)
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
))
4252 Perm_N
: constant Perm_Kind
:= Get_Perm
(N
);
4256 case Current_Checking_Mode
is
4257 -- Check permission R, do nothing
4260 if Perm_N
not in Read_Perm
then
4261 Perm_Error
(N
, Read_Only
, Perm_N
);
4264 -- If shallow type no need for RW, only R
4267 if Is_Shallow
(Etype
(N
)) then
4268 if Perm_N
not in Read_Perm
then
4269 Perm_Error
(N
, Read_Only
, Perm_N
);
4272 -- Check permission RW if deep
4274 if Perm_N
/= Read_Write
then
4275 Perm_Error
(N
, Read_Write
, Perm_N
);
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
);
4286 -- We went through a function call, no permission to
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
));
4301 -- Check permission RW
4304 if Perm_N
/= Read_Write
then
4305 Perm_Error
(N
, Read_Write
, Perm_N
);
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
);
4317 -- We went through a function call, no permission to
4323 -- Set permissions to No on any strict extension of the path
4325 Set_Perm_Extensions
(Tree
, No_Access
);
4328 -- Check permission W
4331 if Perm_N
not in Write_Perm
then
4332 Perm_Error
(N
, Write_Only
, Perm_N
);
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
4342 -- Same if has function component
4344 if Has_Function_Component
(N
) then
4349 -- Get the permission tree for the path
4351 Tree
: constant Perm_Tree_Access
:=
4354 Dummy
: Perm_Tree_Access
;
4358 -- We went through a function call, no permission to
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
);
4375 -- Check permission W
4378 if Perm_N
not in Write_Perm
then
4379 Perm_Error
(N
, Write_Only
, Perm_N
);
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
);
4390 -- We went through a function call, no permission to
4396 -- Set permissions to No on any strict extension of the path
4398 Set_Perm_Extensions
(Tree
, No_Access
);
4402 if Perm_N
not in Read_Perm
then
4403 Perm_Error
(N
, Read_Only
, Perm_N
);
4406 if Is_By_Copy_Type
(Etype
(N
)) then
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
);
4418 -- We went through a function call, no permission to
4424 -- Set permissions to No on any strict extension of the path
4426 Set_Perm_Extensions
(Tree
, Read_Only
);
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
4447 if Nkind
(Decl
) = N_Object_Declaration
then
4448 -- Check RW for object declared, unless the object has never been
4451 if Get
(Current_Initialization_Map
,
4452 Unique_Entity
(Defining_Identifier
(Decl
))) = False
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
)))
4467 Elem
: constant Perm_Tree_Access
:=
4468 Get
(Current_Perm_Env
,
4469 Unique_Entity
(Defining_Identifier
(Decl
)));
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
4479 raise Program_Error
;
4482 if Permission
(Elem
) /= Read_Write
then
4483 Perm_Error
(Decl
, Read_Write
, Permission
(Elem
));
4487 end Return_Declaration
;
4493 -- Start of processing for Return_Declarations
4497 while Present
(N
) loop
4498 Return_Declaration
(N
);
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
;
4525 Item
: Node_Id
:= First_Item
;
4529 while Present
(Item
) loop
4532 -- Ignore abstract states, which play no role in pointer aliasing
4534 if Ekind
(E
) = E_Abstract_State
then
4537 Return_Parameter_Or_Global
(E
, Kind
, Subp
);
4541 end Return_Globals_From_List
;
4543 ----------------------------
4544 -- Return_Globals_Of_Mode --
4545 ----------------------------
4547 procedure Return_Globals_Of_Mode
(Global_Mode
: Name_Id
) is
4552 when Name_Input | Name_Proof_In
=>
4553 Kind
:= E_In_Parameter
;
4555 Kind
:= E_Out_Parameter
;
4557 Kind
:= E_In_Out_Parameter
;
4559 raise Program_Error
;
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
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
);
4578 --------------------------------
4579 -- Return_Parameter_Or_Global --
4580 --------------------------------
4582 procedure Return_Parameter_Or_Global
4587 Elem
: constant Perm_Tree_Access
:= Get
(Current_Perm_Env
, Id
);
4588 pragma Assert
(Elem
/= null);
4591 -- Shallow unaliased parameters and globals cannot introduce pointer
4594 if not Has_Alias
(Id
) and then Is_Shallow
(Etype
(Id
)) then
4597 -- Observed IN parameters and globals need not return a permission to
4600 elsif Mode
= E_In_Parameter
and then not Is_Borrowed_In
(Id
) then
4603 -- All other parameters and globals should return with mode RW to the
4607 if Permission
(Elem
) /= Read_Write
then
4608 Perm_Error_Subprogram_End
4612 Found_Perm
=> Permission
(Elem
));
4615 end Return_Parameter_Or_Global
;
4617 -----------------------
4618 -- Return_Parameters --
4619 -----------------------
4621 procedure Return_Parameters
(Subp
: Entity_Id
) is
4625 Formal
:= First_Formal
(Subp
);
4626 while Present
(Formal
) loop
4627 Return_Parameter_Or_Global
(Formal
, Ekind
(Formal
), Subp
);
4628 Next_Formal
(Formal
);
4630 end Return_Parameters
;
4632 -------------------------
4633 -- Set_Perm_Extensions --
4634 -------------------------
4636 procedure Set_Perm_Extensions
4637 (T
: Perm_Tree_Access
;
4640 procedure Free_Perm_Tree_Children
(T
: Perm_Tree_Access
);
4642 procedure Free_Perm_Tree_Children
(T
: Perm_Tree_Access
)
4646 when Entire_Object
=>
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
=>
4659 Comp
: Perm_Tree_Access
;
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
));
4668 Free_Perm_Tree
(T
.all.Tree
.Other_Components
);
4671 end Free_Perm_Tree_Children
;
4673 Son
: constant Perm_Tree
:=
4675 (Kind => Entire_Object,
4676 Is_Node_Deep => Is_Node_Deep (T),
4677 Permission => Permission (T),
4678 Children_Permission => P);
4681 Free_Perm_Tree_Children (T);
4683 end Set_Perm_Extensions;
4685 ------------------------------
4686 -- Set_Perm_Extensions_Move --
4687 ------------------------------
4689 procedure Set_Perm_Extensions_Move
4690 (T : Perm_Tree_Access;
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);
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 =>
4711 | E_String_Literal_Subtype
4713 Set_Perm_Extensions (T, No_Access);
4715 -- No need to unroll here, directly put sons to No_Access
4718 if Ekind (E) in Access_Subprogram_Kind then
4721 Set_Perm_Extensions (T, No_Access);
4724 -- No unrolling done, too complicated
4726 when E_Class_Wide_Subtype
4729 | E_Incomplete_Subtype
4734 Set_Perm_Extensions (T, No_Access);
4736 -- Expand the tree. Replace the node with Array component.
4739 | E_Array_Subtype =>
4741 Son : Perm_Tree_Access;
4744 Son := new Perm_Tree_Wrapper'
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
,
4764 -- Unroll, and set permission extensions with component type
4768 | E_Record_Type_With_Private
4769 | E_Record_Subtype_With_Private
4771 | E_Protected_Subtype
4774 -- Expand the tree. Replace the node with
4775 -- Record_Component.
4779 Son
: Perm_Tree_Access
;
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
));
4789 (Kind
=> Record_Component
,
4790 Is_Node_Deep
=> Is_Node_Deep
(T
),
4791 Permission
=> Write_Only
,
4792 Component
=> Perm_Tree_Maps
.Nil
,
4794 new Perm_Tree_Wrapper
'
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'
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
));
4817 (T
.all.Tree
.Component
, Elem
, Son
);
4819 Next_Component_Or_Discriminant
(Elem
);
4825 | E_Limited_Private_Type
4826 | E_Limited_Private_Subtype
4828 Set_Perm_Extensions_Move
(T
, Underlying_Type
(E
));
4831 raise Program_Error
;
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
=>
4843 Comp
: Perm_Tree_Access
;
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
);
4855 Set_Perm_Extensions
(Other_Components
(T
), No_Access
);
4858 end Set_Perm_Extensions_Move
;
4860 ------------------------------
4861 -- Set_Perm_Prefixes_Assign --
4862 ------------------------------
4864 function Set_Perm_Prefixes_Assign
4866 return Perm_Tree_Access
4868 C
: constant Perm_Tree_Access
:= Get_Perm_Tree
(N
);
4871 pragma Assert
(Current_Checking_Mode
= Assign
);
4873 -- The function should not be called if has_function_component
4875 pragma Assert
(C
/= null);
4878 when Entire_Object
=>
4879 pragma Assert
(Children_Permission
(C
) = Read_Write
);
4880 C
.all.Tree
.Permission
:= Read_Write
;
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
4897 when Record_Component
=>
4899 Perm
: Perm_Kind
:= Read_Write
;
4901 Comp
: Perm_Tree_Access
;
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
));
4912 Perm
:= Glb
(Perm
, Permission
(Other_Components
(C
)));
4914 C
.all.Tree
.Permission
:= Lub
(Permission
(C
), Perm
);
4919 -- Base identifier. End recursion here.
4923 | N_Defining_Identifier
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
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
;
4957 raise Program_Error
;
4960 end Set_Perm_Prefixes_Assign
;
4962 ----------------------------------
4963 -- Set_Perm_Prefixes_Borrow_Out --
4964 ----------------------------------
4966 function Set_Perm_Prefixes_Borrow_Out
4968 return Perm_Tree_Access
4971 pragma Assert
(Current_Checking_Mode
= Borrow_Out
);
4974 -- Base identifier. Set permission to No.
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);
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
;
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
5014 when N_Selected_Component
=>
5016 C
: constant Perm_Tree_Access
:=
5017 Set_Perm_Prefixes_Borrow_Out
(Prefix
(N
));
5021 -- We went through a function call, do nothing
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.
5038 Selected_Component
: constant Entity_Id
:=
5039 Entity
(Selector_Name
(N
));
5041 Selected_C
: Perm_Tree_Access
:=
5043 (Component
(C
), Selected_Component
);
5046 if Selected_C
= null then
5047 Selected_C
:= Other_Components
(C
);
5050 pragma Assert
(Selected_C
/= null);
5052 Selected_C
.all.Tree
.Permission
:= No_Access
;
5056 elsif Kind
(C
) = Entire_Object
then
5058 -- Expand the tree. Replace the node with
5059 -- Record_Component.
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
);
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.
5081 (Kind
=> Record_Component
,
5082 Is_Node_Deep
=> Is_Node_Deep
(C
),
5083 Permission
=> Permission
(C
),
5084 Component
=> Hashtbl
,
5086 new Perm_Tree_Wrapper
'
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'
5102 (Kind
=> Entire_Object
,
5103 Is_Node_Deep
=> Is_Deep
(Etype
(Elem
)),
5104 Permission
=> ChildrenPerm
,
5105 Children_Permission
=> ChildrenPerm
));
5108 (C
.all.Tree
.Component
, Elem
, Son
);
5110 Next_Component_Or_Discriminant
(Elem
);
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
5118 Selected_Component
: constant Entity_Id
:=
5119 Entity
(Selector_Name
(N
));
5121 Selected_C
: Perm_Tree_Access
:=
5123 (Component
(C
), Selected_Component
);
5126 if Selected_C
= null then
5127 Selected_C
:= Other_Components
(C
);
5130 pragma Assert
(Selected_C
/= null);
5132 Selected_C
.all.Tree
.Permission
:= No_Access
;
5138 raise Program_Error
;
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
5147 when N_Indexed_Component
5151 C
: constant Perm_Tree_Access
:=
5152 Set_Perm_Prefixes_Borrow_Out
(Prefix
(N
));
5156 -- We went through a function call, do nothing
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
5181 -- Expand the tree. Replace node with Array_Component.
5183 Son
: Perm_Tree_Access
;
5186 Son
:= new Perm_Tree_Wrapper
'
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,
5202 return Get_Elem (C);
5205 raise Program_Error;
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
5214 when N_Explicit_Dereference =>
5216 C : constant Perm_Tree_Access :=
5217 Set_Perm_Prefixes_Borrow_Out (Prefix (N));
5221 -- We went through a function call. Do nothing.
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;
5241 elsif Kind (C) = Entire_Object then
5243 -- Expand the tree. Replace the node with Reference.
5245 Son : Perm_Tree_Access;
5248 Son := new Perm_Tree_Wrapper'
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
,
5268 raise Program_Error
;
5272 when N_Function_Call
=>
5276 raise Program_Error
;
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
5291 -- Base identifier. Set permission to W or No depending on Mode.
5297 P
: constant Node_Id
:= Entity
(N
);
5298 C
: constant Perm_Tree_Access
:=
5299 Get
(Current_Perm_Env
, Unique_Entity
(P
));
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
;
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);
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
);
5325 if Mode
= Super_Move
then
5326 C
.all.Tree
.Permission
:= No_Access
;
5328 C
.all.Tree
.Permission
:= Glb
(Write_Only
, Permission
(C
));
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
5350 when N_Selected_Component
=>
5352 C
: constant Perm_Tree_Access
:=
5353 Set_Perm_Prefixes_Move
(Prefix
(N
), Mode
);
5357 -- We went through a function call, do nothing
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
);
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.
5385 Selected_Component
: constant Entity_Id
:=
5386 Entity
(Selector_Name
(N
));
5388 Selected_C
: Perm_Tree_Access
:=
5390 (Component
(C
), Selected_Component
);
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
);
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
;
5412 Selected_C
.all.Tree
.Permission
:=
5413 Glb
(Write_Only
, Permission
(Selected_C
));
5419 elsif Kind
(C
) = Entire_Object
then
5421 -- Expand the tree. Replace the node with
5422 -- Record_Component.
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
;
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.
5448 (Kind
=> Record_Component
,
5449 Is_Node_Deep
=> Is_Node_Deep
(C
),
5450 Permission
=> Permission
(C
),
5451 Component
=> Hashtbl
,
5453 new Perm_Tree_Wrapper
'
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'
5469 (Kind
=> Entire_Object
,
5470 Is_Node_Deep
=> Is_Deep
(Etype
(Elem
)),
5471 Permission
=> Read_Write
,
5472 Children_Permission
=> Read_Write
));
5475 (C
.all.Tree
.Component
, Elem
, Son
);
5477 Next_Component_Or_Discriminant
(Elem
);
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.
5485 Selected_Component
: constant Entity_Id
:=
5486 Entity
(Selector_Name
(N
));
5488 Selected_C
: Perm_Tree_Access
:=
5490 (Component
(C
), Selected_Component
);
5493 if Selected_C
= null then
5494 Selected_C
:= Other_Components
(C
);
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
) =
5505 if Mode
= Super_Move
then
5506 Selected_C
.all.Tree
.Permission
:= No_Access
;
5508 Selected_C
.all.Tree
.Permission
:= Write_Only
;
5515 raise Program_Error
;
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
5524 when N_Indexed_Component
5528 C
: constant Perm_Tree_Access
:=
5529 Set_Perm_Prefixes_Move
(Prefix
(N
), Mode
);
5533 -- We went through a function call, do nothing
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
);
5546 pragma Assert
(Permission
(C
) = Write_Only
5547 or else Permission
(C
) = No_Access
);
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
5560 raise Program_Error
;
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
;
5573 C
.all.Tree
.Get_Elem
.all.Tree
.Permission
:=
5574 Glb
(Write_Only
, Permission
(Get_Elem
(C
)));
5577 return Get_Elem
(C
);
5578 elsif Kind
(C
) = Entire_Object
then
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
;
5590 Son
:= new Perm_Tree_Wrapper
'
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;
5600 Son.all.Tree.Permission := Write_Only;
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),
5612 return Get_Elem (C);
5615 raise Program_Error;
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
5624 when N_Explicit_Dereference =>
5626 C : constant Perm_Tree_Access :=
5627 Set_Perm_Prefixes_Move (Prefix (N), Move);
5631 -- We went through a function call: do nothing
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
5651 raise Program_Error;
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
;
5664 Get_All
(C
).all.Tree
.Permission
:=
5665 Glb
(Write_Only
, Permission
(Get_All
(C
)));
5668 elsif Kind
(C
) = Entire_Object
then
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
;
5680 Son
:= new Perm_Tree_Wrapper
'
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;
5690 Son.all.Tree.Permission := Write_Only;
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
5707 raise Program_Error;
5711 when N_Function_Call =>
5715 raise Program_Error;
5718 end Set_Perm_Prefixes_Move;
5720 -------------------------------
5721 -- Set_Perm_Prefixes_Observe --
5722 -------------------------------
5724 function Set_Perm_Prefixes_Observe
5726 return Perm_Tree_Access
5729 pragma Assert (Current_Checking_Mode = Observe);
5732 -- Base identifier. Set permission to R.
5736 | N_Defining_Identifier
5740 C : Perm_Tree_Access;
5743 if Nkind (N) = N_Defining_Identifier then
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);
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);
5764 C.all.Tree.Permission := Glb (Read_Only, Permission (C));
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
5783 when N_Selected_Component =>
5785 C : constant Perm_Tree_Access :=
5786 Set_Perm_Prefixes_Observe (Prefix (N));
5790 -- We went through a function call, do nothing
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.
5806 Selected_Component : constant Entity_Id :=
5807 Entity (Selector_Name (N));
5809 Selected_C : Perm_Tree_Access :=
5811 (Component (C), Selected_Component);
5814 if Selected_C = null then
5815 Selected_C := Other_Components (C);
5818 pragma Assert (Selected_C /= null);
5820 Selected_C.all.Tree.Permission :=
5821 Glb (Read_Only, Permission (Selected_C));
5825 elsif Kind (C) = Entire_Object then
5827 -- Expand the tree. Replace the node with
5828 -- Record_Component.
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);
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.
5851 (Kind => Record_Component,
5852 Is_Node_Deep => Is_Node_Deep (C),
5853 Permission => Permission (C),
5854 Component => Hashtbl,
5856 new Perm_Tree_Wrapper'
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
'
5872 (Kind => Entire_Object,
5873 Is_Node_Deep => Is_Deep (Etype (Elem)),
5874 Permission => Child_Perm,
5875 Children_Permission => Child_Perm));
5878 (C.all.Tree.Component, Elem, Son);
5880 Next_Component_Or_Discriminant (Elem);
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
5888 Selected_Component : constant Entity_Id :=
5889 Entity (Selector_Name (N));
5891 Selected_C : Perm_Tree_Access :=
5893 (Component (C), Selected_Component);
5896 if Selected_C = null then
5897 Selected_C := Other_Components (C);
5900 pragma Assert (Selected_C /= null);
5902 Selected_C.all.Tree.Permission :=
5903 Glb (Read_Only, Child_Perm);
5909 raise Program_Error;
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
5921 C : constant Perm_Tree_Access :=
5922 Set_Perm_Prefixes_Observe (Prefix (N));
5926 -- We went through a function call, do nothing
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
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));
5954 Son := new Perm_Tree_Wrapper'
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
,
5970 return Get_Elem
(C
);
5974 raise Program_Error
;
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
=>
5984 C
: constant Perm_Tree_Access
:=
5985 Set_Perm_Prefixes_Observe
(Prefix
(N
));
5989 -- We went through a function call, do nothing
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
)));
6007 elsif Kind
(C
) = Entire_Object
then
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
));
6017 Son
:= new Perm_Tree_Wrapper
'
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,
6037 raise Program_Error;
6041 when N_Function_Call =>
6045 raise Program_Error;
6048 end Set_Perm_Prefixes_Observe;
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;
6072 Item : Node_Id := First_Item;
6076 while Present (Item) loop
6079 -- Ignore abstract states, which play no role in pointer aliasing
6081 if Ekind (E) = E_Abstract_State then
6084 Setup_Parameter_Or_Global (E, Kind);
6088 end Setup_Globals_From_List;
6090 ---------------------------
6091 -- Setup_Globals_Of_Mode --
6092 ---------------------------
6094 procedure Setup_Globals_Of_Mode (Global_Mode : Name_Id) is
6099 when Name_Input | Name_Proof_In =>
6100 Kind := E_In_Parameter;
6102 Kind := E_Out_Parameter;
6104 Kind := E_In_Out_Parameter;
6106 raise Program_Error;
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
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);
6125 -------------------------------
6126 -- Setup_Parameter_Or_Global --
6127 -------------------------------
6129 procedure Setup_Parameter_Or_Global
6133 Elem : Perm_Tree_Access;
6136 Elem := new Perm_Tree_Wrapper'
6138 (Kind
=> Entire_Object
,
6139 Is_Node_Deep
=> Is_Deep
(Etype
(Id
)),
6140 Permission
=> Read_Write
,
6141 Children_Permission
=> Read_Write
));
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
6155 Elem
.all.Tree
.Permission
:= Read_Only
;
6156 Elem
.all.Tree
.Children_Permission
:= Read_Only
;
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
;
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
6183 Formal
:= First_Formal
(Subp
);
6184 while Present
(Formal
) loop
6185 Setup_Parameter_Or_Global
(Formal
, Ekind
(Formal
));
6186 Next_Formal
(Formal
);
6188 end Setup_Parameters
;