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.
commit ad88fa39b2c68d806b58563dfe1e19ecf8d143ba
Author: Jason Merrill <ja...@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;
+ }
+}