Super_Move,
-- Enhanced moving semantics (under 'Access). Checks that paths have
- -- Read_Write permission. After moving a path, its permission is set
- -- to No_Access, as well as the permission of its extensions and the
- -- permission of its prefixes up to the first Reference node.
+ -- Read_Write permission (shallow types may have only Write permission).
+ -- After moving a path, its permission is set to No_Access, as well as
+ -- the permission of its extensions and the permission of its prefixes
+ -- up to the first Reference node.
Borrow_Out,
-- Used for actual OUT parameters. Checks that paths have Write_Perm
-- execution.
procedure Return_Parameter_Or_Global
- (Id : Entity_Id;
- Mode : Formal_Kind;
- Subp : Entity_Id);
+ (Id : Entity_Id;
+ Mode : Formal_Kind;
+ Subp : Entity_Id;
+ Global_Var : Boolean);
-- Auxiliary procedure to Return_Parameters and Return_Globals
procedure Return_Parameters (Subp : Entity_Id);
-- global items with appropriate permissions.
procedure Setup_Parameter_Or_Global
- (Id : Entity_Id;
- Mode : Formal_Kind);
+ (Id : Entity_Id;
+ Mode : Formal_Kind;
+ Global_Var : Boolean);
-- Auxiliary procedure to Setup_Parameters and Setup_Globals
procedure Setup_Parameters (Subp : Entity_Id);
declare
Elem : Perm_Tree_Access;
-
+ Deep : constant Boolean :=
+ Is_Deep (Etype (Defining_Identifier (Decl)));
begin
Elem := new Perm_Tree_Wrapper'
(Tree =>
(Kind => Entire_Object,
- Is_Node_Deep =>
- Is_Deep (Etype (Defining_Identifier (Decl))),
+ Is_Node_Deep => Deep,
Permission => Read_Write,
Children_Permission => Read_Write));
-- If unitialized declaration, then set to Write_Only. If a
-- pointer declaration, it has a null default initialization.
- if Nkind (Expression (Decl)) = N_Empty
+ if No (Expression (Decl))
and then not Has_Full_Default_Initialization
(Etype (Defining_Identifier (Decl)))
and then not Is_Access_Type
(Etype (Defining_Identifier (Decl)))
+ -- Objects of shallow types are considered as always
+ -- initialized, leaving the checking of initialization to
+ -- flow analysis.
+ and then Deep
then
Elem.all.Tree.Permission := Write_Only;
Elem.all.Tree.Children_Permission := Write_Only;
Check_Node (Prefix (Expr));
when Name_Image =>
+ Check_List (Expressions (Expr));
+
+ when Name_Img =>
Check_Node (Prefix (Expr));
when Name_SPARK_Mode =>
| N_Use_Type_Clause
| N_Validate_Unchecked_Conversion
| N_Variable_Reference_Marker
- =>
+ =>
null;
-- The following nodes are rewritten by semantic analysis
when N_Identifier
| N_Expanded_Name
=>
- return Has_Alias_Deep (Etype (N));
+ return Is_Aliased (Entity (N)) or else Has_Alias_Deep (Etype (N));
when N_Defining_Identifier =>
- return Has_Alias_Deep (Etype (N));
+ return Is_Aliased (N) or else Has_Alias_Deep (Etype (N));
when N_Type_Conversion
| N_Unchecked_Type_Conversion
procedure Process_Path (N : Node_Id) is
Root : constant Entity_Id := Get_Enclosing_Object (N);
begin
+
-- We ignore if yielding to synchronized
if Present (Root)
-- We ignore shallow unaliased. They are checked in flow analysis,
-- allowing backward compatibility.
- if not Has_Alias (N)
+ if Current_Checking_Mode /= Super_Move
+ and then not Has_Alias (N)
and then Is_Shallow (Etype (N))
then
return;
when Read =>
if Perm_N not in Read_Perm then
Perm_Error (N, Read_Only, Perm_N);
+ return;
end if;
-- If shallow type no need for RW, only R
if Is_Shallow (Etype (N)) then
if Perm_N not in Read_Perm then
Perm_Error (N, Read_Only, Perm_N);
+ return;
end if;
else
-- Check permission RW if deep
if Perm_N /= Read_Write then
Perm_Error (N, Read_Write, Perm_N);
+ return;
end if;
declare
when Super_Move =>
if Perm_N /= Read_Write then
Perm_Error (N, Read_Write, Perm_N);
+ return;
end if;
declare
when Assign =>
if Perm_N not in Write_Perm then
Perm_Error (N, Write_Only, Perm_N);
+ return;
end if;
-- If the tree has an array component, then the permissions do
-- Same if has function component
- if Has_Function_Component (N) then
+ if Has_Function_Component (N) then -- Dead code?
return;
end if;
if Ekind (E) = E_Abstract_State then
null;
else
- Return_Parameter_Or_Global (E, Kind, Subp);
+ Return_Parameter_Or_Global (E, Kind, Subp, Global_Var => True);
end if;
Next_Global (Item);
end loop;
--------------------------------
procedure Return_Parameter_Or_Global
- (Id : Entity_Id;
- Mode : Formal_Kind;
- Subp : Entity_Id)
+ (Id : Entity_Id;
+ Mode : Formal_Kind;
+ Subp : Entity_Id;
+ Global_Var : Boolean)
is
Elem : constant Perm_Tree_Access := Get (Current_Perm_Env, Id);
pragma Assert (Elem /= null);
-- Shallow unaliased parameters and globals cannot introduce pointer
-- aliasing.
- if not Has_Alias (Id) and then Is_Shallow (Etype (Id)) then
+ if not Has_Alias (Id)
+ and then Is_Shallow (Etype (Id))
+ then
null;
-- Observed IN parameters and globals need not return a permission to
-- the caller.
- elsif Mode = E_In_Parameter and then not Is_Borrowed_In (Id) then
+ elsif Mode = E_In_Parameter
+ and then (not Is_Borrowed_In (Id)
+ or else Global_Var)
+ then
null;
-- All other parameters and globals should return with mode RW to the
begin
Formal := First_Formal (Subp);
while Present (Formal) loop
- Return_Parameter_Or_Global (Formal, Ekind (Formal), Subp);
+ Return_Parameter_Or_Global (Formal, Ekind (Formal), Subp, False);
Next_Formal (Formal);
end loop;
end Return_Parameters;
case Kind (C) is
when Entire_Object =>
pragma Assert (Children_Permission (C) = Read_Write);
+ -- Maroua: Children could have read_only perm. Why Read_Write?
C.all.Tree.Permission := Read_Write;
when Reference =>
when Array_Component =>
pragma Assert (C.all.Tree.Get_Elem /= null);
- -- Given that it is not possible to know which element has been
- -- assigned, then the permissions do not get changed in case of
- -- Array_Component.
+ -- Given that it is not possible to know which element has been
+ -- assigned, then the permissions do not get changed in case of
+ -- Array_Component.
null;
Comp : Perm_Tree_Access;
begin
- -- We take the Glb of all the descendants, and then update the
- -- permission of the node with it.
+ -- We take the Glb of all the descendants, and then update the
+ -- permission of the node with it.
Comp := Perm_Tree_Maps.Get_First (Component (C));
while Comp /= null loop
Perm := Glb (Perm, Permission (Comp));
if Ekind (E) = E_Abstract_State then
null;
else
- Setup_Parameter_Or_Global (E, Kind);
+ Setup_Parameter_Or_Global (E, Kind, Global_Var => True);
end if;
Next_Global (Item);
end loop;
-------------------------------
procedure Setup_Parameter_Or_Global
- (Id : Entity_Id;
- Mode : Formal_Kind)
+ (Id : Entity_Id;
+ Mode : Formal_Kind;
+ Global_Var : Boolean)
is
Elem : Perm_Tree_Access;
-- Borrowed IN: RW for everybody
- if Is_Borrowed_In (Id) then
+ if Is_Borrowed_In (Id) and not Global_Var then
Elem.all.Tree.Permission := Read_Write;
Elem.all.Tree.Children_Permission := Read_Write;
begin
Formal := First_Formal (Subp);
while Present (Formal) loop
- Setup_Parameter_Or_Global (Formal, Ekind (Formal));
+ Setup_Parameter_Or_Global
+ (Formal, Ekind (Formal), Global_Var => False);
Next_Formal (Formal);
end loop;
end Setup_Parameters;
-
end Sem_SPARK;