re PR c++/91369 (Implement P0784R7: constexpr new)
authorJakub Jelinek <jakub@redhat.com>
Tue, 3 Dec 2019 19:27:47 +0000 (20:27 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 3 Dec 2019 19:27:47 +0000 (20:27 +0100)
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

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C [new file with mode: 0644]

index c29da7bed798f39c317502fe2fc3693c75a0e9f5..02c730eb1d9113224808fb1e61131bb4d15501e6 100644 (file)
@@ -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.
index 39118200285c67c892a05fc0e1ebfa841abef7ed..5afcc876e7643360dec9e03da655f529a1d471e4 100644 (file)
@@ -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.  */
index 39e8ace59f7981f19ac3e9fdae3a835b13452cb3..ec32c210d59c195308a3c26f5efc3143790535bf 100644 (file)
@@ -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.
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new8.C
new file mode 100644 (file)
index 0000000..c9c852d
--- /dev/null
@@ -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);