On Thu, Jul 28, 2016 at 2:56 AM, Markus Trippelsdorf <mar...@trippelsdorf.de> wrote: > On 2016.07.27 at 17:21 -0400, Jason Merrill wrote: >> On Wed, Jul 27, 2016 at 2:50 AM, Markus Trippelsdorf >> <mar...@trippelsdorf.de> wrote: >> > On 2016.07.23 at 22:55 -0400, Jason Merrill wrote: >> >> Using build_value_init in a base initialization is wrong, because it >> >> calls the complete object constructor and misses protected access. So >> >> let's handle list-value-initialization in expand_aggr_init_1. >> >> >> >> Tested x86_64-pc-linux-gnu, applying to trunk. >> > >> > This patch causes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72457. >> > And because it was backported, the gcc-6 branch is also affected. >> > >> > The following fix was tested on ppc64le. OK for trunk and gcc-6? >> > >> > (Unfortunately the reduced testcase is much too big.) >> > >> > PR c++/72457 >> > *constexpr.c (cx_check_missing_mem_inits): Handle potential >> > NULL_TREE. >> > >> > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c >> > index 6bcb41ae8254..83fd9a4896ac 100644 >> > --- a/gcc/cp/constexpr.c >> > +++ b/gcc/cp/constexpr.c >> > @@ -734,7 +734,7 @@ cx_check_missing_mem_inits (tree fun, tree body, bool >> > complain) >> > || DECL_ARTIFICIAL (index)) >> > continue; >> > } >> > - for (; field != index; field = DECL_CHAIN (field)) >> > + for (; field != NULL_TREE && field != index; field = DECL_CHAIN >> > (field)) >> >> This is wrong; it ends up just skipping over the rest of the fields, >> so we don't check whether they were initialized. Rather, we need to >> handle seeing two initializers in a row for the same field. > > OK. I will let you handle this issue.
This patch fixes the issue in two ways: 1) Avoid adding multiple initializers for the same field when it's initialized twice. 2) Limiting the earlier change to base initialization. Tested x86_64-pc-linux-gnu, applying to trunk and 6.
commit 41bc8ce29bc87e0a1a21cefe4bf9ed41f781d484 Author: Jason Merrill <ja...@redhat.com> Date: Thu Jul 28 17:41:44 2016 -0400 PR c++/72457 - ICE with list-value-initialized base. * init.c (expand_aggr_init_1): Only handle value-init of bases. * constexpr.c (build_data_member_initialization): Handle multiple initializers for the same field. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 6bcb41a..5871689 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -391,7 +391,12 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec) gcc_assert (TREE_TYPE (member) == vtbl_ptr_type_node); } - CONSTRUCTOR_APPEND_ELT (*vec, member, init); + /* Value-initialization can produce multiple initializers for the + same field; use the last one. */ + if (!vec_safe_is_empty (*vec) && (*vec)->last().index == member) + (*vec)->last().value = init; + else + CONSTRUCTOR_APPEND_ELT (*vec, member, init); return true; } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 6362263..1a5766a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1818,9 +1818,9 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, } /* List-initialization from {} becomes value-initialization for non-aggregate - classes with default constructors. Handle this here so protected access - works. */ - if (init && TREE_CODE (init) == TREE_LIST) + classes with default constructors. Handle this here when we're + initializing a base, so protected access works. */ + if (exp != true_exp && init && TREE_CODE (init) == TREE_LIST) { tree elt = TREE_VALUE (init); if (DIRECT_LIST_INIT_P (elt) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-list1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-list1.C new file mode 100644 index 0000000..f831a11 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-list1.C @@ -0,0 +1,15 @@ +// PR c++/72457 +// { dg-do compile { target c++11 } } + +struct A { + int i; + constexpr A(): i(0) {} +}; + +struct B: A { }; + +struct C +{ + B b; + constexpr C() : b{} {} +};