constexpr.c (free_constructor): New.
authorJason Merrill <jason@redhat.com>
Mon, 10 Jun 2019 19:32:34 +0000 (15:32 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 10 Jun 2019 19:32:34 +0000 (15:32 -0400)
* constexpr.c (free_constructor): New.

(cxx_eval_call_expression): Free parameter value CONSTRUCTORs.

From-SVN: r272127

gcc/cp/ChangeLog
gcc/cp/constexpr.c

index 93d5f497400c5a29bd142151dc40fb3c8d0a3758..084e6239bcd922cccb37649017959214e8195ea0 100644 (file)
@@ -1,5 +1,8 @@
 2019-06-10  Jason Merrill  <jason@redhat.com>
 
+       * constexpr.c (free_constructor): New.
+       (cxx_eval_call_expression): Free parameter value CONSTRUCTORs.
+
        * constexpr.c (unshare_constructor): Only unshare if T is itself a
        CONSTRUCTOR.
        (cxx_eval_call_expression): Don't call it on the result here.
index d7adb469b45cdfb341ae54d1dd652e698f91c227..a2f29694462326495309d56440354d1feb30a1d4 100644 (file)
@@ -1350,6 +1350,30 @@ unshare_constructor (tree t)
   return t;
 }
 
+/* If T is a CONSTRUCTOR, ggc_free T and any sub-CONSTRUCTORs.  */
+
+static void
+free_constructor (tree t)
+{
+  if (!t || TREE_CODE (t) != CONSTRUCTOR)
+    return;
+  releasing_vec ctors;
+  vec_safe_push (ctors, t);
+  while (!ctors->is_empty ())
+    {
+      tree c = ctors->pop ();
+      if (vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (c))
+       {
+         constructor_elt *ce;
+         for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
+           if (TREE_CODE (ce->value) == CONSTRUCTOR)
+             vec_safe_push (ctors, ce->value);
+         ggc_free (elts);
+       }
+      ggc_free (c);
+    }
+}
+
 /* Subroutine of cxx_eval_call_expression.
    We are processing a call expression (either CALL_EXPR or
    AGGR_INIT_EXPR) in the context of CTX.  Evaluate
@@ -1398,7 +1422,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 
       if (!*non_constant_p)
        {
-         /* Don't share a CONSTRUCTOR that might be changed.  */
+         /* Unsharing here isn't necessary for correctness, but it
+            significantly improves memory performance for some reason.  */
          arg = unshare_constructor (arg);
          /* Make sure the binding has the same type as the parm.  But
             only for constant args.  */
@@ -1733,7 +1758,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
     void preserve () { do_free = false; }
     ~free_bindings () {
       if (do_free)
-       ggc_free (bindings);
+       {
+         for (int i = 0; i < TREE_VEC_LENGTH (bindings); ++i)
+           free_constructor (TREE_VEC_ELT (bindings, i));
+         ggc_free (bindings);
+       }
     }
   } fb (new_call.bindings);
 
@@ -1804,6 +1833,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       else
        {
          tree body, parms, res;
+         releasing_vec ctors;
 
          /* Reuse or create a new unshared copy of this function's body.  */
          tree copy = get_fundef_copy (new_call.fundef);
@@ -1819,6 +1849,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
              tree arg = TREE_VEC_ELT (bound, i);
              /* Don't share a CONSTRUCTOR that might be changed.  */
              arg = unshare_constructor (arg);
+             if (TREE_CODE (arg) == CONSTRUCTOR)
+               vec_safe_push (ctors, arg);
              ctx->values->put (remapped, arg);
              remapped = DECL_CHAIN (remapped);
            }
@@ -1884,6 +1916,14 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
          for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
            ctx->values->remove (parm);
 
+         /* Free any parameter CONSTRUCTORs we aren't returning directly.  */
+         while (!ctors->is_empty ())
+           {
+             tree c = ctors->pop ();
+             if (c != result)
+               free_constructor (c);
+           }
+
          /* Make the unshared function copy we used available for re-use.  */
          save_fundef_copy (fun, copy);
        }