My recent patch for 88815 and 78244 caused 89083, a P1 9 regression, which happens to be the same problem as 80864 and its many dupes, something I'd been meaning to fix for a long time.
Basically, the problem is repeated reshaping of a constructor, once when parsing, and then again when substituting. With the recent fix, we call reshape_init + digest_init in finish_compound_literal even in a template if the expression is not instantiation-dependent, and then again when tsubst_*. For instance, in initlist107.C, when parsing a functional cast, we call finish_compound_literal which calls reshape_init, which turns { NON_LVALUE_EXPR<1>, NON_LVALUE_EXPR<2> } into { { NON_LVALUE_EXPR<1>, NON_LVALUE_EXPR<2> } } and then digest_init turns that into { .x = { 1, 2 } } which is a compound literal (TREE_HAS_CONSTRUCTOR set), but the subexpression "{ 1, 2 }" isn't. "{ 1, 2 }" will now have the type int[3], so it's not BRACE_ENCLOSED_INITIALIZER_P. And then tsubst_* processes "{ .x = { 1, 2 } }". The case CONSTRUCTOR in tsubst_copy_and_build will call finish_compound_literal on a copy of "{ 1, 2 }" wrapped in a new { }, because the whole expr has TREE_HAS_CONSTRUCTOR. That crashes in reshape_init_r in the 6155 if (TREE_CODE (stripped_init) == CONSTRUCTOR) block; we have a constructor, it's not COMPOUND_LITERAL_P, and because digest_init had given it the type int[3], we hit 6172 gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); As expand_default_init explains in a comment, a CONSTRUCTOR of the target's type is a previously digested initializer, so we should probably do a similar trick here. This fixes all the variants of the problem I've come up with. 80864 is a similar case, we reshape when parsing and then second time in fold_non_dependent_expr called from store_init_value, because of the 'constexpr'. Also update a stale comment. Bootstrapped/regtest running on x86_64-linux, ok for trunk and 8 after a while? 2019-01-29 Marek Polacek <pola...@redhat.com> PR c++/89083, c++/80864 - ICE with list initialization in template. * decl.c (reshape_init_r): Don't reshape a digested initializer. * g++.dg/cpp0x/initlist107.C: New test. * g++.dg/cpp0x/initlist108.C: New test. * g++.dg/cpp0x/initlist109.C: New test. diff --git gcc/cp/decl.c gcc/cp/decl.c index 79eeac177b6..da08ecc21aa 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -6161,11 +6161,17 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p, ; else if (COMPOUND_LITERAL_P (stripped_init)) /* For a nested compound literal, there is no need to reshape since - brace elision is not allowed. Even if we decided to allow it, - we should add a call to reshape_init in finish_compound_literal, - before calling digest_init, so changing this code would still - not be necessary. */ + we called reshape_init in finish_compound_literal, before calling + digest_init. */ gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); + /* Similarly, a CONSTRUCTOR of the target's type is a previously + digested initializer. */ + else if (same_type_ignoring_top_level_qualifiers_p (type, + TREE_TYPE (init))) + { + ++d->cur; + return init; + } else { ++d->cur; diff --git gcc/testsuite/g++.dg/cpp0x/initlist107.C gcc/testsuite/g++.dg/cpp0x/initlist107.C new file mode 100644 index 00000000000..9acfe7cb267 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/initlist107.C @@ -0,0 +1,24 @@ +// PR c++/89083 +// { dg-do compile { target c++11 } } +// { dg-options "-Wmissing-braces" } + +struct A { int x[3]; }; + +template<class T> +decltype(A{1, 2}, T()) fn1(T t) // { dg-warning "missing braces" } +{ + return t; +} + +template<class T> +decltype(A{{1, 2}}, T()) fn2(T t) +{ + return t; +} + +void +f() +{ + fn1(1); + fn2(1); +} diff --git gcc/testsuite/g++.dg/cpp0x/initlist108.C gcc/testsuite/g++.dg/cpp0x/initlist108.C new file mode 100644 index 00000000000..e2839787fa5 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/initlist108.C @@ -0,0 +1,34 @@ +// PR c++/80864 +// { dg-do compile { target c++11 } } +// { dg-options "-Wmissing-braces" } + +struct S { + char c[1]; +}; + +template <typename T> +void +fn () +{ + constexpr S s1 = S{}; + constexpr S s2 = S{{}}; + constexpr S s3 = S{{{}}}; + constexpr S s4 = {}; + constexpr S s5 = {{}}; + constexpr S s6 = {{{}}}; + constexpr S s7{{}}; + constexpr S s8{S{}}; + constexpr S s9{S{{}}}; + constexpr S s10{S{{{}}}}; + constexpr S s11 = S(); + constexpr S s12 = S({}); + constexpr S s13 = S({{}}); + constexpr S s14 = {{}}; + constexpr S s15 = {{{}}}; +} + +void +foo () +{ + fn<int>(); +} diff --git gcc/testsuite/g++.dg/cpp0x/initlist109.C gcc/testsuite/g++.dg/cpp0x/initlist109.C new file mode 100644 index 00000000000..1351a2d57ce --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/initlist109.C @@ -0,0 +1,15 @@ +// PR c++/80864 +// { dg-do compile { target c++11 } } +// { dg-options "-Wmissing-braces" } + +struct S {}; +struct A { S s[1]; }; + +template <typename> +struct R { static constexpr auto h = A{S{}}; }; // { dg-warning "missing braces" } + +template <typename> +struct R2 { static constexpr auto h = A{{S{}}}; }; + +A foo = R<int>::h; +A foo2 = R2<int>::h;