[Ada] Ada_2020: ongoing work for aggregates for bounded containers
authorEd Schonberg <schonberg@adacore.com>
Thu, 13 Aug 2020 14:38:26 +0000 (10:38 -0400)
committerPierre-Marie de Rodat <derodat@adacore.com>
Thu, 22 Oct 2020 12:11:20 +0000 (08:11 -0400)
gcc/ada/

* sem_aggr.adb: (Resolve_Container_Aggregate): For an indexed
container, verify that expressions and component associations
are not both present.
* exp_aggr.adb: Code reorganization, additional comments.
(Expand_Container_Aggregate): Use Aggregate_Size for Iterated_
Component_Associations for indexed aggregates. If present, the
default value of the formal in the constructor function is used
when the size of the aggregate cannot be determined statically.

gcc/ada/exp_aggr.adb
gcc/ada/sem_aggr.adb

index 6c274a2..698f671 100644 (file)
@@ -6909,7 +6909,15 @@ package body Exp_Aggr is
 
       Comp      : Node_Id;
       Decl      : Node_Id;
+      Default   : Node_Id;
       Init_Stat : Node_Id;
+      Siz       : Int;
+
+      function Aggregate_Size return Int;
+      --  Compute number of entries in aggregate, including choices
+      --  that cover a range, as well as iterated constructs.
+      --  Return -1 if the size is not known statically, in which case
+      --  we allocate a default size for the aggregate.
 
       procedure Expand_Iterated_Component (Comp : Node_Id);
       --  Handle iterated_component_association and iterated_Element
@@ -6917,6 +6925,86 @@ package body Exp_Aggr is
       --  given either by a loop parameter specification or an iterator
       --  specification.
 
+      --------------------
+      -- Aggregate_Size --
+      --------------------
+
+      function Aggregate_Size return Int is
+         Comp   : Node_Id;
+         Choice : Node_Id;
+         Lo, Hi : Node_Id;
+         Siz     : Int := 0;
+
+         procedure Add_Range_Size;
+         --  Compute size of component association given by
+         --  range or subtype name.
+
+         procedure Add_Range_Size is
+         begin
+            if Nkind (Lo) = N_Integer_Literal then
+               Siz := Siz + UI_To_Int (Intval (Hi))
+                 - UI_To_Int (Intval (Lo)) + 1;
+            end if;
+         end Add_Range_Size;
+
+      begin
+         if Present (Expressions (N)) then
+            Siz := List_Length (Expressions (N));
+         end if;
+
+         if Present (Component_Associations (N)) then
+            Comp := First (Component_Associations (N));
+            while Present (Comp) loop
+               Choice := First (Choice_List (Comp));
+
+               while Present (Choice) loop
+                  Analyze (Choice);
+
+                  if Nkind (Choice) = N_Range then
+                     Lo := Low_Bound (Choice);
+                     Hi := High_Bound (Choice);
+                     if Nkind (Lo) /= N_Integer_Literal
+                       or else Nkind (Hi) /= N_Integer_Literal
+                     then
+                        return -1;
+                     else
+                        Add_Range_Size;
+                     end if;
+
+                  elsif Is_Entity_Name (Choice)
+                    and then Is_Type (Entity (Choice))
+                  then
+                     Lo := Type_Low_Bound (Entity (Choice));
+                     Hi := Type_High_Bound (Entity (Choice));
+                     if Nkind (Lo) /= N_Integer_Literal
+                       or else Nkind (Hi) /= N_Integer_Literal
+                     then
+                        return -1;
+                     else
+                        Add_Range_Size;
+                     end if;
+
+                     Rewrite (Choice,
+                       Make_Range (Loc,
+                         New_Copy_Tree (Lo),
+                         New_Copy_Tree (Hi)));
+
+                  else
+                     --  Single choice (syntax excludes a subtype
+                     --  indication).
+
+                     Siz := Siz + 1;
+                  end if;
+
+                  Next (Choice);
+               end loop;
+               Next (Comp);
+            end loop;
+         end if;
+
+         return Siz;
+      end Aggregate_Size;
+
       -------------------------------
       -- Expand_Iterated_Component --
       -------------------------------
@@ -7040,35 +7128,78 @@ package body Exp_Aggr is
 
       end Expand_Iterated_Component;
 
+      --  Start of processing for Expand_Container_Aggregate
+
    begin
       Parse_Aspect_Aggregate (Asp,
         Empty_Subp, Add_Named_Subp, Add_Unnamed_Subp,
         New_Indexed_Subp, Assign_Indexed_Subp);
-      Decl :=
-        Make_Object_Declaration (Loc,
-          Defining_Identifier => Temp,
-          Object_Definition   => New_Occurrence_Of (Typ, Loc));
-
-      Insert_Action (N, Decl);
-      if Ekind (Entity (Empty_Subp)) = E_Function then
-         Init_Stat := Make_Assignment_Statement (Loc,
-           Name => New_Occurrence_Of (Temp, Loc),
-           Expression => Make_Function_Call (Loc,
-             Name => New_Occurrence_Of (Entity (Empty_Subp), Loc)));
-      else
-         Init_Stat := Make_Assignment_Statement (Loc,
-           Name => New_Occurrence_Of (Temp, Loc),
-           Expression => New_Occurrence_Of (Entity (Empty_Subp), Loc));
+
+      --  The constructor for bounded containers is a function with
+      --  a parameter that sets the size of the container. If the
+      --  size cannot be determined statically we use a default value.
+
+      Siz := Aggregate_Size;
+      if Siz < 0 then
+         Siz := 10;
       end if;
 
-      Append (Init_Stat, Aggr_Code);
+      if Ekind (Entity (Empty_Subp)) = E_Function
+        and then Present (First_Formal (Entity (Empty_Subp)))
+      then
+         Default := Default_Value (First_Formal (Entity (Empty_Subp)));
+         --  If aggregate size is not static, use default value of
+         --  formal parameter for allocation. We assume that this
+         --  (implementation-dependent) value is static, even though
+         --   the AI does not require it ???.
+
+         if Siz < 0 then
+            Siz := UI_To_Int (Intval (Default));
+         end if;
+
+         Init_Stat :=
+           Make_Object_Declaration (Loc,
+             Defining_Identifier => Temp,
+             Object_Definition   => New_Occurrence_Of (Typ, Loc),
+             Expression => Make_Function_Call (Loc,
+               Name => New_Occurrence_Of (Entity (Empty_Subp), Loc),
+               Parameter_Associations =>
+                 New_List (Make_Integer_Literal (Loc, Siz))));
+
+         Append (Init_Stat, Aggr_Code);
+
+         --  Use default value when aggregate size is not static.
+
+      else
+         Decl :=
+           Make_Object_Declaration (Loc,
+             Defining_Identifier => Temp,
+             Object_Definition   => New_Occurrence_Of (Typ, Loc));
+
+         Insert_Action (N, Decl);
+         if Ekind (Entity (Empty_Subp)) = E_Function then
+            Init_Stat := Make_Assignment_Statement (Loc,
+              Name => New_Occurrence_Of (Temp, Loc),
+              Expression => Make_Function_Call (Loc,
+                Name => New_Occurrence_Of (Entity (Empty_Subp), Loc)));
+         else
+            Init_Stat := Make_Assignment_Statement (Loc,
+              Name => New_Occurrence_Of (Temp, Loc),
+              Expression => New_Occurrence_Of (Entity (Empty_Subp), Loc));
+         end if;
+
+         Append (Init_Stat, Aggr_Code);
+      end if;
 
       ---------------------------
       --  Positional aggregate --
       ---------------------------
 
+      --  If the aggregate is positional the aspect must include
+      --  an Add_Unnamed subprogram.
+
       if Present (Add_Unnamed_Subp)
-        and then No (Assign_Indexed_Subp)
+        and then No (Component_Associations (N))
       then
          if Present (Expressions (N)) then
             declare
@@ -7137,21 +7268,25 @@ package body Exp_Aggr is
                Next (Comp);
             end loop;
          end;
+      end if;
 
       -----------------------
       -- Indexed_Aggregate --
       -----------------------
 
-      elsif Present (Assign_Indexed_Subp) then
+      --  For an indexed aggregate there must be an Assigned_Indexeed
+      --  subprogram. Note that unlike array aggregates, a container
+      --  aggregate must be fully positional or fully indexed. In the
+      --  first case the expansion has already taken place.
+
+      if Present (Assign_Indexed_Subp)
+        and then Present (Component_Associations (N))
+      then
          declare
             Insert : constant Entity_Id := Entity (Assign_Indexed_Subp);
             Index_Type : constant Entity_Id :=
                Etype (Next_Formal (First_Formal (Insert)));
 
-            function Aggregate_Size return Int;
-            --  Compute number of entries in aggregate, including choices
-            --  that cover a range, as well as iterated constructs.
-
             function  Expand_Range_Component
               (Rng  : Node_Id;
                Expr : Node_Id) return Node_Id;
@@ -7165,7 +7300,6 @@ package body Exp_Aggr is
             Pos    : Int := 0;
             Stat   : Node_Id;
             Key    : Node_Id;
-            Size   : Int := 0;
 
             -----------------------------
             -- Expand_Raange_Component --
@@ -7205,74 +7339,8 @@ package body Exp_Aggr is
                           Statements       => Stats);
             end Expand_Range_Component;
 
-            --------------------
-            -- Aggregate_Size --
-            --------------------
-
-            function Aggregate_Size return Int is
-               Comp   : Node_Id;
-               Choice : Node_Id;
-               Lo, Hi : Node_Id;
-               Siz     : Int := 0;
-
-               procedure Add_Range_Size;
-               --  Compute size of component association given by
-               --  range or subtype name.
-
-               procedure Add_Range_Size is
-               begin
-                  if Nkind (Lo) = N_Integer_Literal then
-                     Siz := Siz + UI_To_Int (Intval (Hi))
-                       - UI_To_Int (Intval (Lo)) + 1;
-                  end if;
-               end Add_Range_Size;
-
-            begin
-               if Present (Expressions (N)) then
-                  Siz := List_Length (Expressions (N));
-               end if;
-
-               if Present (Component_Associations (N)) then
-                  Comp := First (Component_Associations (N));
-                  while Present (Comp) loop
-                     Choice := First (Choices (Comp));
-
-                     while Present (Choice) loop
-                        Analyze (Choice);
-
-                        if Nkind (Choice) = N_Range then
-                           Lo := Low_Bound (Choice);
-                           Hi := High_Bound (Choice);
-                           Add_Range_Size;
-
-                        elsif Is_Entity_Name (Choice)
-                          and then Is_Type (Entity (Choice))
-                        then
-                           Lo := Type_Low_Bound (Entity (Choice));
-                           Hi := Type_High_Bound (Entity (Choice));
-                           Add_Range_Size;
-                           Rewrite (Choice,
-                             Make_Range (Loc,
-                               New_Copy_Tree (Lo),
-                               New_Copy_Tree (Hi)));
-
-                        else
-                           Resolve (Choice, Index_Type);
-                           Siz := Siz + 1;
-                        end if;
-
-                        Next (Choice);
-                     end loop;
-                     Next (Comp);
-                  end loop;
-               end if;
-
-               return Siz;
-            end Aggregate_Size;
-
          begin
-            Size := Aggregate_Size;
-            if Size > 0 then
+            if Siz > 0 then
 
                --  Modify the call to the constructor to allocate the
                --  required size for the aggregwte : call the provided
@@ -7280,7 +7348,7 @@ package body Exp_Aggr is
 
                Index :=  Make_Op_Add (Loc,
                  Left_Opnd => New_Copy_Tree (Type_Low_Bound (Index_Type)),
-                 Right_Opnd => Make_Integer_Literal (Loc, Size - 1));
+                 Right_Opnd => Make_Integer_Literal (Loc, Siz - 1));
 
                Set_Expression (Init_Stat,
                   Make_Function_Call (Loc,
@@ -7359,9 +7427,16 @@ package body Exp_Aggr is
                         <<Next_Key>>
                         Next (Key);
                      end loop;
+
                   else
-                     Error_Msg_N ("iterated associations peding", N);
+                     --  Iterated component association. Discard
+                     --  positional insertion procedure.
+
+                     Add_Named_Subp := Assign_Indexed_Subp;
+                     Add_Unnamed_Subp := Empty;
+                     Expand_Iterated_Component (Comp);
                   end if;
+
                   Next (Comp);
                end loop;
             end if;
index 9285c1c..688937e 100644 (file)
@@ -2930,9 +2930,9 @@ package body Sem_Aggr is
          end;
 
       else
-         --  Indexed Aggregate. Both positional and indexed component
-         --  can be present. Choices must be static values or ranges
-         --  with static bounds.
+         --  Indexed Aggregate. Positional or indexed component
+         --  can be present, but not both. Choices must be static
+         --  values or ranges with static bounds.
 
          declare
             Container : constant Entity_Id :=
@@ -2953,6 +2953,12 @@ package body Sem_Aggr is
             end if;
 
             if Present (Component_Associations (N)) then
+               if Present (Expressions (N)) then
+                  Error_Msg_N ("Container aggregate cannot be "
+                    & "both positional and named", N);
+                  return;
+               end if;
+
                Comp := First (Expressions (N));
 
                while Present (Comp) loop