2004-02-02 Vincent Celier <celier@gnat.com> * gprcmd.adb (Check_Args): If condition is false, print the invoked comment before the usage. Gprcmd: Fail when command is not recognized. (Usage): Document command "prefix" * g-md5.adb (Digest): Process last block. (Update): Do not process last block. Store remaining characters and length in Context. * g-md5.ads (Update): Document that several call to update are equivalent to one call with the concatenated string. (Context): Add fields to allow new Update behaviour. * fname-uf.ads/adb (Get_File_Name): New Boolean parameter May_Fail, defaulted to False. When May_Fail is True and no existing file can be found, return No_File. * 6vcstrea.adb: Inlined functions are now wrappers to implementation functions. * lib-writ.adb (Write_With_Lines): When body file does not exist, use spec file name instead on the W line. 2004-02-02 Robert Dewar <dewar@gnat.com> * ali.adb: Read and acquire info from new format restrictions lines * bcheck.adb: Add circuits for checking restrictions with parameters * bindgen.adb: Output dummy restrictions data To be changed later * ali.ads, checks.adb, exp_aggr.adb, exp_attr.adb, exp_ch11.adb, exp_ch3.adb, exp_ch5.adb, exp_ch6.adb, exp_ch7.adb, exp_util.adb, freeze.adb, gnat1drv.adb, sem_attr.adb, sem_ch10.adb, sem_ch11.adb, sem_ch12.adb, targparm.adb, targparm.ads, tbuild.adb, sem_ch2.adb, sem_elab.adb, sem_res.adb: Minor changes for new restrictions handling. * exp_ch9.adb (Build_Master_Entity): Cleanup the code (also suppresses the warning message on access to possibly uninitialized variable S) Minor changes for new restrictions handling. * gnatbind.adb: Minor reformatting Minor changes for new restrictions handling Move circuit for -r processing here from bcheck (cleaner) * gnatcmd.adb, gnatlink.adb: Minor reformatting * lib-writ.adb: Output new format restrictions lines * lib-writ.ads: Document new R format lines for new restrictions handling. * s-restri.ads/adb: New files * Makefile.rtl: Add entry for s-restri.ads/adb * par-ch3.adb: Fix bad error messages starting with upper case letter Minor reformatting * restrict.adb: Major rewrite throughout for new restrictions handling Major point is to handle restrictions with parameters * restrict.ads: Major changes in interface to handle restrictions with parameters. Also generally simplifies setting of restrictions. * snames.ads/adb: New entry for proper handling of No_Requeue * sem_ch3.adb (Count_Tasks): New circuitry for implementing Max_Tasks restriction counting. Other minor changes for new restrictions handling * sem_prag.adb: No_Requeue is a synonym for No_Requeue_Statements. Restriction_Warnings now allows full parameter notation Major rewrite of Restrictions for new restrictions handling 2004-02-02 Javier Miranda <miranda@gnat.com> * par-ch3.adb (P_Identifier_Declarations): Give support to the Ada 0Y syntax rule for object renaming declarations. (P_Array_Type_Definition): Give support for the Ada 0Y syntax rule for component definitions. * sem_ch3.adb (Analyze_Component_Declaration): Give support to access components. (Array_Type_Declaration): Give support to access components. In addition it was also modified to reflect the name of the object in anonymous array types. The old code did not take into account that it is possible to have an unconstrained anonymous array with an initial value. (Check_Or_Process_Discriminants): Allow access discriminant in non-limited types. (Process_Discriminants): Allow access discriminant in non-limited types Initialize the new Access_Definition field in N_Object_Renaming_Decl node. Change Ada0Y to Ada 0Y in comments * sem_ch4.adb (Find_Equality_Types): Allow anonymous access types in equality operators. Change Ada0Y to Ada 0Y in comments * sem_ch8.adb (Analyze_Object_Renaming): Give support to access renamings Change Ada0Y to Ada 0Y in comments * sem_type.adb (Find_Unique_Type): Give support to the equality operators for universal access types Change Ada0Y to Ada 0Y in comments * sinfo.adb (Access_Definition, Set_Access_Definition): New subprograms * sinfo.ads (N_Component_Definition): Addition of Access_Definition field. (N_Object_Renaming_Declaration): Addition of Access_Definition field Change Ada0Y to Ada 0Y in comments * sprint.adb (Sprint_Node_Actual): Give support to the new syntax for component definition and object renaming nodes Change Ada0Y to Ada 0Y in comments 2004-02-02 Jose Ruiz <ruiz@act-europe.fr> * restrict.adb: Use the new restriction identifier No_Requeue_Statements instead of the old No_Requeue for defining the restricted profile. * sem_ch9.adb (Analyze_Requeue): Check the new restriction No_Requeue_Statements. * s-rident.ads: Adding restriction No_Requeue_Statements (AI-00249) that supersedes the GNAT specific restriction No_Requeue. The later is kept for backward compatibility. 2004-02-02 Ed Schonberg <schonberg@gnat.com> * lib.ads, i-cobol.ads, * s-stoele.ads, s-thread.ads, style.ads, 5staprop.adb, atree.adb, atree.ads, g-crc32.ads: Remove redundant pragma and fix incorrect ones. * sem_prag.adb For pragma Inline and pragma Pure_Function, emit a warning if the pragma is redundant. 2004-02-02 Thomas Quinot <quinot@act-europe.fr> * 5staprop.adb: Add missing 'constant' keywords. * Makefile.in: use consistent value for SYMLIB on platforms where libaddr2line is supported. 2004-02-02 Richard Kenner <kenner@vlsi1.ultra.nyu.edu> * utils.c (end_subprog_body): Do not call rest_of_compilation if just annotating types. 2004-02-02 Olivier Hainque <hainque@act-europe.fr> * init.c (__gnat_install_handler): Setup an alternate stack for signal handlers in the environment thread. This allows proper propagation of an exception on stack overflows in this thread even when the builtin ABI stack-checking scheme is used without support for a stack reserve region. * utils.c (create_field_decl): Augment the head comment about bitfield creation, and don't account for DECL_BIT_FIELD in DECL_NONADDRESSABLE_P here, because the former is not accurate enough at this point. Let finish_record_type decide instead. Don't make a bitfield if the field is to be addressable. Always set a size for the field if the record is packed, to ensure the checks for bitfield creation are triggered. (finish_record_type): During last pass over the fields, clear DECL_BIT_FIELD when possible in the !STRICT_ALIGNMENT case, as this is not covered by the calls to layout_decl. Adjust DECL_NONADDRESSABLE_P from DECL_BIT_FIELD. From-SVN: r77110
1958 lines
66 KiB
Ada
1958 lines
66 KiB
Ada
------------------------------------------------------------------------------
|
|
-- --
|
|
-- GNAT COMPILER COMPONENTS --
|
|
-- --
|
|
-- E X P _ C H 1 1 --
|
|
-- --
|
|
-- B o d y --
|
|
-- --
|
|
-- Copyright (C) 1992-2004 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- --
|
|
-- ware Foundation; either version 2, or (at your option) any later ver- --
|
|
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
|
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
|
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
|
|
-- for more details. You should have received a copy of the GNU General --
|
|
-- Public License distributed with GNAT; see file COPYING. If not, write --
|
|
-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
|
|
-- MA 02111-1307, USA. --
|
|
-- --
|
|
-- GNAT was originally developed by the GNAT team at New York University. --
|
|
-- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
-- --
|
|
------------------------------------------------------------------------------
|
|
|
|
with Atree; use Atree;
|
|
with Casing; use Casing;
|
|
with Debug; use Debug;
|
|
with Einfo; use Einfo;
|
|
with Errout; use Errout;
|
|
with Exp_Ch7; use Exp_Ch7;
|
|
with Exp_Util; use Exp_Util;
|
|
with Hostparm; use Hostparm;
|
|
with Inline; use Inline;
|
|
with Lib; use Lib;
|
|
with Namet; use Namet;
|
|
with Nlists; use Nlists;
|
|
with Nmake; use Nmake;
|
|
with Opt; use Opt;
|
|
with Rtsfind; use Rtsfind;
|
|
with Restrict; use Restrict;
|
|
with Rident; use Rident;
|
|
with Sem; use Sem;
|
|
with Sem_Ch5; use Sem_Ch5;
|
|
with Sem_Ch8; use Sem_Ch8;
|
|
with Sem_Res; use Sem_Res;
|
|
with Sem_Util; use Sem_Util;
|
|
with Sinfo; use Sinfo;
|
|
with Sinput; use Sinput;
|
|
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 Uname; use Uname;
|
|
|
|
package body Exp_Ch11 is
|
|
|
|
SD_List : List_Id;
|
|
-- This list gathers the values SDn'Unrestricted_Access used to
|
|
-- construct the unit exception table. It is set to Empty_List if
|
|
-- there are no subprogram descriptors.
|
|
|
|
-----------------------
|
|
-- Local Subprograms --
|
|
-----------------------
|
|
|
|
procedure Expand_Exception_Handler_Tables (HSS : Node_Id);
|
|
-- Subsidiary procedure called by Expand_Exception_Handlers if zero
|
|
-- cost exception handling is installed for this target. Replaces the
|
|
-- exception handler structure with appropriate labeled code and tables
|
|
-- that allow the zero cost exception handling circuits to find the
|
|
-- correct handler (see unit Ada.Exceptions for details).
|
|
|
|
procedure Generate_Subprogram_Descriptor
|
|
(N : Node_Id;
|
|
Loc : Source_Ptr;
|
|
Spec : Entity_Id;
|
|
Slist : List_Id);
|
|
-- Procedure called to generate a subprogram descriptor. N is the
|
|
-- subprogram body node or, in the case of an imported subprogram, is
|
|
-- Empty, and Spec is the entity of the sunprogram. For details of the
|
|
-- required structure, see package System.Exceptions. The generated
|
|
-- subprogram descriptor is appended to Slist. Loc provides the
|
|
-- source location to be used for the generated descriptor.
|
|
|
|
---------------------------
|
|
-- Expand_At_End_Handler --
|
|
---------------------------
|
|
|
|
-- For a handled statement sequence that has a cleanup (At_End_Proc
|
|
-- field set), an exception handler of the following form is required:
|
|
|
|
-- exception
|
|
-- when all others =>
|
|
-- cleanup call
|
|
-- raise;
|
|
|
|
-- Note: this exception handler is treated rather specially by
|
|
-- subsequent expansion in two respects:
|
|
|
|
-- The normal call to Undefer_Abort is omitted
|
|
-- The raise call does not do Defer_Abort
|
|
|
|
-- This is because the current tasking code seems to assume that
|
|
-- the call to the cleanup routine that is made from an exception
|
|
-- handler for the abort signal is called with aborts deferred.
|
|
|
|
-- This expansion is only done if we have front end exception handling.
|
|
-- If we have back end exception handling, then the AT END handler is
|
|
-- left alone, and cleanups (including the exceptional case) are handled
|
|
-- by the back end.
|
|
|
|
-- In the front end case, the exception handler described above handles
|
|
-- the exceptional case. The AT END handler is left in the generated tree
|
|
-- and the code generator (e.g. gigi) must still handle proper generation
|
|
-- of cleanup calls for the non-exceptional case.
|
|
|
|
procedure Expand_At_End_Handler (HSS : Node_Id; Block : Node_Id) is
|
|
Clean : constant Entity_Id := Entity (At_End_Proc (HSS));
|
|
Loc : constant Source_Ptr := Sloc (Clean);
|
|
Ohandle : Node_Id;
|
|
Stmnts : List_Id;
|
|
|
|
begin
|
|
pragma Assert (Present (Clean));
|
|
pragma Assert (No (Exception_Handlers (HSS)));
|
|
|
|
-- Don't expand if back end exception handling active
|
|
|
|
if Exception_Mechanism = Back_End_ZCX_Exceptions then
|
|
return;
|
|
end if;
|
|
|
|
-- Don't expand an At End handler if we have already had configurable
|
|
-- run-time violations, since likely this will just be a matter of
|
|
-- generating useless cascaded messages
|
|
|
|
if Configurable_Run_Time_Violations > 0 then
|
|
return;
|
|
end if;
|
|
|
|
if Restriction_Active (No_Exception_Handlers) then
|
|
return;
|
|
end if;
|
|
|
|
if Present (Block) then
|
|
New_Scope (Block);
|
|
end if;
|
|
|
|
Ohandle :=
|
|
Make_Others_Choice (Loc);
|
|
Set_All_Others (Ohandle);
|
|
|
|
Stmnts := New_List (
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name => New_Occurrence_Of (Clean, Loc)),
|
|
Make_Raise_Statement (Loc));
|
|
|
|
Set_Exception_Handlers (HSS, New_List (
|
|
Make_Exception_Handler (Loc,
|
|
Exception_Choices => New_List (Ohandle),
|
|
Statements => Stmnts)));
|
|
|
|
Analyze_List (Stmnts, Suppress => All_Checks);
|
|
Expand_Exception_Handlers (HSS);
|
|
|
|
if Present (Block) then
|
|
Pop_Scope;
|
|
end if;
|
|
end Expand_At_End_Handler;
|
|
|
|
-------------------------------------
|
|
-- Expand_Exception_Handler_Tables --
|
|
-------------------------------------
|
|
|
|
-- See Ada.Exceptions specification for full details of the data
|
|
-- structures that we need to construct here. As an example of the
|
|
-- transformation that is required, given the structure:
|
|
|
|
-- declare
|
|
-- {declarations}
|
|
-- ..
|
|
-- begin
|
|
-- {statements-1}
|
|
-- ...
|
|
-- exception
|
|
-- when a | b =>
|
|
-- {statements-2}
|
|
-- ...
|
|
-- when others =>
|
|
-- {statements-3}
|
|
-- ...
|
|
-- end;
|
|
|
|
-- We transform this into:
|
|
|
|
-- declare
|
|
-- {declarations}
|
|
-- ...
|
|
-- L1 : label;
|
|
-- L2 : label;
|
|
-- L3 : label;
|
|
-- L4 : Label;
|
|
-- L5 : label;
|
|
|
|
-- begin
|
|
-- <<L1>>
|
|
-- {statements-1}
|
|
-- <<L2>>
|
|
|
|
-- exception
|
|
|
|
-- when a | b =>
|
|
-- <<L3>>
|
|
-- {statements-2}
|
|
|
|
-- HR2 : constant Handler_Record := (
|
|
-- Lo => L1'Address,
|
|
-- Hi => L2'Address,
|
|
-- Id => a'Identity,
|
|
-- Handler => L5'Address);
|
|
|
|
-- HR3 : constant Handler_Record := (
|
|
-- Lo => L1'Address,
|
|
-- Hi => L2'Address,
|
|
-- Id => b'Identity,
|
|
-- Handler => L4'Address);
|
|
|
|
-- when others =>
|
|
-- <<L4>>
|
|
-- {statements-3}
|
|
|
|
-- HR1 : constant Handler_Record := (
|
|
-- Lo => L1'Address,
|
|
-- Hi => L2'Address,
|
|
-- Id => Others_Id,
|
|
-- Handler => L4'Address);
|
|
-- end;
|
|
|
|
-- The exception handlers in the transformed version are marked with the
|
|
-- Zero_Cost_Handling flag set, and all gigi does in this case is simply
|
|
-- to put the handler code somewhere. It can optionally be put inline
|
|
-- between the goto L3 and the label <<L3>> (which is why we generate
|
|
-- that goto in the first place).
|
|
|
|
procedure Expand_Exception_Handler_Tables (HSS : Node_Id) is
|
|
Loc : constant Source_Ptr := Sloc (HSS);
|
|
Handlrs : constant List_Id := Exception_Handlers (HSS);
|
|
Stms : constant List_Id := Statements (HSS);
|
|
Handler : Node_Id;
|
|
|
|
Hlist : List_Id;
|
|
-- This is the list to which handlers are to be appended. It is
|
|
-- either the list for the enclosing subprogram, or the enclosing
|
|
-- selective accept statement (which will turn into a subprogram
|
|
-- during expansion later on).
|
|
|
|
L1 : constant Entity_Id :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_Internal_Name ('L'));
|
|
|
|
L2 : constant Entity_Id :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_Internal_Name ('L'));
|
|
|
|
Lnn : Entity_Id;
|
|
Choice : Node_Id;
|
|
E_Id : Node_Id;
|
|
HR_Ent : Node_Id;
|
|
HL_Ref : Node_Id;
|
|
Item : Node_Id;
|
|
|
|
Subp_Entity : Entity_Id;
|
|
-- This is the entity for the subprogram (or library level package)
|
|
-- to which the handler record is to be attached for later reference
|
|
-- in a subprogram descriptor for this entity.
|
|
|
|
procedure Append_To_Stms (N : Node_Id);
|
|
-- Append given statement to the end of the statements of the
|
|
-- handled sequence of statements and analyze it in place.
|
|
|
|
function Inside_Selective_Accept return Boolean;
|
|
-- This function is called if we are inside the scope of an entry
|
|
-- or task. It checks if the handler is appearing in the context
|
|
-- of a selective accept statement. If so, Hlist is set to
|
|
-- temporarily park the handlers in the N_Accept_Alternative.
|
|
-- node. They will subsequently be moved to the procedure entity
|
|
-- for the procedure built for this alternative. The statements that
|
|
-- follow the Accept within the alternative are not inside the Accept
|
|
-- for purposes of this test, and handlers that may appear within
|
|
-- them belong in the enclosing task procedure.
|
|
|
|
procedure Set_Hlist;
|
|
-- Sets the handler list corresponding to Subp_Entity
|
|
|
|
--------------------
|
|
-- Append_To_Stms --
|
|
--------------------
|
|
|
|
procedure Append_To_Stms (N : Node_Id) is
|
|
begin
|
|
Insert_After_And_Analyze (Last (Stms), N);
|
|
Set_Exception_Junk (N);
|
|
end Append_To_Stms;
|
|
|
|
-----------------------------
|
|
-- Inside_Selective_Accept --
|
|
-----------------------------
|
|
|
|
function Inside_Selective_Accept return Boolean is
|
|
Parnt : Node_Id;
|
|
Curr : Node_Id := HSS;
|
|
|
|
begin
|
|
Parnt := Parent (HSS);
|
|
while Nkind (Parnt) /= N_Compilation_Unit loop
|
|
if Nkind (Parnt) = N_Accept_Alternative
|
|
and then Curr = Accept_Statement (Parnt)
|
|
then
|
|
if Present (Accept_Handler_Records (Parnt)) then
|
|
Hlist := Accept_Handler_Records (Parnt);
|
|
else
|
|
Hlist := New_List;
|
|
Set_Accept_Handler_Records (Parnt, Hlist);
|
|
end if;
|
|
|
|
return True;
|
|
else
|
|
Curr := Parnt;
|
|
Parnt := Parent (Parnt);
|
|
end if;
|
|
end loop;
|
|
|
|
return False;
|
|
end Inside_Selective_Accept;
|
|
|
|
---------------
|
|
-- Set_Hlist --
|
|
---------------
|
|
|
|
procedure Set_Hlist is
|
|
begin
|
|
-- Never try to inline a subprogram with exception handlers
|
|
|
|
Set_Is_Inlined (Subp_Entity, False);
|
|
|
|
if Present (Subp_Entity)
|
|
and then Present (Handler_Records (Subp_Entity))
|
|
then
|
|
Hlist := Handler_Records (Subp_Entity);
|
|
else
|
|
Hlist := New_List;
|
|
Set_Handler_Records (Subp_Entity, Hlist);
|
|
end if;
|
|
end Set_Hlist;
|
|
|
|
-- Start of processing for Expand_Exception_Handler_Tables
|
|
|
|
begin
|
|
-- Nothing to do if this handler has already been processed
|
|
|
|
if Zero_Cost_Handling (HSS) then
|
|
return;
|
|
end if;
|
|
|
|
Set_Zero_Cost_Handling (HSS);
|
|
|
|
-- Find the parent subprogram or package scope containing this
|
|
-- exception frame. This should always find a real package or
|
|
-- subprogram. If it does not it will stop at Standard, but
|
|
-- this cannot legitimately occur.
|
|
|
|
-- We only stop at library level packages, for inner packages
|
|
-- we always attach handlers to the containing procedure.
|
|
|
|
Subp_Entity := Current_Scope;
|
|
Scope_Loop : loop
|
|
|
|
-- Never need tables expanded inside a generic template
|
|
|
|
if Is_Generic_Unit (Subp_Entity) then
|
|
return;
|
|
|
|
-- Stop if we reached containing subprogram. Go to protected
|
|
-- subprogram if there is one defined.
|
|
|
|
elsif Ekind (Subp_Entity) = E_Function
|
|
or else Ekind (Subp_Entity) = E_Procedure
|
|
then
|
|
if Present (Protected_Body_Subprogram (Subp_Entity)) then
|
|
Subp_Entity := Protected_Body_Subprogram (Subp_Entity);
|
|
end if;
|
|
|
|
Set_Hlist;
|
|
exit Scope_Loop;
|
|
|
|
-- Case of within an entry
|
|
|
|
elsif Is_Entry (Subp_Entity) then
|
|
|
|
-- Protected entry, use corresponding body subprogram
|
|
|
|
if Present (Protected_Body_Subprogram (Subp_Entity)) then
|
|
Subp_Entity := Protected_Body_Subprogram (Subp_Entity);
|
|
Set_Hlist;
|
|
exit Scope_Loop;
|
|
|
|
-- Check if we are within a selective accept alternative
|
|
|
|
elsif Inside_Selective_Accept then
|
|
|
|
-- As a side effect, Inside_Selective_Accept set Hlist,
|
|
-- in much the same manner as Set_Hlist, except that
|
|
-- the list involved was the one for the selective accept.
|
|
|
|
exit Scope_Loop;
|
|
end if;
|
|
|
|
-- Case of within library level package
|
|
|
|
elsif Ekind (Subp_Entity) = E_Package
|
|
and then Is_Compilation_Unit (Subp_Entity)
|
|
then
|
|
if Is_Body_Name (Unit_Name (Get_Code_Unit (HSS))) then
|
|
Subp_Entity := Body_Entity (Subp_Entity);
|
|
end if;
|
|
|
|
Set_Hlist;
|
|
exit Scope_Loop;
|
|
|
|
-- Task type case
|
|
|
|
elsif Ekind (Subp_Entity) = E_Task_Type then
|
|
|
|
-- Check if we are within a selective accept alternative
|
|
|
|
if Inside_Selective_Accept then
|
|
|
|
-- As a side effect, Inside_Selective_Accept set Hlist,
|
|
-- in much the same manner as Set_Hlist, except that the
|
|
-- list involved was the one for the selective accept.
|
|
|
|
exit Scope_Loop;
|
|
|
|
-- Stop if we reached task type with task body procedure,
|
|
-- use the task body procedure.
|
|
|
|
elsif Present (Get_Task_Body_Procedure (Subp_Entity)) then
|
|
Subp_Entity := Get_Task_Body_Procedure (Subp_Entity);
|
|
Set_Hlist;
|
|
exit Scope_Loop;
|
|
end if;
|
|
end if;
|
|
|
|
-- If we fall through, keep looking
|
|
|
|
Subp_Entity := Scope (Subp_Entity);
|
|
end loop Scope_Loop;
|
|
|
|
pragma Assert (Subp_Entity /= Standard_Standard);
|
|
|
|
-- Analyze standard labels
|
|
|
|
Analyze_Label_Entity (L1);
|
|
Analyze_Label_Entity (L2);
|
|
|
|
Insert_Before_And_Analyze (First (Stms),
|
|
Make_Label (Loc,
|
|
Identifier => New_Occurrence_Of (L1, Loc)));
|
|
Set_Exception_Junk (First (Stms));
|
|
|
|
Append_To_Stms (
|
|
Make_Label (Loc,
|
|
Identifier => New_Occurrence_Of (L2, Loc)));
|
|
|
|
-- Loop through exception handlers
|
|
|
|
Handler := First_Non_Pragma (Handlrs);
|
|
while Present (Handler) loop
|
|
Set_Zero_Cost_Handling (Handler);
|
|
|
|
-- Add label at start of handler, and goto at the end
|
|
|
|
Lnn :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_Internal_Name ('L'));
|
|
|
|
Analyze_Label_Entity (Lnn);
|
|
|
|
Item :=
|
|
Make_Label (Loc,
|
|
Identifier => New_Occurrence_Of (Lnn, Loc));
|
|
Set_Exception_Junk (Item);
|
|
Insert_Before_And_Analyze (First (Statements (Handler)), Item);
|
|
|
|
-- Loop through choices
|
|
|
|
Choice := First (Exception_Choices (Handler));
|
|
while Present (Choice) loop
|
|
|
|
-- Others (or all others) choice
|
|
|
|
if Nkind (Choice) = N_Others_Choice then
|
|
if All_Others (Choice) then
|
|
E_Id := New_Occurrence_Of (RTE (RE_All_Others_Id), Loc);
|
|
else
|
|
E_Id := New_Occurrence_Of (RTE (RE_Others_Id), Loc);
|
|
end if;
|
|
|
|
-- Special case of VMS_Exception. Not clear what we will do
|
|
-- eventually here if and when we implement zero cost exceptions
|
|
-- on VMS. But at least for now, don't blow up trying to take
|
|
-- a garbage code address for such an exception.
|
|
|
|
elsif Is_VMS_Exception (Entity (Choice)) then
|
|
E_Id := New_Occurrence_Of (RTE (RE_Null_Id), Loc);
|
|
|
|
-- Normal case of specific exception choice
|
|
|
|
else
|
|
E_Id :=
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Entity (Choice), Loc),
|
|
Attribute_Name => Name_Identity);
|
|
end if;
|
|
|
|
HR_Ent :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_Internal_Name ('H'));
|
|
|
|
HL_Ref :=
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (HR_Ent, Loc),
|
|
Attribute_Name => Name_Unrestricted_Access);
|
|
|
|
-- Now we need to add the entry for the new handler record to
|
|
-- the list of handler records for the current subprogram.
|
|
|
|
-- Normally we end up generating the handler records in exactly
|
|
-- the right order. Here right order means innermost first,
|
|
-- since the table will be searched sequentially. Since we
|
|
-- generally expand from outside to inside, the order is just
|
|
-- what we want, and we need to append the new entry to the
|
|
-- end of the list.
|
|
|
|
-- However, there are exceptions, notably in the case where
|
|
-- a generic body is inserted later on. See for example the
|
|
-- case of ACVC test C37213J, which has the following form:
|
|
|
|
-- generic package x ... end x;
|
|
-- package body x is
|
|
-- begin
|
|
-- ...
|
|
-- exception (1)
|
|
-- ...
|
|
-- end x;
|
|
|
|
-- ...
|
|
|
|
-- declare
|
|
-- package q is new x;
|
|
-- begin
|
|
-- ...
|
|
-- exception (2)
|
|
-- ...
|
|
-- end;
|
|
|
|
-- In this case, we will expand exception handler (2) first,
|
|
-- since the expansion of (1) is delayed till later when the
|
|
-- generic body is inserted. But (1) belongs before (2) in
|
|
-- the chain.
|
|
|
|
-- Note that scopes are not totally ordered, because two
|
|
-- scopes can be in parallel blocks, so that it does not
|
|
-- matter what order these entries appear in. An ordering
|
|
-- relation exists if one scope is inside another, and what
|
|
-- we really want is some partial ordering.
|
|
|
|
-- A simple, not very efficient, but adequate algorithm to
|
|
-- achieve this partial ordering is to search the list for
|
|
-- the first entry containing the given scope, and put the
|
|
-- new entry just before it.
|
|
|
|
declare
|
|
New_Scop : constant Entity_Id := Current_Scope;
|
|
Ent : Node_Id;
|
|
|
|
begin
|
|
Ent := First (Hlist);
|
|
loop
|
|
-- If all searched, then we can just put the new
|
|
-- entry at the end of the list (it actually does
|
|
-- not matter where we put it in this case).
|
|
|
|
if No (Ent) then
|
|
Append_To (Hlist, HL_Ref);
|
|
exit;
|
|
|
|
-- If the current scope is within the scope of the
|
|
-- entry then insert the entry before to retain the
|
|
-- proper order as per above discussion.
|
|
|
|
-- Note that for equal entries, we just keep going,
|
|
-- which is fine, the entry will end up at the end
|
|
-- of the list where it belongs.
|
|
|
|
elsif Scope_Within
|
|
(New_Scop, Scope (Entity (Prefix (Ent))))
|
|
then
|
|
Insert_Before (Ent, HL_Ref);
|
|
exit;
|
|
|
|
-- Otherwise keep looking
|
|
|
|
else
|
|
Next (Ent);
|
|
end if;
|
|
end loop;
|
|
end;
|
|
|
|
Item :=
|
|
Make_Object_Declaration (Loc,
|
|
Defining_Identifier => HR_Ent,
|
|
Constant_Present => True,
|
|
Aliased_Present => True,
|
|
Object_Definition =>
|
|
New_Occurrence_Of (RTE (RE_Handler_Record), Loc),
|
|
|
|
Expression =>
|
|
Make_Aggregate (Loc,
|
|
Expressions => New_List (
|
|
Make_Attribute_Reference (Loc, -- Lo
|
|
Prefix => New_Occurrence_Of (L1, Loc),
|
|
Attribute_Name => Name_Address),
|
|
|
|
Make_Attribute_Reference (Loc, -- Hi
|
|
Prefix => New_Occurrence_Of (L2, Loc),
|
|
Attribute_Name => Name_Address),
|
|
|
|
E_Id, -- Id
|
|
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Lnn, Loc), -- Handler
|
|
Attribute_Name => Name_Address))));
|
|
|
|
Set_Handler_List_Entry (Item, HL_Ref);
|
|
Set_Exception_Junk (Item);
|
|
Insert_After_And_Analyze (Last (Statements (Handler)), Item);
|
|
Set_Is_Statically_Allocated (HR_Ent);
|
|
|
|
-- If this is a late insertion (from body instance) it is being
|
|
-- inserted in the component list of an already analyzed aggre-
|
|
-- gate, and must be analyzed explicitly.
|
|
|
|
Analyze_And_Resolve (HL_Ref, RTE (RE_Handler_Record_Ptr));
|
|
|
|
Next (Choice);
|
|
end loop;
|
|
|
|
Next_Non_Pragma (Handler);
|
|
end loop;
|
|
end Expand_Exception_Handler_Tables;
|
|
|
|
-------------------------------
|
|
-- Expand_Exception_Handlers --
|
|
-------------------------------
|
|
|
|
procedure Expand_Exception_Handlers (HSS : Node_Id) is
|
|
Handlrs : constant List_Id := Exception_Handlers (HSS);
|
|
Loc : Source_Ptr;
|
|
Handler : Node_Id;
|
|
Others_Choice : Boolean;
|
|
Obj_Decl : Node_Id;
|
|
|
|
procedure Prepend_Call_To_Handler
|
|
(Proc : RE_Id;
|
|
Args : List_Id := No_List);
|
|
-- Routine to prepend a call to the procedure referenced by Proc at
|
|
-- the start of the handler code for the current Handler.
|
|
|
|
-----------------------------
|
|
-- Prepend_Call_To_Handler --
|
|
-----------------------------
|
|
|
|
procedure Prepend_Call_To_Handler
|
|
(Proc : RE_Id;
|
|
Args : List_Id := No_List)
|
|
is
|
|
Ent : constant Entity_Id := RTE (Proc);
|
|
|
|
begin
|
|
-- If we have no Entity, then we are probably in no run time mode
|
|
-- or some weird error has occured. In either case do do nothing!
|
|
|
|
if Present (Ent) then
|
|
declare
|
|
Call : constant Node_Id :=
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name => New_Occurrence_Of (RTE (Proc), Loc),
|
|
Parameter_Associations => Args);
|
|
|
|
begin
|
|
Prepend_To (Statements (Handler), Call);
|
|
Analyze (Call, Suppress => All_Checks);
|
|
end;
|
|
end if;
|
|
end Prepend_Call_To_Handler;
|
|
|
|
-- Start of processing for Expand_Exception_Handlers
|
|
|
|
begin
|
|
-- Loop through handlers
|
|
|
|
Handler := First_Non_Pragma (Handlrs);
|
|
Handler_Loop : while Present (Handler) loop
|
|
Loc := Sloc (Handler);
|
|
|
|
-- Remove source handler if gnat debug flag N is set
|
|
|
|
if Debug_Flag_Dot_X and then Comes_From_Source (Handler) then
|
|
declare
|
|
H : constant Node_Id := Handler;
|
|
begin
|
|
Next_Non_Pragma (Handler);
|
|
Remove (H);
|
|
goto Continue_Handler_Loop;
|
|
end;
|
|
end if;
|
|
|
|
|
|
-- If an exception occurrence is present, then we must declare it
|
|
-- and initialize it from the value stored in the TSD
|
|
|
|
-- declare
|
|
-- name : Exception_Occurrence;
|
|
--
|
|
-- begin
|
|
-- Save_Occurrence (name, Get_Current_Excep.all)
|
|
-- ...
|
|
-- end;
|
|
|
|
if Present (Choice_Parameter (Handler)) then
|
|
declare
|
|
Cparm : constant Entity_Id := Choice_Parameter (Handler);
|
|
Clc : constant Source_Ptr := Sloc (Cparm);
|
|
Save : Node_Id;
|
|
|
|
begin
|
|
Save :=
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name =>
|
|
New_Occurrence_Of (RTE (RE_Save_Occurrence), Loc),
|
|
Parameter_Associations => New_List (
|
|
New_Occurrence_Of (Cparm, Clc),
|
|
Make_Explicit_Dereference (Loc,
|
|
Make_Function_Call (Loc,
|
|
Name => Make_Explicit_Dereference (Loc,
|
|
New_Occurrence_Of
|
|
(RTE (RE_Get_Current_Excep), Loc))))));
|
|
|
|
Mark_Rewrite_Insertion (Save);
|
|
Prepend (Save, Statements (Handler));
|
|
|
|
Obj_Decl :=
|
|
Make_Object_Declaration (Clc,
|
|
Defining_Identifier => Cparm,
|
|
Object_Definition =>
|
|
New_Occurrence_Of
|
|
(RTE (RE_Exception_Occurrence), Clc));
|
|
Set_No_Initialization (Obj_Decl, True);
|
|
|
|
Rewrite (Handler,
|
|
Make_Exception_Handler (Loc,
|
|
Exception_Choices => Exception_Choices (Handler),
|
|
|
|
Statements => New_List (
|
|
Make_Block_Statement (Loc,
|
|
Declarations => New_List (Obj_Decl),
|
|
Handled_Statement_Sequence =>
|
|
Make_Handled_Sequence_Of_Statements (Loc,
|
|
Statements => Statements (Handler))))));
|
|
|
|
Analyze_List (Statements (Handler), Suppress => All_Checks);
|
|
end;
|
|
end if;
|
|
|
|
-- The processing at this point is rather different for the
|
|
-- JVM case, so we completely separate the processing.
|
|
|
|
-- For the JVM case, we unconditionally call Update_Exception,
|
|
-- passing a call to the intrinsic function Current_Target_Exception
|
|
-- (see JVM version of Ada.Exceptions in 4jexcept.adb for details).
|
|
|
|
if Hostparm.Java_VM then
|
|
declare
|
|
Arg : constant Node_Id :=
|
|
Make_Function_Call (Loc,
|
|
Name => New_Occurrence_Of
|
|
(RTE (RE_Current_Target_Exception), Loc));
|
|
begin
|
|
Prepend_Call_To_Handler (RE_Update_Exception, New_List (Arg));
|
|
end;
|
|
|
|
-- For the normal case, we have to worry about the state of abort
|
|
-- deferral. Generally, we defer abort during runtime handling of
|
|
-- exceptions. When control is passed to the handler, then in the
|
|
-- normal case we undefer aborts. In any case this entire handling
|
|
-- is relevant only if aborts are allowed!
|
|
|
|
elsif Abort_Allowed then
|
|
|
|
-- There are some special cases in which we do not do the
|
|
-- undefer. In particular a finalization (AT END) handler
|
|
-- wants to operate with aborts still deferred.
|
|
|
|
-- We also suppress the call if this is the special handler
|
|
-- for Abort_Signal, since if we are aborting, we want to keep
|
|
-- aborts deferred (one abort is enough thank you very much :-)
|
|
|
|
-- If abort really needs to be deferred the expander must add
|
|
-- this call explicitly, see Exp_Ch9.Expand_N_Asynchronous_Select.
|
|
|
|
Others_Choice :=
|
|
Nkind (First (Exception_Choices (Handler))) = N_Others_Choice;
|
|
|
|
if (Others_Choice
|
|
or else Entity (First (Exception_Choices (Handler))) /=
|
|
Stand.Abort_Signal)
|
|
and then not
|
|
(Others_Choice
|
|
and then All_Others (First (Exception_Choices (Handler))))
|
|
and then Abort_Allowed
|
|
then
|
|
Prepend_Call_To_Handler (RE_Abort_Undefer);
|
|
end if;
|
|
end if;
|
|
|
|
Next_Non_Pragma (Handler);
|
|
|
|
<<Continue_Handler_Loop>>
|
|
null;
|
|
end loop Handler_Loop;
|
|
|
|
-- If all handlers got removed by gnatdN, then remove the list
|
|
|
|
if Debug_Flag_Dot_X
|
|
and then Is_Empty_List (Exception_Handlers (HSS))
|
|
then
|
|
Set_Exception_Handlers (HSS, No_List);
|
|
end if;
|
|
|
|
-- The last step for expanding exception handlers is to expand the
|
|
-- exception tables if zero cost exception handling is active.
|
|
|
|
if Exception_Mechanism = Front_End_ZCX_Exceptions then
|
|
Expand_Exception_Handler_Tables (HSS);
|
|
end if;
|
|
end Expand_Exception_Handlers;
|
|
|
|
------------------------------------
|
|
-- Expand_N_Exception_Declaration --
|
|
------------------------------------
|
|
|
|
-- Generates:
|
|
-- exceptE : constant String := "A.B.EXCEP"; -- static data
|
|
-- except : exception_data := (
|
|
-- Handled_By_Other => False,
|
|
-- Lang => 'A',
|
|
-- Name_Length => exceptE'Length,
|
|
-- Full_Name => exceptE'Address,
|
|
-- HTable_Ptr => null,
|
|
-- Import_Code => 0,
|
|
-- Raise_Hook => null,
|
|
-- );
|
|
|
|
-- (protecting test only needed if not at library level)
|
|
--
|
|
-- exceptF : Boolean := True -- static data
|
|
-- if exceptF then
|
|
-- exceptF := False;
|
|
-- Register_Exception (except'Unchecked_Access);
|
|
-- end if;
|
|
|
|
procedure Expand_N_Exception_Declaration (N : Node_Id) is
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
Id : constant Entity_Id := Defining_Identifier (N);
|
|
L : List_Id := New_List;
|
|
Flag_Id : Entity_Id;
|
|
|
|
Name_Exname : constant Name_Id := New_External_Name (Chars (Id), 'E');
|
|
Exname : constant Node_Id :=
|
|
Make_Defining_Identifier (Loc, Name_Exname);
|
|
|
|
begin
|
|
-- There is no expansion needed when compiling for the JVM since the
|
|
-- JVM has a built-in exception mechanism. See 4jexcept.ads for details.
|
|
|
|
if Hostparm.Java_VM then
|
|
return;
|
|
end if;
|
|
|
|
-- Definition of the external name: nam : constant String := "A.B.NAME";
|
|
|
|
Insert_Action (N,
|
|
Make_Object_Declaration (Loc,
|
|
Defining_Identifier => Exname,
|
|
Constant_Present => True,
|
|
Object_Definition => New_Occurrence_Of (Standard_String, Loc),
|
|
Expression => Make_String_Literal (Loc, Full_Qualified_Name (Id))));
|
|
|
|
Set_Is_Statically_Allocated (Exname);
|
|
|
|
-- Create the aggregate list for type Standard.Exception_Type:
|
|
-- Handled_By_Other component: False
|
|
|
|
Append_To (L, New_Occurrence_Of (Standard_False, Loc));
|
|
|
|
-- Lang component: 'A'
|
|
|
|
Append_To (L,
|
|
Make_Character_Literal (Loc, Name_uA, Get_Char_Code ('A')));
|
|
|
|
-- Name_Length component: Nam'Length
|
|
|
|
Append_To (L,
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Exname, Loc),
|
|
Attribute_Name => Name_Length));
|
|
|
|
-- Full_Name component: Standard.A_Char!(Nam'Address)
|
|
|
|
Append_To (L, Unchecked_Convert_To (Standard_A_Char,
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Exname, Loc),
|
|
Attribute_Name => Name_Address)));
|
|
|
|
-- HTable_Ptr component: null
|
|
|
|
Append_To (L, Make_Null (Loc));
|
|
|
|
-- Import_Code component: 0
|
|
|
|
Append_To (L, Make_Integer_Literal (Loc, 0));
|
|
|
|
-- Raise_Hook component: null
|
|
|
|
Append_To (L, Make_Null (Loc));
|
|
|
|
Set_Expression (N, Make_Aggregate (Loc, Expressions => L));
|
|
Analyze_And_Resolve (Expression (N), Etype (Id));
|
|
|
|
-- Register_Exception (except'Unchecked_Access);
|
|
|
|
if not Restriction_Active (No_Exception_Handlers)
|
|
and then not Restriction_Active (No_Exception_Registration)
|
|
then
|
|
L := New_List (
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name => New_Occurrence_Of (RTE (RE_Register_Exception), Loc),
|
|
Parameter_Associations => New_List (
|
|
Unchecked_Convert_To (RTE (RE_Exception_Data_Ptr),
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Id, Loc),
|
|
Attribute_Name => Name_Unrestricted_Access)))));
|
|
|
|
Set_Register_Exception_Call (Id, First (L));
|
|
|
|
if not Is_Library_Level_Entity (Id) then
|
|
Flag_Id := Make_Defining_Identifier (Loc,
|
|
New_External_Name (Chars (Id), 'F'));
|
|
|
|
Insert_Action (N,
|
|
Make_Object_Declaration (Loc,
|
|
Defining_Identifier => Flag_Id,
|
|
Object_Definition =>
|
|
New_Occurrence_Of (Standard_Boolean, Loc),
|
|
Expression =>
|
|
New_Occurrence_Of (Standard_True, Loc)));
|
|
|
|
Set_Is_Statically_Allocated (Flag_Id);
|
|
|
|
Append_To (L,
|
|
Make_Assignment_Statement (Loc,
|
|
Name => New_Occurrence_Of (Flag_Id, Loc),
|
|
Expression => New_Occurrence_Of (Standard_False, Loc)));
|
|
|
|
Insert_After_And_Analyze (N,
|
|
Make_Implicit_If_Statement (N,
|
|
Condition => New_Occurrence_Of (Flag_Id, Loc),
|
|
Then_Statements => L));
|
|
|
|
else
|
|
Insert_List_After_And_Analyze (N, L);
|
|
end if;
|
|
end if;
|
|
|
|
end Expand_N_Exception_Declaration;
|
|
|
|
---------------------------------------------
|
|
-- Expand_N_Handled_Sequence_Of_Statements --
|
|
---------------------------------------------
|
|
|
|
procedure Expand_N_Handled_Sequence_Of_Statements (N : Node_Id) is
|
|
begin
|
|
if Present (Exception_Handlers (N))
|
|
and then not Restriction_Active (No_Exception_Handlers)
|
|
then
|
|
Expand_Exception_Handlers (N);
|
|
end if;
|
|
|
|
-- The following code needs comments ???
|
|
|
|
if Nkind (Parent (N)) /= N_Package_Body
|
|
and then Nkind (Parent (N)) /= N_Accept_Statement
|
|
and then not Delay_Cleanups (Current_Scope)
|
|
then
|
|
Expand_Cleanup_Actions (Parent (N));
|
|
else
|
|
Set_First_Real_Statement (N, First (Statements (N)));
|
|
end if;
|
|
|
|
end Expand_N_Handled_Sequence_Of_Statements;
|
|
|
|
-------------------------------------
|
|
-- Expand_N_Raise_Constraint_Error --
|
|
-------------------------------------
|
|
|
|
-- The only processing required is to adjust the condition to deal
|
|
-- with the C/Fortran boolean case. This may well not be necessary,
|
|
-- as all such conditions are generated by the expander and probably
|
|
-- are all standard boolean, but who knows what strange optimization
|
|
-- in future may require this adjustment!
|
|
|
|
procedure Expand_N_Raise_Constraint_Error (N : Node_Id) is
|
|
begin
|
|
Adjust_Condition (Condition (N));
|
|
end Expand_N_Raise_Constraint_Error;
|
|
|
|
----------------------------------
|
|
-- Expand_N_Raise_Program_Error --
|
|
----------------------------------
|
|
|
|
-- The only processing required is to adjust the condition to deal
|
|
-- with the C/Fortran boolean case. This may well not be necessary,
|
|
-- as all such conditions are generated by the expander and probably
|
|
-- are all standard boolean, but who knows what strange optimization
|
|
-- in future may require this adjustment!
|
|
|
|
procedure Expand_N_Raise_Program_Error (N : Node_Id) is
|
|
begin
|
|
Adjust_Condition (Condition (N));
|
|
end Expand_N_Raise_Program_Error;
|
|
|
|
------------------------------
|
|
-- Expand_N_Raise_Statement --
|
|
------------------------------
|
|
|
|
procedure Expand_N_Raise_Statement (N : Node_Id) is
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
Ehand : Node_Id;
|
|
E : Entity_Id;
|
|
Str : String_Id;
|
|
|
|
begin
|
|
-- There is no expansion needed for statement "raise <exception>;" when
|
|
-- compiling for the JVM since the JVM has a built-in exception
|
|
-- mechanism. However we need the keep the expansion for "raise;"
|
|
-- statements. See 4jexcept.ads for details.
|
|
|
|
if Present (Name (N)) and then Hostparm.Java_VM then
|
|
return;
|
|
end if;
|
|
|
|
-- Don't expand a raise statement that does not come from source
|
|
-- if we have already had configurable run-time violations, since
|
|
-- most likely it will be junk cascaded nonsense.
|
|
|
|
if Configurable_Run_Time_Violations > 0
|
|
and then not Comes_From_Source (N)
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- Convert explicit raise of Program_Error, Constraint_Error, and
|
|
-- Storage_Error into the corresponding raise (in High_Integrity_Mode
|
|
-- all other raises will get normal expansion and be disallowed,
|
|
-- but this is also faster in all modes).
|
|
|
|
if Present (Name (N)) and then Nkind (Name (N)) = N_Identifier then
|
|
if Entity (Name (N)) = Standard_Constraint_Error then
|
|
Rewrite (N,
|
|
Make_Raise_Constraint_Error (Loc,
|
|
Reason => CE_Explicit_Raise));
|
|
Analyze (N);
|
|
return;
|
|
|
|
elsif Entity (Name (N)) = Standard_Program_Error then
|
|
Rewrite (N,
|
|
Make_Raise_Program_Error (Loc,
|
|
Reason => PE_Explicit_Raise));
|
|
Analyze (N);
|
|
return;
|
|
|
|
elsif Entity (Name (N)) = Standard_Storage_Error then
|
|
Rewrite (N,
|
|
Make_Raise_Storage_Error (Loc,
|
|
Reason => SE_Explicit_Raise));
|
|
Analyze (N);
|
|
return;
|
|
end if;
|
|
end if;
|
|
|
|
-- Case of name present, in this case we expand raise name to
|
|
|
|
-- Raise_Exception (name'Identity, location_string);
|
|
|
|
-- where location_string identifies the file/line of the raise
|
|
|
|
if Present (Name (N)) then
|
|
declare
|
|
Id : Entity_Id := Entity (Name (N));
|
|
|
|
begin
|
|
Build_Location_String (Loc);
|
|
|
|
-- If the exception is a renaming, use the exception that it
|
|
-- renames (which might be a predefined exception, e.g.).
|
|
|
|
if Present (Renamed_Object (Id)) then
|
|
Id := Renamed_Object (Id);
|
|
end if;
|
|
|
|
-- Build a C-compatible string in case of no exception handlers,
|
|
-- since this is what the last chance handler is expecting.
|
|
|
|
if Restriction_Active (No_Exception_Handlers) then
|
|
|
|
-- Generate an empty message if configuration pragma
|
|
-- Suppress_Exception_Locations is set for this unit.
|
|
|
|
if Opt.Exception_Locations_Suppressed then
|
|
Name_Len := 1;
|
|
else
|
|
Name_Len := Name_Len + 1;
|
|
end if;
|
|
|
|
Name_Buffer (Name_Len) := ASCII.NUL;
|
|
end if;
|
|
|
|
|
|
if Opt.Exception_Locations_Suppressed then
|
|
Name_Len := 0;
|
|
end if;
|
|
|
|
Str := String_From_Name_Buffer;
|
|
|
|
-- For VMS exceptions, convert the raise into a call to
|
|
-- lib$stop so it will be handled by __gnat_error_handler.
|
|
|
|
if Is_VMS_Exception (Id) then
|
|
declare
|
|
Excep_Image : String_Id;
|
|
Cond : Node_Id;
|
|
|
|
begin
|
|
if Present (Interface_Name (Id)) then
|
|
Excep_Image := Strval (Interface_Name (Id));
|
|
else
|
|
Get_Name_String (Chars (Id));
|
|
Set_All_Upper_Case;
|
|
Excep_Image := String_From_Name_Buffer;
|
|
end if;
|
|
|
|
if Exception_Code (Id) /= No_Uint then
|
|
Cond :=
|
|
Make_Integer_Literal (Loc, Exception_Code (Id));
|
|
else
|
|
Cond :=
|
|
Unchecked_Convert_To (Standard_Integer,
|
|
Make_Function_Call (Loc,
|
|
Name => New_Occurrence_Of
|
|
(RTE (RE_Import_Value), Loc),
|
|
Parameter_Associations => New_List
|
|
(Make_String_Literal (Loc,
|
|
Strval => Excep_Image))));
|
|
end if;
|
|
|
|
Rewrite (N,
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name =>
|
|
New_Occurrence_Of (RTE (RE_Lib_Stop), Loc),
|
|
Parameter_Associations => New_List (Cond)));
|
|
Analyze_And_Resolve (Cond, Standard_Integer);
|
|
end;
|
|
|
|
-- Not VMS exception case, convert raise to call to the
|
|
-- Raise_Exception routine.
|
|
|
|
else
|
|
Rewrite (N,
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name => New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
|
|
Parameter_Associations => New_List (
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => Name (N),
|
|
Attribute_Name => Name_Identity),
|
|
Make_String_Literal (Loc,
|
|
Strval => Str))));
|
|
end if;
|
|
end;
|
|
|
|
-- Case of no name present (reraise). We rewrite the raise to:
|
|
|
|
-- Reraise_Occurrence_Always (EO);
|
|
|
|
-- where EO is the current exception occurrence. If the current handler
|
|
-- does not have a choice parameter specification, then we provide one.
|
|
|
|
else
|
|
-- Find innermost enclosing exception handler (there must be one,
|
|
-- since the semantics has already verified that this raise statement
|
|
-- is valid, and a raise with no arguments is only permitted in the
|
|
-- context of an exception handler.
|
|
|
|
Ehand := Parent (N);
|
|
while Nkind (Ehand) /= N_Exception_Handler loop
|
|
Ehand := Parent (Ehand);
|
|
end loop;
|
|
|
|
-- Make exception choice parameter if none present. Note that we do
|
|
-- not need to put the entity on the entity chain, since no one will
|
|
-- be referencing this entity by normal visibility methods.
|
|
|
|
if No (Choice_Parameter (Ehand)) then
|
|
E := Make_Defining_Identifier (Loc, New_Internal_Name ('E'));
|
|
Set_Choice_Parameter (Ehand, E);
|
|
Set_Ekind (E, E_Variable);
|
|
Set_Etype (E, RTE (RE_Exception_Occurrence));
|
|
Set_Scope (E, Current_Scope);
|
|
end if;
|
|
|
|
-- Now rewrite the raise as a call to Reraise. A special case arises
|
|
-- if this raise statement occurs in the context of a handler for
|
|
-- all others (i.e. an at end handler). in this case we avoid
|
|
-- the call to defer abort, cleanup routines are expected to be
|
|
-- called in this case with aborts deferred.
|
|
|
|
declare
|
|
Ech : constant Node_Id := First (Exception_Choices (Ehand));
|
|
Ent : Entity_Id;
|
|
|
|
begin
|
|
if Nkind (Ech) = N_Others_Choice
|
|
and then All_Others (Ech)
|
|
then
|
|
Ent := RTE (RE_Reraise_Occurrence_No_Defer);
|
|
else
|
|
Ent := RTE (RE_Reraise_Occurrence_Always);
|
|
end if;
|
|
|
|
Rewrite (N,
|
|
Make_Procedure_Call_Statement (Loc,
|
|
Name => New_Occurrence_Of (Ent, Loc),
|
|
Parameter_Associations => New_List (
|
|
New_Occurrence_Of (Choice_Parameter (Ehand), Loc))));
|
|
end;
|
|
end if;
|
|
|
|
Analyze (N);
|
|
end Expand_N_Raise_Statement;
|
|
|
|
----------------------------------
|
|
-- Expand_N_Raise_Storage_Error --
|
|
----------------------------------
|
|
|
|
-- The only processing required is to adjust the condition to deal
|
|
-- with the C/Fortran boolean case. This may well not be necessary,
|
|
-- as all such conditions are generated by the expander and probably
|
|
-- are all standard boolean, but who knows what strange optimization
|
|
-- in future may require this adjustment!
|
|
|
|
procedure Expand_N_Raise_Storage_Error (N : Node_Id) is
|
|
begin
|
|
Adjust_Condition (Condition (N));
|
|
end Expand_N_Raise_Storage_Error;
|
|
|
|
------------------------------
|
|
-- Expand_N_Subprogram_Info --
|
|
------------------------------
|
|
|
|
procedure Expand_N_Subprogram_Info (N : Node_Id) is
|
|
Loc : constant Source_Ptr := Sloc (N);
|
|
|
|
begin
|
|
-- For now, we replace an Expand_N_Subprogram_Info node with an
|
|
-- attribute reference that gives the address of the procedure.
|
|
-- This is because gigi does not yet recognize this node, and
|
|
-- for the initial targets, this is the right value anyway.
|
|
|
|
Rewrite (N,
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => Identifier (N),
|
|
Attribute_Name => Name_Code_Address));
|
|
|
|
Analyze_And_Resolve (N, RTE (RE_Code_Loc));
|
|
end Expand_N_Subprogram_Info;
|
|
|
|
------------------------------------
|
|
-- Generate_Subprogram_Descriptor --
|
|
------------------------------------
|
|
|
|
procedure Generate_Subprogram_Descriptor
|
|
(N : Node_Id;
|
|
Loc : Source_Ptr;
|
|
Spec : Entity_Id;
|
|
Slist : List_Id)
|
|
is
|
|
Code : Node_Id;
|
|
Ent : Entity_Id;
|
|
Decl : Node_Id;
|
|
Dtyp : Entity_Id;
|
|
Numh : Nat;
|
|
Sdes : Node_Id;
|
|
Hrc : List_Id;
|
|
|
|
begin
|
|
if Exception_Mechanism /= Front_End_ZCX_Exceptions then
|
|
return;
|
|
end if;
|
|
|
|
if Restriction_Active (No_Exception_Handlers) then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress descriptor if we are not generating code. This happens
|
|
-- in the case of a -gnatc -gnatt compilation where we force generics
|
|
-- to be generated, but we still don't want exception tables.
|
|
|
|
if Operating_Mode /= Generate_Code then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress descriptor if we are in No_Exceptions restrictions mode,
|
|
-- since we can never propagate exceptions in any case in this mode.
|
|
-- The same consideration applies for No_Exception_Handlers (which
|
|
-- is also set in High_Integrity_Mode).
|
|
|
|
if Restriction_Active (No_Exceptions)
|
|
or Restriction_Active (No_Exception_Handlers)
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress descriptor if we are inside a generic. There are two
|
|
-- ways that we can tell that, depending on what is going on. If
|
|
-- we are actually inside the processing for a generic right now,
|
|
-- then Expander_Active will be reset. If we are outside the
|
|
-- generic, then we will see the generic entity.
|
|
|
|
if not Expander_Active then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress descriptor is subprogram is marked as eliminated, for
|
|
-- example if this is a subprogram created to analyze a default
|
|
-- expression with potential side effects. Ditto if it is nested
|
|
-- within an eliminated subprogram, for example a cleanup action.
|
|
|
|
declare
|
|
Scop : Entity_Id;
|
|
|
|
begin
|
|
Scop := Spec;
|
|
while Scop /= Standard_Standard loop
|
|
if Is_Generic_Unit (Scop) or else Is_Eliminated (Scop) then
|
|
return;
|
|
end if;
|
|
|
|
Scop := Scope (Scop);
|
|
end loop;
|
|
end;
|
|
|
|
-- Suppress descriptor for original protected subprogram (we will
|
|
-- be called again later to generate the descriptor for the actual
|
|
-- protected body subprogram.) This does not apply to barrier
|
|
-- functions which are there own protected subprogram.
|
|
|
|
if Is_Subprogram (Spec)
|
|
and then Present (Protected_Body_Subprogram (Spec))
|
|
and then Protected_Body_Subprogram (Spec) /= Spec
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress descriptors for packages unless they have at least one
|
|
-- handler. The binder will generate the dummy (no handler) descriptors
|
|
-- for elaboration procedures. We can't do it here, because we don't
|
|
-- know if an elaboration routine does in fact exist.
|
|
|
|
-- If there is at least one handler for the package spec or body
|
|
-- then most certainly an elaboration routine must exist, so we
|
|
-- can safely reference it.
|
|
|
|
if (Nkind (N) = N_Package_Declaration
|
|
or else
|
|
Nkind (N) = N_Package_Body)
|
|
and then No (Handler_Records (Spec))
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress all subprogram descriptors for the file System.Exceptions.
|
|
-- We similarly suppress subprogram descriptors for Ada.Exceptions.
|
|
-- These are all init procs for types which cannot raise exceptions.
|
|
-- The reason this is done is that otherwise we get embarassing
|
|
-- elaboration dependencies.
|
|
|
|
Get_Name_String (Unit_File_Name (Current_Sem_Unit));
|
|
|
|
if Name_Buffer (1 .. 12) = "s-except.ads"
|
|
or else
|
|
Name_Buffer (1 .. 12) = "a-except.ads"
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- Similarly, we need to suppress entries for System.Standard_Library,
|
|
-- since otherwise we get elaboration circularities. Again, this would
|
|
-- better be done with a Suppress_Initialization pragma :-)
|
|
|
|
if Name_Buffer (1 .. 11) = "s-stalib.ad" then
|
|
return;
|
|
end if;
|
|
|
|
-- For now, also suppress entries for s-stoele because we have
|
|
-- some kind of unexplained error there ???
|
|
|
|
if Name_Buffer (1 .. 11) = "s-stoele.ad" then
|
|
return;
|
|
end if;
|
|
|
|
-- And also for g-htable, because it cannot raise exceptions,
|
|
-- and generates some kind of elaboration order problem.
|
|
|
|
if Name_Buffer (1 .. 11) = "g-htable.ad" then
|
|
return;
|
|
end if;
|
|
|
|
-- Suppress subprogram descriptor if already generated. This happens
|
|
-- in the case of late generation from Delay_Subprogram_Descriptors
|
|
-- beging set (where there is more than one instantiation in the list)
|
|
|
|
if Has_Subprogram_Descriptor (Spec) then
|
|
return;
|
|
else
|
|
Set_Has_Subprogram_Descriptor (Spec);
|
|
end if;
|
|
|
|
-- Never generate descriptors for inlined bodies
|
|
|
|
if Analyzing_Inlined_Bodies then
|
|
return;
|
|
end if;
|
|
|
|
-- Here we definitely are going to generate a subprogram descriptor
|
|
|
|
declare
|
|
Hnum : Nat := Homonym_Number (Spec);
|
|
|
|
begin
|
|
if Hnum = 1 then
|
|
Hnum := 0;
|
|
end if;
|
|
|
|
Ent :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_External_Name (Chars (Spec), "SD", Hnum));
|
|
end;
|
|
|
|
if No (Handler_Records (Spec)) then
|
|
Hrc := Empty_List;
|
|
Numh := 0;
|
|
else
|
|
Hrc := Handler_Records (Spec);
|
|
Numh := List_Length (Hrc);
|
|
end if;
|
|
|
|
New_Scope (Spec);
|
|
|
|
-- We need a static subtype for the declaration of the subprogram
|
|
-- descriptor. For the case of 0-3 handlers we can use one of the
|
|
-- predefined subtypes in System.Exceptions. For more handlers,
|
|
-- we build our own subtype here.
|
|
|
|
case Numh is
|
|
when 0 =>
|
|
Dtyp := RTE (RE_Subprogram_Descriptor_0);
|
|
|
|
when 1 =>
|
|
Dtyp := RTE (RE_Subprogram_Descriptor_1);
|
|
|
|
when 2 =>
|
|
Dtyp := RTE (RE_Subprogram_Descriptor_2);
|
|
|
|
when 3 =>
|
|
Dtyp := RTE (RE_Subprogram_Descriptor_3);
|
|
|
|
when others =>
|
|
Dtyp :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_Internal_Name ('T'));
|
|
|
|
-- Set the constructed type as global, since we will be
|
|
-- referencing the object that is of this type globally
|
|
|
|
Set_Is_Statically_Allocated (Dtyp);
|
|
|
|
Decl :=
|
|
Make_Subtype_Declaration (Loc,
|
|
Defining_Identifier => Dtyp,
|
|
Subtype_Indication =>
|
|
Make_Subtype_Indication (Loc,
|
|
Subtype_Mark =>
|
|
New_Occurrence_Of (RTE (RE_Subprogram_Descriptor), Loc),
|
|
Constraint =>
|
|
Make_Index_Or_Discriminant_Constraint (Loc,
|
|
Constraints => New_List (
|
|
Make_Integer_Literal (Loc, Numh)))));
|
|
|
|
Append (Decl, Slist);
|
|
|
|
-- We analyze the descriptor for the subprogram and package
|
|
-- case, but not for the imported subprogram case (it will
|
|
-- be analyzed when the freeze entity actions are analyzed.
|
|
|
|
if Present (N) then
|
|
Analyze (Decl);
|
|
end if;
|
|
|
|
Set_Exception_Junk (Decl);
|
|
end case;
|
|
|
|
-- Prepare the code address entry for the table entry. For the normal
|
|
-- case of being within a procedure, this is simply:
|
|
|
|
-- P'Code_Address
|
|
|
|
-- where P is the procedure, but for the package case, it is
|
|
|
|
-- P'Elab_Body'Code_Address
|
|
-- P'Elab_Spec'Code_Address
|
|
|
|
-- for the body and spec respectively. Note that we do our own
|
|
-- analysis of these attribute references, because we know in this
|
|
-- case that the prefix of ELab_Body/Spec is a visible package,
|
|
-- which can be referenced directly instead of using the general
|
|
-- case expansion for these attributes.
|
|
|
|
if Ekind (Spec) = E_Package then
|
|
Code :=
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Spec, Loc),
|
|
Attribute_Name => Name_Elab_Spec);
|
|
Set_Etype (Code, Standard_Void_Type);
|
|
Set_Analyzed (Code);
|
|
|
|
elsif Ekind (Spec) = E_Package_Body then
|
|
Code :=
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Spec_Entity (Spec), Loc),
|
|
Attribute_Name => Name_Elab_Body);
|
|
Set_Etype (Code, Standard_Void_Type);
|
|
Set_Analyzed (Code);
|
|
|
|
else
|
|
Code := New_Occurrence_Of (Spec, Loc);
|
|
end if;
|
|
|
|
Code :=
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => Code,
|
|
Attribute_Name => Name_Code_Address);
|
|
|
|
Set_Etype (Code, RTE (RE_Address));
|
|
Set_Analyzed (Code);
|
|
|
|
-- Now we can build the subprogram descriptor
|
|
|
|
Sdes :=
|
|
Make_Object_Declaration (Loc,
|
|
Defining_Identifier => Ent,
|
|
Constant_Present => True,
|
|
Aliased_Present => True,
|
|
Object_Definition => New_Occurrence_Of (Dtyp, Loc),
|
|
|
|
Expression =>
|
|
Make_Aggregate (Loc,
|
|
Expressions => New_List (
|
|
Make_Integer_Literal (Loc, Numh), -- Num_Handlers
|
|
|
|
Code, -- Code
|
|
|
|
-- temp code ???
|
|
|
|
-- Make_Subprogram_Info (Loc, -- Subprogram_Info
|
|
-- Identifier =>
|
|
-- New_Occurrence_Of (Spec, Loc)),
|
|
|
|
New_Copy_Tree (Code),
|
|
|
|
Make_Aggregate (Loc, -- Handler_Records
|
|
Expressions => Hrc))));
|
|
|
|
Set_Exception_Junk (Sdes);
|
|
Set_Is_Subprogram_Descriptor (Sdes);
|
|
|
|
Append (Sdes, Slist);
|
|
|
|
-- We analyze the descriptor for the subprogram and package case,
|
|
-- but not for the imported subprogram case (it will be analyzed
|
|
-- when the freeze entity actions are analyzed.
|
|
|
|
if Present (N) then
|
|
Analyze (Sdes);
|
|
end if;
|
|
|
|
-- We can now pop the scope used for analyzing the descriptor
|
|
|
|
Pop_Scope;
|
|
|
|
-- We need to set the descriptor as statically allocated, since
|
|
-- it will be referenced from the unit exception table.
|
|
|
|
Set_Is_Statically_Allocated (Ent);
|
|
|
|
-- Append the resulting descriptor to the list. We do this only
|
|
-- if we are in the main unit. You might think that we could
|
|
-- simply skip generating the descriptors completely if we are
|
|
-- not in the main unit, but in fact this is not the case, since
|
|
-- we have problems with inconsistent serial numbers for internal
|
|
-- names if we do this.
|
|
|
|
if In_Extended_Main_Code_Unit (Spec) then
|
|
Append_To (SD_List,
|
|
Make_Attribute_Reference (Loc,
|
|
Prefix => New_Occurrence_Of (Ent, Loc),
|
|
Attribute_Name => Name_Unrestricted_Access));
|
|
|
|
Unit_Exception_Table_Present := True;
|
|
end if;
|
|
|
|
end Generate_Subprogram_Descriptor;
|
|
|
|
------------------------------------------------------------
|
|
-- Generate_Subprogram_Descriptor_For_Imported_Subprogram --
|
|
------------------------------------------------------------
|
|
|
|
procedure Generate_Subprogram_Descriptor_For_Imported_Subprogram
|
|
(Spec : Entity_Id;
|
|
Slist : List_Id)
|
|
is
|
|
begin
|
|
Generate_Subprogram_Descriptor (Empty, Sloc (Spec), Spec, Slist);
|
|
end Generate_Subprogram_Descriptor_For_Imported_Subprogram;
|
|
|
|
------------------------------------------------
|
|
-- Generate_Subprogram_Descriptor_For_Package --
|
|
------------------------------------------------
|
|
|
|
procedure Generate_Subprogram_Descriptor_For_Package
|
|
(N : Node_Id;
|
|
Spec : Entity_Id)
|
|
is
|
|
Adecl : Node_Id;
|
|
|
|
begin
|
|
-- If N is empty with prior errors, ignore
|
|
|
|
if Total_Errors_Detected /= 0 and then No (N) then
|
|
return;
|
|
end if;
|
|
|
|
-- Do not generate if no exceptions
|
|
|
|
if Restriction_Active (No_Exception_Handlers) then
|
|
return;
|
|
end if;
|
|
|
|
-- Otherwise generate descriptor
|
|
|
|
Adecl := Aux_Decls_Node (Parent (N));
|
|
|
|
if No (Actions (Adecl)) then
|
|
Set_Actions (Adecl, New_List);
|
|
end if;
|
|
|
|
Generate_Subprogram_Descriptor (N, Sloc (N), Spec, Actions (Adecl));
|
|
end Generate_Subprogram_Descriptor_For_Package;
|
|
|
|
---------------------------------------------------
|
|
-- Generate_Subprogram_Descriptor_For_Subprogram --
|
|
---------------------------------------------------
|
|
|
|
procedure Generate_Subprogram_Descriptor_For_Subprogram
|
|
(N : Node_Id;
|
|
Spec : Entity_Id)
|
|
is
|
|
begin
|
|
-- If we have no subprogram body and prior errors, ignore
|
|
|
|
if Total_Errors_Detected /= 0 and then No (N) then
|
|
return;
|
|
end if;
|
|
|
|
-- Do not generate if no exceptions
|
|
|
|
if Restriction_Active (No_Exception_Handlers) then
|
|
return;
|
|
end if;
|
|
|
|
-- Else generate descriptor
|
|
|
|
declare
|
|
HSS : constant Node_Id := Handled_Statement_Sequence (N);
|
|
|
|
begin
|
|
if No (Exception_Handlers (HSS)) then
|
|
Generate_Subprogram_Descriptor
|
|
(N, Sloc (N), Spec, Statements (HSS));
|
|
else
|
|
Generate_Subprogram_Descriptor
|
|
(N, Sloc (N),
|
|
Spec, Statements (Last (Exception_Handlers (HSS))));
|
|
end if;
|
|
end;
|
|
end Generate_Subprogram_Descriptor_For_Subprogram;
|
|
|
|
-----------------------------------
|
|
-- Generate_Unit_Exception_Table --
|
|
-----------------------------------
|
|
|
|
-- The only remaining thing to generate here is to generate the
|
|
-- reference to the subprogram descriptor chain. See Ada.Exceptions
|
|
-- for details of required data structures.
|
|
|
|
procedure Generate_Unit_Exception_Table is
|
|
Loc : constant Source_Ptr := No_Location;
|
|
Num : Nat;
|
|
Decl : Node_Id;
|
|
Ent : Entity_Id;
|
|
Next_Ent : Entity_Id;
|
|
Stent : Entity_Id;
|
|
|
|
begin
|
|
-- Nothing to be done if zero length exceptions not active
|
|
|
|
if Exception_Mechanism /= Front_End_ZCX_Exceptions then
|
|
return;
|
|
end if;
|
|
|
|
-- Nothing to do if no exceptions
|
|
|
|
if Restriction_Active (No_Exception_Handlers) then
|
|
return;
|
|
end if;
|
|
|
|
-- Remove any entries from SD_List that correspond to eliminated
|
|
-- subprograms.
|
|
|
|
Ent := First (SD_List);
|
|
while Present (Ent) loop
|
|
Next_Ent := Next (Ent);
|
|
if Is_Eliminated (Scope (Entity (Prefix (Ent)))) then
|
|
Remove (Ent); -- After this, there is no Next (Ent) anymore
|
|
end if;
|
|
|
|
Ent := Next_Ent;
|
|
end loop;
|
|
|
|
-- Nothing to do if no unit exception table present.
|
|
-- An empty table can result from subprogram elimination,
|
|
-- in such a case, eliminate the exception table itself.
|
|
|
|
if Is_Empty_List (SD_List) then
|
|
Unit_Exception_Table_Present := False;
|
|
return;
|
|
end if;
|
|
|
|
-- Do not generate table in a generic
|
|
|
|
if Inside_A_Generic then
|
|
return;
|
|
end if;
|
|
|
|
-- Generate the unit exception table
|
|
|
|
-- subtype Tnn is Subprogram_Descriptors_Record (Num);
|
|
-- __gnat_unitname__SDP : aliased constant Tnn :=
|
|
-- Num,
|
|
-- (sub1'unrestricted_access,
|
|
-- sub2'unrestricted_access,
|
|
-- ...
|
|
-- subNum'unrestricted_access));
|
|
|
|
Num := List_Length (SD_List);
|
|
|
|
Stent :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => New_Internal_Name ('T'));
|
|
|
|
Insert_Library_Level_Action (
|
|
Make_Subtype_Declaration (Loc,
|
|
Defining_Identifier => Stent,
|
|
Subtype_Indication =>
|
|
Make_Subtype_Indication (Loc,
|
|
Subtype_Mark =>
|
|
New_Occurrence_Of
|
|
(RTE (RE_Subprogram_Descriptors_Record), Loc),
|
|
Constraint =>
|
|
Make_Index_Or_Discriminant_Constraint (Loc,
|
|
Constraints => New_List (
|
|
Make_Integer_Literal (Loc, Num))))));
|
|
|
|
Set_Is_Statically_Allocated (Stent);
|
|
|
|
Get_External_Unit_Name_String (Unit_Name (Main_Unit));
|
|
Name_Buffer (1 + 7 .. Name_Len + 7) := Name_Buffer (1 .. Name_Len);
|
|
Name_Buffer (1 .. 7) := "__gnat_";
|
|
Name_Len := Name_Len + 7;
|
|
Add_Str_To_Name_Buffer ("__SDP");
|
|
|
|
Ent :=
|
|
Make_Defining_Identifier (Loc,
|
|
Chars => Name_Find);
|
|
|
|
Get_Name_String (Chars (Ent));
|
|
Set_Interface_Name (Ent,
|
|
Make_String_Literal (Loc, Strval => String_From_Name_Buffer));
|
|
|
|
Decl :=
|
|
Make_Object_Declaration (Loc,
|
|
Defining_Identifier => Ent,
|
|
Object_Definition => New_Occurrence_Of (Stent, Loc),
|
|
Constant_Present => True,
|
|
Aliased_Present => True,
|
|
Expression =>
|
|
Make_Aggregate (Loc,
|
|
New_List (
|
|
Make_Integer_Literal (Loc, List_Length (SD_List)),
|
|
|
|
Make_Aggregate (Loc,
|
|
Expressions => SD_List))));
|
|
|
|
Insert_Library_Level_Action (Decl);
|
|
|
|
Set_Is_Exported (Ent, True);
|
|
Set_Is_Public (Ent, True);
|
|
Set_Is_Statically_Allocated (Ent, True);
|
|
|
|
Get_Name_String (Chars (Ent));
|
|
Set_Interface_Name (Ent,
|
|
Make_String_Literal (Loc,
|
|
Strval => String_From_Name_Buffer));
|
|
|
|
end Generate_Unit_Exception_Table;
|
|
|
|
----------------
|
|
-- Initialize --
|
|
----------------
|
|
|
|
procedure Initialize is
|
|
begin
|
|
SD_List := Empty_List;
|
|
end Initialize;
|
|
|
|
----------------------
|
|
-- Is_Non_Ada_Error --
|
|
----------------------
|
|
|
|
function Is_Non_Ada_Error (E : Entity_Id) return Boolean is
|
|
begin
|
|
if not OpenVMS_On_Target then
|
|
return False;
|
|
end if;
|
|
|
|
Get_Name_String (Chars (E));
|
|
|
|
-- Note: it is a little irregular for the body of exp_ch11 to know
|
|
-- the details of the encoding scheme for names, but on the other
|
|
-- hand, gigi knows them, and this is for gigi's benefit anyway!
|
|
|
|
if Name_Buffer (1 .. 30) /= "system__aux_dec__non_ada_error" then
|
|
return False;
|
|
end if;
|
|
|
|
return True;
|
|
end Is_Non_Ada_Error;
|
|
|
|
----------------------------
|
|
-- Remove_Handler_Entries --
|
|
----------------------------
|
|
|
|
procedure Remove_Handler_Entries (N : Node_Id) is
|
|
function Check_Handler_Entry (N : Node_Id) return Traverse_Result;
|
|
-- This function checks one node for a possible reference to a
|
|
-- handler entry that must be deleted. it always returns OK.
|
|
|
|
function Remove_All_Handler_Entries is new
|
|
Traverse_Func (Check_Handler_Entry);
|
|
-- This defines the traversal operation
|
|
|
|
Discard : Traverse_Result;
|
|
pragma Warnings (Off, Discard);
|
|
|
|
function Check_Handler_Entry (N : Node_Id) return Traverse_Result is
|
|
begin
|
|
if Nkind (N) = N_Object_Declaration then
|
|
|
|
if Present (Handler_List_Entry (N)) then
|
|
Remove (Handler_List_Entry (N));
|
|
Delete_Tree (Handler_List_Entry (N));
|
|
Set_Handler_List_Entry (N, Empty);
|
|
|
|
elsif Is_Subprogram_Descriptor (N) then
|
|
declare
|
|
SDN : Node_Id;
|
|
|
|
begin
|
|
SDN := First (SD_List);
|
|
while Present (SDN) loop
|
|
if Defining_Identifier (N) = Entity (Prefix (SDN)) then
|
|
Remove (SDN);
|
|
Delete_Tree (SDN);
|
|
exit;
|
|
end if;
|
|
|
|
Next (SDN);
|
|
end loop;
|
|
end;
|
|
end if;
|
|
end if;
|
|
|
|
return OK;
|
|
end Check_Handler_Entry;
|
|
|
|
-- Start of processing for Remove_Handler_Entries
|
|
|
|
begin
|
|
if Exception_Mechanism = Front_End_ZCX_Exceptions then
|
|
Discard := Remove_All_Handler_Entries (N);
|
|
end if;
|
|
end Remove_Handler_Entries;
|
|
|
|
end Exp_Ch11;
|