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, since
trying to assign to a member of a virtual base reads the vptr of an object
that was never created.
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.
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);
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);
+}
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. */
+ /* Clobber the object now that 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. */
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
{
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;
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;
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;
--- /dev/null
+// 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);
{
{
D1 *p = (D1*)new char[sizeof (D1)];
- p->b0i = __LINE__;
+ p->b0i = __LINE__; // { dg-warning -Wuninitialized }
sink (p);
}
{
{
D2 *p = (D2*)new char[sizeof (D2)];
- p->b0i = __LINE__;
+ p->b0i = __LINE__; // { dg-warning -Wuninitialized }
sink (p);
}
{
{
D3 *p = (D3*)new char[sizeof (D3)];
- p->b0i = __LINE__;
+ p->b0i = __LINE__; // { dg-warning -Wuninitialized }
sink (p);
}
{
{
D1 *p = (D1*)new char[sizeof (D1)];
- *p->b0a = __LINE__; // { dg-warning "-Warray-bounds" "pr99630" { xfail *-*-* } }
+ *p->b0a = __LINE__; // { dg-warning "-Wuninitialized" }
sink (p);
}
{
{
D2 *p = (D2*)new char[sizeof (D2)];
- *p->b0a = __LINE__; // { dg-warning "-Warray-bounds" "pr99630" { xfail *-*-* } }
+ *p->b0a = __LINE__; // { dg-warning "-Wuninitialized" }
sink (p);
}
{
{
D3 *p = (D3*)new char[sizeof (D3)];
- *p->b0a = __LINE__; // { dg-warning "-Warray-bounds" "pr99630" { xfail *-*-* } }
+ *p->b0a = __LINE__; // { dg-warning "-Wuninitialized" }
sink (p);
}