[Ada] Missing finalization of generalized indexed element
Arnaud Charlet
charlet@adacore.com
Wed Sep 6 12:06:00 GMT 2017
This patch modifies the finalization mechanism to recognize a heavily expanded
generalized indexing where the element type requires finalization actions.
------------
-- Source --
------------
-- types.ads
with Ada.Finalization; use Ada.Finalization;
package Types is
type Element is new Controlled with record
Id : Natural := 0;
end record;
procedure Adjust (Obj : in out Element);
procedure Finalize (Obj : in out Element);
procedure Initialize (Obj : In out Element);
subtype Index is Integer range 1 .. 3;
type Collection is array (Index) of Element;
type Vector is new Controlled with record
Id : Natural := 0;
Elements : Collection;
end record
with Constant_Indexing => Element_At;
procedure Adjust (Obj : in out Vector);
procedure Finalize (Obj : in out Vector);
procedure Initialize (Obj : In out Vector);
function Element_At
(Obj : Vector;
Pos : Index) return Element'Class;
function Make_Vector return Vector'Class;
end Types;
-- types.adb
with Ada.Text_IO; use Ada.Text_IO;
package body Types is
Id_Gen : Natural := 10;
procedure Adjust (Obj : in out Element) is
Old_Id : constant Natural := Obj.Id;
New_Id : constant Natural := Old_Id + 1;
begin
if Old_Id = 0 then
Put_Line (" Element adj ERROR");
else
Put_Line (" Element adj" & Old_Id'Img & " ->" & New_Id'Img);
Obj.Id := New_Id;
end if;
end Adjust;
procedure Adjust (Obj : in out Vector) is
Old_Id : constant Natural := Obj.Id;
New_Id : constant Natural := Old_Id + 1;
begin
if Old_Id = 0 then
Put_Line (" Vector adj ERROR");
else
Put_Line (" Vector adj" & Old_Id'Img & " ->" & New_Id'Img);
Obj.Id := New_Id;
end if;
end Adjust;
function Element_At
(Obj : Vector;
Pos : Index) return Element'Class
is
begin
return Obj.Elements (Pos);
end Element_At;
procedure Finalize (Obj : in out Element) is
begin
if Obj.Id = 0 then
Put_Line (" Element fin ERROR");
else
Put_Line (" Element fin" & Obj.Id'Img);
Obj.Id := 0;
end if;
end Finalize;
procedure Finalize (Obj : in out Vector) is
begin
if Obj.Id = 0 then
Put_Line (" Vector fin ERROR");
else
Put_Line (" Vector fin" & Obj.Id'Img);
Obj.Id := 0;
end if;
end Finalize;
procedure Initialize (Obj : In out Element) is
begin
Obj.Id := Id_Gen;
Id_Gen := Id_Gen + 10;
Put_Line (" Element ini" & Obj.Id'Img);
end Initialize;
procedure Initialize (Obj : In out Vector) is
begin
Obj.Id := Id_Gen;
Id_Gen := Id_Gen + 10;
Put_Line (" Vector ini" & Obj.Id'Img);
end Initialize;
function Make_Vector return Vector'Class is
Result : Vector;
begin
return Result;
end Make_Vector;
end Types;
-- main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Types; use Types;
procedure Main is
begin
Put_Line ("Main");
declare
Vec : Vector'Class := Make_Vector;
Elem : Element'Class := Vec (1);
begin
Put_Line ("Main middle");
end;
Put_Line ("Main end");
end Main;
----------------------------
-- Compilation and output --
----------------------------
$ gnatmake -q main.adb
$ ./main.adb
Main
Element ini 10
Element ini 20
Element ini 30
Vector ini 40
Element adj 10 -> 11
Element adj 20 -> 21
Element adj 30 -> 31
Vector adj 40 -> 41
Vector fin 40
Element fin 30
Element fin 20
Element fin 10
Element adj 11 -> 12
Element adj 21 -> 22
Element adj 31 -> 32
Vector adj 41 -> 42
Vector fin 41
Element fin 31
Element fin 21
Element fin 11
Element adj 12 -> 13
Element adj 13 -> 14
Element fin 13
Main middle
Element fin 14
Vector fin 42
Element fin 32
Element fin 22
Element fin 12
Main end
Tested on x86_64-pc-linux-gnu, committed on trunk
2017-09-06 Hristian Kirtchev <kirtchev@adacore.com>
* exp_util.adb (Is_Controlled_Indexing): New routine.
(Is_Displace_Call): Use routine Strip to remove indirections.
(Is_Displacement_Of_Object_Or_Function_Result): Code clean up. Add a
missing case of controlled generalized indexing.
(Is_Source_Object): Use routine Strip to remove indirections.
(Strip): New routine.
-------------- next part --------------
Index: exp_util.adb
===================================================================
--- exp_util.adb (revision 251784)
+++ exp_util.adb (working copy)
@@ -7590,22 +7590,28 @@
(Obj_Id : Entity_Id) return Boolean
is
function Is_Controlled_Function_Call (N : Node_Id) return Boolean;
- -- Determine if particular node denotes a controlled function call. The
- -- call may have been heavily expanded.
+ -- Determine whether node N denotes a controlled function call
+ function Is_Controlled_Indexing (N : Node_Id) return Boolean;
+ -- Determine whether node N denotes a generalized indexing form which
+ -- involves a controlled result.
+
function Is_Displace_Call (N : Node_Id) return Boolean;
- -- Determine whether a particular node is a call to Ada.Tags.Displace.
- -- The call might be nested within other actions such as conversions.
+ -- Determine whether node N denotes a call to Ada.Tags.Displace
function Is_Source_Object (N : Node_Id) return Boolean;
-- Determine whether a particular node denotes a source object
+ function Strip (N : Node_Id) return Node_Id;
+ -- Examine arbitrary node N by stripping various indirections and return
+ -- the "real" node.
+
---------------------------------
-- Is_Controlled_Function_Call --
---------------------------------
function Is_Controlled_Function_Call (N : Node_Id) return Boolean is
- Expr : Node_Id := Original_Node (N);
+ Expr : Node_Id;
begin
-- When a function call appears in Object.Operation format, the
@@ -7617,6 +7623,7 @@
-- Obj.Func (Formal => Actual) N_Function_Call, whose Name is an
-- N_Selected_Component
+ Expr := Original_Node (N);
loop
if Nkind (Expr) = N_Function_Call then
Expr := Name (Expr);
@@ -7643,31 +7650,28 @@
and then Needs_Finalization (Etype (Entity (Expr)));
end Is_Controlled_Function_Call;
+ ----------------------------
+ -- Is_Controlled_Indexing --
+ ----------------------------
+
+ function Is_Controlled_Indexing (N : Node_Id) return Boolean is
+ Expr : constant Node_Id := Original_Node (N);
+
+ begin
+ return
+ Nkind (Expr) = N_Indexed_Component
+ and then Present (Generalized_Indexing (Expr))
+ and then Needs_Finalization (Etype (Expr));
+ end Is_Controlled_Indexing;
+
----------------------
-- Is_Displace_Call --
----------------------
function Is_Displace_Call (N : Node_Id) return Boolean is
- Call : Node_Id;
+ Call : constant Node_Id := Strip (N);
begin
- -- Strip various actions which may precede a call to Displace
-
- Call := N;
- loop
- if Nkind (Call) = N_Explicit_Dereference then
- Call := Prefix (Call);
-
- elsif Nkind_In (Call, N_Type_Conversion,
- N_Unchecked_Type_Conversion)
- then
- Call := Expression (Call);
-
- else
- exit;
- end if;
- end loop;
-
return
Present (Call)
and then Nkind (Call) = N_Function_Call
@@ -7679,38 +7683,48 @@
----------------------
function Is_Source_Object (N : Node_Id) return Boolean is
- Obj : Node_Id;
+ Obj : constant Node_Id := Strip (N);
begin
- -- Strip various actions which may be associated with the object
+ return
+ Present (Obj)
+ and then Comes_From_Source (Obj)
+ and then Nkind (Obj) in N_Has_Entity
+ and then Is_Object (Entity (Obj));
+ end Is_Source_Object;
- Obj := N;
+ -----------
+ -- Strip --
+ -----------
+
+ function Strip (N : Node_Id) return Node_Id is
+ Result : Node_Id;
+
+ begin
+ Result := N;
loop
- if Nkind (Obj) = N_Explicit_Dereference then
- Obj := Prefix (Obj);
+ if Nkind (Result) = N_Explicit_Dereference then
+ Result := Prefix (Result);
- elsif Nkind_In (Obj, N_Type_Conversion,
- N_Unchecked_Type_Conversion)
+ elsif Nkind_In (Result, N_Type_Conversion,
+ N_Unchecked_Type_Conversion)
then
- Obj := Expression (Obj);
+ Result := Expression (Result);
else
exit;
end if;
end loop;
- return
- Present (Obj)
- and then Nkind (Obj) in N_Has_Entity
- and then Is_Object (Entity (Obj))
- and then Comes_From_Source (Obj);
- end Is_Source_Object;
+ return Result;
+ end Strip;
-- Local variables
- Decl : constant Node_Id := Parent (Obj_Id);
+ Obj_Decl : constant Node_Id := Declaration_Node (Obj_Id);
Obj_Typ : constant Entity_Id := Base_Type (Etype (Obj_Id));
- Orig_Decl : constant Node_Id := Original_Node (Decl);
+ Orig_Decl : constant Node_Id := Original_Node (Obj_Decl);
+ Orig_Expr : Node_Id;
-- Start of processing for Is_Displacement_Of_Object_Or_Function_Result
@@ -7719,34 +7733,52 @@
-- Obj : CW_Type := Function_Call (...);
- -- rewritten into:
+ -- is rewritten into:
- -- Tmp : ... := Function_Call (...)'reference;
- -- Obj : CW_Type renames (... Ada.Tags.Displace (Tmp));
+ -- Temp : ... := Function_Call (...)'reference;
+ -- Obj : CW_Type renames (... Ada.Tags.Displace (Temp));
-- where the return type of the function and the class-wide type require
-- dispatch table pointer displacement.
-- Case 2:
+ -- Obj : CW_Type := Container (...);
+
+ -- is rewritten into:
+
+ -- Temp : ... := Function_Call (Container, ...)'reference;
+ -- Obj : CW_Type renames (... Ada.Tags.Displace (Temp));
+
+ -- where the container element type and the class-wide type require
+ -- dispatch table pointer dispacement.
+
+ -- Case 3:
+
-- Obj : CW_Type := Src_Obj;
- -- rewritten into:
+ -- is rewritten into:
-- Obj : CW_Type renames (... Ada.Tags.Displace (Src_Obj));
-- where the type of the source object and the class-wide type require
-- dispatch table pointer displacement.
- return
- Nkind (Decl) = N_Object_Renaming_Declaration
- and then Nkind (Orig_Decl) = N_Object_Declaration
- and then Comes_From_Source (Orig_Decl)
- and then Is_Class_Wide_Type (Obj_Typ)
- and then Is_Displace_Call (Renamed_Object (Obj_Id))
- and then
- (Is_Controlled_Function_Call (Expression (Orig_Decl))
- or else Is_Source_Object (Expression (Orig_Decl)));
+ if Nkind (Obj_Decl) = N_Object_Renaming_Declaration
+ and then Is_Class_Wide_Type (Obj_Typ)
+ and then Is_Displace_Call (Renamed_Object (Obj_Id))
+ and then Nkind (Orig_Decl) = N_Object_Declaration
+ and then Comes_From_Source (Orig_Decl)
+ then
+ Orig_Expr := Expression (Orig_Decl);
+
+ return
+ Is_Controlled_Function_Call (Orig_Expr)
+ or else Is_Controlled_Indexing (Orig_Expr)
+ or else Is_Source_Object (Orig_Expr);
+ end if;
+
+ return False;
end Is_Displacement_Of_Object_Or_Function_Result;
------------------------------
More information about the Gcc-patches
mailing list