On Sun, Jun 14, 2026 at 11:42 AM Egas Ribeiro <[email protected]> wrote: > > I was initially implementing a language hook like I specified in my > proposal: > ```cpp > void register_language_semantics (const language_semantics *); > const language_semantics *get_language_semantics (); > > /* Abstract base class for queries about a language's semantics */ > class language_semantics > { > public: > /* Return true if a handler of HANDLER_TYPE can catch an exception > of EXCEPTION_TYPE, per the language's exception-matching rules. */ > virtual bool eh_may_catch_p (tree handler_type, tree exception_type) const > = 0; > }; > ``` > However, I think this is better done as a langhook similar to > eh_personality/eh_runtime_type rather than a new ana::language_semantics > interface for two reasons: > > Adding this new class would imply we want to add multiple frontend > semantic queries eventually, but realistically there's just this one > since vfunc resolution looks like it'll reuse ipa-devirt rather than > needing a frontend query. > > The second reason is where the implementation for each > language_semantics would live. it would have to be somewhere like > cp-gimplify.cc (which isn't ideal), and then the object would have to be > registered somewhere once by each frontend, maybe by adding a single > static instance. > > Thoughts on adding lang_hooks.exception_handler_matches_p next to the > other EH hooks? Or would it be better to keep analyzer-specific > semantics out of the general langhook table? > > I left the ChangeLog entries and the commit message minimal for this > RFC, if this direction is OK I will submit it again with a complete > commit message. > > exception-subclass-1's xfail now passes with the fix as expected, > however exception-subclass-2 still fails; I'll ask about this separately > in this thread. > > Here is the general idea of the implementation as a lang hook:
So looking into a previous GSoC on exceptions handling. I noticed the same_or_derived_type function in tree-eh.cc on https://gcc.gnu.org/cgit/gcc/log/?h=devel/nothrow-detection branch. It looks exactly what you need here. Thanks, Andrea > > -- >8 -- > > From f938d778068537839fc7e50b85869fb624d23b10 Mon Sep 17 00:00:00 2001 > From: Egas Ribeiro <[email protected]> > Date: Sun, 14 Jun 2026 18:46:28 +0100 > Subject: [PATCH] analyzer: exception subclass matching [PR119697] > > PR analyzer/119697 > gcc/ChangeLog: > * langhooks.h (struct lang_hooks): Add eh_may_catch_p. > * langhooks-def.h (LANG_HOOKS_EH_MAY_CATCH_P): New. > (LANG_HOOKS_INITIALIZER): Add it. > > gcc/cp/ChangeLog: > * except.cc (can_convert_eh): Make non-static. > * cp-tree.h (can_convert_eh): Declare. > * cp-lang.cc (LANG_HOOKS_EH_MAY_CATCH_P): New. > > gcc/analyzer/ChangeLog: > * ops.cc (exception_matches_type_p): Use eh_may_catch_p > langhook. > > gcc/testsuite/ChangeLog: > * g++.dg/analyzer/exception-subclass-1.C: Remove xfail. > * g++.dg/analyzer/exception-subclass-3.C: New test. > > Signed-off-by: Egas Ribeiro <[email protected]> > --- > gcc/analyzer/ops.cc | 13 ++---- > gcc/cp/cp-lang.cc | 2 + > gcc/cp/cp-tree.h | 1 + > gcc/cp/except.cc | 2 +- > gcc/langhooks-def.h | 2 + > gcc/langhooks.h | 4 ++ > .../g++.dg/analyzer/exception-subclass-1.C | 2 +- > .../g++.dg/analyzer/exception-subclass-3.C | 46 +++++++++++++++++++ > 8 files changed, 60 insertions(+), 12 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/analyzer/exception-subclass-3.C > > diff --git a/gcc/analyzer/ops.cc b/gcc/analyzer/ops.cc > index 898eaf56485..4aac77d0c1e 100644 > --- a/gcc/analyzer/ops.cc > +++ b/gcc/analyzer/ops.cc > @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see > #include "cgraph.h" > #include "text-art/dump.h" > #include "text-art/tree-widget.h" > +#include "langhooks.h" > > #include "analyzer/ops.h" > #include "analyzer/call-details.h" > @@ -1950,18 +1951,10 @@ public: > }; > > static bool > -exception_matches_type_p (tree exception_type, > - tree catch_type) > +exception_matches_type_p (tree handler_type, tree exception_type) > { > - if (catch_type == exception_type) > + if (lang_hooks.eh_may_catch_p (handler_type, exception_type)) > return true; > - > - /* TODO (PR analyzer/119697): we should also handle subclasses etc; > - see the rules in https://en.cppreference.com/w/cpp/language/catch > - > - It looks like we should be calling (or emulating) > - can_convert_eh from the C++ FE, but that's specific to the C++ FE. */ > - > return false; > } > > diff --git a/gcc/cp/cp-lang.cc b/gcc/cp/cp-lang.cc > index c9d02cc7302..f1096fece1e 100644 > --- a/gcc/cp/cp-lang.cc > +++ b/gcc/cp/cp-lang.cc > @@ -78,6 +78,8 @@ static const char *cp_get_sarif_source_language (const char > *); > #define LANG_HOOKS_EH_PERSONALITY cp_eh_personality > #undef LANG_HOOKS_EH_RUNTIME_TYPE > #define LANG_HOOKS_EH_RUNTIME_TYPE build_eh_type_type > +#undef LANG_HOOKS_EH_MAY_CATCH_P > +#define LANG_HOOKS_EH_MAY_CATCH_P can_convert_eh > #undef LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE > #define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE cxx_enum_underlying_base_type > #undef LANG_HOOKS_PREPROCESS_MAIN_FILE > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 6df271d5e35..64466dbe41e 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -7855,6 +7855,7 @@ extern tree build_exc_ptr (void); > extern tree build_throw (location_t, tree, > tsubst_flags_t); > extern int nothrow_libfn_p (const_tree); > +extern bool can_convert_eh (tree, tree); > extern void check_handlers (tree); > extern tree finish_noexcept_expr (tree, tsubst_flags_t); > extern bool expr_noexcept_p (tree, tsubst_flags_t); > diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc > index e1e082ef1ac..4f40a49ae3f 100644 > --- a/gcc/cp/except.cc > +++ b/gcc/cp/except.cc > @@ -973,7 +973,7 @@ nothrow_libfn_p (const_tree fn) > /* Returns nonzero if an exception of type FROM will be caught by a > handler for type TO, as per [except.handle]. */ > > -static bool > +bool > can_convert_eh (tree to, tree from) > { > to = non_reference (to); > diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h > index 33a99266187..2980901b93f 100644 > --- a/gcc/langhooks-def.h > +++ b/gcc/langhooks-def.h > @@ -149,6 +149,7 @@ extern const char *lhd_get_sarif_source_language (const > char *); > #define LANG_HOOKS_INIT_TS lhd_do_nothing > #define LANG_HOOKS_EH_PERSONALITY lhd_gcc_personality > #define LANG_HOOKS_EH_RUNTIME_TYPE lhd_pass_through_t > +#define LANG_HOOKS_EH_MAY_CATCH_P hook_bool_tree_tree_false > #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS NULL > #define LANG_HOOKS_BLOCK_MAY_FALLTHRU hook_bool_const_tree_true > #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP false > @@ -406,6 +407,7 @@ extern void lhd_end_section (void); > LANG_HOOKS_EXPR_TO_DECL, \ > LANG_HOOKS_EH_PERSONALITY, \ > LANG_HOOKS_EH_RUNTIME_TYPE, \ > + LANG_HOOKS_EH_MAY_CATCH_P, \ > LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS, \ > LANG_HOOKS_BLOCK_MAY_FALLTHRU, \ > LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \ > diff --git a/gcc/langhooks.h b/gcc/langhooks.h > index 546d7ddcdfb..921c1740fd1 100644 > --- a/gcc/langhooks.h > +++ b/gcc/langhooks.h > @@ -644,6 +644,10 @@ struct lang_hooks > /* Map a type to a runtime object to match type. */ > tree (*eh_runtime_type) (tree); > > + /* Return true if a handler of HANDLER_TYPE can catch an exception > + of EXCEPTION_TYPE, per the language's exception-matching rules. */ > + bool (*eh_may_catch_p) (tree handler_type, tree exception_type); > + > /* If non-NULL, this is a function that returns a function decl to be > executed if an unhandled exception is propagated out of a cleanup > region. For example, in C++, an exception thrown by a destructor > diff --git a/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C > b/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C > index 79df33021dd..552013957e4 100644 > --- a/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C > +++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C > @@ -13,7 +13,7 @@ int test () > try { > throw io_error(); > } catch (exception &exc) { > - __analyzer_dump_path (); // { dg-message "path" "PR analyzer/119697" { > xfail *-*-* } } > + __analyzer_dump_path (); // { dg-message "path" "PR analyzer/119697" } > return -1; > } > __analyzer_dump_path (); // { dg-bogus "path" } > diff --git a/gcc/testsuite/g++.dg/analyzer/exception-subclass-3.C > b/gcc/testsuite/g++.dg/analyzer/exception-subclass-3.C > new file mode 100644 > index 00000000000..890cee8b0a5 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-3.C > @@ -0,0 +1,46 @@ > +#include "../../gcc.dg/analyzer/analyzer-decls.h" > + > +struct Base {}; > +struct Derived : Base {}; > +struct Unrelated {}; > + > +void test_unrelated () > +{ > + try { > + throw Derived (); > + } > + catch (Unrelated &) { > + __analyzer_dump_path (); // { dg-bogus "path" } > + } > +} > + > +void test_object_vs_pointer () > +{ > + try { > + throw Derived (); > + } > + catch (Base *) { > + __analyzer_dump_path (); // { dg-bogus "path" } > + } > +} > + > +void test_wrong_direction () > +{ > + try { > + throw Base (); > + } > + catch (Derived &) { > + __analyzer_dump_path (); // { dg-bogus "path" } > + } > +} > + > +void test_pointer_base () > +{ > + static Derived d; > + try { > + throw &d; > + } > + catch (Base *) { > + __analyzer_dump_path (); // { dg-message "path" } > + } > +} > -- > 2.54.0 >
