On 03/04/2014 05:14 PM, Jason Merrill wrote:
In C++11, copy-list-initialization by explicit constructor is an error, even for the default constructor. But this combined with the change of aggregate initialization to use {} for any missing initializers means that well-formed C++03 code becomes ill-formed in C++11. Until the committee decides what to do about this, let's call the implicit initializers direct-initialization.
...and for array initialization as well. Tested x86_64-pc-linux-gnu, applying to trunk.
commit ef09581840cc49d85599a2a9f2c855d8c8b60d9f Author: Jason Merrill <ja...@redhat.com> Date: Fri Aug 1 16:13:54 2014 -0400 PR c++/60417 * init.c (build_vec_init): Set CONSTRUCTOR_IS_DIRECT_INIT on init-list for trailing elements. * typeck2.c (process_init_constructor_array): Likewise. diff --git a/gcc/cp/init.c b/gcc/cp/init.c index f8cae28..eeee5bb3 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3545,19 +3545,11 @@ build_vec_init (tree base, tree maxindex, tree init, try_block = begin_try_block (); } - /* If the initializer is {}, then all elements are initialized from {}. - But for non-classes, that's the same as value-initialization. */ + bool empty_list = false; if (init && BRACE_ENCLOSED_INITIALIZER_P (init) && CONSTRUCTOR_NELTS (init) == 0) - { - if (CLASS_TYPE_P (type)) - /* Leave init alone. */; - else - { - init = NULL_TREE; - explicit_value_init_p = true; - } - } + /* Skip over the handling of non-empty init lists. */ + empty_list = true; /* Maybe pull out constant value when from_array? */ @@ -3677,14 +3669,8 @@ build_vec_init (tree base, tree maxindex, tree init, vec_free (new_vec); } - /* Any elements without explicit initializers get {}. */ - if (cxx_dialect >= cxx11 && AGGREGATE_TYPE_P (type)) - init = build_constructor (init_list_type_node, NULL); - else - { - init = NULL_TREE; - explicit_value_init_p = true; - } + /* Any elements without explicit initializers get T{}. */ + empty_list = true; } else if (from_array) { @@ -3699,6 +3685,26 @@ build_vec_init (tree base, tree maxindex, tree init, } } + /* If the initializer is {}, then all elements are initialized from T{}. + But for non-classes, that's the same as value-initialization. */ + if (empty_list) + { + if (cxx_dialect >= cxx11 && AGGREGATE_TYPE_P (type)) + { + if (BRACE_ENCLOSED_INITIALIZER_P (init) + && CONSTRUCTOR_NELTS (init) == 0) + /* Reuse it. */; + else + init = build_constructor (init_list_type_node, NULL); + CONSTRUCTOR_IS_DIRECT_INIT (init) = true; + } + else + { + init = NULL_TREE; + explicit_value_init_p = true; + } + } + /* Now, default-initialize any remaining elements. We don't need to do that if a) the type does not need constructing, or b) we've already initialized all the elements. diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 59a4760..20523fa 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1239,8 +1239,9 @@ process_init_constructor_array (tree type, tree init, { /* If this type needs constructors run for default-initialization, we can't rely on the back end to do it for us, so make the - initialization explicit by list-initializing from {}. */ + initialization explicit by list-initializing from T{}. */ next = build_constructor (init_list_type_node, NULL); + CONSTRUCTOR_IS_DIRECT_INIT (next) = true; next = massage_init_elt (TREE_TYPE (type), next, complain); if (initializer_zerop (next)) /* The default zero-initialization is fine for us; don't diff --git a/gcc/testsuite/g++.dg/init/explicit2.C b/gcc/testsuite/g++.dg/init/explicit2.C new file mode 100644 index 0000000..d1dbb39 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/explicit2.C @@ -0,0 +1,8 @@ +// PR c++/60417 + +struct A { explicit A(int = 0); }; + +int main() +{ + A a[1] = { }; +}