diff mbox series

[COMMITTED,35/35] ada: Improve deriving initial sizes for container aggregates

Message ID 20240517083207.130391-35-poulhies@adacore.com
State New
Headers show
Series [COMMITTED,01/35] ada: Add support for 'Object_Size to pragma Compile_Time_{Warning, Error} | expand

Commit Message

Marc Poulhiès May 17, 2024, 8:32 a.m. UTC
From: Viljar Indus <indus@adacore.com>

Deriving the initial size of container aggregates is necessary
for deriving the correct capacity for bounded containers.

Add support for deriving the correct initial size
when the container aggregate is iterating over an array
object.

gcc/ada/

	* exp_aggr.adb (Expand_Container_Aggregate):
	Derive the size for iterable aggregates in the case of
	one-dimensional array objects.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/exp_aggr.adb | 83 +++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 28 deletions(-)
diff mbox series

Patch

diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index 892f47ceb05..2476675604c 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -6693,9 +6693,9 @@  package body Exp_Aggr is
 
             --  If one or more of the associations is one of the iterated
             --  forms, and is either an association with nonstatic bounds
-            --  or is an iterator over an iterable object, then treat the
-            --  whole container aggregate as having a nonstatic number of
-            --  elements.
+            --  or is an iterator over an iterable object where the size
+            --  cannot be derived, then treat the whole container aggregate as
+            --  having a nonstatic number of elements.
 
             declare
                Has_Nonstatic_Length : Boolean := False;
@@ -6725,37 +6725,43 @@  package body Exp_Aggr is
             Comp := First (Component_Associations (N));
 
             while Present (Comp) loop
-               Choice := First (Choice_List (Comp));
+               if Present (Choice_List (Comp)) then
+                  Choice := First (Choice_List (Comp));
 
-               while Present (Choice) loop
-                  Analyze (Choice);
+                  while Present (Choice) loop
+                     Analyze (Choice);
 
-                  if Nkind (Choice) = N_Range then
-                     Lo := Low_Bound (Choice);
-                     Hi := High_Bound (Choice);
-                     Add_Range_Size;
+                     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;
+                     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)));
+                        Rewrite (Choice,
+                          Make_Range (Loc,
+                            New_Copy_Tree (Lo),
+                            New_Copy_Tree (Hi)));
 
-                  else
-                     --  Single choice (syntax excludes a subtype
-                     --  indication).
+                     else
+                        --  Single choice (syntax excludes a subtype
+                        --  indication).
 
-                     Siz := Siz + 1;
-                  end if;
+                        Siz := Siz + 1;
+                     end if;
 
-                  Next (Choice);
-               end loop;
+                     Next (Choice);
+                  end loop;
+
+               elsif Nkind (Comp) = N_Iterated_Component_Association then
+
+                  Siz := Siz + Build_Siz_Exp (Comp);
+               end if;
                Next (Comp);
             end loop;
          end if;
@@ -6770,6 +6776,7 @@  package body Exp_Aggr is
       function Build_Siz_Exp (Comp : Node_Id) return Int is
          Lo, Hi       : Node_Id;
          Temp_Siz_Exp : Node_Id;
+         It           : Node_Id;
 
       begin
          if Nkind (Comp) = N_Range then
@@ -6835,8 +6842,28 @@  package body Exp_Aggr is
             end if;
 
          elsif Nkind (Comp) = N_Iterated_Component_Association then
-            return Build_Siz_Exp (First (Discrete_Choices (Comp)));
+            if Present (Iterator_Specification (Comp)) then
+
+               --  If the static size of the iterable object is known,
+               --  attempt to return it.
+
+               It := Name (Iterator_Specification (Comp));
+               Preanalyze (It);
 
+               --  Handle the simplest cases for now where It denotes a
+               --  top-level one-dimensional array objects".
+
+               if Nkind (It) in N_Identifier
+                 and then Ekind (Etype (It)) = E_Array_Subtype
+                 and then No (Next_Index (First_Index (Etype (It))))
+               then
+                  return Build_Siz_Exp (First_Index (Etype (It)));
+               end if;
+
+               return -1;
+            else
+               return Build_Siz_Exp (First (Discrete_Choices (Comp)));
+            end if;
          elsif Nkind (Comp) = N_Iterated_Element_Association then
             return -1;