diff options
Diffstat (limited to 'gcc/ada/exp_ch5.adb')
-rw-r--r-- | gcc/ada/exp_ch5.adb | 1154 |
1 files changed, 540 insertions, 614 deletions
diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb index 7410db22552..d3db4afceb3 100644 --- a/gcc/ada/exp_ch5.adb +++ b/gcc/ada/exp_ch5.adb @@ -29,6 +29,7 @@ with Checks; use Checks; with Debug; use Debug; with Einfo; use Einfo; with Elists; use Elists; +with Exp_Atag; use Exp_Atag; with Exp_Aggr; use Exp_Aggr; with Exp_Ch6; use Exp_Ch6; with Exp_Ch7; use Exp_Ch7; @@ -127,10 +128,6 @@ package body Exp_Ch5 is -- pointers which are not 'part of the value' and must not be changed -- upon assignment. N is the original Assignment node. - procedure No_Secondary_Stack_Case (N : Node_Id); - -- Obsolete code to deal with functions for which - -- Function_Returns_With_DSP is True. - function Possible_Bit_Aligned_Component (N : Node_Id) return Boolean; -- This function is used in processing the assignment of a record or -- indexed component. The argument N is either the left hand or right @@ -1401,7 +1398,7 @@ package body Exp_Ch5 is begin -- Ada 2005 (AI-327): Handle assignment to priority of protected object - -- Rewrite an assignment to X'Priority into a run-time call. + -- Rewrite an assignment to X'Priority into a run-time call -- For example: X'Priority := New_Prio_Expr; -- ...is expanded into Set_Ceiling (X._Object, New_Prio_Expr); @@ -1759,7 +1756,7 @@ package body Exp_Ch5 is -- Build-in-place function call case. Note that we're not yet doing -- build-in-place for user-written assignment statements; the - -- assignment here came from can aggregate. + -- assignment here came from an aggregate. elsif Ada_Version >= Ada_05 and then Is_Build_In_Place_Function_Call (Rhs) @@ -1830,7 +1827,7 @@ package body Exp_Ch5 is -- In case of assignment to a class-wide tagged type, before -- the assignment we generate run-time check to ensure that - -- the tag of the Target is covered by the tag of the source + -- the tags of source and target match. if Is_Class_Wide_Type (Typ) and then Is_Tagged_Type (Typ) @@ -1839,21 +1836,19 @@ package body Exp_Ch5 is Append_To (L, Make_Raise_Constraint_Error (Loc, Condition => - Make_Op_Not (Loc, - Make_Function_Call (Loc, - Name => New_Reference_To - (RTE (RE_CW_Membership), Loc), - Parameter_Associations => New_List ( + Make_Op_Ne (Loc, + Left_Opnd => Make_Selected_Component (Loc, - Prefix => - Duplicate_Subexpr (Lhs), + Prefix => Duplicate_Subexpr (Lhs), Selector_Name => - Make_Identifier (Loc, Name_uTag)), + Make_Identifier (Loc, + Chars => Name_uTag)), + Right_Opnd => Make_Selected_Component (Loc, - Prefix => - Duplicate_Subexpr (Rhs), + Prefix => Duplicate_Subexpr (Rhs), Selector_Name => - Make_Identifier (Loc, Name_uTag))))), + Make_Identifier (Loc, + Chars => Name_uTag))), Reason => CE_Tag_Check_Failed)); end if; @@ -1861,7 +1856,8 @@ package body Exp_Ch5 is Make_Procedure_Call_Statement (Loc, Name => New_Reference_To (Op, Loc), Parameter_Associations => New_List ( - Unchecked_Convert_To (F_Typ, Duplicate_Subexpr (Lhs)), + Unchecked_Convert_To (F_Typ, + Duplicate_Subexpr (Lhs)), Unchecked_Convert_To (F_Typ, Duplicate_Subexpr (Rhs))))); end; @@ -1872,8 +1868,8 @@ package body Exp_Ch5 is -- We can't afford to have destructive Finalization Actions -- in the Self assignment case, so if the target and the -- source are not obviously different, code is generated to - -- avoid the self assignment case - -- + -- avoid the self assignment case: + -- if lhs'address /= rhs'address then -- <code for controlled and/or tagged assignment> -- end if; @@ -1901,7 +1897,7 @@ package body Exp_Ch5 is -- We need to set up an exception handler for implementing -- 7.6.1 (18). The remaining adjustments are tackled by the -- implementation of adjust for record_controllers (see - -- s-finimp.adb) + -- s-finimp.adb). -- This is skipped if we have no finalization @@ -1914,7 +1910,7 @@ package body Exp_Ch5 is Make_Handled_Sequence_Of_Statements (Loc, Statements => L, Exception_Handlers => New_List ( - Make_Exception_Handler (Loc, + Make_Implicit_Exception_Handler (Loc, Exception_Choices => New_List (Make_Others_Choice (Loc)), Statements => New_List ( @@ -1931,7 +1927,7 @@ package body Exp_Ch5 is Make_Handled_Sequence_Of_Statements (Loc, Statements => L))); -- If no restrictions on aborts, protect the whole assignement - -- for controlled objects as per 9.8(11) + -- for controlled objects as per 9.8(11). if Controlled_Type (Typ) and then Expand_Ctrl_Actions @@ -2366,61 +2362,6 @@ package body Exp_Ch5 is -- initial values might need to be set). procedure Expand_N_Extended_Return_Statement (N : Node_Id) is - - function Is_Build_In_Place_Function (Fun : Entity_Id) return Boolean; - -- F must be of type E_Function or E_Generic_Function. Return True if it - -- uses build-in-place for the result object. In Ada 95, this must be - -- False for inherently limited result type. In Ada 2005, this must be - -- True for inherently limited result type. For other types, we have a - -- choice -- build-in-place is usually more efficient for large things, - -- and less efficient for small things. However, we had better not use - -- build-in-place if the Convention is other than Ada, because that - -- would disturb mixed-language programs. - -- - -- Note that for the non-inherently-limited cases, we must make the same - -- decision for Ada 95 and 2005, so that mixed-dialect programs work. - -- - -- ???This function will be needed when compiling the call sites; - -- we will have to move it to a more global place. - - -------------------------------- - -- Is_Build_In_Place_Function -- - -------------------------------- - - function Is_Build_In_Place_Function (Fun : Entity_Id) return Boolean is - R_Type : constant Entity_Id := Underlying_Type (Etype (Fun)); - - begin - -- First, the cases that matter for correctness - - if Is_Inherently_Limited_Type (R_Type) then - return Ada_Version >= Ada_05 and then not Debug_Flag_Dot_L; - - -- Note: If you have Convention (C) on an inherently limited - -- type, you're on your own. That is, the C code will have to be - -- carefully written to know about the Ada conventions. - - elsif - Has_Foreign_Convention (R_Type) - or else - Has_Foreign_Convention (Fun) - then - return False; - - -- Second, the efficiency-related decisions. It would be obnoxiously - -- inefficient to use build-in-place for elementary types. For - -- composites, we could return False if the subtype is known to be - -- small (<= one or two words?) but we don't bother with that yet. - - else - return Is_Composite_Type (R_Type); - end if; - end Is_Build_In_Place_Function; - - ------------------------ - -- Local Declarations -- - ------------------------ - Loc : constant Source_Ptr := Sloc (N); Return_Object_Entity : constant Entity_Id := @@ -2433,10 +2374,83 @@ package body Exp_Ch5 is Is_Build_In_Place_Function (Parent_Function); Return_Stm : Node_Id; + Statements : List_Id; Handled_Stm_Seq : Node_Id; Result : Node_Id; Exp : Node_Id; + function Move_Activation_Chain return Node_Id; + -- Construct a call to System.Tasking.Stages.Move_Activation_Chain + -- with parameters: + -- From current activation chain + -- To activation chain passed in by the caller + -- New_Master master passed in by the caller + + function Move_Final_List return Node_Id; + -- Construct call to System.Finalization_Implementation.Move_Final_List + -- with parameters: + -- From finalization list of the return statement + -- To finalization list passed in by the caller + + --------------------- + -- Move_Activation_Chain -- + --------------------- + + function Move_Activation_Chain return Node_Id is + Activation_Chain_Formal : constant Entity_Id := + Build_In_Place_Formal (Parent_Function, BIP_Activation_Chain); + To : constant Node_Id := + New_Reference_To (Activation_Chain_Formal, Loc); + Master_Formal : constant Entity_Id := + Build_In_Place_Formal (Parent_Function, BIP_Master); + New_Master : constant Node_Id := + New_Reference_To (Master_Formal, Loc); + + Chain_Entity : Entity_Id; + From : Node_Id; + begin + Chain_Entity := First_Entity (Return_Statement_Entity (N)); + while Chars (Chain_Entity) /= Name_uChain loop + Chain_Entity := Next_Entity (Chain_Entity); + end loop; + + From := + Make_Attribute_Reference (Loc, + Prefix => New_Reference_To (Chain_Entity, Loc), + Attribute_Name => Name_Unrestricted_Access); + -- ??? I'm not sure why "Make_Identifier (Loc, Name_uChain)" doesn't + -- work, instead of "New_Reference_To (Chain_Entity, Loc)" above. + + return + Make_Procedure_Call_Statement (Loc, + Name => New_Reference_To (RTE (RE_Move_Activation_Chain), Loc), + Parameter_Associations => New_List (From, To, New_Master)); + end Move_Activation_Chain; + + --------------------- + -- Move_Final_List -- + --------------------- + + function Move_Final_List return Node_Id is + Flist : constant Entity_Id := + Finalization_Chain_Entity (Return_Statement_Entity (N)); + + From : constant Node_Id := New_Reference_To (Flist, Loc); + + Caller_Final_List : constant Entity_Id := + Build_In_Place_Formal + (Parent_Function, BIP_Final_List); + + To : constant Node_Id := + New_Reference_To (Caller_Final_List, Loc); + + begin + return + Make_Procedure_Call_Statement (Loc, + Name => New_Reference_To (RTE (RE_Move_Final_List), Loc), + Parameter_Associations => New_List (From, To)); + end Move_Final_List; + -- Start of processing for Expand_N_Extended_Return_Statement begin @@ -2448,27 +2462,63 @@ package body Exp_Ch5 is Handled_Stm_Seq := Handled_Statement_Sequence (N); + -- Build a simple_return_statement that returns the return object when + -- there is a statement sequence, or no expression, or the result will + -- be built in place. Note however that we currently do this for all + -- composite cases, even though nonlimited composite results are not yet + -- built in place (though we plan to do so eventually). + if Present (Handled_Stm_Seq) - or else Is_Build_In_Place + or else Is_Composite_Type (Etype (Parent_Function)) or else No (Exp) then - -- Build simple_return_statement that returns the return object + Statements := New_List; + + if Present (Handled_Stm_Seq) then + Append_To (Statements, Handled_Stm_Seq); + end if; + + -- If control gets past the above Statements, we have successfully + -- completed the return statement. If the result type has controlled + -- parts, we call Move_Final_List to transfer responsibility for + -- finalization of the return object to the caller. An alternative + -- would be to declare a Success flag in the function, initialize it + -- to False, and set it to True here. Then move the Move_Final_List + -- call into the cleanup code, and check Success. If Success then + -- Move_Final_List else do finalization. Then we can remove the + -- abort-deferral and the nulling-out of the From parameter from + -- Move_Final_List. Note that the current method is not quite + -- correct in the rather obscure case of a select-then-abort + -- statement whose abortable part contains the return statement. + + if Is_Controlled (Etype (Parent_Function)) + or else Has_Controlled_Component (Etype (Parent_Function)) + then + Append_To (Statements, Move_Final_List); + end if; + + -- Similarly to the above Move_Final_List, if the result type + -- contains tasks, we call Move_Activation_Chain. Later, the cleanup + -- code will call Complete_Master, which will terminate any + -- unactivated tasks belonging to the return statement master. But + -- Move_Activation_Chain updates their master to be that of the + -- caller, so they will not be terminated unless the return + -- statement completes unsuccessfully due to exception, abort, goto, + -- or exit. + + if Has_Task (Etype (Parent_Function)) then + Append_To (Statements, Move_Activation_Chain); + end if; + + -- Build a simple_return_statement that returns the return object Return_Stm := Make_Return_Statement (Loc, Expression => New_Occurrence_Of (Return_Object_Entity, Loc)); + Append_To (Statements, Return_Stm); - if Present (Handled_Stm_Seq) then - Handled_Stm_Seq := - Make_Handled_Sequence_Of_Statements (Loc, - Statements => New_List (Handled_Stm_Seq, Return_Stm)); - else - Handled_Stm_Seq := - Make_Handled_Sequence_Of_Statements (Loc, - Statements => New_List (Return_Stm)); - end if; - - pragma Assert (Present (Handled_Stm_Seq)); + Handled_Stm_Seq := + Make_Handled_Sequence_Of_Statements (Loc, Statements); end if; -- Case where we build a block @@ -2479,7 +2529,29 @@ package body Exp_Ch5 is Declarations => Return_Object_Declarations (N), Handled_Statement_Sequence => Handled_Stm_Seq); - if Is_Build_In_Place then + -- We set the entity of the new block statement to be that of the + -- return statement. This is necessary so that various fields, such + -- as Finalization_Chain_Entity carry over from the return statement + -- to the block. Note that this block is unusual, in that its entity + -- is an E_Return_Statement rather than an E_Block. + + Set_Identifier + (Result, New_Occurrence_Of (Return_Statement_Entity (N), Loc)); + + -- If the object decl was already rewritten as a renaming, then + -- we don't want to do the object allocation and transformation of + -- of the return object declaration to a renaming. This case occurs + -- when the return object is initialized by a call to another + -- build-in-place function, and that function is responsible for the + -- allocation of the return object. + + if Is_Build_In_Place + and then + Nkind (Return_Object_Decl) = N_Object_Renaming_Declaration + then + Set_By_Ref (Return_Stm); -- Return build-in-place results by ref + + elsif Is_Build_In_Place then -- Locate the implicit access parameter associated with the -- the caller-supplied return object and convert the return @@ -2503,84 +2575,282 @@ package body Exp_Ch5 is -- ... declare - Return_Obj_Id : constant Entity_Id := - Defining_Identifier (Return_Object_Decl); - Return_Obj_Typ : constant Entity_Id := Etype (Return_Obj_Id); - Return_Obj_Expr : constant Node_Id := - Expression (Return_Object_Decl); - Obj_Acc_Formal : Entity_Id := Extra_Formals (Parent_Function); - Obj_Acc_Deref : Node_Id; - Init_Assignment : Node_Id; + Return_Obj_Id : constant Entity_Id := + Defining_Identifier (Return_Object_Decl); + Return_Obj_Typ : constant Entity_Id := Etype (Return_Obj_Id); + Return_Obj_Expr : constant Node_Id := + Expression (Return_Object_Decl); + Result_Subt : constant Entity_Id := + Etype (Parent_Function); + Constr_Result : constant Boolean := + Is_Constrained (Result_Subt); + Obj_Alloc_Formal : Entity_Id; + Object_Access : Entity_Id; + Obj_Acc_Deref : Node_Id; + Init_Assignment : Node_Id := Empty; begin -- Build-in-place results must be returned by reference Set_By_Ref (Return_Stm); - -- Locate the implicit access parameter passed by the caller. - -- It might be better to search for that with a symbol table - -- lookup, but for now we traverse the extra actuals to find - -- the access parameter (currently there can only be one). + -- Retrieve the implicit access parameter passed by the caller - while Present (Obj_Acc_Formal) loop - exit when - Ekind (Etype (Obj_Acc_Formal)) = E_Anonymous_Access_Type; - Next_Formal_With_Extras (Obj_Acc_Formal); - end loop; + Object_Access := + Build_In_Place_Formal (Parent_Function, BIP_Object_Access); - -- ??? pragma Assert (Present (Obj_Acc_Formal)); + -- If the return object's declaration includes an expression + -- and the declaration isn't marked as No_Initialization, then + -- we need to generate an assignment to the object and insert + -- it after the declaration before rewriting it as a renaming + -- (otherwise we'll lose the initialization). - -- For now we only rewrite the object if we can locate the - -- implicit access parameter. Normally there should be one - -- if Build_In_Place is true, but at the moment it's only - -- created in the more restrictive case of constrained - -- inherently limited result subtypes. ??? + if Present (Return_Obj_Expr) + and then not No_Initialization (Return_Object_Decl) + then + Init_Assignment := + Make_Assignment_Statement (Loc, + Name => New_Reference_To (Return_Obj_Id, Loc), + Expression => Relocate_Node (Return_Obj_Expr)); + Set_Assignment_OK (Name (Init_Assignment)); + Set_No_Ctrl_Actions (Init_Assignment); - if Present (Obj_Acc_Formal) then + Set_Parent (Expression (Init_Assignment), Init_Assignment); - -- If the return object's declaration includes an expression - -- and the declaration isn't marked as No_Initialization, - -- then we need to generate an assignment to the object and - -- insert it after the declaration before rewriting it as - -- a renaming (otherwise we'll lose the initialization). + Set_Expression (Return_Object_Decl, Empty); - if Present (Return_Obj_Expr) - and then not No_Initialization (Return_Object_Decl) + if Is_Class_Wide_Type (Etype (Return_Obj_Id)) + and then not Is_Class_Wide_Type + (Etype (Expression (Init_Assignment))) then - Init_Assignment := - Make_Assignment_Statement (Loc, - Name => New_Reference_To (Return_Obj_Id, Loc), - Expression => Relocate_Node (Return_Obj_Expr)); - Set_Assignment_OK (Name (Init_Assignment)); - Set_No_Ctrl_Actions (Init_Assignment); - - -- ??? Should we be setting the parent of the expression - -- here? - -- Set_Parent - -- (Expression (Init_Assignment), Init_Assignment); - - Set_Expression (Return_Object_Decl, Empty); + Rewrite (Expression (Init_Assignment), + Make_Type_Conversion (Loc, + Subtype_Mark => + New_Occurrence_Of + (Etype (Return_Obj_Id), Loc), + Expression => + Relocate_Node (Expression (Init_Assignment)))); + end if; + if Constr_Result then Insert_After (Return_Object_Decl, Init_Assignment); end if; + end if; - -- Replace the return object declaration with a renaming - -- of a dereference of the implicit access formal. + -- When the function's subtype is unconstrained, a run-time + -- test is needed to determine the form of allocation to use + -- for the return object. The function has an implicit formal + -- parameter that indicates this. If the BIP_Alloc_Form formal + -- has the value one, then the caller has passed access to an + -- existing object for use as the return object. If the value + -- is two, then the return object must be allocated on the + -- secondary stack. Otherwise, the object must be allocated in + -- a storage pool. Currently the last case is only supported + -- for the global heap (user-defined storage pools TBD ???). We + -- generate an if statement to test the implicit allocation + -- formal and initialize a local access value appropriately, + -- creating allocators in the secondary stack and global heap + -- cases. + + if not Constr_Result then + Obj_Alloc_Formal := + Build_In_Place_Formal (Parent_Function, BIP_Alloc_Form); + + declare + Ref_Type : Entity_Id; + Ptr_Type_Decl : Node_Id; + Alloc_Obj_Id : Entity_Id; + Alloc_Obj_Decl : Node_Id; + Alloc_If_Stmt : Node_Id; + SS_Allocator : Node_Id; + Heap_Allocator : Node_Id; + + begin + -- Reuse the itype created for the function's implicit + -- access formal. This avoids the need to create a new + -- access type here, plus it allows assigning the access + -- formal directly without applying a conversion. + + -- Ref_Type := Etype (Object_Access); + + -- Create an access type designating the function's + -- result subtype. + + Ref_Type := + Make_Defining_Identifier (Loc, New_Internal_Name ('A')); + + Ptr_Type_Decl := + Make_Full_Type_Declaration (Loc, + Defining_Identifier => Ref_Type, + Type_Definition => + Make_Access_To_Object_Definition (Loc, + All_Present => True, + Subtype_Indication => + New_Reference_To (Return_Obj_Typ, Loc))); + + Insert_Before_And_Analyze + (Return_Object_Decl, Ptr_Type_Decl); + + -- Create an access object that will be initialized to an + -- access value denoting the return object, either coming + -- from an implicit access value passed in by the caller + -- or from the result of an allocator. + + Alloc_Obj_Id := + Make_Defining_Identifier (Loc, + Chars => New_Internal_Name ('R')); + Set_Etype (Alloc_Obj_Id, Ref_Type); + + Alloc_Obj_Decl := + Make_Object_Declaration (Loc, + Defining_Identifier => Alloc_Obj_Id, + Object_Definition => New_Reference_To + (Ref_Type, Loc)); + + Insert_Before_And_Analyze + (Return_Object_Decl, Alloc_Obj_Decl); + + -- Create allocators for both the secondary stack and + -- global heap. If there's an initialization expression, + -- then create these as initialized allocators. + + if Present (Return_Obj_Expr) + and then not No_Initialization (Return_Object_Decl) + then + Heap_Allocator := + Make_Allocator (Loc, + Expression => + Make_Qualified_Expression (Loc, + Subtype_Mark => + New_Reference_To (Return_Obj_Typ, Loc), + Expression => + New_Copy_Tree (Return_Obj_Expr))); + + SS_Allocator := New_Copy_Tree (Heap_Allocator); + + else + Heap_Allocator := + Make_Allocator (Loc, + New_Reference_To (Return_Obj_Typ, Loc)); - Obj_Acc_Deref := - Make_Explicit_Dereference (Loc, - Prefix => New_Reference_To (Obj_Acc_Formal, Loc)); + -- If the object requires default initialization then + -- that will happen later following the elaboration of + -- the object renaming. If we don't turn it off here + -- then the object will be default initialized twice. - Rewrite (Return_Object_Decl, - Make_Object_Renaming_Declaration (Loc, - Defining_Identifier => Return_Obj_Id, - Access_Definition => Empty, - Subtype_Mark => New_Occurrence_Of - (Return_Obj_Typ, Loc), - Name => Obj_Acc_Deref)); + Set_No_Initialization (Heap_Allocator); - Set_Renamed_Object (Return_Obj_Id, Obj_Acc_Deref); + SS_Allocator := New_Copy_Tree (Heap_Allocator); + end if; + + Set_Storage_Pool + (SS_Allocator, RTE (RE_SS_Pool)); + Set_Procedure_To_Call + (SS_Allocator, RTE (RE_SS_Allocate)); + + -- Create an if statement to test the BIP_Alloc_Form + -- formal and initialize the access object to either the + -- BIP_Object_Access formal (BIP_Alloc_Form = 0), the + -- result of allocaing the object in the secondary stack + -- (BIP_Alloc_Form = 1), or else an allocator to create + -- the return object in the heap (BIP_Alloc_Form = 2). + + -- ??? An unchecked type conversion must be made in the + -- case of assigning the access object formal to the + -- local access object, because a normal conversion would + -- be illegal in some cases (such as converting access- + -- to-unconstrained to access-to-constrained), but the + -- the unchecked conversion will presumably fail to work + -- right in just such cases. It's not clear at all how to + -- handle this. ??? + + Alloc_If_Stmt := + Make_If_Statement (Loc, + Condition => + Make_Op_Eq (Loc, + Left_Opnd => + New_Reference_To (Obj_Alloc_Formal, Loc), + Right_Opnd => + Make_Integer_Literal (Loc, + UI_From_Int (BIP_Allocation_Form'Pos + (Caller_Allocation)))), + Then_Statements => + New_List (Make_Assignment_Statement (Loc, + Name => + New_Reference_To + (Alloc_Obj_Id, Loc), + Expression => + Make_Unchecked_Type_Conversion (Loc, + Subtype_Mark => + New_Reference_To (Ref_Type, Loc), + Expression => + New_Reference_To + (Object_Access, Loc)))), + Elsif_Parts => + New_List (Make_Elsif_Part (Loc, + Condition => + Make_Op_Eq (Loc, + Left_Opnd => + New_Reference_To + (Obj_Alloc_Formal, Loc), + Right_Opnd => + Make_Integer_Literal (Loc, + UI_From_Int ( + BIP_Allocation_Form'Pos + (Secondary_Stack)))), + Then_Statements => + New_List + (Make_Assignment_Statement (Loc, + Name => + New_Reference_To + (Alloc_Obj_Id, Loc), + Expression => + SS_Allocator)))), + Else_Statements => + New_List (Make_Assignment_Statement (Loc, + Name => + New_Reference_To + (Alloc_Obj_Id, Loc), + Expression => + Heap_Allocator))); + + -- If a separate initialization assignment was created + -- earlier, append that following the assignment of the + -- implicit access formal to the access object, to ensure + -- that the return object is initialized in that case. + + if Present (Init_Assignment) then + Append_To + (Then_Statements (Alloc_If_Stmt), + Init_Assignment); + end if; + + Insert_After_And_Analyze (Alloc_Obj_Decl, Alloc_If_Stmt); + + -- Remember the local access object for use in the + -- dereference of the renaming created below. + + Object_Access := Alloc_Obj_Id; + end; end if; + + -- Replace the return object declaration with a renaming of a + -- dereference of the access value designating the return + -- object. + + Obj_Acc_Deref := + Make_Explicit_Dereference (Loc, + Prefix => New_Reference_To (Object_Access, Loc)); + + Rewrite (Return_Object_Decl, + Make_Object_Renaming_Declaration (Loc, + Defining_Identifier => Return_Obj_Id, + Access_Definition => Empty, + Subtype_Mark => New_Occurrence_Of + (Return_Obj_Typ, Loc), + Name => Obj_Acc_Deref)); + + Set_Renamed_Object (Return_Obj_Id, Obj_Acc_Deref); end; end if; @@ -2622,8 +2892,8 @@ package body Exp_Ch5 is -- Expand_N_If_Statement -- --------------------------- - -- First we deal with the case of C and Fortran convention boolean - -- values, with zero/non-zero semantics. + -- First we deal with the case of C and Fortran convention boolean values, + -- with zero/non-zero semantics. -- Second, we deal with the obvious rewriting for the cases where the -- condition of the IF is known at compile time to be True or False. @@ -2647,8 +2917,8 @@ package body Exp_Ch5 is -- end if; -- This rewriting is needed if at least one elsif part has a non-empty - -- Condition_Actions list. We also do the same processing if there is - -- a constant condition in an elsif part (in conjunction with the first + -- Condition_Actions list. We also do the same processing if there is a + -- constant condition in an elsif part (in conjunction with the first -- processing step mentioned above, for the recursive call made to deal -- with the created inner if, this deals with properly optimizing the -- cases of constant elsif conditions). @@ -2668,8 +2938,8 @@ package body Exp_Ch5 is while Compile_Time_Known_Value (Condition (N)) loop - -- If condition is True, we can simply rewrite the if statement - -- now by replacing it by the series of then statements. + -- If condition is True, we can simply rewrite the if statement now + -- by replacing it by the series of then statements. if Is_True (Expr_Value (Condition (N))) then @@ -2687,10 +2957,10 @@ package body Exp_Ch5 is -- the Then statements else - -- We do not delete the condition if constant condition - -- warnings are enabled, since otherwise we end up deleting - -- the desired warning. Of course the backend will get rid - -- of this True/False test anyway, so nothing is lost here. + -- We do not delete the condition if constant condition warnings + -- are enabled, since otherwise we end up deleting the desired + -- warning. Of course the backend will get rid of this True/False + -- test anyway, so nothing is lost here. if not Constant_Condition_Warnings then Kill_Dead_Code (Condition (N)); @@ -2698,8 +2968,8 @@ package body Exp_Ch5 is Kill_Dead_Code (Then_Statements (N), Warn_On_Deleted_Code); - -- If there are no elsif statements, then we simply replace - -- the entire if statement by the sequence of else statements. + -- If there are no elsif statements, then we simply replace the + -- entire if statement by the sequence of else statements. if No (Elsif_Parts (N)) then if No (Else_Statements (N)) @@ -2715,9 +2985,9 @@ package body Exp_Ch5 is return; - -- If there are elsif statements, the first of them becomes - -- the if/then section of the rebuilt if statement This is - -- the case where we loop to reprocess this copied condition. + -- If there are elsif statements, the first of them becomes the + -- if/then section of the rebuilt if statement This is the case + -- where we loop to reprocess this copied condition. else Hed := Remove_Head (Elsif_Parts (N)); @@ -2747,18 +3017,18 @@ package body Exp_Ch5 is while Present (E) loop Adjust_Condition (Condition (E)); - -- If there are condition actions, then we rewrite the if - -- statement as indicated above. We also do the same rewrite - -- if the condition is True or False. The further processing - -- of this constant condition is then done by the recursive - -- call to expand the newly created if statement + -- If there are condition actions, then rewrite the if statement + -- as indicated above. We also do the same rewrite for a True or + -- False condition. The further processing of this constant + -- condition is then done by the recursive call to expand the + -- newly created if statement if Present (Condition_Actions (E)) or else Compile_Time_Known_Value (Condition (E)) then - -- Note this is not an implicit if statement, since it is - -- part of an explicit if statement in the source (or of an - -- implicit if statement that has already been tested). + -- Note this is not an implicit if statement, since it is part + -- of an explicit if statement in the source (or of an implicit + -- if statement that has already been tested). New_If := Make_If_Statement (Sloc (E), @@ -2913,9 +3183,9 @@ package body Exp_Ch5 is -- range bounds here, since they were frozen with constant declarations -- and it is during that process that the validity checking is done. - -- Handle the case where we have a for loop with the range type being - -- an enumeration type with non-standard representation. In this case - -- we expand: + -- Handle the case where we have a for loop with the range type being an + -- enumeration type with non-standard representation. In this case we + -- expand: -- for x in [reverse] a .. b loop -- ... @@ -2952,8 +3222,8 @@ package body Exp_Ch5 is Make_Defining_Identifier (Loc, Chars => New_External_Name (Chars (Loop_Id), 'P')); - -- If the type has a contiguous representation, successive - -- values can be generated as offsets from the first literal. + -- If the type has a contiguous representation, successive values + -- can be generated as offsets from the first literal. if Has_Contiguous_Rep (Btype) then Expr := @@ -3033,8 +3303,8 @@ package body Exp_Ch5 is Analyze (N); end; - -- Second case, if we have a while loop with Condition_Actions set, - -- then we change it into a plain loop: + -- Second case, if we have a while loop with Condition_Actions set, then + -- we change it into a plain loop: -- while C loop -- ... @@ -3064,10 +3334,10 @@ package body Exp_Ch5 is Prepend (ES, Statements (N)); Insert_List_Before (ES, Condition_Actions (Isc)); - -- This is not an implicit loop, since it is generated in - -- response to the loop statement being processed. If this - -- is itself implicit, the restriction has already been - -- checked. If not, it is an explicit loop. + -- This is not an implicit loop, since it is generated in response + -- to the loop statement being processed. If this is itself + -- implicit, the restriction has already been checked. If not, + -- it is an explicit loop. Rewrite (N, Make_Loop_Statement (Sloc (N), @@ -3167,8 +3437,8 @@ package body Exp_Ch5 is pragma Assert (Is_Entry (Scope_Id)); - -- Look at the enclosing block to see whether the return is from - -- an accept statement or an entry body. + -- Look at the enclosing block to see whether the return is from an + -- accept statement or an entry body. for J in reverse 0 .. Cur_Idx loop Scope_Id := Scope_Stack.Table (J).Entity; @@ -3249,9 +3519,9 @@ package body Exp_Ch5 is -- Deal with returning variable length objects and controlled types - -- Nothing to do if we are returning by reference, or this is not a - -- type that requires special processing (indicated by the fact that - -- it requires a cleanup scope for the secondary stack case). + -- Nothing to do if we are returning by reference, or this is not type + -- that requires special processing (indicated by the fact that it + -- requires a cleanup scope for the secondary stack case). if Is_Inherently_Limited_Type (T) then null; @@ -3282,158 +3552,6 @@ package body Exp_Ch5 is end if; end; - -- Case of secondary stack not used - - elsif Function_Returns_With_DSP (Scope_Id) then - - -- The DSP method is no longer in use. We would like to ignore DSP - -- while implementing AI-318; hence the raise below. - - if True then - raise Program_Error; - end if; - - -- Here what we need to do is to always return by reference, since - -- we will return with the stack pointer depressed. We may need to - -- do a copy to a local temporary before doing this return. - - No_Secondary_Stack_Case : declare - Local_Copy_Required : Boolean := False; - -- Set to True if a local copy is required - - Copy_Ent : Entity_Id; - -- Used for the target entity if a copy is required - - Decl : Node_Id; - -- Declaration used to create copy if needed - - procedure Test_Copy_Required (Expr : Node_Id); - -- Determines if Expr represents a return value for which a - -- copy is required. More specifically, a copy is not required - -- if Expr represents an object or component of an object that - -- is either in the local subprogram frame, or is constant. - -- If a copy is required, then Local_Copy_Required is set True. - - ------------------------ - -- Test_Copy_Required -- - ------------------------ - - procedure Test_Copy_Required (Expr : Node_Id) is - Ent : Entity_Id; - - begin - -- If component, test prefix (object containing component) - - if Nkind (Expr) = N_Indexed_Component - or else - Nkind (Expr) = N_Selected_Component - then - Test_Copy_Required (Prefix (Expr)); - return; - - -- See if we have an entity name - - elsif Is_Entity_Name (Expr) then - Ent := Entity (Expr); - - -- Constant entity is always OK, no copy required - - if Ekind (Ent) = E_Constant then - return; - - -- No copy required for local variable - - elsif Ekind (Ent) = E_Variable - and then Scope (Ent) = Current_Subprogram - then - return; - end if; - end if; - - -- All other cases require a copy - - Local_Copy_Required := True; - end Test_Copy_Required; - - -- Start of processing for No_Secondary_Stack_Case - - begin - -- No copy needed if result is from a function call. - -- In this case the result is already being returned by - -- reference with the stack pointer depressed. - - -- To make up for a gcc 2.8.1 deficiency (???), we perform - -- the copy for array types if the constrained status of the - -- target type is different from that of the expression. - - if Requires_Transient_Scope (T) - and then - (not Is_Array_Type (T) - or else Is_Constrained (T) = Is_Constrained (Return_Type) - or else Controlled_Type (T)) - and then Nkind (Exp) = N_Function_Call - then - Set_By_Ref (N); - - -- We always need a local copy for a controlled type, since - -- we are required to finalize the local value before return. - -- The copy will automatically include the required finalize. - -- Moreover, gigi cannot make this copy, since we need special - -- processing to ensure proper behavior for finalization. - - -- Note: the reason we are returning with a depressed stack - -- pointer in the controlled case (even if the type involved - -- is constrained) is that we must make a local copy to deal - -- properly with the requirement that the local result be - -- finalized. - - elsif Controlled_Type (Utyp) then - Copy_Ent := - Make_Defining_Identifier (Loc, - Chars => New_Internal_Name ('R')); - - -- Build declaration to do the copy, and insert it, setting - -- Assignment_OK, because we may be copying a limited type. - -- In addition we set the special flag to inhibit finalize - -- attachment if this is a controlled type (since this attach - -- must be done by the caller, otherwise if we attach it here - -- we will finalize the returned result prematurely). - - Decl := - Make_Object_Declaration (Loc, - Defining_Identifier => Copy_Ent, - Object_Definition => New_Occurrence_Of (Return_Type, Loc), - Expression => Relocate_Node (Exp)); - - Set_Assignment_OK (Decl); - Set_Delay_Finalize_Attach (Decl); - Insert_Action (N, Decl); - - -- Now the actual return uses the copied value - - Rewrite (Exp, New_Occurrence_Of (Copy_Ent, Loc)); - Analyze_And_Resolve (Exp, Return_Type); - - -- Since we have made the copy, gigi does not have to, so - -- we set the By_Ref flag to prevent another copy being made. - - Set_By_Ref (N); - - -- Non-controlled cases - - else - Test_Copy_Required (Exp); - - -- If a local copy is required, then gigi will make the - -- copy, otherwise, we can return the result directly, - -- so set By_Ref to suppress the gigi copy. - - if not Local_Copy_Required then - Set_By_Ref (N); - end if; - end if; - end No_Secondary_Stack_Case; - -- Here if secondary stack is used else @@ -3457,12 +3575,12 @@ package body Exp_Ch5 is -- case either the result is already on the secondary stack, or is -- already being returned with the stack pointer depressed and no -- further processing is required except to set the By_Ref flag to - -- ensure that gigi does not attempt an extra unnecessary copy. - -- (actually not just unnecessary but harmfully wrong in the case - -- of a controlled type, where gigi does not know how to do a copy). - -- To make up for a gcc 2.8.1 deficiency (???), we perform - -- the copy for array types if the constrained status of the - -- target type is different from that of the expression. + -- ensure that gigi does not attempt an extra unnecessary copy + -- (actually not just unnecessary but harmfully wrong in the case of + -- a controlled type, where gigi does not know how to do a copy). To + -- make up for a gcc 2.8.1 deficiency (???), we perform the copy for + -- array types if the constrained status of the target type is + -- different from that of the expression. if Requires_Transient_Scope (T) and then @@ -3474,25 +3592,25 @@ package body Exp_Ch5 is then Set_By_Ref (N); - -- Remove side effects from the expression now so that - -- other part of the expander do not have to reanalyze - -- this node without this optimization + -- Remove side effects from the expression now so that other parts + -- of the expander do not have to reanalyze the node without this + -- optimization. Rewrite (Exp, Duplicate_Subexpr_No_Checks (Exp)); -- For controlled types, do the allocation on the secondary stack -- manually in order to call adjust at the right time: + -- type Anon1 is access Return_Type; -- for Anon1'Storage_pool use ss_pool; -- Anon2 : anon1 := new Return_Type'(expr); -- return Anon2.all; + -- We do the same for classwide types that are not potentially -- controlled (by the virtue of restriction No_Finalization) because -- gigi is not able to properly allocate class-wide types. - elsif Is_Class_Wide_Type (Utyp) - or else Controlled_Type (Utyp) - then + elsif CW_Or_Controlled_Type (Utyp) then declare Loc : constant Source_Ptr := Sloc (N); Temp : constant Entity_Id := @@ -3550,13 +3668,12 @@ package body Exp_Ch5 is end if; end if; - -- Implement the rules of 6.5(8-10), which require a tag check in - -- the case of a limited tagged return type, and tag reassignment - -- for nonlimited tagged results. These actions are needed when - -- the return type is a specific tagged type and the result - -- expression is a conversion or a formal parameter, because in - -- that case the tag of the expression might differ from the tag - -- of the specific result type. + -- Implement the rules of 6.5(8-10), which require a tag check in the + -- case of a limited tagged return type, and tag reassignment for + -- nonlimited tagged results. These actions are needed when the return + -- type is a specific tagged type and the result expression is a + -- conversion or a formal parameter, because in that case the tag of the + -- expression might differ from the tag of the specific result type. if Is_Tagged_Type (Utyp) and then not Is_Class_Wide_Type (Utyp) @@ -3565,8 +3682,8 @@ package body Exp_Ch5 is or else (Is_Entity_Name (Exp) and then Ekind (Entity (Exp)) in Formal_Kind)) then - -- When the return type is limited, perform a check that the - -- tag of the result is the same as the tag of the return type. + -- When the return type is limited, perform a check that the tag of + -- the result is the same as the tag of the return type. if Is_Limited_Type (Return_Type) then Insert_Action (Exp, @@ -3586,14 +3703,13 @@ package body Exp_Ch5 is Loc))), Reason => CE_Tag_Check_Failed)); - -- If the result type is a specific nonlimited tagged type, - -- then we have to ensure that the tag of the result is that - -- of the result type. This is handled by making a copy of the - -- expression in the case where it might have a different tag, - -- namely when the expression is a conversion or a formal - -- parameter. We create a new object of the result type and - -- initialize it from the expression, which will implicitly - -- force the tag to be set appropriately. + -- If the result type is a specific nonlimited tagged type, then we + -- have to ensure that the tag of the result is that of the result + -- type. This is handled by making a copy of the expression in the + -- case where it might have a different tag, namely when the + -- expression is a conversion or a formal parameter. We create a new + -- object of the result type and initialize it from the expression, + -- which will implicitly force the tag to be set appropriately. else Result_Id := @@ -3640,16 +3756,10 @@ package body Exp_Ch5 is Condition => Make_Op_Gt (Loc, Left_Opnd => - Make_Function_Call (Loc, - Name => - New_Reference_To - (RTE (RE_Get_Access_Level), Loc), - Parameter_Associations => - New_List (Make_Attribute_Reference (Loc, - Prefix => - Duplicate_Subexpr (Exp), - Attribute_Name => - Name_Tag))), + Build_Get_Access_Level (Loc, + Make_Attribute_Reference (Loc, + Prefix => Duplicate_Subexpr (Exp), + Attribute_Name => Name_Tag)), Right_Opnd => Make_Integer_Literal (Loc, Scope_Depth (Enclosing_Dynamic_Scope (Scope_Id)))), @@ -3683,8 +3793,8 @@ package body Exp_Ch5 is if Kind = E_Procedure or else Kind = E_Generic_Procedure then return; - -- If it is a nested return within an extended one, replace it - -- with a return of the previously declared return object. + -- If it is a nested return within an extended one, replace it with a + -- return of the previously declared return object. elsif Kind = E_Return_Statement then Rewrite (N, @@ -3699,8 +3809,8 @@ package body Exp_Ch5 is pragma Assert (Is_Entry (Scope_Id)); - -- Look at the enclosing block to see whether the return is from - -- an accept statement or an entry body. + -- Look at the enclosing block to see whether the return is from an + -- accept statement or an entry body. for J in reverse 0 .. Scope_Stack.Last loop Scope_Id := Scope_Stack.Table (J).Entity; @@ -3740,8 +3850,8 @@ package body Exp_Ch5 is Rewrite (N, Goto_Stat); Analyze (N); - -- If it is a return from an entry body, put a Complete_Entry_Body - -- call in front of the return. + -- If it is a return from an entry body, put a Complete_Entry_Body call + -- in front of the return. elsif Is_Protected_Type (Scope_Id) then Call := @@ -3818,25 +3928,20 @@ package body Exp_Ch5 is -- The type of the expression (not necessarily the same as R_Type) begin - -- The DSP method is no longer in use - - pragma Assert (not Function_Returns_With_DSP (Scope_Id)); - -- We rewrite "return <expression>;" to be: -- return _anon_ : <return_subtype> := <expression> -- The expansion produced by Expand_N_Extended_Return_Statement will - -- contain simple return statements (for example, a block containing a + -- contain simple return statements (for example, a block containing -- simple return of the return object), which brings us back here with -- Comes_From_Extended_Return_Statement set. To avoid infinite -- recursion, we do not transform into an extended return if -- Comes_From_Extended_Return_Statement is True. -- The reason for this design is that for Ada 2005 limited returns, we - -- need to reify the return object, so we can build it "in place", - -- and we need a block statement to hang finalization and tasking stuff - -- off of. + -- need to reify the return object, so we can build it "in place", and + -- we need a block statement to hang finalization and tasking stuff. -- ??? In order to avoid disruption, we avoid translating to extended -- return except in the cases where we really need to (Ada 2005 @@ -3878,11 +3983,11 @@ package body Exp_Ch5 is -- of an extended return statement (either written by the user, or -- generated by the above code). - -- Always normalize C/Fortran boolean result. This is not always - -- necessary, but it seems a good idea to minimize the passing - -- around of non-normalized values, and in any case this handles - -- the processing of barrier functions for protected types, which - -- turn the condition into a return statement. + -- Always normalize C/Fortran boolean result. This is not always needed, + -- but it seems a good idea to minimize the passing around of non- + -- normalized values, and in any case this handles the processing of + -- barrier functions for protected types, which turn the condition into + -- a return statement. if Is_Boolean_Type (Exptyp) and then Nonzero_Is_True (Exptyp) @@ -3943,18 +4048,6 @@ package body Exp_Ch5 is end if; end; - -- Case of secondary stack not used - - elsif Function_Returns_With_DSP (Scope_Id) then - - -- The DSP method is no longer in use. We would like to ignore DSP - -- while implementing AI-318; hence the following assertion. Keep the - -- old code around in case DSP is revived someday. - - pragma Assert (False); - - No_Secondary_Stack_Case (N); - -- Here if secondary stack is used else @@ -3989,15 +4082,14 @@ package body Exp_Ch5 is and then (not Is_Array_Type (Exptyp) or else Is_Constrained (Exptyp) = Is_Constrained (R_Type) - or else Is_Class_Wide_Type (Utyp) - or else Controlled_Type (Exptyp)) + or else CW_Or_Controlled_Type (Utyp)) and then Nkind (Exp) = N_Function_Call then Set_By_Ref (N); - -- Remove side effects from the expression now so that - -- other part of the expander do not have to reanalyze - -- this node without this optimization + -- Remove side effects from the expression now so that other parts + -- of the expander do not have to reanalyze this node without this + -- optimization Rewrite (Exp, Duplicate_Subexpr_No_Checks (Exp)); @@ -4013,9 +4105,7 @@ package body Exp_Ch5 is -- controlled (by the virtue of restriction No_Finalization) because -- gigi is not able to properly allocate class-wide types. - elsif Is_Class_Wide_Type (Utyp) - or else Controlled_Type (Utyp) - then + elsif CW_Or_Controlled_Type (Utyp) then declare Loc : constant Source_Ptr := Sloc (N); Temp : constant Entity_Id := @@ -4073,13 +4163,12 @@ package body Exp_Ch5 is end if; end if; - -- Implement the rules of 6.5(8-10), which require a tag check in - -- the case of a limited tagged return type, and tag reassignment - -- for nonlimited tagged results. These actions are needed when - -- the return type is a specific tagged type and the result - -- expression is a conversion or a formal parameter, because in - -- that case the tag of the expression might differ from the tag - -- of the specific result type. + -- Implement the rules of 6.5(8-10), which require a tag check in the + -- case of a limited tagged return type, and tag reassignment for + -- nonlimited tagged results. These actions are needed when the return + -- type is a specific tagged type and the result expression is a + -- conversion or a formal parameter, because in that case the tag of the + -- expression might differ from the tag of the specific result type. if Is_Tagged_Type (Utyp) and then not Is_Class_Wide_Type (Utyp) @@ -4109,14 +4198,13 @@ package body Exp_Ch5 is Loc))), Reason => CE_Tag_Check_Failed)); - -- If the result type is a specific nonlimited tagged type, - -- then we have to ensure that the tag of the result is that - -- of the result type. This is handled by making a copy of the - -- expression in the case where it might have a different tag, - -- namely when the expression is a conversion or a formal - -- parameter. We create a new object of the result type and - -- initialize it from the expression, which will implicitly - -- force the tag to be set appropriately. + -- If the result type is a specific nonlimited tagged type, then we + -- have to ensure that the tag of the result is that of the result + -- type. This is handled by making a copy of the expression in the + -- case where it might have a different tag, namely when the + -- expression is a conversion or a formal parameter. We create a new + -- object of the result type and initialize it from the expression, + -- which will implicitly force the tag to be set appropriately. else declare @@ -4168,16 +4256,10 @@ package body Exp_Ch5 is Condition => Make_Op_Gt (Loc, Left_Opnd => - Make_Function_Call (Loc, - Name => - New_Reference_To - (RTE (RE_Get_Access_Level), Loc), - Parameter_Associations => - New_List (Make_Attribute_Reference (Loc, - Prefix => - Duplicate_Subexpr (Exp), - Attribute_Name => - Name_Tag))), + Build_Get_Access_Level (Loc, + Make_Attribute_Reference (Loc, + Prefix => Duplicate_Subexpr (Exp), + Attribute_Name => Name_Tag)), Right_Opnd => Make_Integer_Literal (Loc, Scope_Depth (Enclosing_Dynamic_Scope (Scope_Id)))), @@ -4200,8 +4282,8 @@ package body Exp_Ch5 is Save_Tag : constant Boolean := Is_Tagged_Type (T) and then not No_Ctrl_Actions (N) and then not Java_VM; - -- Tags are not saved and restored when Java_VM because JVM tags - -- are represented implicitly in objects. + -- Tags are not saved and restored when Java_VM because JVM tags are + -- represented implicitly in objects. Res : List_Id; Tag_Tmp : Entity_Id; @@ -4271,8 +4353,8 @@ package body Exp_Ch5 is -- specific to each object of the type, not to the value being assigned. -- Thus they need to be left intact during the assignment. We achieve -- this by constructing a Storage_Array subtype, and by overlaying - -- objects of this type on the source and target of the assignment. - -- The assignment is then rewritten to assignments of slices of these + -- objects of this type on the source and target of the assignment. The + -- assignment is then rewritten to assignments of slices of these -- arrays, copying the user data, and leaving the pointers untouched. if Ctrl_Act then @@ -4306,10 +4388,9 @@ package body Exp_Ch5 is (Rec : Entity_Id; Lo : Node_Id; Hi : Node_Id) return Node_Id; - -- Build and return a slice of an array of type S overlaid - -- on object Rec, with bounds specified by Lo and Hi. If either - -- bound is empty, a default of S'First (respectively S'Last) - -- is used. + -- Build and return a slice of an array of type S overlaid on + -- object Rec, with bounds specified by Lo and Hi. If either bound + -- is empty, a default of S'First (respectively S'Last) is used. ----------------- -- Build_Slice -- @@ -4328,12 +4409,12 @@ package body Exp_Ch5 is Make_Attribute_Reference (Loc, Prefix => Rec, Attribute_Name => Name_Address)); - -- Access value designating an opaque storage array of - -- type S overlaid on record Rec. + -- Access value designating an opaque storage array of type S + -- overlaid on record Rec. begin - -- Compute slice bounds using S'First (1) and S'Last - -- as default values when not specified by the caller. + -- Compute slice bounds using S'First (1) and S'Last as default + -- values when not specified by the caller. if No (Lo) then Lo_Bound := Make_Integer_Literal (Loc, 1); @@ -4613,161 +4694,6 @@ package body Exp_Ch5 is return Empty_List; end Make_Tag_Ctrl_Assignment; - ----------------------------- - -- No_Secondary_Stack_Case -- - ----------------------------- - - procedure No_Secondary_Stack_Case (N : Node_Id) is - pragma Assert (False); -- DSP method no longer in use - - Loc : constant Source_Ptr := Sloc (N); - Exp : constant Node_Id := Expression (N); - T : constant Entity_Id := Etype (Exp); - Scope_Id : constant Entity_Id := - Return_Applies_To (Return_Statement_Entity (N)); - Return_Type : constant Entity_Id := Etype (Scope_Id); - Utyp : constant Entity_Id := Underlying_Type (Return_Type); - - -- Here what we need to do is to always return by reference, since - -- we will return with the stack pointer depressed. We may need to - -- do a copy to a local temporary before doing this return. - - Local_Copy_Required : Boolean := False; - -- Set to True if a local copy is required - - Copy_Ent : Entity_Id; - -- Used for the target entity if a copy is required - - Decl : Node_Id; - -- Declaration used to create copy if needed - - procedure Test_Copy_Required (Expr : Node_Id); - -- Determines if Expr represents a return value for which a - -- copy is required. More specifically, a copy is not required - -- if Expr represents an object or component of an object that - -- is either in the local subprogram frame, or is constant. - -- If a copy is required, then Local_Copy_Required is set True. - - ------------------------ - -- Test_Copy_Required -- - ------------------------ - - procedure Test_Copy_Required (Expr : Node_Id) is - Ent : Entity_Id; - - begin - -- If component, test prefix (object containing component) - - if Nkind (Expr) = N_Indexed_Component - or else - Nkind (Expr) = N_Selected_Component - then - Test_Copy_Required (Prefix (Expr)); - return; - - -- See if we have an entity name - - elsif Is_Entity_Name (Expr) then - Ent := Entity (Expr); - - -- Constant entity is always OK, no copy required - - if Ekind (Ent) = E_Constant then - return; - - -- No copy required for local variable - - elsif Ekind (Ent) = E_Variable - and then Scope (Ent) = Current_Subprogram - then - return; - end if; - end if; - - -- All other cases require a copy - - Local_Copy_Required := True; - end Test_Copy_Required; - - -- Start of processing for No_Secondary_Stack_Case - - begin - -- No copy needed if result is from a function call. - -- In this case the result is already being returned by - -- reference with the stack pointer depressed. - - -- To make up for a gcc 2.8.1 deficiency (???), we perform - -- the copy for array types if the constrained status of the - -- target type is different from that of the expression. - - if Requires_Transient_Scope (T) - and then - (not Is_Array_Type (T) - or else Is_Constrained (T) = Is_Constrained (Return_Type) - or else Controlled_Type (T)) - and then Nkind (Exp) = N_Function_Call - then - Set_By_Ref (N); - - -- We always need a local copy for a controlled type, since - -- we are required to finalize the local value before return. - -- The copy will automatically include the required finalize. - -- Moreover, gigi cannot make this copy, since we need special - -- processing to ensure proper behavior for finalization. - - -- Note: the reason we are returning with a depressed stack - -- pointer in the controlled case (even if the type involved - -- is constrained) is that we must make a local copy to deal - -- properly with the requirement that the local result be - -- finalized. - - elsif Controlled_Type (Utyp) then - Copy_Ent := - Make_Defining_Identifier (Loc, - Chars => New_Internal_Name ('R')); - - -- Build declaration to do the copy, and insert it, setting - -- Assignment_OK, because we may be copying a limited type. - -- In addition we set the special flag to inhibit finalize - -- attachment if this is a controlled type (since this attach - -- must be done by the caller, otherwise if we attach it here - -- we will finalize the returned result prematurely). - - Decl := - Make_Object_Declaration (Loc, - Defining_Identifier => Copy_Ent, - Object_Definition => New_Occurrence_Of (Return_Type, Loc), - Expression => Relocate_Node (Exp)); - - Set_Assignment_OK (Decl); - Set_Delay_Finalize_Attach (Decl); - Insert_Action (N, Decl); - - -- Now the actual return uses the copied value - - Rewrite (Exp, New_Occurrence_Of (Copy_Ent, Loc)); - Analyze_And_Resolve (Exp, Return_Type); - - -- Since we have made the copy, gigi does not have to, so - -- we set the By_Ref flag to prevent another copy being made. - - Set_By_Ref (N); - - -- Non-controlled cases - - else - Test_Copy_Required (Exp); - - -- If a local copy is required, then gigi will make the - -- copy, otherwise, we can return the result directly, - -- so set By_Ref to suppress the gigi copy. - - if not Local_Copy_Required then - Set_By_Ref (N); - end if; - end if; - end No_Secondary_Stack_Case; - ------------------------------------ -- Possible_Bit_Aligned_Component -- ------------------------------------ @@ -4821,9 +4747,9 @@ package body Exp_Ch5 is end if; end; - -- If we have neither a record nor array component, it means that - -- we have fallen off the top testing prefixes recursively, and - -- we now have a stand alone object, where we don't have a problem + -- If we have neither a record nor array component, it means that we + -- have fallen off the top testing prefixes recursively, and we now + -- have a stand alone object, where we don't have a problem. when others => return False; |