mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-10 05:50:28 +08:00
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
This commit is contained in:
parent
21cd858929
commit
ee1de08d4d
@ -1,3 +1,20 @@
|
||||
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>
|
||||
|
||||
PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
|
||||
|
@ -1025,8 +1025,10 @@ struct constexpr_global_ctx {
|
||||
/* Heap VAR_DECLs created during the evaluation of the outermost constant
|
||||
expression. */
|
||||
auto_vec<tree, 16> heap_vars;
|
||||
/* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */
|
||||
vec<tree> *cleanups;
|
||||
/* 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
|
||||
@ -1039,8 +1041,8 @@ struct constexpr_ctx {
|
||||
constexpr_global_ctx *global;
|
||||
/* The innermost call we're evaluating. */
|
||||
constexpr_call *call;
|
||||
/* SAVE_EXPRs that we've seen within the current LOOP_EXPR. NULL if we
|
||||
aren't inside a loop. */
|
||||
/* SAVE_EXPRs and TARGET_EXPR_SLOT vars of TARGET_EXPRs that we've seen
|
||||
within the current LOOP_EXPR. NULL if we aren't inside a loop. */
|
||||
vec<tree> *save_exprs;
|
||||
/* The CONSTRUCTOR we're currently building up for an aggregate
|
||||
initializer. */
|
||||
@ -2085,8 +2087,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
|
||||
else
|
||||
ctx->global->values.put (res, NULL_TREE);
|
||||
|
||||
/* Track the callee's evaluated SAVE_EXPRs so that we can forget
|
||||
their values after the call. */
|
||||
/* Track the callee's evaluated SAVE_EXPRs and TARGET_EXPRs so that
|
||||
we can forget their values after the call. */
|
||||
constexpr_ctx ctx_with_save_exprs = *ctx;
|
||||
auto_vec<tree, 10> save_exprs;
|
||||
ctx_with_save_exprs.save_exprs = &save_exprs;
|
||||
@ -2135,7 +2137,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
|
||||
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;
|
||||
tree 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,
|
||||
gcc_assert (*jump_target);
|
||||
}
|
||||
|
||||
/* Forget saved values of SAVE_EXPRs. */
|
||||
/* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */
|
||||
unsigned int i;
|
||||
tree 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,
|
||||
&& (!switches (jump_target) || count == 0)
|
||||
&& !*non_constant_p);
|
||||
|
||||
/* Forget saved values of SAVE_EXPRs. */
|
||||
/* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */
|
||||
unsigned int i;
|
||||
tree 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,
|
||||
*non_constant_p = true;
|
||||
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))))
|
||||
{
|
||||
/* We're being expanded without an explicit target, so start
|
||||
@ -5024,13 +5035,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
||||
if (!*non_constant_p)
|
||||
/* Adjust the type of the result to the type of the temporary. */
|
||||
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)
|
||||
{
|
||||
tree slot = TARGET_EXPR_SLOT (t);
|
||||
r = unshare_constructor (r);
|
||||
ctx->global->values.put (slot, r);
|
||||
return slot;
|
||||
}
|
||||
return TARGET_EXPR_SLOT (t);
|
||||
break;
|
||||
|
||||
case INIT_EXPR:
|
||||
@ -5080,10 +5092,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
||||
}
|
||||
break;
|
||||
|
||||
case NON_LVALUE_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 CLEANUP_POINT_EXPR:
|
||||
case MUST_NOT_THROW_EXPR:
|
||||
case EXPR_STMT:
|
||||
case EH_SPEC_BLOCK:
|
||||
@ -5093,6 +5110,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
||||
jump_target);
|
||||
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:
|
||||
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
|
||||
non_constant_p, overflow_p,
|
||||
@ -5903,6 +5940,9 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
|
||||
r = TARGET_EXPR_INITIAL (r);
|
||||
}
|
||||
|
||||
auto_vec<tree, 16> cleanups;
|
||||
global_ctx.cleanups = &cleanups;
|
||||
|
||||
instantiate_constexpr_fns (r);
|
||||
r = cxx_eval_constant_expression (&ctx, r,
|
||||
false, &non_constant_p, &overflow_p);
|
||||
@ -5912,6 +5952,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
|
||||
else
|
||||
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
|
||||
constexpr variables with mutable members, but we can't copy those
|
||||
members to another constexpr variable. */
|
||||
|
@ -1,3 +1,8 @@
|
||||
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>
|
||||
|
||||
* gcc.target/aarch64/sve/acle/general-c/struct_1.c: New test.
|
||||
|
18
gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C
Normal file
18
gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C
Normal file
@ -0,0 +1,18 @@
|
||||
// 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);
|
Loading…
x
Reference in New Issue
Block a user