diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a115317a03c..a48b14c2091 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-01-31 Marek Polacek + + PR c++/89083, c++/80864 - ICE with list initialization in template. + * constexpr.c (adjust_temp_type): Use copy_node and change the type + instead of using build_constructor. + * decl.c (reshape_init_r): Don't reshape a digested initializer. + Return the initializer for COMPOUND_LITERAL_P. + 2019-01-30 Jason Merrill PR c++/88752 - ICE with lambda and constexpr if. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 42681416760..19eb44fc0c0 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1291,7 +1291,12 @@ adjust_temp_type (tree type, tree temp) return temp; /* Avoid wrapping an aggregate value in a NOP_EXPR. */ if (TREE_CODE (temp) == CONSTRUCTOR) - return build_constructor (type, CONSTRUCTOR_ELTS (temp)); + { + /* build_constructor wouldn't retain various CONSTRUCTOR flags. */ + tree t = copy_node (temp); + TREE_TYPE (t) = type; + return t; + } if (TREE_CODE (temp) == EMPTY_CLASS_EXPR) return build0 (EMPTY_CLASS_EXPR, type); gcc_assert (scalarish_type_p (type)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 79eeac177b6..65ba812deb6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6154,20 +6154,29 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p, { if (TREE_CODE (stripped_init) == CONSTRUCTOR) { - if (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE (init))) - /* There is no need to reshape pointer-to-member function - initializers, as they are always constructed correctly - by the front end. */ - ; - else if (COMPOUND_LITERAL_P (stripped_init)) + tree init_type = TREE_TYPE (init); + if (init_type && TYPE_PTRMEMFUNC_P (init_type)) + /* There is no need to call reshape_init for pointer-to-member + function initializers, as they are always constructed correctly + by the front end. Here we have e.g. {.__pfn=0B, .__delta=0}, + which is missing outermost braces. We should warn below, and + one of the routines below will wrap it in additional { }. */; /* 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. */ - gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); + we called reshape_init in finish_compound_literal, before calling + digest_init. */ + else if (COMPOUND_LITERAL_P (stripped_init) + /* Similarly, a CONSTRUCTOR of the target's type is a + previously digested initializer. */ + || same_type_ignoring_top_level_qualifiers_p (type, + init_type)) + { + ++d->cur; + gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); + return init; + } else { + /* Something that hasn't been reshaped yet. */ ++d->cur; gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); return reshape_init (type, init, complain); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 25cf4cdafaa..ce63dad84d0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2019-01-31 Marek Polacek + + PR c++/89083, c++/80864 - ICE with list initialization in template. + * g++.dg/cpp0x/initlist107.C: New test. + * g++.dg/cpp0x/initlist108.C: New test. + * g++.dg/cpp0x/initlist109.C: New test. + * g++.dg/cpp0x/initlist110.C: New test. + * g++.dg/cpp0x/initlist111.C: New test. + * g++.dg/cpp0x/initlist112.C: New test. + * g++.dg/init/ptrfn4.C: New test. + 2019-01-31 David Malcolm PR c/89122 diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist107.C b/gcc/testsuite/g++.dg/cpp0x/initlist107.C new file mode 100644 index 00000000000..9acfe7cb267 --- /dev/null +++ b/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 +decltype(A{1, 2}, T()) fn1(T t) // { dg-warning "missing braces" } +{ + return t; +} + +template +decltype(A{{1, 2}}, T()) fn2(T t) +{ + return t; +} + +void +f() +{ + fn1(1); + fn2(1); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist108.C b/gcc/testsuite/g++.dg/cpp0x/initlist108.C new file mode 100644 index 00000000000..e2839787fa5 --- /dev/null +++ b/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 +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(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist109.C b/gcc/testsuite/g++.dg/cpp0x/initlist109.C new file mode 100644 index 00000000000..1351a2d57ce --- /dev/null +++ b/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 +struct R { static constexpr auto h = A{S{}}; }; // { dg-warning "missing braces" } + +template +struct R2 { static constexpr auto h = A{{S{}}}; }; + +A foo = R::h; +A foo2 = R2::h; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist110.C b/gcc/testsuite/g++.dg/cpp0x/initlist110.C new file mode 100644 index 00000000000..7bb229cbc7e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist110.C @@ -0,0 +1,32 @@ +// PR c++/89083 +// { dg-do compile { target c++11 } } + +struct C { int a[3]; int i; }; +struct B { C c[3]; }; +struct A { B b[3]; }; + +template +decltype(A{N, N}, T()) fn1(T t) +{ + return t; +} + +template +decltype(A{{{N, N, N}, {N + 1}}}, T()) fn2(T t) +{ + return t; +} + +template +decltype(A{{N + M}}, T()) fn3(T t) +{ + return t; +} + +void +f() +{ + fn1(1); + fn2(1); + fn3(1); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist111.C b/gcc/testsuite/g++.dg/cpp0x/initlist111.C new file mode 100644 index 00000000000..7f96115e618 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist111.C @@ -0,0 +1,32 @@ +// PR c++/80864 +// { dg-do compile { target c++11 } } + +struct S { + int c[3]; +}; + +template +void +fn () +{ + constexpr S s1 = S{N}; + constexpr S s2 = S{{N, N}}; + constexpr S s3 = S{N, N}; + constexpr S s4 = {N}; + constexpr S s5 = {{N}}; + constexpr S s6 = {N, N}; + constexpr S s7{{N}}; + constexpr S s8{S{N}}; + constexpr S s9{S{{N}}}; + constexpr S s10{S{{N}}}; + constexpr S s11 = S({N}); + constexpr S s12 = S({{N}}); + constexpr S s13 = {{N}}; + constexpr S s14 = {{N, N, N}}; +} + +void +foo () +{ + fn(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist112.C b/gcc/testsuite/g++.dg/cpp0x/initlist112.C new file mode 100644 index 00000000000..cd97098eec5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist112.C @@ -0,0 +1,14 @@ +// PR c++/80864 +// { dg-do compile { target c++11 } } + +struct S {int a[2]; }; +struct A { S s[1]; }; + +template +struct R { static constexpr auto h = A{S{N}}; }; + +template +struct R2 { static constexpr auto h = A{S{{N, N}}}; }; + +A foo = R::h; +A foo2 = R2::h; diff --git a/gcc/testsuite/g++.dg/init/ptrfn4.C b/gcc/testsuite/g++.dg/init/ptrfn4.C new file mode 100644 index 00000000000..e1635c86483 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/ptrfn4.C @@ -0,0 +1,19 @@ +// { dg-do compile } +// { dg-options "-Wmissing-braces" } + +struct S { }; +typedef void (S::*fptr1) (int); + +struct A { + fptr1 f; +}; + +A a[] = +{ + (fptr1) 0, +}; // { dg-warning "missing braces around initializer" } + +A a2[] = +{ + { (fptr1) 0 } +};