[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