Tested x86_64-pc-linux-gnu.  Jakub, does this make sense to you?

-- 8< --

And also add the clobber for non-placement new.

For now let's limit the clobber of an array with non-constant bound to
placement new in constant evaluation, where we need it to set the active
member of a union.

And catch some additional cases of there being no actual data to clobber.

This changes the diagnostics in a couple of analyzer tests, but the new
diagnostics are also valid.

It also adds some -Wuninitialized warnings which seem like an improvement;
the lines that now warn about an uninitialized vptr are correct, trying to
access a member of a virtual base accesses the vptr of an object that
doesn't exist.

gcc/cp/ChangeLog:

        * init.cc (build_new_1): Also clobber for non-placement new.
        Only loop clobber in constexpr.
        * expr.cc (wrap_with_if_consteval): New.
        * cp-tree.h (wrap_with_if_consteval): Declare.

gcc/testsuite/ChangeLog:

        * g++.dg/analyzer/new-2.C: Adjust diags.
        * g++.dg/analyzer/noexcept-new.C: Adjust diags.
        * g++.dg/warn/Warray-bounds-23.C: Add warnings.
        * g++.dg/warn/Warray-bounds-24.C: Add warnings.
        * g++.dg/cpp26/constexpr-new4a.C: New test.
---
 gcc/cp/cp-tree.h                             |  1 +
 gcc/cp/expr.cc                               | 16 ++++++++++
 gcc/cp/init.cc                               | 33 +++++++++++++-------
 gcc/testsuite/g++.dg/analyzer/new-2.C        |  4 +--
 gcc/testsuite/g++.dg/analyzer/noexcept-new.C | 12 +++----
 gcc/testsuite/g++.dg/cpp26/constexpr-new4a.C | 21 +++++++++++++
 gcc/testsuite/g++.dg/warn/Warray-bounds-23.C |  6 ++--
 gcc/testsuite/g++.dg/warn/Warray-bounds-24.C |  6 ++--
 8 files changed, 74 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp26/constexpr-new4a.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5f8dfad7bf4..7298d3b81bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7561,6 +7561,7 @@ extern tree mark_lvalue_use_nonread               (tree);
 extern tree mark_type_use                      (tree);
 extern tree mark_discarded_use                 (tree);
 extern void mark_exp_read                      (tree);
+extern tree wrap_with_if_consteval             (tree);
 
 /* friend.cc */
 extern int is_friend                           (tree, tree);
diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index 32dc3eee78f..f2e99397aca 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -430,3 +430,19 @@ fold_for_warn (tree x)
 
   return c_fully_fold (x, /*for_init*/false, /*maybe_constp*/NULL);
 }
+
+/* Make EXPR only execute during constant evaluation by wrapping it in a
+   statement-expression containing 'if consteval'.  */
+
+tree
+wrap_with_if_consteval (tree expr)
+{
+  tree stmtex = begin_stmt_expr ();
+  tree ifcev = begin_if_stmt ();
+  IF_STMT_CONSTEVAL_P (ifcev) = true;
+  finish_if_stmt_cond (boolean_false_node, ifcev);
+  finish_expr_stmt (expr);
+  finish_then_clause (ifcev);
+  finish_if_stmt (ifcev);
+  return finish_stmt_expr (stmtex, /*no scope*/true);
+}
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 912298728ac..3b0bb2d6808 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3557,15 +3557,17 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, 
tree nelts,
     alloc_expr = maybe_wrap_new_for_constexpr (alloc_expr, type,
                                               cookie_size);
 
-  bool std_placement = std_placement_new_fn_p (alloc_fn);
+  const bool std_placement = std_placement_new_fn_p (alloc_fn);
 
   /* For std placement new, clobber the object if the constructor won't do it
      in start_preparsed_function.  This is most important for activating an
      array in a union (c++/121068), but should also help the optimizers.  */
   const bool do_clobber
-    = (std_placement && flag_lifetime_dse > 1
+    = (flag_lifetime_dse > 1
        && !processing_template_decl
        && !is_empty_type (elt_type)
+       && !integer_zerop (TYPE_SIZE (type))
+       && (!outer_nelts || !integer_zerop (cst_outer_nelts))
        && (!*init || CLASS_TYPE_P (elt_type)));
 
   /* In the simple case, we can stop now.  */
@@ -3665,15 +3667,24 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, 
tree nelts,
       if (array_p && TREE_CODE (cst_outer_nelts) != INTEGER_CST)
        {
          /* Clobber each element rather than the array at once.  */
-         tree clobber = build_clobber (elt_type, CLOBBER_OBJECT_BEGIN);
-         CONSTRUCTOR_IS_DIRECT_INIT (clobber) = true;
-         tree maxindex = cp_build_binary_op (input_location,
-                                             MINUS_EXPR, outer_nelts,
-                                             integer_one_node,
-                                             complain);
-         clobber_expr = build_vec_init (data_addr, maxindex, clobber,
-                                        /*valinit*/false, /*from_arr*/0,
-                                        complain, nullptr);
+         /* But for now, limit a clobber loop to placement new during
+            constant-evaluation, as cddce1 thinks it might be infinite, leading
+            to bogus warnings on Wstringop-overflow-4.C (2025-09-30).  We
+            need it in constexpr for constexpr-new4a.C.  */
+         if (std_placement && current_function_decl
+             && maybe_constexpr_fn (current_function_decl))
+           {
+             tree clobber = build_clobber (elt_type, CLOBBER_OBJECT_BEGIN);
+             CONSTRUCTOR_IS_DIRECT_INIT (clobber) = true;
+             tree maxindex = cp_build_binary_op (input_location,
+                                                 MINUS_EXPR, outer_nelts,
+                                                 integer_one_node,
+                                                 complain);
+             clobber_expr = build_vec_init (data_addr, maxindex, clobber,
+                                            /*valinit*/false, /*from_arr*/0,
+                                            complain, nullptr);
+             clobber_expr = wrap_with_if_consteval (clobber_expr);
+           }
        }
       else
        {
diff --git a/gcc/testsuite/g++.dg/analyzer/new-2.C 
b/gcc/testsuite/g++.dg/analyzer/new-2.C
index 391d159a53a..9337569e60b 100644
--- a/gcc/testsuite/g++.dg/analyzer/new-2.C
+++ b/gcc/testsuite/g++.dg/analyzer/new-2.C
@@ -59,9 +59,9 @@ void test_nonthrowing ()
 
   int z = *y + 2;  /* { dg-warning "dereference of NULL 'y'" } */
   /* { dg-bogus "use of uninitialized value '\\*y'" "" { target *-*-* } .-1 } 
*/
-  z = *x + 4; /* { dg-warning "dereference of possibly-NULL 'x'" } */
+  z = *x + 4; /* { dg-warning "dereference of NULL 'x'" } */
   /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 
} */
-  z = arr[0] + 4; /* { dg-warning "dereference of possibly-NULL 'arr'" } */
+  z = arr[0] + 4; /* { dg-warning "dereference of NULL 'arr'" } */
   /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } 
.-1 } */
 
   delete y;
diff --git a/gcc/testsuite/g++.dg/analyzer/noexcept-new.C 
b/gcc/testsuite/g++.dg/analyzer/noexcept-new.C
index f4bb4956d26..11225431b57 100644
--- a/gcc/testsuite/g++.dg/analyzer/noexcept-new.C
+++ b/gcc/testsuite/g++.dg/analyzer/noexcept-new.C
@@ -11,15 +11,15 @@ struct A
 
 void test_throwing ()
 {
-  int* x = new int;
+  int* x = new int; /* { dg-warning "dereference of possibly-NULL" } */
   int* y = new int(); /* { dg-warning "dereference of possibly-NULL" } */
-  int* arr = new int[10];
+  int* arr = new int[10]; /* { dg-warning "dereference of possibly-NULL" } */
   A *a = new A(); /* { dg-warning "dereference of possibly-NULL" } */
 
   int z = *y + 2;
-  z = *x + 4; /* { dg-warning "dereference of possibly-NULL 'x'" } */
+  z = *x + 4;
   /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 
} */
-  z = arr[0] + 4; /* { dg-warning "dereference of possibly-NULL 'arr'" } */
+  z = arr[0] + 4;
   /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } 
.-1 } */
   a->y = a->x + 3;
 
@@ -37,9 +37,9 @@ void test_nonthrowing ()
 
   int z = *y + 2; /* { dg-warning "dereference of NULL 'y'" } */
   /* { dg-bogus "use of uninitialized value '\\*y'" "" { target *-*-* } .-1 } 
*/
-  z = *x + 4; /* { dg-warning "dereference of possibly-NULL 'x'" } */
+  z = *x + 4; /* { dg-warning "dereference of NULL 'x'" } */
   /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 
} */
-  z = arr[0] + 4; /* { dg-warning "dereference of possibly-NULL 'arr'" } */
+  z = arr[0] + 4; /* { dg-warning "dereference of NULL 'arr'" } */
   /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } 
.-1 } */
 
   delete y;
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new4a.C 
b/gcc/testsuite/g++.dg/cpp26/constexpr-new4a.C
new file mode 100644
index 00000000000..d621293f3a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new4a.C
@@ -0,0 +1,21 @@
+// PR c++/121068
+// { dg-do compile { target c++26 } }
+
+constexpr void *operator new (__SIZE_TYPE__, void *p) { return p; }
+constexpr void *operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+consteval int
+foo(int n)
+{
+    using T = int;
+    union { T arr[3]; };
+    new(arr) T[n]; // makes arr active
+    for (int i = 0; i < 3; ++i)
+      arr[i].~T();
+
+    new (arr + 2) T{10}; // A
+
+    return 1;
+};
+
+constexpr int g = foo(3);
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-23.C 
b/gcc/testsuite/g++.dg/warn/Warray-bounds-23.C
index c43a7dea3ef..7f6a6395ac7 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-23.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-23.C
@@ -34,7 +34,7 @@ void test_D1_b0i ()
 {
   {
     D1 *p = (D1*)new char[sizeof (D1)];
-    p->b0i = __LINE__;
+    p->b0i = __LINE__;         // { dg-warning -Wuninitialized }
     sink (p);
   }
 
@@ -110,7 +110,7 @@ void test_D2_b0i ()
 {
   {
     D2 *p = (D2*)new char[sizeof (D2)];
-    p->b0i = __LINE__;
+    p->b0i = __LINE__;         // { dg-warning -Wuninitialized }
     sink (p);
   }
 
@@ -201,7 +201,7 @@ void test_D3_b0i ()
 {
   {
     D3 *p = (D3*)new char[sizeof (D3)];
-    p->b0i = __LINE__;
+    p->b0i = __LINE__;         // { dg-warning -Wuninitialized }
     sink (p);
   }
 
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-24.C 
b/gcc/testsuite/g++.dg/warn/Warray-bounds-24.C
index 071453a485d..068195ab1b0 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-24.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-24.C
@@ -34,7 +34,7 @@ void test_D1_b0a ()
 {
   {
     D1 *p = (D1*)new char[sizeof (D1)];
-    *p->b0a = __LINE__;                 // { dg-warning "-Warray-bounds" 
"pr99630" { xfail *-*-* } }
+    *p->b0a = __LINE__;                 // { dg-warning "-Wuninitialized" }
     sink (p);
   }
 
@@ -110,7 +110,7 @@ void test_D2_b0a ()
 {
   {
     D2 *p = (D2*)new char[sizeof (D2)];
-    *p->b0a = __LINE__;                 // { dg-warning "-Warray-bounds" 
"pr99630" { xfail *-*-* } }
+    *p->b0a = __LINE__;                 // { dg-warning "-Wuninitialized" }
     sink (p);
   }
 
@@ -201,7 +201,7 @@ void test_D3_b0a ()
 {
   {
     D3 *p = (D3*)new char[sizeof (D3)];
-    *p->b0a = __LINE__;                 // { dg-warning "-Warray-bounds" 
"pr99630" { xfail *-*-* } }
+    *p->b0a = __LINE__;                 // { dg-warning "-Wuninitialized" }
     sink (p);
   }
 

base-commit: f4b60fe6d6a16f54347af476e88d534f3666ea08
-- 
2.51.0

Reply via email to