aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/doc/gnat_rm
diff options
context:
space:
mode:
authorAlexandre Oliva <oliva@adacore.com>2024-11-13 19:21:56 -0300
committerMarc Poulhiès <dkm@gcc.gnu.org>2025-01-03 16:39:12 +0100
commitfbe14f65eddd7f450079cff893a2ddc8fb454543 (patch)
tree86e6db67e16308de32e6fee3feb85e03186e91bc /gcc/ada/doc/gnat_rm
parent758de5fed10a7c964bb06a143a3dc3c308721ddd (diff)
downloadgcc-fbe14f65eddd7f450079cff893a2ddc8fb454543.zip
gcc-fbe14f65eddd7f450079cff893a2ddc8fb454543.tar.gz
gcc-fbe14f65eddd7f450079cff893a2ddc8fb454543.tar.bz2
ada: Handle C++ exception hierarchies
This patch introduces support for defining exceptions in Ada with C++'s notion of exception type compatibility, such as handling occurrences of derived types, and obtaining class-wide access to the thrown/raised objects. As a bonus, it adds support for C++ dependent (wrapped) exceptions, and introduces types and interfaces to match C++'s std::type_info and std::exception. Support for C++ exceptions with base-type matching, added to raise-gcc by calling subprograms in Ada units, requires these units and their dependencies to be linked into programs that link with raise-gcc. gcc/ada/ChangeLog: * Makefile.rtl (GNATRTL_NONTASKING_OBJS): Add g-cpp, g-cppstd, and g-cstyin. * doc/gnat_rm/interfacing_to_other_languages.rst (Interfacing to C++): Document class-wide matching and new interfaces. * exp_prag.adb (Expand_Pragma_Import_Or_Interface): Add class-wide exception matching support with 'B' as language identifier. * libgnat/a-exexpr.adb (Setup_Current_Excep): Add Id formal. (Set_Foreign_Occurrence): Likewise. (Propagate_GCC_Exception): Adjust. (Set_Exception_Parameter): Likewise. (Unhandled_Except_Handler): Likewise. * libgnat/g-cpp.ads: New. * libgnat/g-cppexc.adb (Raise_Cpp_Exception): Match 'B' lang id. (Get_Object_Address): New. (Get_Object): Rewrite. (Get_Access_To_Object): New. (Get_Access_To_Tagged_Object): New. (Get_Type_Info): New. (Convert_Caught_Object): New. * libgnat/g-cppexc.ads (Get_Object_Address): New. (Get_Object): Note the Cpp Convention requirement. (Get_Access_To_Object): New. (Get_Access_To_Tagged_Object): New. (Get_Type_Info): New. * libgnat/g-cppstd.adb: New. * libgnat/g-cppstd.ads: New. * libgnat/g-csclex.ads: New, unused. * libgnat/g-cstyin.adb: New. * libgnat/g-cstyin.ads: New. * libgnat/g-excact.adb (Exception_Language): New. (Is_Foreign_Exception): Rewrite. * libgnat/g-excact.ads (Exception_Languages): New. (Exception_Language): New. * libgnat/s-stalib.ads (Lang): Document 'B'. * raise-gcc.c (__gnat_setup_current_excep): Add Exception_Id formal. (CXX_DEPENDENT_EXCEPTION_CLASS): New. (cxx_type_info): New. (__cxa_exception): Rename exceptionType to encompass PrimaryException. (_GNAT_Exception): Drop wrapper. (EID_For): Adjust. (exception_class_eq): Likewise. (__gnat_exception_language_is_cplusplus): New. (__gnat_exception_language_is_ada): New. (__gnat_convert_caught_object): Declare. (__gnat_get_cxx_dependent_exception): New. (__gnat_maybe_get_cxx_dependent_exception): New. (__gnat_get_cxx_exception_type_info): New. (__gnat_obtain_caught_object): New. (is_handled_by): Adjust. [!CERT] Add eid formal, handle dependent exceptions and base-type matches. (get_action_description_for) [!CERT]: Add eid formal. Adjust. (personality_body): Adjust. * gcc-interface/Make-lang.in (GNAT_ADA_OBJS, GNATBIND_OBJS) [!STAGE1]: Add new g-cpp, g-cppstd, g-cstyin + preexisting g-cppexc and i-cstrin. * gnat-style.texi: Regenerate. * gnat_rm.texi: Regenerate.
Diffstat (limited to 'gcc/ada/doc/gnat_rm')
-rw-r--r--gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst163
1 files changed, 162 insertions, 1 deletions
diff --git a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
index ad0be51..03cd330 100644
--- a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
+++ b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
@@ -121,7 +121,168 @@ It is also possible to import a C++ exception using the following syntax:
The ``External_Name`` is the name of the C++ RTTI symbol. You can then
-cover a specific C++ exception in an exception handler.
+cover a specific C++ exception in an exception handler. If the string
+ends with "'Class", as if referencing the Class attribute of the C++
+type, that enables "class-wide" type matching, i.e., instances of C++
+classes derived from the one denoted by the RTTI symbol, that would be
+caught by C++ handlers for that type, will also be caught by Ada
+handlers for ``Entity``. For non-class-wide RTTI symbols imported from
+C++, only exact type matches will be handled. C++ rethrown (dependent)
+exceptions are not distinguishable from the corresponding primary
+exceptions: they are handled exactly as if the primary exception had
+been raised.
+
+With imported exceptions, especially with base-type matching, a single
+handled_sequence_of_statements may have exception handlers with
+choices that cover the same C++ types in ways that GNAT cannot detect.
+For example, C++ classes ``base`` and ``derived`` may be imported as
+exceptions with base-type matching, but GNAT does not know that they
+are related by inheritance, only the runtime will know it. Given:
+
+::
+
+ exception
+ when Derived_Exception => null;
+ when Base_Exception => null;
+ when others => null;
+
+the earliest handler that matches the type of the raised object will
+be selected. If an instance of ``derived`` or a further derived type
+is raised, the first handler will be used; if an instance of ``base``
+that is not an instance of ``derived`` is raised, the second handler
+will be used; raised objects that are not instances of ``base`` will
+be handled by the ``others`` handler. However, if the handlers were
+reordered (``others`` must remain last), the ``Derived_Exception``
+handler would never be used, because ``Base_Exception`` would match
+any instances of ``derived`` before ``Derived_Exception`` or
+``others`` handlers were considered. Mixing exact-type and base-type
+matching exceptions may also involve overlapping handlers that GNAT
+will not reject: an exact-type ``Base_Only_Exception`` handler placed
+before ``Base_Exception`` will handle instances of ``base``, whereas
+instances of derived types will be handled by
+``Base_Exception``. Swapping them will cause ``Base_Exception`` to
+handle all instances of ``base`` and derived types, so that a
+subsequent handler for ``Base_Only_Exception`` will never be selected.
+
+The C++ object associated with a C++ ``Exception_Occurrence`` may be
+obtained by calling the ``GNAT.CPP_Exceptions.Get_Object_Address``
+function. There are convenience generic wrappers named ``Get_Object``,
+``Get_Access_To_Object``, and ``Get_Access_To_Tagged_Object``,
+parameterized on the expected Ada type. Note that, for exceptions
+imported from C++, the address of the object is that of the subobject
+of the type associated with the exception, which may have a different
+address from that of the full object; for C++ exceptions handled by
+``others`` handlers, however, the address of the full object is
+returned.
+
+E.g., if the imported exception uses the RTTI symbol for the base
+class, followed by "'Class", and the C++ code raises (throws) an
+instance of a derived class, a handler for that imported exception
+will catch this ``Exception_Occurrence``, and ``Get_Object_Address``
+will return the address of the base subobject of the raised derived
+object; ``Get_Object``, ``Get_Access_To_Object`` and
+``Get_Access_To_Tagged_Object`` only convert that address to the
+parameterized type, so the specified type ought to be a type that
+imports the C++ type whose RTTI symbol was named in the declared
+exception, i.e., base, not derived or any other type. GNAT cannot
+detect or report if a type is named that does not match the handler's
+RTTI-specified type.
+
+For ``others`` handlers, and for exact type matches, the full object
+is obtained. The ``Get_Type_Info`` function that takes an
+``Exception_Occurrence`` argument can be used to verify the type of
+the C++ object raised as an exception. The other ``Get_Type_Info``
+function, that takes an ``Exception_Id``, obtains the type expected by
+the handler, and no such type exists for ``others`` handlers.
+``GNAT.CPP.Std.Name`` can then convert the opaque
+``GNAT.CPP.Std.Type_Info_Ptr`` access to ``std::type_info`` objects,
+returned by either ``Get_Type_Info`` function, to a C++ mangled type
+name.
+
+If an ``Exception_Occurrence`` was raised from C++, or following C++
+conventions, ``GNAT.Exception_Actions.Exception_Language`` will return
+``EL_Cpp``, whether the exception handler is an imported C++ exception
+or ``others``. ``GNAT.Exception_Actions.Is_Foreign_Exception`` returns
+True for all of these, as well as for any case in which
+``Exception_Language`` is not ``EL_Ada``.
+
+::
+
+ -- Given the following partial package specification:
+
+ Base_Exception : exception;
+ pragma Import (Cpp, Base_Exception, "_ZTI4base'Class");
+ -- Handle instances of base, and of subclasses.
+
+ type Base is limited tagged record
+ [...]
+ end record;
+ pragma Import (Cpp, Base);
+
+ type Derived is limited tagged record
+ [...]
+ end record;
+ pragma Import (Cpp, Derived);
+
+ type Unrelated is access procedure (B : Boolean);
+
+ function Get_Base_Obj_Acc is
+ new Get_Access_To_Tagged_Object (Base);
+ function Get_Derived_Obj_Acc is
+ new Get_Access_To_Tagged_Object (Derived);
+ function Get_Unrelated_Obj_Acc is
+ new Get_Access_To_Object (Unrelated);
+
+ procedure Raise_Derived;
+ -- Raises an instance of derived (with a base subobject).
+
+
+ -- The comments next to each statement indicate the behavior of
+ -- the following pseudocode blocks:
+
+ begin
+ Raise_Derived;
+ exception
+ when BEx : Base_Exception =>
+ ?? := Is_Foreign_Exception (BEx); -- True
+ ?? := Exception_Language (BEx); -- EL_Cpp
+ ?? := Name (Get_Type_Info (BEx)); -- "7derived"
+ ?? := Name (Get_Type_Info (Exception_Identity (BEx))); -- "4base"
+ ?? := Get_Object_Address (BEx); -- base subobject in derived object
+ ?? := Get_Base_Obj_Acc (BEx): -- ditto, as access to Base
+ ?? := Get_Derived_Obj_Acc (BEx): -- ditto, NO ERROR DETECTED!
+ ?? := Get_Unrelated_Obj_Acc (BEx): -- ditto, NO ERROR DETECTED!
+ end;
+
+
+ begin
+ Raise_Derived;
+ exception
+ when BEx : others =>
+ ?? := Is_Foreign_Exception (BEx); -- True
+ ?? := Exception_Language (BEx); -- EL_Cpp
+ ?? := Name (Get_Type_Info (BEx)); -- "7derived"
+ ?? := Get_Type_Info (Exception_Identity (BEx)); -- null
+ ?? := Get_Object_Address (BEx); -- full derived object
+ ?? := Get_Derived_Obj_Acc (BEx): -- ditto, as access to Derived
+ ?? := Get_Base_Obj_Acc (BEx): -- ditto, NO ERROR DETECTED!
+ ?? := Get_Unrelated_Obj_Acc (BEx): -- ditto, NO ERROR DETECTED!
+ end;
+
+The calls marked with ``NO ERROR DETECTED!`` will compile sucessfully,
+even though the types specified in the specializations of the generic
+function do not match the type of the exception object that the
+function is expected to return. Mismatches between derived and base
+types are particularly relevant because they will appear to work as
+long as there isn't any offset between pointers to these types. This
+may hold in many cases, but is subject to change with various possible
+changes to the derived class.
+
+The ``GNAT.CPP.Std`` package offers interfaces corresponding to the
+C++ standard type ``std::type_info``. Function ``To_Type_Info_Ptr``
+builds an opaque ``Type_Info_Ptr`` to reference a ``std::type_info``
+object at a given ``System.Address``.
+
.. _Interfacing_to_COBOL: