On Fri, 2026-06-19 at 19:19 +0100, Egas Ribeiro wrote: > This patch assumes that can_convert_eh isn't altered to cover more of > [except.handle]. I submitted a patch for c++ as well that changes > can_convert_eh. If that is accepted, another patch can be submitted > later removing the redundant cxx_eh_may_catch_p wrapper. This patch > is > correct regardless of the outcome of that patch. > > In the tests for this patch I did not cover the C++17 > function-pointer-conversion row of [except.handle], because it is > very > uncommon in practice and I didn't think it warranted its own test. > Let me know if I should add that and I can resubmit the patch. > > Bootstrapped and regtested on x86_64-pc-linux-gnu. > > -- >8 -- > > The analyzer's exception_matches_type_p only treated an exception as > caught when the handler type and exception type were identical, so a > handler catching a base class did not match a thrown derived class. > > Add an eh_may_catch_p langhook returning whether a handler of one > type > catches an exception of another per the language's rules. The > default > returns false, preserving behavior for frontends without exception > support (such as C). The C++ frontend implements it via > cxx_eh_may_catch_p, which delegates to can_convert_eh (now non- > static) > and additionally handles the nullptr_t case from [except.handle] that > can_convert_eh does not model. This keeps the analyzer language- > agnostic > and the C++ catch-matching rules in the frontend. > > gcc/ChangeLog: > * langhooks.h (struct lang_hooks): Add eh_may_catch_p. > * langhooks-def.h (LANG_HOOKS_EH_MAY_CATCH_P): Define as > hook_bool_tree_tree_false. > (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 (cxx_eh_may_catch_p): New function. > (LANG_HOOKS_EH_MAY_CATCH_P): Define as cxx_eh_may_catch_p. > > gcc/analyzer/ChangeLog: > * ops.cc: Include "langhooks.h". > (exception_matches_type_p): Use the eh_may_catch_p langhook; > fix catch/exception argument order. > > gcc/testsuite/ChangeLog: > * g++.dg/analyzer/exception-dynamic-spec.C: Remove xfail. > * g++.dg/analyzer/exception-subclass-1.C: Remove xfail. > __analyzer_dump_path in the catch handler. > * g++.dg/analyzer/exception-subclass-2.C: Add > __analyzer_dump_path in the catch handler; > Add __analyzer_eval to interprocedural call. > * g++.dg/analyzer/exception-subclass-3.C: New test. > * g++.dg/analyzer/exception-subclass-4.C: New test.
Minor nit: the ChangeLog entries should have references to PR analyzer/119697 within them. > > Signed-off-by: Egas Ribeiro <[email protected]> > --- [...snip...] > 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..ec61789bacf > --- /dev/null > +++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-3.C > @@ -0,0 +1,123 @@ > +#include "../../gcc.dg/analyzer/analyzer-decls.h" > + > +struct Base {}; > +struct Derived : Base {}; > +struct Unrelated {}; > + > +struct Child : Base {}; > +struct Grandchild : Child {}; > + > +struct SiblingA : Base {}; > +struct SiblingB : Base {}; > + > +struct B1 {}; > +struct B2 {}; > +struct MultiDerived : B1, B2 {}; > + > +struct Amb {}; > +struct Mid1 : Amb {}; > +struct Mid2 : Amb {}; > +struct AmbDerived : Mid1, Mid2 {}; > + > +struct PrivDerived : private Base {}; > + > +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" } > + } > +} > + > +void test_grandchild () > +{ > + try { > + throw Grandchild (); > + } > + catch (Base &) { > + __analyzer_dump_path (); // { dg-message "path" } > + } > +} > + > +void test_sibling () > +{ > + try { > + throw SiblingA (); > + } > + catch (SiblingB &) { > + __analyzer_dump_path (); // { dg-bogus "path" } > + } > +} > + > +void test_multiple_inheritance () > +{ > + try { > + throw MultiDerived (); > + } > + catch (B1 &) { > + __analyzer_dump_path (); // { dg-message "path" } > + } > +} Can you also add a test of catching MultiDerived against B2 & please? I don't think we currently have test coverage of the analyzer reading/writing fields of a parent class with multiple-inheritance for parents that aren't the first, and IIRC that involves some extra logic for locating where the parent is stored within the child. Could you have a go at adding a test for this please (probably in a fresh testcase though, as it's only tangentially related to exceptions). [...snip...] Thanks for the updated patch. Looks good to me from the analyzer point-of-view, but we're waiting on Jason's opinion on whether he's OK with exposing the "may catch" logic like this via a langhook. Jason? Thanks Dave
