]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Check for *jump_target earlier in cxx_bind_parameters_in_call [PR121601]
authorJakub Jelinek <jakub@redhat.com>
Mon, 25 Aug 2025 14:27:35 +0000 (16:27 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 25 Aug 2025 14:27:35 +0000 (16:27 +0200)
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  <jakub@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
gcc/testsuite/g++.dg/cpp26/constexpr-eh16.C [new file with mode: 0644]

index e5438b25478a10e5a5bf745ac01fd53dbd1e4ea4..701420ca8ec018b0e13dd1125c58e3c194808a16 100644 (file)
@@ -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 (file)
index 0000000..790a2b7
--- /dev/null
@@ -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 }