raise-gcc.c
52.4 KB
-
[Ada] Improve last exception info availability from C++ handlers · 557b744a
The Most_Recent_Exception service failed to provide accurate information on an Ada exception caught by a C++ handler for foreign exceptions. The service relies on updates of a "current exception buffer" from live exception objects at various points of the propagation process and this update was not performed early enough for the case of foreign exception handlers in non-Ada handlers. The correction applied here consists in moving one of the updates earlier in the raise process, just before unwinding starts, then refine the update API to prevent a redundant copy during the unwinding search phase for the same exception. The example below, compiled with gcc -c b.cc gnatmake -g main.adb -largs b.o --LINK=g++ is expected to run and display ada info: Checking Most_Recent_Exception for CONSTRAINT_ERROR ... OK! // b.cc extern "C" { void foo (); extern void _ada_trigger (); extern void _ada_occurrence_info (); } void foo () { try { _ada_trigger (); } catch (const abi::__foreign_exception &e) { printf ("ada info:\n"); _ada_occurrence_info(); } } -- main.adb with EH; procedure Main is begin EH.Foo; end; -- eh.adb with Gnat.Most_Recent_Exception; with Ada.Text_IO; use Ada.Text_IO; package body EH is procedure Ada_Trigger is begin raise Constraint_Error; end; procedure Ada_Occurrence_Info is begin Check_MRE ("CONSTRAINT_ERROR"); end; function Pre_Check_MRE (Ename : String) return Exception_Id is MROA : Exception_Occurrence_Access := GNAT.Most_Recent_Exception.Occurrence_Access; begin Put ("Checking Most_Recent_Exception for " & Ename & " ... "); if MROA = null then Put_Line ("Most recent exception occurrence access is NULL"); return Null_Id; else return Exception_Identity (MROA.all); end if; end; procedure Diagnose_MRE (MRID : Exception_Id; Ok : Boolean) is begin if Ok then Put_Line ("OK!"); else Put_Line ("Err, Most_Recent_Exception was " & Exception_Name (MRID)); end if; end; procedure Check_MRE (Eid : Exception_Id) is MRID : Exception_Id := Pre_Check_MRE (Ename => Exception_Name (Eid)); begin Diagnose_MRE (MRID, Ok => Eid = MRID); end; procedure Check_MRE (Ename : String) is MRID : Exception_Id := Pre_Check_MRE (Ename => Ename); begin Diagnose_MRE (MRID, Ok => Ename = Exception_Name (MRID)); end; end; -- eh.ads with Ada.Exceptions; use Ada.Exceptions; package EH is procedure Ada_Trigger with Export, Convention => C, External_Name => "_ada_trigger"; procedure Ada_Occurrence_Info with Export, Convention => C, External_Name => "_ada_occurrence_info"; procedure Foo with Import, Convention => C, External_Name => "foo"; procedure Check_MRE (Eid : Exception_Id); procedure Check_MRE (Ename : String); end; 2018-06-11 Olivier Hainque <hainque@adacore.com> gcc/ada/ * libgnat/s-excmac*.ads: Factorize Unwind_Action definitions ... * libgnat/a-exexpr.adb: ... Here, then add comments describing the major datastructures associated with the current exception raised. (Setup_Current_Excep): Accept a "Phase" argument conveying the unwinding phase during which this subprogram is called. For an Ada exception, don't update the current exception buffer from the raised exception object during SEARCH_PHASE, as this is redundant with the call now issued just before propagation starts. (Propagate_GCC_Exception): Move call to Setup_Current_Excep ahead of the unwinding start, conveying Phase 0. (Unhandled_Except_Handler): Pass UA_CLEANUP_PHASE as the Phase value on the call to Setup_Current_Excep. * raise-gcc.c (personality_body): Pass uw_phases as the Phase argument on calls to Setup_Current_Excep. From-SVN: r261426
Olivier Hainque committed