mirror of git://gcc.gnu.org/git/gcc.git
c++: clobber non-placement new
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.
This commit is contained in:
parent
d52a81fdb3
commit
d77b548fb6
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
/* 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. */
|
||||
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue