Commit ee1de08d 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 cleanups member,
	initialize it in the ctor.
	(cxx_eval_constant_expression) <case TARGET_EXPR>: If TARGET_EXPR_SLOT
	is already in the values hash_map, don't evaluate it again.  Put
	TARGET_EXPR_SLOT into hash_map even if not lval, and push it into
	save_exprs too.  If there is TARGET_EXPR_CLEANUP and not
	CLEANUP_EH_ONLY, push the cleanup to cleanups vector.
	<case CLEANUP_POINT_EXPR>: Save outer cleanups, set cleanups to
	local auto_vec, after evaluating the body evaluate cleanups and
	restore previous cleanups.
	<case TRY_CATCH_EXPR>: Don't crash if the first operand is NULL_TREE.
	(cxx_eval_outermost_constant_expr): Set cleanups to local auto_vec,
	after evaluating the expression evaluate cleanups.

	* g++.dg/cpp2a/constexpr-new8.C: New test.

From-SVN: r278945
parent 21cd8589
2019-12-03 Jakub Jelinek <jakub@redhat.com>
PR c++/91369
* constexpr.c (struct constexpr_global_ctx): Add cleanups member,
initialize it in the ctor.
(cxx_eval_constant_expression) <case TARGET_EXPR>: If TARGET_EXPR_SLOT
is already in the values hash_map, don't evaluate it again. Put
TARGET_EXPR_SLOT into hash_map even if not lval, and push it into
save_exprs too. If there is TARGET_EXPR_CLEANUP and not
CLEANUP_EH_ONLY, push the cleanup to cleanups vector.
<case CLEANUP_POINT_EXPR>: Save outer cleanups, set cleanups to
local auto_vec, after evaluating the body evaluate cleanups and
restore previous cleanups.
<case TRY_CATCH_EXPR>: Don't crash if the first operand is NULL_TREE.
(cxx_eval_outermost_constant_expr): Set cleanups to local auto_vec,
after evaluating the expression evaluate cleanups.
2019-12-03 Marek Polacek <polacek@redhat.com> 2019-12-03 Marek Polacek <polacek@redhat.com>
PR c++/91363 - P0960R3: Parenthesized initialization of aggregates. PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
......
...@@ -1025,8 +1025,10 @@ struct constexpr_global_ctx { ...@@ -1025,8 +1025,10 @@ struct constexpr_global_ctx {
/* Heap VAR_DECLs created during the evaluation of the outermost constant /* Heap VAR_DECLs created during the evaluation of the outermost constant
expression. */ expression. */
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. */
vec<tree> *cleanups;
/* Constructor. */ /* Constructor. */
constexpr_global_ctx () : constexpr_ops_count (0) {} constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL) {}
}; };
/* The constexpr expansion context. CALL is the current function /* The constexpr expansion context. CALL is the current function
...@@ -1039,8 +1041,8 @@ struct constexpr_ctx { ...@@ -1039,8 +1041,8 @@ struct constexpr_ctx {
constexpr_global_ctx *global; constexpr_global_ctx *global;
/* The innermost call we're evaluating. */ /* The innermost call we're evaluating. */
constexpr_call *call; constexpr_call *call;
/* SAVE_EXPRs that we've seen within the current LOOP_EXPR. NULL if we /* SAVE_EXPRs and TARGET_EXPR_SLOT vars of TARGET_EXPRs that we've seen
aren't inside a loop. */ within the current LOOP_EXPR. NULL if we aren't inside a loop. */
vec<tree> *save_exprs; vec<tree> *save_exprs;
/* The CONSTRUCTOR we're currently building up for an aggregate /* The CONSTRUCTOR we're currently building up for an aggregate
initializer. */ initializer. */
...@@ -2085,8 +2087,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2085,8 +2087,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
else else
ctx->global->values.put (res, NULL_TREE); ctx->global->values.put (res, NULL_TREE);
/* Track the callee's evaluated SAVE_EXPRs so that we can forget /* Track the callee's evaluated SAVE_EXPRs and TARGET_EXPRs so that
their values after the call. */ we can forget their values after the call. */
constexpr_ctx ctx_with_save_exprs = *ctx; constexpr_ctx ctx_with_save_exprs = *ctx;
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;
...@@ -2135,7 +2137,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -2135,7 +2137,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
TREE_READONLY (e) = true; TREE_READONLY (e) = true;
} }
/* Forget the saved values of the callee's SAVE_EXPRs. */ /* Forget the saved values of the callee's SAVE_EXPRs and
TARGET_EXPRs. */
unsigned int i; unsigned int i;
tree save_expr; tree save_expr;
FOR_EACH_VEC_ELT (save_exprs, i, save_expr) FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
...@@ -4635,7 +4638,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, ...@@ -4635,7 +4638,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
gcc_assert (*jump_target); gcc_assert (*jump_target);
} }
/* Forget saved values of SAVE_EXPRs. */ /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */
unsigned int i; unsigned int i;
tree save_expr; tree save_expr;
FOR_EACH_VEC_ELT (save_exprs, i, save_expr) FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
...@@ -4659,7 +4662,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, ...@@ -4659,7 +4662,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
&& (!switches (jump_target) || count == 0) && (!switches (jump_target) || count == 0)
&& !*non_constant_p); && !*non_constant_p);
/* Forget saved values of SAVE_EXPRs. */ /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */
unsigned int i; unsigned int i;
tree save_expr; tree save_expr;
FOR_EACH_VEC_ELT (save_exprs, i, save_expr) FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
...@@ -5004,6 +5007,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -5004,6 +5007,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true; *non_constant_p = true;
break; break;
} }
/* Avoid evaluating a TARGET_EXPR more than once. */
if (tree *p = ctx->global->values.get (TARGET_EXPR_SLOT (t)))
{
if (lval)
return TARGET_EXPR_SLOT (t);
r = *p;
break;
}
if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t)))) if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t))))
{ {
/* We're being expanded without an explicit target, so start /* We're being expanded without an explicit target, so start
...@@ -5024,13 +5035,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -5024,13 +5035,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (!*non_constant_p) if (!*non_constant_p)
/* Adjust the type of the result to the type of the temporary. */ /* Adjust the type of the result to the type of the temporary. */
r = adjust_temp_type (TREE_TYPE (t), r); r = adjust_temp_type (TREE_TYPE (t), r);
if (TARGET_EXPR_CLEANUP (t) && !CLEANUP_EH_ONLY (t))
ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t));
r = unshare_constructor (r);
ctx->global->values.put (TARGET_EXPR_SLOT (t), r);
if (ctx->save_exprs)
ctx->save_exprs->safe_push (TARGET_EXPR_SLOT (t));
if (lval) if (lval)
{ return TARGET_EXPR_SLOT (t);
tree slot = TARGET_EXPR_SLOT (t);
r = unshare_constructor (r);
ctx->global->values.put (slot, r);
return slot;
}
break; break;
case INIT_EXPR: case INIT_EXPR:
...@@ -5080,10 +5092,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -5080,10 +5092,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
} }
break; break;
case NON_LVALUE_EXPR:
case TRY_CATCH_EXPR: case TRY_CATCH_EXPR:
if (TREE_OPERAND (t, 0) == NULL_TREE)
{
r = void_node;
break;
}
/* FALLTHRU */
case NON_LVALUE_EXPR:
case TRY_BLOCK: case TRY_BLOCK:
case CLEANUP_POINT_EXPR:
case MUST_NOT_THROW_EXPR: case MUST_NOT_THROW_EXPR:
case EXPR_STMT: case EXPR_STMT:
case EH_SPEC_BLOCK: case EH_SPEC_BLOCK:
...@@ -5093,6 +5110,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -5093,6 +5110,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
jump_target); jump_target);
break; break;
case CLEANUP_POINT_EXPR:
{
auto_vec<tree, 2> cleanups;
vec<tree> *prev_cleanups = ctx->global->cleanups;
ctx->global->cleanups = &cleanups;
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
lval,
non_constant_p, overflow_p,
jump_target);
ctx->global->cleanups = prev_cleanups;
unsigned int i;
tree cleanup;
/* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
cxx_eval_constant_expression (ctx, cleanup, false,
non_constant_p, overflow_p,
jump_target);
}
break;
case TRY_FINALLY_EXPR: case TRY_FINALLY_EXPR:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
non_constant_p, overflow_p, non_constant_p, overflow_p,
...@@ -5903,6 +5940,9 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, ...@@ -5903,6 +5940,9 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
r = TARGET_EXPR_INITIAL (r); r = TARGET_EXPR_INITIAL (r);
} }
auto_vec<tree, 16> cleanups;
global_ctx.cleanups = &cleanups;
instantiate_constexpr_fns (r); instantiate_constexpr_fns (r);
r = cxx_eval_constant_expression (&ctx, r, r = cxx_eval_constant_expression (&ctx, r,
false, &non_constant_p, &overflow_p); false, &non_constant_p, &overflow_p);
...@@ -5912,6 +5952,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, ...@@ -5912,6 +5952,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
else else
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
unsigned int i;
tree cleanup;
/* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
cxx_eval_constant_expression (&ctx, cleanup, false,
&non_constant_p, &overflow_p);
/* Mutable logic is a bit tricky: we want to allow initialization of /* Mutable logic is a bit tricky: we want to allow initialization of
constexpr variables with mutable members, but we can't copy those constexpr variables with mutable members, but we can't copy those
members to another constexpr variable. */ members to another constexpr variable. */
......
2019-12-03 Jakub Jelinek <jakub@redhat.com>
PR c++/91369
* g++.dg/cpp2a/constexpr-new8.C: New test.
2019-12-03 Richard Sandiford <richard.sandiford@arm.com> 2019-12-03 Richard Sandiford <richard.sandiford@arm.com>
* gcc.target/aarch64/sve/acle/general-c/struct_1.c: New test. * gcc.target/aarch64/sve/acle/general-c/struct_1.c: New test.
......
// PR c++/91369
// { dg-do compile { target c++2a } }
struct A {
constexpr A () : p{new int} {}
constexpr ~A () { delete p; }
int *p;
};
constexpr bool
test ()
{
A{};
return true;
}
constexpr auto res = test ();
static_assert (res);
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