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

Reply via email to