https://gcc.gnu.org/g:52c29a6a9dac6caec24b75cae17ecb3558c39504
commit r16-3368-g52c29a6a9dac6caec24b75cae17ecb3558c39504 Author: Jakub Jelinek <ja...@redhat.com> Date: Mon Aug 25 16:27:35 2025 +0200 c++: Check for *jump_target earlier in cxx_bind_parameters_in_call [PR121601] The following testcase ICEs, because the /* Check we aren't dereferencing a null pointer when calling a non-static member function, which is undefined behaviour. */ if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun) && integer_zerop (arg) /* But ignore calls from within compiler-generated code, to handle cases like lambda function pointer conversion operator thunks which pass NULL as the 'this' pointer. */ && !(TREE_CODE (t) == CALL_EXPR && CALL_FROM_THUNK_P (t))) { if (!ctx->quiet) error_at (cp_expr_loc_or_input_loc (x), "dereferencing a null pointer"); *non_constant_p = true; } checking is done before testing if (*jump_target). Especially when throws (jump_target), arg can be (and is on this testcase) NULL_TREE, so calling integer_zerop on it ICEs. Fixed by moving the if (*jump_target) test earlier. 2025-08-25 Jakub Jelinek <ja...@redhat.com> PR c++/121601 * constexpr.cc (cxx_bind_parameters_in_call): Move break if *jump_target before the check for null this object pointer. * g++.dg/cpp26/constexpr-eh16.C: New test. Diff: --- gcc/cp/constexpr.cc | 4 ++-- gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index e5438b25478a..701420ca8ec0 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -2694,6 +2694,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, non_constant_p, overflow_p, jump_target); + if (*jump_target) + break; /* Check we aren't dereferencing a null pointer when calling a non-static member function, which is undefined behaviour. */ if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun) @@ -2711,8 +2713,6 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p && ctx->quiet) break; - if (*jump_target) - break; /* Just discard ellipsis args after checking their constantitude. */ if (!parms) continue; diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C b/gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C new file mode 100644 index 000000000000..790a2b70d998 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C @@ -0,0 +1,19 @@ +// PR c++/121601 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct A { + constexpr const char *data () const noexcept { return "abc"; } + constexpr unsigned size () const noexcept { return 3; } +}; + +constexpr A +foo () +{ + return true ? throw 42 : A {}; // { dg-warning "expression '<throw-expression>' is not a constant expression" "" { target c++20_down } } +} // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } .-1 } + +static_assert (false, foo ()); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_down } } +// { dg-error "'constexpr A foo\\\(\\\)' called in a constant expression" "" { target c++23_down } .-1 } +// { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target *-*-* } .-2 } +// { dg-error "uncaught exception '42'" "" { target c++26 } .-3 }