-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2010, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2011, 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- --
with Snames; use Snames;
with Stand; use Stand;
with Stringt; use Stringt;
+with Targparm; use Targparm;
with Tbuild; use Tbuild;
with Uintp; use Uintp;
with Urealp; use Urealp;
---------------------------------
procedure Expand_Binary_Operator_Call (N : Node_Id) is
- T1 : constant Entity_Id := Underlying_Type (Left_Opnd (N));
- T2 : constant Entity_Id := Underlying_Type (Right_Opnd (N));
+ T1 : constant Entity_Id := Underlying_Type (Etype (Left_Opnd (N)));
+ T2 : constant Entity_Id := Underlying_Type (Etype (Right_Opnd (N)));
TR : constant Entity_Id := Etype (N);
T3 : Entity_Id;
Res : Node_Id;
- Siz : constant Uint := UI_Max (Esize (T1), Esize (T2));
+ Siz : constant Uint := UI_Max (RM_Size (T1), RM_Size (T2));
-- Maximum of operand sizes
begin
+ -- Nothing to do if the operands have the same modular type
+
+ if Base_Type (T1) = Base_Type (T2)
+ and then Is_Modular_Integer_Type (T1)
+ then
+ return;
+ end if;
+
-- Use Unsigned_32 for sizes of 32 or below, else Unsigned_64
if Siz > 32 then
-- subsequent reanalysis.
Res := New_Copy (N);
- Set_Etype (Res, Empty);
- Set_Entity (Res, Empty);
+ Set_Etype (Res, T3);
+
+ case Nkind (N) is
+ when N_Op_And =>
+ Set_Entity (Res, Standard_Op_And);
+ when N_Op_Or =>
+ Set_Entity (Res, Standard_Op_Or);
+ when N_Op_Xor =>
+ Set_Entity (Res, Standard_Op_Xor);
+ when others =>
+ raise Program_Error;
+ end case;
-- Convert operands to large enough intermediate type
-- If the result type is not parent of Tag_Arg then we need to
-- locate the tag of the secondary dispatch table.
- if not Is_Ancestor (Etype (Result_Typ), Etype (Tag_Arg)) then
- pragma Assert (not Is_Interface (Etype (Tag_Arg)));
-
- Iface_Tag :=
- Make_Object_Declaration (Loc,
- Defining_Identifier => Make_Temporary (Loc, 'V'),
- Object_Definition =>
- New_Reference_To (RTE (RE_Tag), Loc),
- Expression =>
- Make_Function_Call (Loc,
- Name => New_Reference_To (RTE (RE_Secondary_Tag), Loc),
- Parameter_Associations => New_List (
- Relocate_Node (Tag_Arg),
- New_Reference_To
- (Node (First_Elmt (Access_Disp_Table
- (Etype (Etype (Act_Constr))))),
- Loc))));
- Insert_Action (N, Iface_Tag);
+ if not Is_Ancestor (Etype (Result_Typ), Etype (Tag_Arg),
+ Use_Full_View => True)
+ and then Tagged_Type_Expansion
+ then
+ -- Obtain the reference to the Ada.Tags service before generating
+ -- the Object_Declaration node to ensure that if this service is
+ -- not available in the runtime then we generate a clear error.
+
+ declare
+ Fname : constant Node_Id :=
+ New_Reference_To (RTE (RE_Secondary_Tag), Loc);
+
+ begin
+ pragma Assert (not Is_Interface (Etype (Tag_Arg)));
+
+ Iface_Tag :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Make_Temporary (Loc, 'V'),
+ Object_Definition =>
+ New_Reference_To (RTE (RE_Tag), Loc),
+ Expression =>
+ Make_Function_Call (Loc,
+ Name => Fname,
+ Parameter_Associations => New_List (
+ Relocate_Node (Tag_Arg),
+ New_Reference_To
+ (Node (First_Elmt (Access_Disp_Table
+ (Etype (Etype (Act_Constr))))),
+ Loc))));
+ Insert_Action (N, Iface_Tag);
+ end;
end if;
end if;
-- structures to find and terminate those components.
procedure Expand_Unc_Deallocation (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- Arg : constant Node_Id := First_Actual (N);
- Typ : constant Entity_Id := Etype (Arg);
- Stmts : constant List_Id := New_List;
- Rtyp : constant Entity_Id := Underlying_Type (Root_Type (Typ));
- Pool : constant Entity_Id := Associated_Storage_Pool (Rtyp);
-
- Desig_T : constant Entity_Id := Designated_Type (Typ);
- Gen_Code : Node_Id;
- Free_Node : Node_Id;
- Deref : Node_Id;
- Free_Arg : Node_Id;
- Free_Cod : List_Id;
- Blk : Node_Id;
+ Arg : constant Node_Id := First_Actual (N);
+ Loc : constant Source_Ptr := Sloc (N);
+ Typ : constant Entity_Id := Etype (Arg);
+ Desig_T : constant Entity_Id := Designated_Type (Typ);
+ Rtyp : constant Entity_Id := Underlying_Type (Root_Type (Typ));
+ Pool : constant Entity_Id := Associated_Storage_Pool (Rtyp);
+ Stmts : constant List_Id := New_List;
+ Needs_Fin : constant Boolean := Needs_Finalization (Desig_T);
+
+ Finalizer_Data : Finalization_Exception_Data;
+
+ Blk : Node_Id := Empty;
+ Deref : Node_Id;
+ Final_Code : List_Id;
+ Free_Arg : Node_Id;
+ Free_Node : Node_Id;
+ Gen_Code : Node_Id;
Arg_Known_Non_Null : constant Boolean := Known_Non_Null (N);
-- This captures whether we know the argument to be non-null so that
-- Processing for pointer to controlled type
- if Needs_Finalization (Desig_T) then
+ if Needs_Fin then
Deref :=
Make_Explicit_Dereference (Loc,
Prefix => Duplicate_Subexpr_No_Checks (Arg));
Set_Etype (Deref, Desig_T);
end if;
- Free_Cod :=
- Make_Final_Call
- (Ref => Deref,
- Typ => Desig_T,
- With_Detach => New_Reference_To (Standard_True, Loc));
+ -- The finalization call is expanded wrapped in a block to catch any
+ -- possible exception. If an exception does occur, then Program_Error
+ -- must be raised following the freeing of the object and its removal
+ -- from the finalization collection's list. We set a flag to record
+ -- that an exception was raised, and save its occurrence for use in
+ -- the later raise.
+ --
+ -- Generate:
+ -- Abort : constant Boolean :=
+ -- Exception_Occurrence (Get_Current_Excep.all.all) =
+ -- Standard'Abort_Signal'Identity;
+ -- <or>
+ -- Abort : constant Boolean := False; -- no abort
+
+ -- E : Exception_Occurrence;
+ -- Raised : Boolean := False;
+ --
+ -- begin
+ -- [Deep_]Finalize (Obj);
+ -- exception
+ -- when others =>
+ -- Raised := True;
+ -- Save_Occurrence (E, Get_Current_Excep.all.all);
+ -- end;
+
+ Build_Object_Declarations (Finalizer_Data, Stmts, Loc);
+
+ Final_Code := New_List (
+ Make_Block_Statement (Loc,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (
+ Make_Final_Call (Obj_Ref => Deref, Typ => Desig_T)),
+ Exception_Handlers => New_List (
+ Build_Exception_Handler (Finalizer_Data)))));
+
+ -- For .NET/JVM, detach the object from the containing finalization
+ -- collection before finalizing it.
+
+ if VM_Target /= No_VM and then Is_Controlled (Desig_T) then
+ Prepend_To (Final_Code,
+ Make_Detach_Call (New_Copy_Tree (Arg)));
+ end if;
+
+ -- If aborts are allowed, then the finalization code must be
+ -- protected by an abort defer/undefer pair.
if Abort_Allowed then
- Prepend_To (Free_Cod,
+ Prepend_To (Final_Code,
Build_Runtime_Call (Loc, RE_Abort_Defer));
Blk :=
Make_Block_Statement (Loc, Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
- Statements => Free_Cod,
+ Statements => Final_Code,
At_End_Proc =>
New_Occurrence_Of (RTE (RE_Abort_Undefer_Direct), Loc)));
- -- We now expand the exception (at end) handler. We set a
- -- temporary parent pointer since we have not attached Blk
- -- to the tree yet.
-
- Set_Parent (Blk, N);
- Analyze (Blk);
- Expand_At_End_Handler
- (Handled_Statement_Sequence (Blk), Entity (Identifier (Blk)));
Append (Blk, Stmts);
-
- -- We kill saved current values, since analyzing statements not
- -- properly attached to the tree can set wrong current values.
-
- Kill_Current_Values;
-
else
- Append_List_To (Stmts, Free_Cod);
+ Append_List_To (Stmts, Final_Code);
end if;
end if;
Nam2 : Node_Id;
begin
- -- An Abort followed by a Free will not do what the user
- -- expects, because the abort is not immediate. This is
- -- worth a friendly warning.
+ -- An Abort followed by a Free will not do what the user expects,
+ -- because the abort is not immediate. This is worth a warning.
while Present (Stat)
and then not Comes_From_Source (Original_Node (Stat))
Append_To (Stmts, Free_Node);
Set_Storage_Pool (Free_Node, Pool);
- -- Attach to tree before analysis of generated subtypes below.
+ -- Attach to tree before analysis of generated subtypes below
Set_Parent (Stmts, Parent (N));
if Is_RTE (Pool, RE_SS_Pool) then
null;
- elsif Is_Class_Wide_Type (Etype (Pool)) then
+ -- Case of a class-wide pool type: make a dispatching call to
+ -- Deallocate through the class-wide Deallocate_Any.
- -- Case of a class-wide pool type: make a dispatching call
- -- to Deallocate through the class-wide Deallocate_Any.
+ elsif Is_Class_Wide_Type (Etype (Pool)) then
+ Set_Procedure_To_Call (Free_Node, RTE (RE_Deallocate_Any));
- Set_Procedure_To_Call (Free_Node,
- RTE (RE_Deallocate_Any));
+ -- Case of a specific pool type: make a statically bound call
else
- -- Case of a specific pool type: make a statically bound call
-
Set_Procedure_To_Call (Free_Node,
Find_Prim_Op (Etype (Pool), Name_Deallocate));
end if;
if Present (Procedure_To_Call (Free_Node)) then
- -- For all cases of a Deallocate call, the back-end needs to be
- -- able to compute the size of the object being freed. This may
- -- require some adjustments for objects of dynamic size.
+ -- For all cases of a Deallocate call, the back-end needs to be able
+ -- to compute the size of the object being freed. This may require
+ -- some adjustments for objects of dynamic size.
--
-- If the type is class wide, we generate an implicit type with the
-- right dynamic size, so that the deallocate call gets the right
D_Type : Entity_Id;
begin
- Set_Etype (Deref, Typ);
Set_Parent (Deref, Free_Node);
D_Subtyp := Make_Subtype_From_Expr (Deref, Desig_T);
Set_Expression (Free_Node, Free_Arg);
end if;
- -- Only remaining step is to set result to null, or generate a
- -- raise of constraint error if the target object is "not null".
+ -- Only remaining step is to set result to null, or generate a raise of
+ -- Constraint_Error if the target object is "not null".
if Can_Never_Be_Null (Etype (Arg)) then
Append_To (Stmts,
end;
end if;
+ -- Generate a test of whether any earlier finalization raised an
+ -- exception, and in that case raise Program_Error with the previous
+ -- exception occurrence.
+
+ -- Generate:
+ -- if Raised and then not Abort then
+ -- raise Program_Error; -- for .NET and
+ -- -- restricted RTS
+ -- <or>
+ -- Raise_From_Controlled_Operation (E); -- all other cases
+ -- end if;
+
+ if Needs_Fin then
+ Append_To (Stmts, Build_Raise_Statement (Finalizer_Data));
+ end if;
+
-- If we know the argument is non-null, then make a block statement
-- that contains the required statements, no need for a test.
Rewrite (N, Gen_Code);
Analyze (N);
+
+ -- If we generated a block with an At_End_Proc, expand the exception
+ -- handler. We need to wait until after everything else is analyzed.
+
+ if Present (Blk) then
+ Expand_At_End_Handler
+ (Handled_Statement_Sequence (Blk), Entity (Identifier (Blk)));
+ end if;
end Expand_Unc_Deallocation;
-----------------------