Commit f74f6092 by Jakub Jelinek Committed by Jakub Jelinek

re PR c++/91369 (Implement P0784R7: constexpr new)

	PR c++/91369
	* constexpr.c (struct constexpr_global_ctx): Add heap_alloc_count
	member, initialize it to zero in ctor.
	(cxx_eval_call_expression): Bump heap_dealloc_count when deleting
	a heap object.  Don't cache calls to functions which allocate some
	heap objects and don't deallocate them or deallocate some heap
	objects they didn't allocate.

	* g++.dg/cpp1y/constexpr-new.C: Expect an error explaining why
	static_assert failed for C++2a.
	* g++.dg/cpp2a/constexpr-new9.C: New test.

From-SVN: r279943
parent 6ac22177
2020-01-07 Jakub Jelinek <jakub@redhat.com>
PR c++/91369
* constexpr.c (struct constexpr_global_ctx): Add heap_alloc_count
member, initialize it to zero in ctor.
(cxx_eval_call_expression): Bump heap_dealloc_count when deleting
a heap object. Don't cache calls to functions which allocate some
heap objects and don't deallocate them or deallocate some heap
objects they didn't allocate.
2020-01-06 Jason Merrill <jason@redhat.com> 2020-01-06 Jason Merrill <jason@redhat.com>
PR c++/92552 - ICE with inherited constrained default ctor. PR c++/92552 - ICE with inherited constrained default ctor.
......
...@@ -1041,8 +1041,11 @@ struct constexpr_global_ctx { ...@@ -1041,8 +1041,11 @@ struct constexpr_global_ctx {
auto_vec<tree, 16> heap_vars; auto_vec<tree, 16> heap_vars;
/* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */ /* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */
vec<tree> *cleanups; vec<tree> *cleanups;
/* Number of heap VAR_DECL deallocations. */
unsigned heap_dealloc_count;
/* Constructor. */ /* Constructor. */
constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL) {} constexpr_global_ctx ()
: constexpr_ops_count (0), cleanups (NULL), heap_dealloc_count (0) {}
}; };
/* The constexpr expansion context. CALL is the current function /* The constexpr expansion context. CALL is the current function
...@@ -2056,6 +2059,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2056,6 +2059,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{ {
DECL_NAME (var) = heap_deleted_identifier; DECL_NAME (var) = heap_deleted_identifier;
ctx->global->values.remove (var); ctx->global->values.remove (var);
ctx->global->heap_dealloc_count++;
return void_node; return void_node;
} }
else if (DECL_NAME (var) == heap_deleted_identifier) else if (DECL_NAME (var) == heap_deleted_identifier)
...@@ -2281,6 +2285,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2281,6 +2285,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
} }
else else
{ {
bool cacheable = true;
if (result && result != error_mark_node) if (result && result != error_mark_node)
/* OK */; /* OK */;
else if (!DECL_SAVED_TREE (fun)) else if (!DECL_SAVED_TREE (fun))
...@@ -2346,6 +2351,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2346,6 +2351,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
auto_vec<tree, 10> save_exprs; auto_vec<tree, 10> save_exprs;
ctx_with_save_exprs.save_exprs = &save_exprs; ctx_with_save_exprs.save_exprs = &save_exprs;
ctx_with_save_exprs.call = &new_call; ctx_with_save_exprs.call = &new_call;
unsigned save_heap_alloc_count = ctx->global->heap_vars.length ();
unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count;
tree jump_target = NULL_TREE; tree jump_target = NULL_TREE;
cxx_eval_constant_expression (&ctx_with_save_exprs, body, cxx_eval_constant_expression (&ctx_with_save_exprs, body,
...@@ -2417,6 +2424,33 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2417,6 +2424,33 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
/* Make the unshared function copy we used available for re-use. */ /* Make the unshared function copy we used available for re-use. */
save_fundef_copy (fun, copy); save_fundef_copy (fun, copy);
/* If the call allocated some heap object that hasn't been
deallocated during the call, or if it deallocated some heap
object it has not allocated, the call isn't really stateless
for the constexpr evaluation and should not be cached.
It is fine if the call allocates something and deallocates it
too. */
if (entry
&& (save_heap_alloc_count != ctx->global->heap_vars.length ()
|| (save_heap_dealloc_count
!= ctx->global->heap_dealloc_count)))
{
tree heap_var;
unsigned int i;
if ((ctx->global->heap_vars.length ()
- ctx->global->heap_dealloc_count)
!= save_heap_alloc_count - save_heap_dealloc_count)
cacheable = false;
else
FOR_EACH_VEC_ELT_FROM (ctx->global->heap_vars, i, heap_var,
save_heap_alloc_count)
if (DECL_NAME (heap_var) != heap_deleted_identifier)
{
cacheable = false;
break;
}
}
} }
if (result == error_mark_node) if (result == error_mark_node)
...@@ -2426,7 +2460,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2426,7 +2460,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
else if (!result) else if (!result)
result = void_node; result = void_node;
if (entry) if (entry)
entry->result = result; entry->result = cacheable ? result : error_mark_node;
} }
/* The result of a constexpr function must be completely initialized. /* The result of a constexpr function must be completely initialized.
......
2020-01-07 Jakub Jelinek <jakub@redhat.com>
PR c++/91369
* g++.dg/cpp1y/constexpr-new.C: Expect an error explaining why
static_assert failed for C++2a.
* g++.dg/cpp2a/constexpr-new9.C: New test.
2020-01-06 Richard Sandiford <richard.sandiford@arm.com> 2020-01-06 Richard Sandiford <richard.sandiford@arm.com>
* gcc.target/aarch64/sve/asrdiv_1.c: Remove trailing %s. * gcc.target/aarch64/sve/asrdiv_1.c: Remove trailing %s.
......
...@@ -5,7 +5,7 @@ constexpr int *f4(bool b) { ...@@ -5,7 +5,7 @@ constexpr int *f4(bool b) {
return nullptr; return nullptr;
} else { } else {
return new int{42}; // { dg-error "call to non-.constexpr." "" { target c++17_down } } return new int{42}; // { dg-error "call to non-.constexpr." "" { target c++17_down } }
} } // { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target c++2a } .-1 }
} }
static_assert(f4(true) == nullptr, ""); static_assert(f4(true) == nullptr, "");
static_assert(f4(false) == nullptr, ""); // { dg-error "non-.constant. condition|" } static_assert(f4(false) == nullptr, ""); // { dg-error "non-.constant. condition|" }
// PR c++/91369
// { dg-do compile { target c++2a } }
struct S {
constexpr S (int *i) : i{i} {}
constexpr ~S () { delete[] i; }
int *i;
};
constexpr S foo (int x) { return { new int[x] () }; }
constexpr bool bar () { foo (1); return true; }
constexpr bool baz () { foo (1); return false; }
static_assert (bar ());
static_assert (!baz ());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment