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.

	* 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.

From-SVN: r268428
This commit is contained in:
Marek Polacek 2019-01-31 20:21:11 +00:00 committed by Marek Polacek
parent 1d4b4f4979
commit b27f74e777
11 changed files with 215 additions and 12 deletions

View File

@ -1,3 +1,11 @@
2019-01-31 Marek Polacek <polacek@redhat.com>
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 <jason@redhat.com>
PR c++/88752 - ICE with lambda and constexpr if.

View File

@ -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));

View File

@ -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);

View File

@ -1,3 +1,14 @@
2019-01-31 Marek Polacek <polacek@redhat.com>
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 <dmalcolm@redhat.com>
PR c/89122

View File

@ -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);
}

View File

@ -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>();
}

View File

@ -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;

View File

@ -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<class T, int N>
decltype(A{N, N}, T()) fn1(T t)
{
return t;
}
template<class T, int N>
decltype(A{{{N, N, N}, {N + 1}}}, T()) fn2(T t)
{
return t;
}
template<class T, int N, int M>
decltype(A{{N + M}}, T()) fn3(T t)
{
return t;
}
void
f()
{
fn1<int, 10>(1);
fn2<int, 10>(1);
fn3<int, 10, 20>(1);
}

View File

@ -0,0 +1,32 @@
// PR c++/80864
// { dg-do compile { target c++11 } }
struct S {
int c[3];
};
template <typename T, int N>
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<int, 10>();
}

View File

@ -0,0 +1,14 @@
// PR c++/80864
// { dg-do compile { target c++11 } }
struct S {int a[2]; };
struct A { S s[1]; };
template <typename, int N>
struct R { static constexpr auto h = A{S{N}}; };
template <typename, int N>
struct R2 { static constexpr auto h = A{S{{N, N}}}; };
A foo = R<int, 10>::h;
A foo2 = R2<int, 10>::h;

View File

@ -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 }
};