diff mbox

C++ PATCH for c++/57510 (memory leak with initializer_list)

Message ID 548A580D.2000806@redhat.com
State New
Headers show

Commit Message

Jason Merrill Dec. 12, 2014, 2:50 a.m. UTC
We want to deal with initialization of an array reference/init-list 
temporary the same way that we handle initialization of an array variable.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit ad88fa39b2c68d806b58563dfe1e19ecf8d143ba
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Dec 10 14:14:05 2014 -0500

    	PR c++/57510
    	* typeck2.c (split_nonconstant_init_1): Handle arrays here.
    	(store_init_value): Not here.
    	(split_nonconstant_init): Look through TARGET_EXPR.  No longer static.
    	* cp-tree.h: Declare split_nonconstant_init.
    	* call.c (set_up_extended_ref_temp): Use split_nonconstant_init.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d8075bd..312dfdf 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -9574,7 +9574,7 @@  set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
   else
     /* Create the INIT_EXPR that will initialize the temporary
        variable.  */
-    init = build2 (INIT_EXPR, type, var, expr);
+    init = split_nonconstant_init (var, expr);
   if (at_function_scope_p ())
     {
       add_decl_expr (var);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d41a834..ad1cc71 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6291,6 +6291,7 @@  extern int abstract_virtuals_error_sfinae	(tree, tree, tsubst_flags_t);
 extern int abstract_virtuals_error_sfinae	(abstract_class_use, tree, tsubst_flags_t);
 
 extern tree store_init_value			(tree, tree, vec<tree, va_gc>**, int);
+extern tree split_nonconstant_init		(tree, tree);
 extern bool check_narrowing			(tree, tree, tsubst_flags_t);
 extern tree digest_init				(tree, tree, tsubst_flags_t);
 extern tree digest_init_flags			(tree, tree, int);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 92c0417..c53a9b5 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -604,6 +604,17 @@  split_nonconstant_init_1 (tree dest, tree init)
     case ARRAY_TYPE:
       inner_type = TREE_TYPE (type);
       array_type_p = true;
+      if ((TREE_SIDE_EFFECTS (init)
+	   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+	  || array_of_runtime_bound_p (type))
+	{
+	  /* For an array, we only need/want a single cleanup region rather
+	     than one per element.  */
+	  tree code = build_vec_init (dest, NULL_TREE, init, false, 1,
+				      tf_warning_or_error);
+	  add_stmt (code);
+	  return true;
+	}
       /* FALLTHRU */
 
     case RECORD_TYPE:
@@ -721,11 +732,13 @@  split_nonconstant_init_1 (tree dest, tree init)
    perform the non-constant part of the initialization to DEST.
    Returns the code for the runtime init.  */
 
-static tree
+tree
 split_nonconstant_init (tree dest, tree init)
 {
   tree code;
 
+  if (TREE_CODE (init) == TARGET_EXPR)
+    init = TARGET_EXPR_INITIAL (init);
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
       code = push_stmt_list ();
@@ -830,17 +843,7 @@  store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       && (TREE_SIDE_EFFECTS (value)
 	  || array_of_runtime_bound_p (type)
 	  || ! reduced_constant_expression_p (value)))
-    {
-      if (TREE_CODE (type) == ARRAY_TYPE
-	  && (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))
-	      || array_of_runtime_bound_p (type)))
-	/* For an array, we only need/want a single cleanup region rather
-	   than one per element.  */
-	return build_vec_init (decl, NULL_TREE, value, false, 1,
-			       tf_warning_or_error);
-      else
-	return split_nonconstant_init (decl, value);
-    }
+    return split_nonconstant_init (decl, value);
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL
      is an automatic variable, the middle end will turn this into a
      dynamic initialization later.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist90.C b/gcc/testsuite/g++.dg/cpp0x/initlist90.C
new file mode 100644
index 0000000..330517a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist90.C
@@ -0,0 +1,35 @@ 
+// PR c++/57510
+// { dg-do run { target c++11 } }
+
+#include <initializer_list>
+
+struct counter
+{
+  static int n;
+
+  counter() { ++n; }
+  counter(const counter&) { ++n; }
+  ~counter() { --n; }
+};
+
+int counter::n = 0;
+
+struct X
+{
+    X () { if (counter::n > 1) throw 1; }
+
+    counter c;
+};
+
+int main ()
+{
+  try
+  {
+    auto x = { X{}, X{} };
+  }
+  catch (...)
+  {
+    if ( counter::n != 0 )
+      throw;
+  }
+}