summaryrefslogtreecommitdiff
path: root/gcc/ada/exp_aggr.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_aggr.adb')
-rw-r--r--gcc/ada/exp_aggr.adb1196
1 files changed, 792 insertions, 404 deletions
diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index b63cc53c993..0985ead93a7 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2002 Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2003 Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -114,6 +114,11 @@ package body Exp_Aggr is
-- an entity that allows to know if the value being created needs to be
-- attached to the final list in case of pragma finalize_Storage_Only.
+ function Has_Mutable_Components (Typ : Entity_Id) return Boolean;
+ -- Return true if one of the component is of a discriminated type with
+ -- defaults. An aggregate for a type with mutable components must be
+ -- expanded into individual assignments.
+
procedure Initialize_Discriminants (N : Node_Id; Typ : Entity_Id);
-- If the type of the aggregate is a type extension with renamed discrimi-
-- nants, we must initialize the hidden discriminants of the parent.
@@ -132,7 +137,7 @@ package body Exp_Aggr is
procedure Convert_To_Positional
(N : Node_Id;
- Max_Others_Replicate : Nat := 5;
+ Max_Others_Replicate : Nat := 5;
Handle_Bit_Packed : Boolean := False);
-- If possible, convert named notation to positional notation. This
-- conversion is possible only in some static cases. If the conversion
@@ -169,11 +174,14 @@ package body Exp_Aggr is
-- loops and assignments that are needed for the expansion of the array
-- aggregate N.
--
- -- N is the (sub-)aggregate node to be expanded into code.
+ -- N is the (sub-)aggregate node to be expanded into code. This node
+ -- has been fully analyzed, and its Etype is properly set.
--
-- Index is the index node corresponding to the array sub-aggregate N.
--
-- Into is the target expression into which we are copying the aggregate.
+ -- Note that this node may not have been analyzed yet, and so the Etype
+ -- field may not be set.
--
-- Scalar_Comp is True if the component type of the aggregate is scalar.
--
@@ -193,7 +201,7 @@ package body Exp_Aggr is
Target : Node_Id;
Flist : Node_Id := Empty;
Obj : Entity_Id := Empty)
- return List_Id;
+ return List_Id;
-- N is a nested (record or array) aggregate that has been marked
-- with 'Delay_Expansion'. Typ is the expected type of the
-- aggregate and Target is a (duplicable) expression that will
@@ -413,9 +421,9 @@ package body Exp_Aggr is
-- Returns a new reference to the index type name.
function Gen_Assign (Ind : Node_Id; Expr : Node_Id) return List_Id;
- -- Ind must be a side-effect free expression.
- -- If the input aggregate N to Build_Loop contains no sub-aggregates,
- -- This routine returns the assignment statement
+ -- Ind must be a side-effect free expression. If the input aggregate
+ -- N to Build_Loop contains no sub-aggregates, then this function
+ -- returns the assignment statement:
--
-- Into (Indices, Ind) := Expr;
--
@@ -445,7 +453,7 @@ package body Exp_Aggr is
-- Into (Indices, J) := Expr;
-- end loop;
--
- -- Otherwise we call Build_Code recursively.
+ -- Otherwise we call Build_Code recursively
function Local_Compile_Time_Known_Value (E : Node_Id) return Boolean;
function Local_Expr_Value (E : Node_Id) return Uint;
@@ -465,9 +473,8 @@ package body Exp_Aggr is
Expr_Pos : Node_Id;
Expr : Node_Id;
To_Pos : Node_Id;
-
- U_To : Uint;
- U_Val : Uint := UI_From_Int (Val);
+ U_To : Uint;
+ U_Val : constant Uint := UI_From_Int (Val);
begin
-- Note: do not try to optimize the case of Val = 0, because
@@ -625,7 +632,7 @@ package body Exp_Aggr is
----------------
function Gen_Assign (Ind : Node_Id; Expr : Node_Id) return List_Id is
- L : List_Id := New_List;
+ L : constant List_Id := New_List;
F : Entity_Id;
A : Node_Id;
@@ -679,7 +686,6 @@ package body Exp_Aggr is
and then Present (Scope (Entity (Into)))
then
F := Find_Final_List (Scope (Entity (Into)));
-
else
F := Find_Final_List (Current_Scope);
end if;
@@ -692,15 +698,16 @@ package body Exp_Aggr is
Add_Loop_Actions (
Build_Array_Aggr_Code
(Expr, Next_Index (Index),
- Into, Scalar_Comp, New_Indices, F));
+ Into, Scalar_Comp, New_Indices, F));
end if;
-- If we get here then we are at a bottom-level (sub-)aggregate
- Indexed_Comp := Checks_Off (
- Make_Indexed_Component (Loc,
- Prefix => New_Copy_Tree (Into),
- Expressions => New_Indices));
+ Indexed_Comp :=
+ Checks_Off
+ (Make_Indexed_Component (Loc,
+ Prefix => New_Copy_Tree (Into),
+ Expressions => New_Indices));
Set_Assignment_OK (Indexed_Comp);
@@ -717,7 +724,7 @@ package body Exp_Aggr is
elsif Present (Next (First (New_Indices))) then
- -- this is a multidimensional array. Recover the component
+ -- This is a multidimensional array. Recover the component
-- type from the outermost aggregate, because subaggregates
-- do not have an assigned type.
@@ -740,10 +747,9 @@ package body Exp_Aggr is
end;
end if;
- if (Nkind (Expr_Q) = N_Aggregate
- or else Nkind (Expr_Q) = N_Extension_Aggregate)
+ if Nkind (Expr_Q) = N_Aggregate
+ or else Nkind (Expr_Q) = N_Extension_Aggregate
then
-
-- At this stage the Expression may not have been
-- analyzed yet because the array aggregate code has not
-- been updated to use the Expansion_Delayed flag and
@@ -837,8 +843,8 @@ package body Exp_Aggr is
L_Body : List_Id;
-- The statements to execute in the loop
- S : List_Id := New_List;
- -- list of statement
+ S : constant List_Id := New_List;
+ -- List of statements
Tcopy : Node_Id;
-- Copy of expression tree, used for checking purposes
@@ -950,7 +956,6 @@ package body Exp_Aggr is
-- end loop;
function Gen_While (L, H : Node_Id; Expr : Node_Id) return List_Id is
-
W_J : Node_Id;
W_Decl : Node_Id;
@@ -962,13 +967,13 @@ package body Exp_Aggr is
W_Index_Succ : Node_Id;
-- Index_Base'Succ (J)
- W_Increment : Node_Id;
+ W_Increment : Node_Id;
-- W_J := Index_Base'Succ (W)
- W_Body : List_Id := New_List;
+ W_Body : constant List_Id := New_List;
-- The statements to execute in the loop
- S : List_Id := New_List;
+ S : constant List_Id := New_List;
-- list of statement
begin
@@ -995,7 +1000,7 @@ package body Exp_Aggr is
Append_To (S, W_Decl);
- -- construct " while W_J < H"
+ -- Construct " while W_J < H"
W_Iteration_Scheme :=
Make_Iteration_Scheme
@@ -1053,8 +1058,8 @@ package body Exp_Aggr is
return Compile_Time_Known_Value (E)
or else
(Nkind (E) = N_Attribute_Reference
- and then Attribute_Name (E) = Name_Val
- and then Compile_Time_Known_Value (First (Expressions (E))));
+ and then Attribute_Name (E) = Name_Val
+ and then Compile_Time_Known_Value (First (Expressions (E))));
end Local_Compile_Time_Known_Value;
----------------------
@@ -1075,6 +1080,7 @@ package body Exp_Aggr is
Assoc : Node_Id;
Choice : Node_Id;
Expr : Node_Id;
+ Typ : Entity_Id;
Others_Expr : Node_Id := Empty;
@@ -1084,8 +1090,8 @@ package body Exp_Aggr is
-- the code generated by Build_Array_Aggr_Code is executed then these
-- bounds are OK. Otherwise a Constraint_Error would have been raised.
- Aggr_Low : constant Node_Id := Duplicate_Subexpr (Aggr_L);
- Aggr_High : constant Node_Id := Duplicate_Subexpr (Aggr_H);
+ Aggr_Low : constant Node_Id := Duplicate_Subexpr_No_Checks (Aggr_L);
+ Aggr_High : constant Node_Id := Duplicate_Subexpr_No_Checks (Aggr_H);
-- After Duplicate_Subexpr these are side-effect free.
Low : Node_Id;
@@ -1098,12 +1104,33 @@ package body Exp_Aggr is
Nb_Elements : Int;
-- Number of elements in the positional aggregate
- New_Code : List_Id := New_List;
+ New_Code : constant List_Id := New_List;
-- Start of processing for Build_Array_Aggr_Code
begin
+ -- First before we start, a special case. if we have a bit packed
+ -- array represented as a modular type, then clear the value to
+ -- zero first, to ensure that unused bits are properly cleared.
+
+ Typ := Etype (N);
+
+ if Present (Typ)
+ and then Is_Bit_Packed_Array (Typ)
+ and then Is_Modular_Integer_Type (Packed_Array_Type (Typ))
+ then
+ Append_To (New_Code,
+ Make_Assignment_Statement (Loc,
+ Name => New_Copy_Tree (Into),
+ Expression =>
+ Unchecked_Convert_To (Typ,
+ Make_Integer_Literal (Loc, Uint_0))));
+ end if;
+
+ -- We can skip this
-- STEP 1: Process component associations
+ -- For those associations that may generate a loop, initialize
+ -- Loop_Actions to collect inserted actions that may be crated.
if No (Expressions (N)) then
@@ -1111,22 +1138,24 @@ package body Exp_Aggr is
Assoc := First (Component_Associations (N));
while Present (Assoc) loop
-
Choice := First (Choices (Assoc));
while Present (Choice) loop
-
if Nkind (Choice) = N_Others_Choice then
+ Set_Loop_Actions (Assoc, New_List);
Others_Expr := Expression (Assoc);
exit;
end if;
Get_Index_Bounds (Choice, Low, High);
+ if Low /= High then
+ Set_Loop_Actions (Assoc, New_List);
+ end if;
+
Nb_Choices := Nb_Choices + 1;
Table (Nb_Choices) := (Choice_Lo => Low,
Choice_Hi => High,
Choice_Node => Expression (Assoc));
-
Next (Choice);
end loop;
@@ -1147,7 +1176,6 @@ package body Exp_Aggr is
Low := Table (J).Choice_Lo;
High := Table (J).Choice_Hi;
Expr := Table (J).Choice_Node;
-
Append_List (Gen_Loop (Low, High, Expr), To => New_Code);
end loop;
@@ -1161,7 +1189,6 @@ package body Exp_Aggr is
begin
for J in 0 .. Nb_Choices loop
-
if J = 0 then
Low := Aggr_Low;
else
@@ -1174,7 +1201,7 @@ package body Exp_Aggr is
High := Add (-1, To => Table (J + 1).Choice_Lo);
end if;
- -- If this is an expansion within an init_proc, make
+ -- If this is an expansion within an init proc, make
-- sure that discriminant references are replaced by
-- the corresponding discriminal.
@@ -1261,7 +1288,6 @@ package body Exp_Aggr is
Comp_Type : Entity_Id;
Selector : Entity_Id;
Comp_Expr : Node_Id;
- Comp_Kind : Node_Kind;
Expr_Q : Node_Id;
Internal_Final_List : Node_Id;
@@ -1300,11 +1326,11 @@ package body Exp_Aggr is
F : Node_Id;
Attach : Node_Id;
Init_Pr : Boolean)
- return List_Id;
+ return List_Id;
-- returns the list of statements necessary to initialize the internal
-- controller of the (possible) ancestor typ into target and attach
-- it to finalization list F. Init_Pr conditions the call to the
- -- init_proc since it may already be done due to ancestor initialization
+ -- init proc since it may already be done due to ancestor initialization
---------------------------------
-- Ancestor_Discriminant_Value --
@@ -1341,6 +1367,7 @@ package body Exp_Aggr is
if Disc = Corresp_Disc then
return Duplicate_Subexpr (Expression (Assoc));
end if;
+
Corresp_Disc :=
Corresponding_Discriminant (Corresp_Disc);
end loop;
@@ -1496,19 +1523,21 @@ package body Exp_Aggr is
F : Node_Id;
Attach : Node_Id;
Init_Pr : Boolean)
- return List_Id
+ return List_Id
is
+ L : constant List_Id := New_List;
Ref : Node_Id;
- L : List_Id := New_List;
begin
- -- _init_proc (target._controller);
+ -- Generate:
+ -- init-proc (target._controller);
-- initialize (target._controller);
-- Attach_to_Final_List (target._controller, F);
- Ref := Make_Selected_Component (Loc,
- Prefix => Convert_To (Typ, New_Copy_Tree (Target)),
- Selector_Name => Make_Identifier (Loc, Name_uController));
+ Ref :=
+ Make_Selected_Component (Loc,
+ Prefix => Convert_To (Typ, New_Copy_Tree (Target)),
+ Selector_Name => Make_Identifier (Loc, Name_uController));
Set_Assignment_OK (Ref);
if Init_Pr then
@@ -1537,7 +1566,6 @@ package body Exp_Aggr is
-- Start of processing for Build_Record_Aggr_Code
begin
-
-- Deal with the ancestor part of extension aggregates
-- or with the discriminants of the root type
@@ -1546,14 +1574,13 @@ package body Exp_Aggr is
A : constant Node_Id := Ancestor_Part (N);
begin
-
-- If the ancestor part is a subtype mark "T", we generate
- -- _init_proc (T(tmp)); if T is constrained and
- -- _init_proc (S(tmp)); where S applies an appropriate
+
+ -- init-proc (T(tmp)); if T is constrained and
+ -- init-proc (S(tmp)); where S applies an appropriate
-- constraint if T is unconstrained
if Is_Entity_Name (A) and then Is_Type (Entity (A)) then
-
Ancestor_Is_Subtype_Mark := True;
if Is_Constrained (Entity (A)) then
@@ -1568,13 +1595,15 @@ package body Exp_Aggr is
elsif Has_Discriminants (Entity (A)) then
declare
- Anc_Typ : Entity_Id := Entity (A);
- Discrim : Entity_Id := First_Discriminant (Anc_Typ);
- Anc_Constr : List_Id := New_List;
+ Anc_Typ : constant Entity_Id := Entity (A);
+ Anc_Constr : constant List_Id := New_List;
+ Discrim : Entity_Id;
Disc_Value : Node_Id;
New_Indic : Node_Id;
Subt_Decl : Node_Id;
+
begin
+ Discrim := First_Discriminant (Anc_Typ);
while Present (Discrim) loop
Disc_Value := Ancestor_Discriminant_Value (Discrim);
Append_To (Anc_Constr, Disc_Value);
@@ -1676,6 +1705,8 @@ package body Exp_Aggr is
end if;
end;
+ -- Normal case (not an extension aggregate)
+
else
-- Generate the discriminant expressions, component by component.
-- If the base type is an unchecked union, the discriminants are
@@ -1685,7 +1716,6 @@ package body Exp_Aggr is
if Has_Discriminants (Typ)
and then not Is_Unchecked_Union (Base_Type (Typ))
then
-
-- ??? The discriminants of the object not inherited in the type
-- of the object should be initialized here
@@ -1698,7 +1728,7 @@ package body Exp_Aggr is
Discriminant_Value : Node_Id;
begin
- Discriminant := First_Girder_Discriminant (Typ);
+ Discriminant := First_Stored_Discriminant (Typ);
while Present (Discriminant) loop
@@ -1721,7 +1751,7 @@ package body Exp_Aggr is
Set_No_Ctrl_Actions (Instr);
Append_To (L, Instr);
- Next_Girder_Discriminant (Discriminant);
+ Next_Stored_Discriminant (Discriminant);
end loop;
end;
end if;
@@ -1737,11 +1767,12 @@ package body Exp_Aggr is
while Present (Comp) loop
Selector := Entity (First (Choices (Comp)));
+ -- ???
+
if Ekind (Selector) /= E_Discriminant
or else Nkind (N) = N_Extension_Aggregate
then
Comp_Type := Etype (Selector);
- Comp_Kind := Nkind (Expression (Comp));
Comp_Expr :=
Make_Selected_Component (Loc,
Prefix => New_Copy_Tree (Target),
@@ -1764,6 +1795,7 @@ package body Exp_Aggr is
New_Copy_Tree (Target)),
Selector_Name =>
Make_Identifier (Loc, Name_uController));
+
Internal_Final_List :=
Make_Selected_Component (Loc,
Prefix => Internal_Final_List,
@@ -1772,14 +1804,18 @@ package body Exp_Aggr is
-- The internal final list can be part of a constant object
Set_Assignment_OK (Internal_Final_List);
+
else
Internal_Final_List := Empty;
end if;
+ -- ???
+
if Is_Delayed_Aggregate (Expr_Q) then
Append_List_To (L,
Late_Expansion (Expr_Q, Comp_Type, Comp_Expr,
Internal_Final_List));
+
else
Instr :=
Make_OK_Assignment_Statement (Loc,
@@ -1826,6 +1862,42 @@ package body Exp_Aggr is
With_Attach => Make_Integer_Literal (Loc, 1)));
end if;
end if;
+
+ -- ???
+
+ elsif Ekind (Selector) = E_Discriminant
+ and then Nkind (N) /= N_Extension_Aggregate
+ and then Nkind (Parent (N)) = N_Component_Association
+ and then Is_Constrained (Typ)
+ then
+ -- We must check that the discriminant value imposed by the
+ -- context is the same as the value given in the subaggregate,
+ -- because after the expansion into assignments there is no
+ -- record on which to perform a regular discriminant check.
+
+ declare
+ D_Val : Elmt_Id;
+ Disc : Entity_Id;
+
+ begin
+ D_Val := First_Elmt (Discriminant_Constraint (Typ));
+ Disc := First_Discriminant (Typ);
+
+ while Chars (Disc) /= Chars (Selector) loop
+ Next_Discriminant (Disc);
+ Next_Elmt (D_Val);
+ end loop;
+
+ pragma Assert (Present (D_Val));
+
+ Append_To (L,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Op_Ne (Loc,
+ Left_Opnd => New_Copy_Tree (Node (D_Val)),
+ Right_Opnd => Expression (Comp)),
+ Reason => CE_Discriminant_Check_Failed));
+ end;
end if;
Next (Comp);
@@ -1834,7 +1906,7 @@ package body Exp_Aggr is
-- If the type is tagged, the tag needs to be initialized (unless
-- compiling for the Java VM where tags are implicit). It is done
-- late in the initialization process because in some cases, we call
- -- the init_proc of an ancestor which will not leave out the right tag
+ -- the init proc of an ancestor which will not leave out the right tag
if Ancestor_Is_Expression then
null;
@@ -1898,8 +1970,7 @@ package body Exp_Aggr is
External_Final_List := Empty;
end if;
- -- initialize and attach the outer object in the is_controlled
- -- case
+ -- Initialize and attach the outer object in the is_controlled case
if Is_Controlled (Typ) then
if Ancestor_Is_Subtype_Mark then
@@ -1912,33 +1983,7 @@ package body Exp_Aggr is
Parameter_Associations => New_List (New_Copy_Tree (Ref))));
end if;
- -- ??? when the ancestor part is an expression, the global
- -- object is already attached at the wrong level. It should
- -- be detached and re-attached. We have a design problem here.
-
- if Ancestor_Is_Expression
- and then Has_Controlled_Component (Init_Typ)
- then
- null;
-
- elsif Has_Controlled_Component (Typ) then
- F := Make_Selected_Component (Loc,
- Prefix => New_Copy_Tree (Target),
- Selector_Name => Make_Identifier (Loc, Name_uController));
- F := Make_Selected_Component (Loc,
- Prefix => F,
- Selector_Name => Make_Identifier (Loc, Name_F));
-
- Ref := New_Copy_Tree (Target);
- Set_Assignment_OK (Ref);
-
- Append_To (L,
- Make_Attach_Call (
- Obj_Ref => Ref,
- Flist_Ref => F,
- With_Attach => Make_Integer_Literal (Loc, 1)));
-
- else -- is_Controlled (Typ) and not Has_Controlled_Component (Typ)
+ if not Has_Controlled_Component (Typ) then
Ref := New_Copy_Tree (Target);
Set_Assignment_OK (Ref);
Append_To (Start_L,
@@ -1949,7 +1994,7 @@ package body Exp_Aggr is
end if;
end if;
- -- in the Has_Controlled component case, all the intermediate
+ -- In the Has_Controlled component case, all the intermediate
-- controllers must be initialized
if Has_Controlled_Component (Typ) then
@@ -1962,7 +2007,7 @@ package body Exp_Aggr is
Outer_Typ := Base_Type (Typ);
- -- find outer type with a controller
+ -- Find outer type with a controller
while Outer_Typ /= Init_Typ
and then not Has_New_Controlled_Component (Outer_Typ)
@@ -1970,7 +2015,7 @@ package body Exp_Aggr is
Outer_Typ := Etype (Outer_Typ);
end loop;
- -- attach it to the outer record controller to the
+ -- Attach it to the outer record controller to the
-- external final list
if Outer_Typ = Init_Typ then
@@ -1981,7 +2026,8 @@ package body Exp_Aggr is
F => External_Final_List,
Attach => Attach,
Init_Pr => Ancestor_Is_Expression));
- At_Root := True;
+
+ At_Root := True;
Inner_Typ := Init_Typ;
else
@@ -1998,6 +2044,18 @@ package body Exp_Aggr is
not Is_Tagged_Type (Typ) or else Inner_Typ = Outer_Typ;
end if;
+ -- The outer object has to be attached as well
+
+ if Is_Controlled (Typ) then
+ Ref := New_Copy_Tree (Target);
+ Set_Assignment_OK (Ref);
+ Append_To (Start_L,
+ Make_Attach_Call (
+ Obj_Ref => Ref,
+ Flist_Ref => New_Copy_Tree (External_Final_List),
+ With_Attach => New_Copy_Tree (Attach)));
+ end if;
+
-- Initialize the internal controllers for tagged types with
-- more than one controller.
@@ -2008,9 +2066,11 @@ package body Exp_Aggr is
Prefix => Convert_To (Outer_Typ, New_Copy_Tree (Target)),
Selector_Name =>
Make_Identifier (Loc, Name_uController));
- F := Make_Selected_Component (Loc,
- Prefix => F,
- Selector_Name => Make_Identifier (Loc, Name_F));
+ F :=
+ Make_Selected_Component (Loc,
+ Prefix => F,
+ Selector_Name => Make_Identifier (Loc, Name_F));
+
Append_List_To (Start_L,
Init_Controller (
Target => Target,
@@ -2027,7 +2087,7 @@ package body Exp_Aggr is
Inner_Typ := Etype (Inner_Typ);
end loop;
- -- if not done yet attach the controller of the ancestor part
+ -- If not done yet attach the controller of the ancestor part
if Outer_Typ /= Init_Typ
and then Inner_Typ = Init_Typ
@@ -2037,9 +2097,10 @@ package body Exp_Aggr is
Make_Selected_Component (Loc,
Prefix => Convert_To (Outer_Typ, New_Copy_Tree (Target)),
Selector_Name => Make_Identifier (Loc, Name_uController));
- F := Make_Selected_Component (Loc,
- Prefix => F,
- Selector_Name => Make_Identifier (Loc, Name_F));
+ F :=
+ Make_Selected_Component (Loc,
+ Prefix => F,
+ Selector_Name => Make_Identifier (Loc, Name_F));
Attach := Make_Integer_Literal (Loc, 1);
Append_List_To (Start_L,
@@ -2065,8 +2126,11 @@ package body Exp_Aggr is
Loc : constant Source_Ptr := Sloc (Aggr);
Typ : constant Entity_Id := Etype (Aggr);
Temp : constant Entity_Id := Defining_Identifier (Decl);
- Occ : constant Node_Id := Unchecked_Convert_To (Typ,
- Make_Explicit_Dereference (Loc, New_Reference_To (Temp, Loc)));
+
+ Occ : constant Node_Id :=
+ Unchecked_Convert_To (Typ,
+ Make_Explicit_Dereference (Loc,
+ New_Reference_To (Temp, Loc)));
Access_Type : constant Entity_Id := Etype (Temp);
@@ -2082,7 +2146,7 @@ package body Exp_Aggr is
--------------------------------
procedure Convert_Aggr_In_Assignment (N : Node_Id) is
- Aggr : Node_Id := Expression (N);
+ Aggr : Node_Id := Expression (N);
Typ : constant Entity_Id := Etype (Aggr);
Occ : constant Node_Id := New_Copy_Tree (Name (N));
@@ -2102,11 +2166,82 @@ package body Exp_Aggr is
procedure Convert_Aggr_In_Object_Decl (N : Node_Id) is
Obj : constant Entity_Id := Defining_Identifier (N);
- Aggr : Node_Id := Expression (N);
+ Aggr : Node_Id := Expression (N);
Loc : constant Source_Ptr := Sloc (Aggr);
Typ : constant Entity_Id := Etype (Aggr);
Occ : constant Node_Id := New_Occurrence_Of (Obj, Loc);
+ function Discriminants_Ok return Boolean;
+ -- If the object type is constrained, the discriminants in the
+ -- aggregate must be checked against the discriminants of the subtype.
+ -- This cannot be done using Apply_Discriminant_Checks because after
+ -- expansion there is no aggregate left to check.
+
+ ----------------------
+ -- Discriminants_Ok --
+ ----------------------
+
+ function Discriminants_Ok return Boolean is
+ Cond : Node_Id := Empty;
+ Check : Node_Id;
+ D : Entity_Id;
+ Disc1 : Elmt_Id;
+ Disc2 : Elmt_Id;
+ Val1 : Node_Id;
+ Val2 : Node_Id;
+
+ begin
+ D := First_Discriminant (Typ);
+ Disc1 := First_Elmt (Discriminant_Constraint (Typ));
+ Disc2 := First_Elmt (Discriminant_Constraint (Etype (Obj)));
+
+ while Present (Disc1) and then Present (Disc2) loop
+ Val1 := Node (Disc1);
+ Val2 := Node (Disc2);
+
+ if not Is_OK_Static_Expression (Val1)
+ or else not Is_OK_Static_Expression (Val2)
+ then
+ Check := Make_Op_Ne (Loc,
+ Left_Opnd => Duplicate_Subexpr (Val1),
+ Right_Opnd => Duplicate_Subexpr (Val2));
+
+ if No (Cond) then
+ Cond := Check;
+
+ else
+ Cond := Make_Or_Else (Loc,
+ Left_Opnd => Cond,
+ Right_Opnd => Check);
+ end if;
+
+ elsif Expr_Value (Val1) /= Expr_Value (Val2) then
+ Apply_Compile_Time_Constraint_Error (Aggr,
+ Msg => "incorrect value for discriminant&?",
+ Reason => CE_Discriminant_Check_Failed,
+ Ent => D);
+ return False;
+ end if;
+
+ Next_Discriminant (D);
+ Next_Elmt (Disc1);
+ Next_Elmt (Disc2);
+ end loop;
+
+ -- If any discriminant constraint is non-static, emit a check.
+
+ if Present (Cond) then
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition => Cond,
+ Reason => CE_Discriminant_Check_Failed));
+ end if;
+
+ return True;
+ end Discriminants_Ok;
+
+ -- Start of processing for Convert_Aggr_In_Object_Decl
+
begin
Set_Assignment_OK (Occ);
@@ -2114,6 +2249,14 @@ package body Exp_Aggr is
Aggr := Expression (Aggr);
end if;
+ if Has_Discriminants (Typ)
+ and then Typ /= Etype (Obj)
+ and then Is_Constrained (Etype (Obj))
+ and then not Discriminants_Ok
+ then
+ return;
+ end if;
+
Insert_Actions_After (N, Late_Expansion (Aggr, Typ, Occ, Obj => Obj));
Set_No_Initialization (N);
Initialize_Discriminants (N, Typ);
@@ -2127,14 +2270,13 @@ package body Exp_Aggr is
Loc : constant Source_Ptr := Sloc (N);
Temp : Entity_Id;
- Instr : Node_Id;
- Target_Expr : Node_Id;
- Parent_Kind : Node_Kind;
- Unc_Decl : Boolean := False;
- Parent_Node : Node_Id;
+ Instr : Node_Id;
+ Target_Expr : Node_Id;
+ Parent_Kind : Node_Kind;
+ Unc_Decl : Boolean := False;
+ Parent_Node : Node_Id;
begin
-
Parent_Node := Parent (N);
Parent_Kind := Nkind (Parent_Node);
@@ -2147,24 +2289,26 @@ package body Exp_Aggr is
begin
Parent_Node := Parent (Parent_Node);
Parent_Kind := Nkind (Parent_Node);
+
if Parent_Kind = N_Object_Declaration then
Unc_Decl :=
not Is_Entity_Name (Object_Definition (Parent_Node))
- or else Has_Discriminants (
- Entity (Object_Definition (Parent_Node)))
- or else Is_Class_Wide_Type (
- Entity (Object_Definition (Parent_Node)));
+ or else Has_Discriminants
+ (Entity (Object_Definition (Parent_Node)))
+ or else Is_Class_Wide_Type
+ (Entity (Object_Definition (Parent_Node)));
end if;
end;
end if;
-- Just set the Delay flag in the following cases where the
-- transformation will be done top down from above
+
-- - internal aggregate (transformed when expanding the parent)
-- - allocators (see Convert_Aggr_In_Allocator)
-- - object decl (see Convert_Aggr_In_Object_Decl)
-- - safe assignments (see Convert_Aggr_Assignments)
- -- so far only the assignments in the init_procs are taken
+ -- so far only the assignments in the init procs are taken
-- into account
if Parent_Kind = N_Aggregate
@@ -2209,231 +2353,316 @@ package body Exp_Aggr is
procedure Convert_To_Positional
(N : Node_Id;
- Max_Others_Replicate : Nat := 5;
+ Max_Others_Replicate : Nat := 5;
Handle_Bit_Packed : Boolean := False)
is
- Loc : constant Source_Ptr := Sloc (N);
- Typ : constant Entity_Id := Etype (N);
- Ndim : constant Pos := Number_Dimensions (Typ);
- Xtyp : constant Entity_Id := Etype (First_Index (Typ));
- Indx : constant Node_Id := First_Index (Base_Type (Typ));
- Blo : constant Node_Id := Type_Low_Bound (Etype (Indx));
- Lo : constant Node_Id := Type_Low_Bound (Xtyp);
- Hi : constant Node_Id := Type_High_Bound (Xtyp);
- Lov : Uint;
- Hiv : Uint;
-
- -- The following constant determines the maximum size of an
- -- aggregate produced by converting named to positional
- -- notation (e.g. from others clauses). This avoids running
- -- away with attempts to convert huge aggregates.
-
- -- The normal limit is 5000, but we increase this limit to
- -- 2**24 (about 16 million) if Restrictions (No_Elaboration_Code)
- -- or Restrictions (No_Implicit_Loops) is specified, since in
- -- either case, we are at risk of declaring the program illegal
- -- because of this limit.
-
- Max_Aggr_Size : constant Nat :=
- 5000 + (2 ** 24 - 5000) * Boolean'Pos
- (Restrictions (No_Elaboration_Code)
- or else
- Restrictions (No_Implicit_Loops));
+ Typ : constant Entity_Id := Etype (N);
- begin
- -- For now, we only handle the one dimensional case and aggregates
- -- that are not part of a component_association
+ function Flatten
+ (N : Node_Id;
+ Ix : Node_Id;
+ Ixb : Node_Id)
+ return Boolean;
+ -- Convert the aggregate into a purely positional form if possible.
+
+ function Is_Flat (N : Node_Id; Dims : Int) return Boolean;
+ -- Non trivial for multidimensional aggregate.
+
+ -------------
+ -- Flatten --
+ -------------
+
+ function Flatten
+ (N : Node_Id;
+ Ix : Node_Id;
+ Ixb : Node_Id)
+ return Boolean
+ is
+ Loc : constant Source_Ptr := Sloc (N);
+ Blo : constant Node_Id := Type_Low_Bound (Etype (Ixb));
+ Lo : constant Node_Id := Type_Low_Bound (Etype (Ix));
+ Hi : constant Node_Id := Type_High_Bound (Etype (Ix));
+ Lov : Uint;
+ Hiv : Uint;
+
+ -- The following constant determines the maximum size of an
+ -- aggregate produced by converting named to positional
+ -- notation (e.g. from others clauses). This avoids running
+ -- away with attempts to convert huge aggregates.
+
+ -- The normal limit is 5000, but we increase this limit to
+ -- 2**24 (about 16 million) if Restrictions (No_Elaboration_Code)
+ -- or Restrictions (No_Implicit_Loops) is specified, since in
+ -- either case, we are at risk of declaring the program illegal
+ -- because of this limit.
+
+ Max_Aggr_Size : constant Nat :=
+ 5000 + (2 ** 24 - 5000) * Boolean'Pos
+ (Restrictions (No_Elaboration_Code)
+ or else
+ Restrictions (No_Implicit_Loops));
+ begin
- if Ndim > 1 or else Nkind (Parent (N)) = N_Aggregate
- or else Nkind (Parent (N)) = N_Component_Association
- then
- return;
- end if;
+ if Nkind (Original_Node (N)) = N_String_Literal then
+ return True;
+ end if;
- -- If already positional, nothing to do!
+ -- Bounds need to be known at compile time
- if No (Component_Associations (N)) then
- return;
- end if;
+ if not Compile_Time_Known_Value (Lo)
+ or else not Compile_Time_Known_Value (Hi)
+ then
+ return False;
+ end if;
- -- Bounds need to be known at compile time
+ -- Get bounds and check reasonable size (positive, not too large)
+ -- Also only handle bounds starting at the base type low bound
+ -- for now since the compiler isn't able to handle different low
+ -- bounds yet. Case such as new String'(3..5 => ' ') will get
+ -- the wrong bounds, though it seems that the aggregate should
+ -- retain the bounds set on its Etype (see C64103E and CC1311B).
- if not Compile_Time_Known_Value (Lo)
- or else not Compile_Time_Known_Value (Hi)
- then
- return;
- end if;
+ Lov := Expr_Value (Lo);
+ Hiv := Expr_Value (Hi);
- -- Normally we do not attempt to convert bit packed arrays. The
- -- exception is when we are explicitly asked to do so (this call
- -- is from the Packed_Array_Aggregate_Handled procedure).
+ if Hiv < Lov
+ or else (Hiv - Lov > Max_Aggr_Size)
+ or else not Compile_Time_Known_Value (Blo)
+ or else (Lov /= Expr_Value (Blo))
+ then
+ return False;
+ end if;
- if Is_Bit_Packed_Array (Typ)
- and then not Handle_Bit_Packed
- then
- return;
- end if;
+ -- Bounds must be in integer range (for array Vals below)
- -- Do not convert to positional if controlled components are
- -- involved since these require special processing
+ if not UI_Is_In_Int_Range (Lov)
+ or else
+ not UI_Is_In_Int_Range (Hiv)
+ then
+ return False;
+ end if;
- if Has_Controlled_Component (Typ) then
- return;
- end if;
+ -- Determine if set of alternatives is suitable for conversion
+ -- and build an array containing the values in sequence.
- -- Get bounds and check reasonable size (positive, not too large)
- -- Also only handle bounds starting at the base type low bound for now
- -- since the compiler isn't able to handle different low bounds yet.
+ declare
+ Vals : array (UI_To_Int (Lov) .. UI_To_Int (Hiv))
+ of Node_Id := (others => Empty);
+ -- The values in the aggregate sorted appropriately
- Lov := Expr_Value (Lo);
- Hiv := Expr_Value (Hi);
+ Vlist : List_Id;
+ -- Same data as Vals in list form
- if Hiv < Lov
- or else (Hiv - Lov > Max_Aggr_Size)
- or else not Compile_Time_Known_Value (Blo)
- or else (Lov /= Expr_Value (Blo))
- then
- return;
- end if;
+ Rep_Count : Nat;
+ -- Used to validate Max_Others_Replicate limit
- -- Bounds must be in integer range (for array Vals below)
+ Elmt : Node_Id;
+ Num : Int := UI_To_Int (Lov);
+ Choice : Node_Id;
+ Lo, Hi : Node_Id;
- if not UI_Is_In_Int_Range (Lov)
- or else
- not UI_Is_In_Int_Range (Hiv)
- then
- return;
- end if;
+ begin
+ if Present (Expressions (N)) then
+ Elmt := First (Expressions (N));
+
+ while Present (Elmt) loop
+ if Nkind (Elmt) = N_Aggregate
+ and then Present (Next_Index (Ix))
+ and then
+ not Flatten (Elmt, Next_Index (Ix), Next_Index (Ixb))
+ then
+ return False;
+ end if;
- -- Determine if set of alternatives is suitable for conversion
- -- and build an array containing the values in sequence.
+ Vals (Num) := Relocate_Node (Elmt);
+ Num := Num + 1;
- declare
- Vals : array (UI_To_Int (Lov) .. UI_To_Int (Hiv))
- of Node_Id := (others => Empty);
- -- The values in the aggregate sorted appropriately
+ Next (Elmt);
+ end loop;
+ end if;
- Vlist : List_Id;
- -- Same data as Vals in list form
+ if No (Component_Associations (N)) then
+ return True;
+ end if;
- Rep_Count : Nat;
- -- Used to validate Max_Others_Replicate limit
+ Elmt := First (Component_Associations (N));
- Elmt : Node_Id;
- Num : Int := UI_To_Int (Lov);
- Choice : Node_Id;
- Lo, Hi : Node_Id;
+ if Nkind (Expression (Elmt)) = N_Aggregate then
+ if Present (Next_Index (Ix))
+ and then
+ not Flatten
+ (Expression (Elmt), Next_Index (Ix), Next_Index (Ixb))
+ then
+ return False;
+ end if;
+ end if;
- begin
- if Present (Expressions (N)) then
- Elmt := First (Expressions (N));
- while Present (Elmt) loop
- Vals (Num) := Relocate_Node (Elmt);
- Num := Num + 1;
- Next (Elmt);
- end loop;
- end if;
+ Component_Loop : while Present (Elmt) loop
+ Choice := First (Choices (Elmt));
+ Choice_Loop : while Present (Choice) loop
+
+ -- If we have an others choice, fill in the missing elements
+ -- subject to the limit established by Max_Others_Replicate.
+
+ if Nkind (Choice) = N_Others_Choice then
+ Rep_Count := 0;
+
+ for J in Vals'Range loop
+ if No (Vals (J)) then
+ Vals (J) := New_Copy_Tree (Expression (Elmt));
+ Rep_Count := Rep_Count + 1;
+
+ -- Check for maximum others replication. Note that
+ -- we skip this test if either of the restrictions
+ -- No_Elaboration_Code or No_Implicit_Loops is
+ -- active, or if this is a preelaborable unit.
+
+ declare
+ P : constant Entity_Id :=
+ Cunit_Entity (Current_Sem_Unit);
+
+ begin
+ if Restrictions (No_Elaboration_Code)
+ or else Restrictions (No_Implicit_Loops)
+ or else Is_Preelaborated (P)
+ or else (Ekind (P) = E_Package_Body
+ and then
+ Is_Preelaborated (Spec_Entity (P)))
+ then
+ null;
+ elsif Rep_Count > Max_Others_Replicate then
+ return False;
+ end if;
+ end;
+ end if;
+ end loop;
- Elmt := First (Component_Associations (N));
- Component_Loop : while Present (Elmt) loop
+ exit Component_Loop;
- Choice := First (Choices (Elmt));
- Choice_Loop : while Present (Choice) loop
+ -- Case of a subtype mark
- -- If we have an others choice, fill in the missing elements
- -- subject to the limit established by Max_Others_Replicate.
+ elsif Nkind (Choice) = N_Identifier
+ and then Is_Type (Entity (Choice))
+ then
+ Lo := Type_Low_Bound (Etype (Choice));
+ Hi := Type_High_Bound (Etype (Choice));
- if Nkind (Choice) = N_Others_Choice then
- Rep_Count := 0;
+ -- Case of subtype indication
- for J in Vals'Range loop
- if No (Vals (J)) then
- Vals (J) := New_Copy_Tree (Expression (Elmt));
- Rep_Count := Rep_Count + 1;
-
- -- Check for maximum others replication. Note that
- -- we skip this test if either of the restrictions
- -- No_Elaboration_Code or No_Implicit_Loops is
- -- active, or if this is a preelaborable unit.
-
- if Rep_Count > Max_Others_Replicate
- and then not Restrictions (No_Elaboration_Code)
- and then not Restrictions (No_Implicit_Loops)
- and then not
- Is_Preelaborated (Cunit_Entity (Current_Sem_Unit))
- then
- return;
- end if;
+ elsif Nkind (Choice) = N_Subtype_Indication then
+ Lo := Low_Bound (Range_Expression (Constraint (Choice)));
+ Hi := High_Bound (Range_Expression (Constraint (Choice)));
+
+ -- Case of a range
+
+ elsif Nkind (Choice) = N_Range then
+ Lo := Low_Bound (Choice);
+ Hi := High_Bound (Choice);
+
+ -- Normal subexpression case
+
+ else pragma Assert (Nkind (Choice) in N_Subexpr);
+ if not Compile_Time_Known_Value (Choice) then
+ return False;
+
+ else
+ Vals (UI_To_Int (Expr_Value (Choice))) :=
+ New_Copy_Tree (Expression (Elmt));
+ goto Continue;
end if;
- end loop;
+ end if;
+
+ -- Range cases merge with Lo,Hi said
+
+ if not Compile_Time_Known_Value (Lo)
+ or else
+ not Compile_Time_Known_Value (Hi)
+ then
+ return False;
+ else
+ for J in UI_To_Int (Expr_Value (Lo)) ..
+ UI_To_Int (Expr_Value (Hi))
+ loop
+ Vals (J) := New_Copy_Tree (Expression (Elmt));
+ end loop;
+ end if;
- exit Component_Loop;
+ <<Continue>>
+ Next (Choice);
+ end loop Choice_Loop;
- -- Case of a subtype mark
+ Next (Elmt);
+ end loop Component_Loop;
- elsif (Nkind (Choice) = N_Identifier
- and then Is_Type (Entity (Choice)))
- then
- Lo := Type_Low_Bound (Etype (Choice));
- Hi := Type_High_Bound (Etype (Choice));
+ -- If we get here the conversion is possible
- -- Case of subtype indication
+ Vlist := New_List;
+ for J in Vals'Range loop
+ Append (Vals (J), Vlist);
+ end loop;
- elsif Nkind (Choice) = N_Subtype_Indication then
- Lo := Low_Bound (Range_Expression (Constraint (Choice)));
- Hi := High_Bound (Range_Expression (Constraint (Choice)));
+ Rewrite (N, Make_Aggregate (Loc, Expressions => Vlist));
+ Set_Aggregate_Bounds (N, Aggregate_Bounds (Original_Node (N)));
+ return True;
+ end;
+ end Flatten;
- -- Case of a range
+ -------------
+ -- Is_Flat --
+ -------------
- elsif Nkind (Choice) = N_Range then
- Lo := Low_Bound (Choice);
- Hi := High_Bound (Choice);
+ function Is_Flat (N : Node_Id; Dims : Int) return Boolean is
+ Elmt : Node_Id;
- -- Normal subexpression case
+ begin
+ if Dims = 0 then
+ return True;
- else pragma Assert (Nkind (Choice) in N_Subexpr);
- if not Compile_Time_Known_Value (Choice) then
- return;
+ elsif Nkind (N) = N_Aggregate then
+ if Present (Component_Associations (N)) then
+ return False;
- else
- Vals (UI_To_Int (Expr_Value (Choice))) :=
- New_Copy_Tree (Expression (Elmt));
- goto Continue;
+ else
+ Elmt := First (Expressions (N));
+
+ while Present (Elmt) loop
+ if not Is_Flat (Elmt, Dims - 1) then
+ return False;
end if;
- end if;
- -- Range cases merge with Lo,Hi said
+ Next (Elmt);
+ end loop;
- if not Compile_Time_Known_Value (Lo)
- or else
- not Compile_Time_Known_Value (Hi)
- then
- return;
- else
- for J in UI_To_Int (Expr_Value (Lo)) ..
- UI_To_Int (Expr_Value (Hi))
- loop
- Vals (J) := New_Copy_Tree (Expression (Elmt));
- end loop;
- end if;
+ return True;
+ end if;
+ else
+ return True;
+ end if;
+ end Is_Flat;
- <<Continue>>
- Next (Choice);
- end loop Choice_Loop;
+ -- Start of processing for Convert_To_Positional
- Next (Elmt);
- end loop Component_Loop;
+ begin
+ if Is_Flat (N, Number_Dimensions (Typ)) then
+ return;
+ end if;
+
+ if Is_Bit_Packed_Array (Typ)
+ and then not Handle_Bit_Packed
+ then
+ return;
+ end if;
- -- If we get here the conversion is possible
+ -- Do not convert to positional if controlled components are
+ -- involved since these require special processing
- Vlist := New_List;
- for J in Vals'Range loop
- Append (Vals (J), Vlist);
- end loop;
+ if Has_Controlled_Component (Typ) then
+ return;
+ end if;
- Rewrite (N, Make_Aggregate (Loc, Expressions => Vlist));
+ if Flatten (N, First_Index (Typ), First_Index (Base_Type (Typ))) then
Analyze_And_Resolve (N, Typ);
- end;
+ end if;
end Convert_To_Positional;
----------------------------
@@ -2454,11 +2683,17 @@ package body Exp_Aggr is
-- (c) For multidimensional arrays make sure that all subaggregates
-- corresponding to the same dimension have the same bounds.
- -- 2. Check if the aggregate can be statically processed. If this is the
+ -- 2. Check for packed array aggregate which can be converted to a
+ -- constant so that the aggregate disappeares completely.
+
+ -- 3. Check case of nested aggregate. Generally nested aggregates are
+ -- handled during the processing of the parent aggregate.
+
+ -- 4. Check if the aggregate can be statically processed. If this is the
-- case pass it as is to Gigi. Note that a necessary condition for
-- static processing is that the aggregate be fully positional.
- -- 3. If in place aggregate expansion is possible (i.e. no need to create
+ -- 5. If in place aggregate expansion is possible (i.e. no need to create
-- a temporary) then mark the aggregate as such and return. Otherwise
-- create a new temporary and generate the appropriate initialization
-- code.
@@ -2522,6 +2757,14 @@ package body Exp_Aggr is
-- be done in place, because none of the new values can depend on the
-- components of the target of the assignment.
+ function Must_Slide (N : Node_Id; Typ : Entity_Id) return Boolean;
+ -- A static aggregate in an object declaration can in most cases be
+ -- expanded in place. The one exception is when the aggregate is given
+ -- with component associations that specify different bounds from those
+ -- of the type definition in the object declaration. In this rather
+ -- pathological case the aggregate must slide, and we must introduce
+ -- an intermediate temporary to hold it.
+
procedure Others_Check (Sub_Aggr : Node_Id; Dim : Pos);
-- Checks that if an others choice is present in any sub-aggregate no
-- aggregate index is outside the bounds of the index constraint.
@@ -2533,14 +2776,14 @@ package body Exp_Aggr is
----------------------------
procedure Build_Constrained_Type (Positional : Boolean) is
- Loc : constant Source_Ptr := Sloc (N);
- Agg_Type : Entity_Id;
- Comp : Node_Id;
- Decl : Node_Id;
- Typ : constant Entity_Id := Etype (N);
- Indices : List_Id := New_List;
- Num : Int;
- Sub_Agg : Node_Id;
+ Loc : constant Source_Ptr := Sloc (N);
+ Agg_Type : Entity_Id;
+ Comp : Node_Id;
+ Decl : Node_Id;
+ Typ : constant Entity_Id := Etype (N);
+ Indices : constant List_Id := New_List;
+ Num : Int;
+ Sub_Agg : Node_Id;
begin
Agg_Type :=
@@ -2574,7 +2817,6 @@ package body Exp_Aggr is
end loop;
else
-
-- We know the aggregate type is unconstrained and the
-- aggregate is not processable by the back end, therefore
-- not necessarily positional. Retrieve the bounds of each
@@ -2637,22 +2879,22 @@ package body Exp_Aggr is
elsif Aggr_Hi = Ind_Hi then
Cond :=
Make_Op_Lt (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Lo),
- Right_Opnd => Duplicate_Subexpr (Ind_Lo));
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Lo),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Ind_Lo));
elsif Aggr_Lo = Ind_Lo then
Cond :=
Make_Op_Gt (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Hi),
- Right_Opnd => Duplicate_Subexpr (Ind_Hi));
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Hi),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Ind_Hi));
else
Cond :=
Make_Or_Else (Loc,
Left_Opnd =>
Make_Op_Lt (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Lo),
- Right_Opnd => Duplicate_Subexpr (Ind_Lo)),
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Lo),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Ind_Lo)),
Right_Opnd =>
Make_Op_Gt (Loc,
@@ -2665,8 +2907,8 @@ package body Exp_Aggr is
Make_And_Then (Loc,
Left_Opnd =>
Make_Op_Le (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Lo),
- Right_Opnd => Duplicate_Subexpr (Aggr_Hi)),
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Lo),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Hi)),
Right_Opnd => Cond);
@@ -2695,10 +2937,10 @@ package body Exp_Aggr is
Ind_Typ : constant Entity_Id := Aggr_Index_Typ (Dim);
-- The index type for this dimension.
- Cond : Node_Id := Empty;
+ Cond : Node_Id := Empty;
- Assoc : Node_Id;
- Expr : Node_Id;
+ Assoc : Node_Id;
+ Expr : Node_Id;
begin
-- If index checks are on generate the test
@@ -2722,22 +2964,22 @@ package body Exp_Aggr is
elsif Aggr_Hi = Sub_Hi then
Cond :=
Make_Op_Ne (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Lo),
- Right_Opnd => Duplicate_Subexpr (Sub_Lo));
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Lo),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Sub_Lo));
elsif Aggr_Lo = Sub_Lo then
Cond :=
Make_Op_Ne (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Hi),
- Right_Opnd => Duplicate_Subexpr (Sub_Hi));
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Hi),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Sub_Hi));
else
Cond :=
Make_Or_Else (Loc,
Left_Opnd =>
Make_Op_Ne (Loc,
- Left_Opnd => Duplicate_Subexpr (Aggr_Lo),
- Right_Opnd => Duplicate_Subexpr (Sub_Lo)),
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Aggr_Lo),
+ Right_Opnd => Duplicate_Subexpr_Move_Checks (Sub_Lo)),
Right_Opnd =>
Make_Op_Ne (Loc,
@@ -2784,8 +3026,8 @@ package body Exp_Aggr is
----------------------------
procedure Compute_Others_Present (Sub_Aggr : Node_Id; Dim : Pos) is
- Assoc : Node_Id;
- Expr : Node_Id;
+ Assoc : Node_Id;
+ Expr : Node_Id;
begin
if Present (Component_Associations (Sub_Aggr)) then
@@ -2823,17 +3065,16 @@ package body Exp_Aggr is
end if;
end Compute_Others_Present;
- -------------------------
- -- Has_Address_Clause --
- -------------------------
+ ------------------------
+ -- Has_Address_Clause --
+ ------------------------
function Has_Address_Clause (D : Node_Id) return Boolean is
- Id : Entity_Id := Defining_Identifier (D);
+ Id : constant Entity_Id := Defining_Identifier (D);
Decl : Node_Id := Next (D);
begin
while Present (Decl) loop
-
if Nkind (Decl) = N_At_Clause
and then Chars (Identifier (Decl)) = Chars (Id)
then
@@ -2943,6 +3184,10 @@ package body Exp_Aggr is
function Check_Component (Comp : Node_Id) return Boolean;
-- Do the recursive traversal, after copy.
+ ---------------------
+ -- Check_Component --
+ ---------------------
+
function Check_Component (Comp : Node_Id) return Boolean is
begin
if Is_Overloaded (Comp) then
@@ -2969,7 +3214,7 @@ package body Exp_Aggr is
and then Check_Component (Prefix (Comp)));
end Check_Component;
- -- Start of processing for Safe_Component
+ -- Start of processing for Safe_Component
begin
-- If the component appears in an association that may
@@ -3052,6 +3297,49 @@ package body Exp_Aggr is
return Safe_Aggregate (N);
end In_Place_Assign_OK;
+ ----------------
+ -- Must_Slide --
+ ----------------
+
+ function Must_Slide (N : Node_Id; Typ : Entity_Id) return Boolean
+ is
+ Obj_Type : Entity_Id := Etype (Defining_Identifier (Parent (N)));
+
+ L1, L2, H1, H2 : Node_Id;
+
+ begin
+ -- No sliding if the type of the object is not established yet, if
+ -- it is an unconstrained type whose actual subtype comes from the
+ -- aggregate, or if the two types are identical.
+
+ if not Is_Array_Type (Obj_Type) then
+ return False;
+
+ elsif not Is_Constrained (Obj_Type) then
+ return False;
+
+ elsif Typ = Obj_Type then
+ return False;
+
+ else
+ -- Sliding can only occur along the first dimension
+
+ Get_Index_Bounds (First_Index (Typ), L1, H1);
+ Get_Index_Bounds (First_Index (Obj_Type), L2, H2);
+
+ if not Is_Static_Expression (L1)
+ or else not Is_Static_Expression (L2)
+ or else not Is_Static_Expression (H1)
+ or else not Is_Static_Expression (H2)
+ then
+ return False;
+ else
+ return Expr_Value (L1) /= Expr_Value (L2)
+ or else Expr_Value (H1) /= Expr_Value (H2);
+ end if;
+ end if;
+ end Must_Slide;
+
------------------
-- Others_Check --
------------------
@@ -3204,14 +3492,16 @@ package body Exp_Aggr is
Prefix => New_Reference_To (Ind_Typ, Loc),
Attribute_Name => Name_Pos,
Expressions =>
- New_List (Duplicate_Subexpr (Aggr_Lo))),
+ New_List
+ (Duplicate_Subexpr_Move_Checks (Aggr_Lo))),
Right_Opnd => Make_Integer_Literal (Loc, Nb_Elements - 1)),
Right_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Reference_To (Ind_Typ, Loc),
Attribute_Name => Name_Pos,
- Expressions => New_List (Duplicate_Subexpr (Aggr_Hi))));
+ Expressions => New_List (
+ Duplicate_Subexpr_Move_Checks (Aggr_Hi))));
-- If we are dealing with an aggregate containing an others
-- choice and discrete choices we generate the following test:
@@ -3224,13 +3514,17 @@ package body Exp_Aggr is
Make_Or_Else (Loc,
Left_Opnd =>
Make_Op_Lt (Loc,
- Left_Opnd => Duplicate_Subexpr (Choices_Lo),
- Right_Opnd => Duplicate_Subexpr (Aggr_Lo)),
+ Left_Opnd =>
+ Duplicate_Subexpr_Move_Checks (Choices_Lo),
+ Right_Opnd =>
+ Duplicate_Subexpr_Move_Checks (Aggr_Lo)),
Right_Opnd =>
Make_Op_Gt (Loc,
- Left_Opnd => Duplicate_Subexpr (Choices_Hi),
- Right_Opnd => Duplicate_Subexpr (Aggr_Hi)));
+ Left_Opnd =>
+ Duplicate_Subexpr (Choices_Hi),
+ Right_Opnd =>
+ Duplicate_Subexpr (Aggr_Hi)));
end if;
if Present (Cond) then
@@ -3270,10 +3564,10 @@ package body Exp_Aggr is
-- Remaining Expand_Array_Aggregate variables
Tmp : Entity_Id;
- -- Holds the temporary aggregate value.
+ -- Holds the temporary aggregate value
Tmp_Decl : Node_Id;
- -- Holds the declaration of Tmp.
+ -- Holds the declaration of Tmp
Aggr_Code : List_Id;
Parent_Node : Node_Id;
@@ -3297,7 +3591,10 @@ package body Exp_Aggr is
pragma Assert (not Raises_Constraint_Error (N));
- -- STEP 1: Check (a)
+ -- STEP 1a.
+
+ -- Check that the index range defined by aggregate bounds is
+ -- compatible with corresponding index subtype.
Index_Compatibility_Check : declare
Aggr_Index_Range : Node_Id := First_Index (Typ);
@@ -3342,11 +3639,17 @@ package body Exp_Aggr is
end loop;
end Index_Compatibility_Check;
- -- STEP 1: Check (b)
+ -- STEP 1b.
+
+ -- If an others choice is present check that no aggregate
+ -- index is outside the bounds of the index constraint.
Others_Check (N, 1);
- -- STEP 1: Check (c)
+ -- STEP 1c.
+
+ -- For multidimensional arrays make sure that all subaggregates
+ -- corresponding to the same dimension have the same bounds.
if Aggr_Dimension > 1 then
Check_Same_Aggr_Bounds (N, 1);
@@ -3354,23 +3657,37 @@ package body Exp_Aggr is
-- STEP 2.
- -- First try to convert to positional form. If the result is not
- -- an aggregate any more, then we are done with the analysis (it
- -- it could be a string literal or an identifier for a temporary
- -- variable following this call). If result is an analyzed aggregate
- -- the transformation was also successful and we are done as well.
+ -- Here we test for is packed array aggregate that we can handle
+ -- at compile time. If so, return with transformation done. Note
+ -- that we do this even if the aggregate is nested, because once
+ -- we have done this processing, there is no more nested aggregate!
+
+ if Packed_Array_Aggregate_Handled (N) then
+ return;
+ end if;
+
+ -- At this point we try to convert to positional form
Convert_To_Positional (N);
+ -- if the result is no longer an aggregate (e.g. it may be a string
+ -- literal, or a temporary which has the needed value), then we are
+ -- done, since there is no longer a nested aggregate.
+
if Nkind (N) /= N_Aggregate then
return;
+ -- We are also done if the result is an analyzed aggregate
+ -- This case could use more comments ???
+
elsif Analyzed (N)
and then N /= Original_Node (N)
then
return;
end if;
+ -- Now see if back end processing is possible
+
if Backend_Processing_Possible (N) then
-- If the aggregate is static but the constraints are not, build
@@ -3405,6 +3722,8 @@ package body Exp_Aggr is
return;
end if;
+ -- STEP 3.
+
-- Delay expansion for nested aggregates it will be taken care of
-- when the parent aggregate is expanded
@@ -3428,17 +3747,10 @@ package body Exp_Aggr is
return;
end if;
- -- STEP 3.
+ -- STEP 4.
-- Look if in place aggregate expansion is possible
- -- First case to test for is packed array aggregate that we can
- -- handle at compile time. If so, return with transformation done.
-
- if Packed_Array_Aggregate_Handled (N) then
- return;
- end if;
-
-- For object declarations we build the aggregate in place, unless
-- the array is bit-packed or the component is controlled.
@@ -3461,6 +3773,7 @@ package body Exp_Aggr is
if Comes_From_Source (Parent (N))
and then Nkind (Parent (N)) = N_Object_Declaration
+ and then not Must_Slide (N, Typ)
and then N = Expression (Parent (N))
and then not Is_Bit_Packed_Array (Typ)
and then not Has_Controlled_Component (Typ)
@@ -3494,6 +3807,13 @@ package body Exp_Aggr is
if Etype (Tmp) /= Etype (N) then
Apply_Length_Check (N, Etype (Tmp));
+
+ if Nkind (N) = N_Raise_Constraint_Error then
+
+ -- Static error, nothing further to expand
+
+ return;
+ end if;
end if;
elsif Maybe_In_Place_OK
@@ -3514,6 +3834,10 @@ package body Exp_Aggr is
return;
+ -- Step 5
+
+ -- In place aggregate expansion is not possible
+
else
Maybe_In_Place_OK := False;
Tmp := Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
@@ -3597,6 +3921,10 @@ package body Exp_Aggr is
else
Expand_Array_Aggregate (N);
end if;
+
+ exception
+ when RE_Not_Available =>
+ return;
end Expand_N_Aggregate;
----------------------------------
@@ -3616,7 +3944,7 @@ package body Exp_Aggr is
Typ : constant Entity_Id := Etype (N);
begin
- -- If the ancestor is a subtype mark, an init_proc must be called
+ -- If the ancestor is a subtype mark, an init proc must be called
-- on the resulting object which thus has to be materialized in
-- the front-end
@@ -3643,6 +3971,10 @@ package body Exp_Aggr is
Parent_Expr => A);
end if;
end if;
+
+ exception
+ when RE_Not_Available =>
+ return;
end Expand_N_Extension_Aggregate;
-----------------------------
@@ -3654,10 +3986,10 @@ package body Exp_Aggr is
Orig_Tag : Node_Id := Empty;
Parent_Expr : Node_Id := Empty)
is
- Loc : constant Source_Ptr := Sloc (N);
- Comps : constant List_Id := Component_Associations (N);
- Typ : constant Entity_Id := Etype (N);
- Base_Typ : constant Entity_Id := Base_Type (Typ);
+ Loc : constant Source_Ptr := Sloc (N);
+ Comps : constant List_Id := Component_Associations (N);
+ Typ : constant Entity_Id := Etype (N);
+ Base_Typ : constant Entity_Id := Base_Type (Typ);
function Has_Delayed_Nested_Aggregate_Or_Tagged_Comps return Boolean;
-- Checks the presence of a nested aggregate which needs Late_Expansion
@@ -3668,7 +4000,7 @@ package body Exp_Aggr is
--------------------------------------------------
function Has_Delayed_Nested_Aggregate_Or_Tagged_Comps return Boolean is
- C : Node_Id;
+ C : Node_Id;
Expr_Q : Node_Id;
begin
@@ -3678,7 +4010,6 @@ package body Exp_Aggr is
C := First (Comps);
while Present (C) loop
-
if Nkind (Expression (C)) = N_Qualified_Expression then
Expr_Q := Expression (Expression (C));
else
@@ -3710,7 +4041,7 @@ package body Exp_Aggr is
end loop;
return False;
- end Has_Delayed_Nested_Aggregate_Or_Tagged_Comps;
+ end Has_Delayed_Nested_Aggregate_Or_Tagged_Comps;
-- Remaining Expand_Record_Aggregate variables
@@ -3721,6 +4052,21 @@ package body Exp_Aggr is
-- Start of processing for Expand_Record_Aggregate
begin
+ -- If the aggregate is to be assigned to an atomic variable, we
+ -- have to prevent a piecemeal assignment even if the aggregate
+ -- is to be expanded. We create a temporary for the aggregate, and
+ -- assign the temporary instead, so that the back end can generate
+ -- an atomic move for it.
+
+ if Is_Atomic (Typ)
+ and then (Nkind (Parent (N)) = N_Object_Declaration
+ or else Nkind (Parent (N)) = N_Assignment_Statement)
+ and then Comes_From_Source (Parent (N))
+ then
+ Expand_Atomic_Aggregate (N, Typ);
+ return;
+ end if;
+
-- Gigi doesn't handle properly temporaries of variable size
-- so we generate it in the front-end
@@ -3751,6 +4097,14 @@ package body Exp_Aggr is
elsif Is_Tagged_Type (Typ) and then Has_Discriminants (Typ) then
Convert_To_Assignments (N, Typ);
+ -- If some components are mutable, the size of the aggregate component
+ -- may be disctinct from the default size of the type component, so
+ -- we need to expand to insure that the back-end copies the proper
+ -- size of the data.
+
+ elsif Has_Mutable_Components (Typ) then
+ Convert_To_Assignments (N, Typ);
+
-- In all other cases we generate a proper aggregate that
-- can be handled by gigi.
@@ -3764,29 +4118,29 @@ package body Exp_Aggr is
elsif Is_Derived_Type (Typ) then
- -- For untagged types, non-girder discriminants are replaced
- -- with girder discriminants, which are the ones that gigi uses
+ -- For untagged types, non-stored discriminants are replaced
+ -- with stored discriminants, which are the ones that gigi uses
-- to describe the type and its components.
Generate_Aggregate_For_Derived_Type : declare
+ Constraints : constant List_Id := New_List;
First_Comp : Node_Id;
Discriminant : Entity_Id;
- Constraints : List_Id := New_List;
Decl : Node_Id;
Num_Disc : Int := 0;
Num_Gird : Int := 0;
- procedure Prepend_Girder_Values (T : Entity_Id);
- -- Scan the list of girder discriminants of the type, and
+ procedure Prepend_Stored_Values (T : Entity_Id);
+ -- Scan the list of stored discriminants of the type, and
-- add their values to the aggregate being built.
---------------------------
- -- Prepend_Girder_Values --
+ -- Prepend_Stored_Values --
---------------------------
- procedure Prepend_Girder_Values (T : Entity_Id) is
+ procedure Prepend_Stored_Values (T : Entity_Id) is
begin
- Discriminant := First_Girder_Discriminant (T);
+ Discriminant := First_Stored_Discriminant (T);
while Present (Discriminant) loop
New_Comp :=
@@ -3808,9 +4162,9 @@ package body Exp_Aggr is
end if;
First_Comp := New_Comp;
- Next_Girder_Discriminant (Discriminant);
+ Next_Stored_Discriminant (Discriminant);
end loop;
- end Prepend_Girder_Values;
+ end Prepend_Stored_Values;
-- Start of processing for Generate_Aggregate_For_Derived_Type
@@ -3832,25 +4186,25 @@ package body Exp_Aggr is
end if;
end loop;
- -- Insert girder discriminant associations in the correct
- -- order. If there are more girder discriminants than new
+ -- Insert stored discriminant associations in the correct
+ -- order. If there are more stored discriminants than new
-- discriminants, there is at least one new discriminant
- -- that constrains more than one of the girders. In this
- -- case we need to construct a proper subtype of the parent
- -- type, in order to supply values to all the components.
- -- Otherwise there is one-one correspondence between the
- -- constraints and the girder discriminants.
+ -- that constrains more than one of the stored discriminants.
+ -- In this case we need to construct a proper subtype of
+ -- the parent type, in order to supply values to all the
+ -- components. Otherwise there is one-one correspondence
+ -- between the constraints and the stored discriminants.
First_Comp := Empty;
- Discriminant := First_Girder_Discriminant (Base_Type (Typ));
+ Discriminant := First_Stored_Discriminant (Base_Type (Typ));
while Present (Discriminant) loop
Num_Gird := Num_Gird + 1;
- Next_Girder_Discriminant (Discriminant);
+ Next_Stored_Discriminant (Discriminant);
end loop;
- -- Case of more girder discriminants than new discriminants
+ -- Case of more stored discriminants than new discriminants
if Num_Gird > Num_Disc then
@@ -3858,7 +4212,7 @@ package body Exp_Aggr is
-- the proper implementation type for the aggregate, and
-- convert it to the intended target type.
- Discriminant := First_Girder_Discriminant (Base_Type (Typ));
+ Discriminant := First_Stored_Discriminant (Base_Type (Typ));
while Present (Discriminant) loop
New_Comp :=
@@ -3868,7 +4222,7 @@ package body Exp_Aggr is
Typ,
Discriminant_Constraint (Typ)));
Append (New_Comp, Constraints);
- Next_Girder_Discriminant (Discriminant);
+ Next_Stored_Discriminant (Discriminant);
end loop;
Decl :=
@@ -3885,7 +4239,7 @@ package body Exp_Aggr is
(Loc, Constraints)));
Insert_Action (N, Decl);
- Prepend_Girder_Values (Base_Type (Typ));
+ Prepend_Stored_Values (Base_Type (Typ));
Set_Etype (N, Defining_Identifier (Decl));
Set_Analyzed (N);
@@ -3894,11 +4248,11 @@ package body Exp_Aggr is
Analyze (N);
-- Case where we do not have fewer new discriminants than
- -- girder discriminants, so in this case we can simply
- -- use the girder discriminants of the subtype.
+ -- stored discriminants, so in this case we can simply
+ -- use the stored discriminants of the subtype.
else
- Prepend_Girder_Values (Typ);
+ Prepend_Stored_Values (Typ);
end if;
end Generate_Aggregate_For_Derived_Type;
end if;
@@ -4053,8 +4407,9 @@ package body Exp_Aggr is
--------------------------
function Is_Delayed_Aggregate (N : Node_Id) return Boolean is
- Node : Node_Id := N;
+ Node : Node_Id := N;
Kind : Node_Kind := Nkind (Node);
+
begin
if Kind = N_Qualified_Expression then
Node := Expression (Node);
@@ -4076,11 +4431,10 @@ package body Exp_Aggr is
(N : Node_Id;
Typ : Entity_Id;
Target : Node_Id;
- Flist : Node_Id := Empty;
+ Flist : Node_Id := Empty;
Obj : Entity_Id := Empty)
-
- return List_Id is
-
+ return List_Id
+ is
begin
if Is_Record_Type (Etype (N)) then
return Build_Record_Aggr_Code (N, Typ, Target, Flist, Obj);
@@ -4315,14 +4669,19 @@ package body Exp_Aggr is
-- Loop to set the values
- Aggregate_Val := Uint_0;
- Expr := First (Expressions (N));
- for J in 1 .. Len loop
- Aggregate_Val :=
- Aggregate_Val + Get_Component_Val (Expr) * Uint_2 ** Shift;
- Shift := Shift + Incr;
- Next (Expr);
- end loop;
+ if Len = 0 then
+ Aggregate_Val := Uint_0;
+ else
+ Expr := First (Expressions (N));
+ Aggregate_Val := Get_Component_Val (Expr) * Uint_2 ** Shift;
+
+ for J in 2 .. Len loop
+ Shift := Shift + Incr;
+ Next (Expr);
+ Aggregate_Val :=
+ Aggregate_Val + Get_Component_Val (Expr) * Uint_2 ** Shift;
+ end loop;
+ end if;
-- Now we can rewrite with the proper value
@@ -4354,6 +4713,30 @@ package body Exp_Aggr is
return False;
end Packed_Array_Aggregate_Handled;
+ ----------------------------
+ -- Has_Mutable_Components --
+ ----------------------------
+
+ function Has_Mutable_Components (Typ : Entity_Id) return Boolean is
+ Comp : Entity_Id;
+
+ begin
+ Comp := First_Component (Typ);
+
+ while Present (Comp) loop
+ if Is_Record_Type (Etype (Comp))
+ and then Has_Discriminants (Etype (Comp))
+ and then not Is_Constrained (Etype (Comp))
+ then
+ return True;
+ end if;
+
+ Next_Component (Comp);
+ end loop;
+
+ return False;
+ end Has_Mutable_Components;
+
------------------------------
-- Initialize_Discriminants --
------------------------------
@@ -4378,7 +4761,7 @@ package body Exp_Aggr is
and then Nkind (N) /= N_Extension_Aggregate
then
- -- Call init_proc to set discriminants.
+ -- Call init proc to set discriminants.
-- There should eventually be a special procedure for this ???
Ref := New_Reference_To (Defining_Identifier (N), Loc);
@@ -4438,6 +4821,11 @@ package body Exp_Aggr is
Iteration_Scheme => L_Iter,
Statements => New_List (L_Body));
+ -- Set type of aggregate to be type of lhs in assignment,
+ -- to suppress redundant length checks.
+
+ Set_Etype (N, Etype (Name (Parent (N))));
+
Rewrite (Parent (N), Stat);
Analyze (Parent (N));
return True;
@@ -4452,8 +4840,8 @@ package body Exp_Aggr is
---------------------
procedure Sort_Case_Table (Case_Table : in out Case_Table_Type) is
- L : Int := Case_Table'First;
- U : Int := Case_Table'Last;
+ L : constant Int := Case_Table'First;
+ U : constant Int := Case_Table'Last;
K : Int;
J : Int;
T : Case_Bounds;