This patch avoids incorrect compilation errors if a derived type has a
parent type for which the Iterable aspect is specified, and a "for
... of" loop is used on an object of the derived type.

The following test should compile quietly.

gcc -c seqs-main.adb

package Seqs is
   type Container is null record
     with Iterable =>
       (First => First_Element,
        Next => Next,
        Has_Element => Has_Element,
        Element => Get_Element);

   type Cursor is new Integer;
   type Element is new Boolean;
   type Element_Access is access all Element;

   function First_Element (Self : Container) return Cursor;
   function Next (Self : Container; C : Cursor) return Cursor;
   function Has_Element (Self : Container; C : Cursor) return Boolean;
   function Get_Element (Self : Container; C : Cursor) return Element_Access;

   type Derived is new Container;
end Seqs;

procedure Seqs.Main is
   S : Derived;
begin
   for X of S loop
      null;
   end loop;
end Seqs.Main;

Tested on x86_64-pc-linux-gnu, committed on trunk

2017-09-18  Bob Duff  <d...@adacore.com>

        * exp_ch5.adb (Build_Formal_Container_Iteration,
        Expand_Formal_Container_Element_Loop): Convert the container to the
        root type before passing it to the iteration operations, so it will be
        of the right type.

Index: exp_ch5.adb
===================================================================
--- exp_ch5.adb (revision 252907)
+++ exp_ch5.adb (working copy)
@@ -74,6 +74,12 @@
    --  Utility to create declarations and loop statement for both forms
    --  of formal container iterators.
 
+   function Convert_To_Iterable_Type
+     (Container : Entity_Id; Loc : Source_Ptr) return Node_Id;
+   --  Returns New_Occurrence_Of (Container), possibly converted to an
+   --  ancestor type, if the type of Container inherited the Iterable
+   --  aspect_specification from that ancestor.
+
    function Change_Of_Representation (N : Node_Id) return Boolean;
    --  Determine if the right-hand side of assignment N is a type conversion
    --  which requires a change of representation. Called only for the array
@@ -189,7 +195,7 @@
             Make_Function_Call (Loc,
               Name                   => New_Occurrence_Of (First_Op, Loc),
               Parameter_Associations => New_List (
-                New_Occurrence_Of (Container, Loc))));
+                Convert_To_Iterable_Type (Container, Loc))));
 
       --  Statement that advances cursor in loop
 
@@ -200,7 +206,7 @@
             Make_Function_Call (Loc,
               Name                   => New_Occurrence_Of (Next_Op, Loc),
               Parameter_Associations => New_List (
-                New_Occurrence_Of (Container, Loc),
+                Convert_To_Iterable_Type (Container, Loc),
                 New_Occurrence_Of (Cursor, Loc))));
 
       --  Iterator is rewritten as a while_loop
@@ -211,13 +217,12 @@
             Make_Iteration_Scheme (Loc,
               Condition =>
                 Make_Function_Call (Loc,
-                  Name                   =>
-                    New_Occurrence_Of (Has_Element_Op, Loc),
+                  Name => New_Occurrence_Of (Has_Element_Op, Loc),
                   Parameter_Associations => New_List (
-                    New_Occurrence_Of (Container, Loc),
+                    Convert_To_Iterable_Type (Container, Loc),
                     New_Occurrence_Of (Cursor, Loc)))),
-          Statements       => Stats,
-          End_Label        => Empty);
+          Statements => Stats,
+          End_Label  => Empty);
    end Build_Formal_Container_Iteration;
 
    ------------------------------
@@ -233,6 +238,26 @@
             not Same_Representation (Etype (Rhs), Etype (Expression (Rhs)));
    end Change_Of_Representation;
 
+   ------------------------------
+   -- Convert_To_Iterable_Type --
+   ------------------------------
+
+   function Convert_To_Iterable_Type
+     (Container : Entity_Id; Loc : Source_Ptr) return Node_Id
+   is
+      Typ    : constant Entity_Id  := Base_Type (Etype (Container));
+      Aspect : constant Node_Id := Find_Aspect (Typ, Aspect_Iterable);
+      Result : Node_Id := New_Occurrence_Of (Container, Loc);
+   begin
+      if Entity (Aspect) /= Typ then
+         Result := Make_Type_Conversion (Loc,
+                     Subtype_Mark => New_Occurrence_Of (Entity (Aspect), Loc),
+                     Expression   => Result);
+      end if;
+
+      return Result;
+   end Convert_To_Iterable_Type;
+
    -------------------------
    -- Expand_Assign_Array --
    -------------------------
@@ -3207,7 +3232,7 @@
            Make_Function_Call (Loc,
              Name                   => New_Occurrence_Of (Element_Op, Loc),
              Parameter_Associations => New_List (
-               New_Occurrence_Of (Container, Loc),
+               Convert_To_Iterable_Type (Container, Loc),
                New_Occurrence_Of (Cursor, Loc))));
 
          Set_Statements (New_Loop,
@@ -3226,7 +3251,7 @@
                Make_Function_Call (Loc,
                  Name                   => New_Occurrence_Of (Element_Op, Loc),
                  Parameter_Associations => New_List (
-                   New_Occurrence_Of (Container, Loc),
+                   Convert_To_Iterable_Type (Container, Loc),
                    New_Occurrence_Of (Cursor, Loc))));
 
          Prepend (Elmt_Ref, Stats);

Reply via email to