From: Jakub Jelinek Date: Tue, 3 Dec 2019 19:27:47 +0000 (+0100) Subject: re PR c++/91369 (Implement P0784R7: constexpr new) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ee1de08d4d22648cf3168caa60e283135755da85;p=gcc.git 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) : 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. : Save outer cleanups, set cleanups to local auto_vec, after evaluating the body evaluate cleanups and restore previous cleanups. : 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c29da7bed79..02c730eb1d9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2019-12-03 Jakub Jelinek + + PR c++/91369 + * constexpr.c (struct constexpr_global_ctx): Add cleanups member, + initialize it in the ctor. + (cxx_eval_constant_expression) : 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. + : Save outer cleanups, set cleanups to + local auto_vec, after evaluating the body evaluate cleanups and + restore previous cleanups. + : 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 PR c++/91363 - P0960R3: Parenthesized initialization of aggregates. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 39118200285..5afcc876e76 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1025,8 +1025,10 @@ struct constexpr_global_ctx { /* Heap VAR_DECLs created during the evaluation of the outermost constant expression. */ auto_vec heap_vars; + /* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */ + vec *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 *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 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 cleanups; + vec *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 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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 39e8ace59f7..ec32c210d59 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-12-03 Jakub Jelinek + + PR c++/91369 + * g++.dg/cpp2a/constexpr-new8.C: New test. + 2019-12-03 Richard Sandiford * gcc.target/aarch64/sve/acle/general-c/struct_1.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C new file mode 100644 index 00000000000..c9c852dfc37 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C @@ -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);