Hi! 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. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 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. --- gcc/cp/constexpr.cc.jj 2025-08-23 15:00:04.185789011 +0200 +++ gcc/cp/constexpr.cc 2025-08-23 15:06:40.170528383 +0200 @@ -2694,6 +2694,8 @@ cxx_bind_parameters_in_call (const const 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 const /* 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; --- gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C.jj 2025-08-23 15:14:50.589013243 +0200 +++ gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C 2025-08-23 15:19:29.653305666 +0200 @@ -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 } Jakub