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