This patch adds an informational warning to alert the user to the fact that
GNAT currently mishandles coextensions and that they will not be finalized or
deallocated with their respective owners in some as they should according
to RM 13.11.2 (9/3).
------------
-- Source --
------------
-- types.ads
with Ada.Finalization; use Ada.Finalization;
package Types is
type Ctrl_Discr is new Controlled with record
Id : Natural;
end record;
type Ctrl_Discr_Ptr is access all Ctrl_Discr;
procedure Finalize (Obj : in out Ctrl_Discr);
procedure Initialize (Obj : in out Ctrl_Discr);
type Discr_B is null record;
type Discr_B_Ptr is access all Discr_B;
type Ctrl_Owner_B (Discr : access Discr_B) is new Controlled with record
Id : Natural;
end record;
type Ctrl_Owner_B_Ptr is access all Ctrl_Owner_B;
procedure Finalize (Obj : in out Ctrl_Owner_B);
procedure Initialize (Obj : in out Ctrl_Owner_B);
type Ctrl_Owner (Discr : access Ctrl_Discr) is new Controlled with record
Id : Natural;
end record;
type Ctrl_Owner_Ptr is access all Ctrl_Owner;
procedure Finalize (Obj : in out Ctrl_Owner);
procedure Initialize (Obj : in out Ctrl_Owner);
type Owner (Discr : access Ctrl_Discr) is null record;
type Owner_Ptr is access all Owner;
type Owner_B (Discr : access Discr_B) is null record;
type Owner_B_Ptr is access all Owner_B;
function New_Id return Natural;
end Types;
-- types.adb
with Ada.Text_IO; use Ada.Text_IO;
package body Types is
Id_Gen : Natural := 0;
procedure Finalize (Obj : in out Ctrl_Discr) is
begin
Put_Line (" fin Discr:" & Obj.Id'Img);
Obj.Id := 0;
end Finalize;
procedure Finalize (Obj : in out Ctrl_Owner) is
begin
Put_Line (" fin Ctrl_Owner:" & Obj.Id'Img);
Obj.Id := 0;
end Finalize;
procedure Finalize (Obj : in out Ctrl_Owner_B) is
begin
Put_Line (" fin Ctrl_Owner_B:" & Obj.Id'Image);
Obj.Id := 0;
end;
procedure Initialize (Obj : in out Ctrl_Discr) is
begin
Obj.Id := New_Id;
Put_Line (" ini Discr:" & Obj.Id'Img);
end Initialize;
procedure Initialize (Obj : in out Ctrl_Owner) is
begin
Obj.Id := New_Id;
Put_Line (" ini Ctrl_Owner:" & Obj.Id'Img);
end Initialize;
procedure Initialize (Obj : in out Ctrl_Owner_B) is
begin
Obj.Id := New_Id;
Put_Line (" ini Ctrl_Owner_B:" & Obj.Id'Img);
end Initialize;
function New_Id return Natural is
begin
Id_Gen := Id_Gen + 1;
return Id_Gen;
end New_Id;
end Types;
-- main.adb
with Ada.Finalization; use Ada.Finalization;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Deallocation;
with Types; use Types;
procedure Main is
procedure Free is
new Ada.Unchecked_Deallocation (Ctrl_Owner, Ctrl_Owner_Ptr);
procedure Free is
new Ada.Unchecked_Deallocation (Owner, Owner_Ptr);
procedure Free is
new Ada.Unchecked_Deallocation (Ctrl_Owner_B, Ctrl_Owner_B_Ptr);
procedure Free is
new Ada.Unchecked_Deallocation (Owner_B, Owner_B_Ptr);
begin
Put_Line ("Ctrl_Owner named access - non-controlled discr");
declare
D_Ptr_1 : constant Discr_B_Ptr := new Discr_B;
D_Ptr_2 : constant access Discr_B := new Discr_B;
O_Ptr_1 : Ctrl_Owner_B_Ptr :=
new Ctrl_Owner_B'(Controlled with Discr => new Discr_B,
Id => New_Id);
O_Ptr_2 : Ctrl_Owner_B_Ptr :=
new Ctrl_Owner_B'(Controlled with Discr => D_Ptr_1,
Id => New_Id);
O_Ptr_3 : Ctrl_Owner_B_Ptr :=
new Ctrl_Owner_B'(Controlled with Discr => D_Ptr_2,
Id => New_Id);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Ctrl_Owner anonymous access - non-controlled discr");
declare
D_Ptr_1 : constant Discr_B_Ptr := new Discr_B;
D_Ptr_2 : constant access Discr_B := new Discr_B;
O_Ptr_1 : access Ctrl_Owner_B :=
new Ctrl_Owner_B'(Controlled with Discr => new Discr_B,
Id => New_Id);
O_Ptr_2 : access Ctrl_Owner_B :=
new Ctrl_Owner_B'(Controlled with Discr => D_Ptr_1,
Id => New_Id);
O_Ptr_3 : access Ctrl_Owner_B :=
new Ctrl_Owner_B'(Controlled with Discr => D_Ptr_2,
Id => New_Id);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Owner named access - non-controlled discr");
declare
D_Ptr_1 : constant Discr_B_Ptr := new Discr_B;
D_Ptr_2 : constant access Discr_B := new Discr_B;
O_Ptr_1 : Owner_B_Ptr := new Owner_B'(Discr => new Discr_B);
O_Ptr_2 : Owner_B_Ptr := new Owner_B'(Discr => D_Ptr_1);
O_Ptr_3 : Owner_B_Ptr := new Owner_B'(Discr => D_Ptr_2);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Owner anonymous access - non-controlled discr");
declare
D_Ptr_1 : constant Discr_B_Ptr := new Discr_B;
D_Ptr_2 : constant access Discr_B := new Discr_B;
O_Ptr_1 : access Owner_B := new Owner_B'(Discr => new Discr_B);
O_Ptr_2 : access Owner_B := new Owner_B'(Discr => D_Ptr_1);
O_Ptr_3 : access Owner_B := new Owner_B'(Discr => D_Ptr_2);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Ctrl_Owner named access - controlled discr");
declare
D_Ptr_1 : constant Ctrl_Discr_Ptr := new Ctrl_Discr;
D_Ptr_2 : constant access Ctrl_Discr := new Ctrl_Discr;
O_Ptr_1 : Ctrl_Owner_Ptr :=
new Ctrl_Owner'(Controlled with Discr => new Ctrl_Discr,
Id => New_Id);
O_Ptr_2 : Ctrl_Owner_Ptr :=
new Ctrl_Owner'(Controlled with Discr => D_Ptr_1,
Id => New_Id);
O_Ptr_3 : Ctrl_Owner_Ptr :=
new Ctrl_Owner'(Controlled with Discr => D_Ptr_2,
Id => New_Id);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Ctrl_Owner anonymous access - controlled discr");
declare
D_Ptr_1 : constant Ctrl_Discr_Ptr := new Ctrl_Discr;
D_Ptr_2 : constant access Ctrl_Discr := new Ctrl_Discr;
O_Ptr_1 : access Ctrl_Owner :=
new Ctrl_Owner'(Controlled with Discr => new Ctrl_Discr,
Id => New_Id);
O_Ptr_2 : access Ctrl_Owner :=
new Ctrl_Owner'(Controlled with Discr => D_Ptr_1,
Id => New_Id);
O_Ptr_3 : access Ctrl_Owner :=
new Ctrl_Owner'(Controlled with Discr => D_Ptr_2,
Id => New_Id);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Owner named access - controlled discr");
declare
D_Ptr_1 : constant Ctrl_Discr_Ptr := new Ctrl_Discr;
D_Ptr_2 : constant access Ctrl_Discr := new Ctrl_Discr;
O_Ptr_1 : Owner_Ptr := new Owner'(Discr => new Ctrl_Discr);
O_Ptr_2 : Owner_Ptr := new Owner'(Discr => D_Ptr_1);
O_Ptr_3 : Owner_Ptr := new Owner'(Discr => D_Ptr_2);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
Put_Line ("Owner anonymous access - controlled discr");
declare
D_Ptr_1 : constant Ctrl_Discr_Ptr := new Ctrl_Discr;
D_Ptr_2 : constant access Ctrl_Discr := new Ctrl_Discr;
O_Ptr_1 : access Owner := new Owner'(Discr => new Ctrl_Discr);
O_Ptr_2 : access Owner := new Owner'(Discr => D_Ptr_1);
O_Ptr_3 : access Owner := new Owner'(Discr => D_Ptr_2);
begin
Free (O_Ptr_1);
Free (O_Ptr_2);
Free (O_Ptr_3);
end;
end Main;
----------------------------
-- Compilation and output --
----------------------------
& gnatmake -q main.adb
main.adb:24:62: info: coextension will not be deallocated when its associated
owner is finalized
main.adb:47:62: info: coextension will not be deallocated when its associated
owner is finalized
main.adb:69:54: info: coextension will not be deallocated when its associated
owner is deallocated
main.adb:85:57: info: coextension will not be deallocated when its associated
owner is deallocated
main.adb:102:60: info: coextension will not be finalized when its associated
owner is finalized
main.adb:125:60: info: coextension will not be finalized when its associated
owner is finalized
main.adb:147:50: info: coextension will not be finalized when its associated
owner is deallocated
main.adb:163:53: info: coextension will not be finalized when its associated
owner is deallocated
Tested on x86_64-pc-linux-gnu, committed on trunk
2017-11-08 Justin Squirek <[email protected]>
* sem_res.adb (Resolve_Allocator): Add info messages corresponding to
the owner and corresponding coextension.
Index: sem_res.adb
===================================================================
--- sem_res.adb (revision 254544)
+++ sem_res.adb (working copy)
@@ -5143,6 +5143,38 @@
if not Is_Static_Coextension (N) then
Set_Is_Dynamic_Coextension (N);
+
+ -- ??? We currently do not handle finalization and deallocation
+ -- of coextensions properly so let's at least warn the user
+ -- about it.
+
+ if Is_Controlled_Active (Desig_T) then
+ if Is_Controlled_Active
+ (Defining_Identifier
+ (Parent (Associated_Node_For_Itype (Typ))))
+ then
+ Error_Msg_N
+ ("info: coextension will not be finalized when its "
+ & "associated owner is finalized", N);
+ else
+ Error_Msg_N
+ ("info: coextension will not be finalized when its "
+ & "associated owner is deallocated", N);
+ end if;
+ else
+ if Is_Controlled_Active
+ (Defining_Identifier
+ (Parent (Associated_Node_For_Itype (Typ))))
+ then
+ Error_Msg_N
+ ("info: coextension will not be deallocated when its "
+ & "associated owner is finalized", N);
+ else
+ Error_Msg_N
+ ("info: coextension will not be deallocated when its "
+ & "associated owner is deallocated", N);
+ end if;
+ end if;
end if;
-- Cleanup for potential static coextensions