Commit a1c9c9ff by Jason Merrill

c++: Fix ({ ... }) array mem-initializer.

Here, we were going down the wrong path in perform_member_init because of
the incorrect parens around the mem-initializer for the array.  And then
cxx_eval_vec_init_1 didn't know what to do with a CONSTRUCTOR as the
initializer.  The latter issue was a straightforward fix, but I also wanted
to fix us silently accepting the parens, which led to factoring out handling
of TREE_LIST and flexarrays.  The latter led to adjusting the expected
behavior on flexary29.C: we should complain about the initializer, but not
complain about a missing initializer.

As I commented on PR 92812, in this process I noticed that we weren't
handling C++20 parenthesized aggregate initialization as a mem-initializer.
So my TREE_LIST handling includes a commented out section that should
probably be part of a future fix for that issue; with it uncommented we
continue to crash on the testcase in C++20 mode, but should instead complain
about the braced-init-list not being a valid initializer for an A.

	PR c++/86917
	* init.c (perform_member_init): Simplify.
	* constexpr.c (cx_check_missing_mem_inits): Allow uninitialized
	flexarray.
	(cxx_eval_vec_init_1): Handle CONSTRUCTOR.
parent c422cec5
2020-02-04 Jason Merrill <jason@redhat.com>
PR c++/86917
* init.c (perform_member_init): Simplify.
* constexpr.c (cx_check_missing_mem_inits): Allow uninitialized
flexarray.
(cxx_eval_vec_init_1): Handle CONSTRUCTOR.
2020-02-04 Iain Sandoe <iain@sandoe.co.uk> 2020-02-04 Iain Sandoe <iain@sandoe.co.uk>
* coroutines.cc (find_promise_type): Delete unused forward * coroutines.cc (find_promise_type): Delete unused forward
......
...@@ -826,7 +826,12 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) ...@@ -826,7 +826,12 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain)
return true; return true;
continue; continue;
} }
ftype = strip_array_types (TREE_TYPE (field)); ftype = TREE_TYPE (field);
if (!ftype || !TYPE_P (ftype) || !COMPLETE_TYPE_P (ftype))
/* A flexible array can't be intialized here, so don't complain
that it isn't. */
continue;
ftype = strip_array_types (ftype);
if (type_has_constexpr_default_constructor (ftype)) if (type_has_constexpr_default_constructor (ftype))
{ {
/* It's OK to skip a member with a trivial constexpr ctor. /* It's OK to skip a member with a trivial constexpr ctor.
...@@ -3784,6 +3789,10 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, ...@@ -3784,6 +3789,10 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
unsigned HOST_WIDE_INT i; unsigned HOST_WIDE_INT i;
tsubst_flags_t complain = ctx->quiet ? tf_none : tf_warning_or_error; tsubst_flags_t complain = ctx->quiet ? tf_none : tf_warning_or_error;
if (init && TREE_CODE (init) == CONSTRUCTOR)
return cxx_eval_bare_aggregate (ctx, init, lval,
non_constant_p, overflow_p);
/* For the default constructor, build up a call to the default /* For the default constructor, build up a call to the default
constructor of the element type. We only need to handle class types constructor of the element type. We only need to handle class types
here, as for a constructor to be constexpr, all members must be here, as for a constructor to be constexpr, all members must be
......
...@@ -801,6 +801,17 @@ perform_member_init (tree member, tree init) ...@@ -801,6 +801,17 @@ perform_member_init (tree member, tree init)
member); member);
} }
if (maybe_reject_flexarray_init (member, init))
return;
if (init && TREE_CODE (init) == TREE_LIST
&& (DIRECT_LIST_INIT_P (TREE_VALUE (init))
/* FIXME C++20 parenthesized aggregate init (PR 92812). */
|| !(/* cxx_dialect >= cxx2a ? CP_AGGREGATE_TYPE_P (type) */
/* : */CLASS_TYPE_P (type))))
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
if (init == void_type_node) if (init == void_type_node)
{ {
/* mem() means value-initialization. */ /* mem() means value-initialization. */
...@@ -832,12 +843,7 @@ perform_member_init (tree member, tree init) ...@@ -832,12 +843,7 @@ perform_member_init (tree member, tree init)
} }
else if (init else if (init
&& (TYPE_REF_P (type) && (TYPE_REF_P (type)
/* Pre-digested NSDMI. */ || (TREE_CODE (init) == CONSTRUCTOR
|| (((TREE_CODE (init) == CONSTRUCTOR
&& TREE_TYPE (init) == type)
/* { } mem-initializer. */
|| (TREE_CODE (init) == TREE_LIST
&& DIRECT_LIST_INIT_P (TREE_VALUE (init))))
&& (CP_AGGREGATE_TYPE_P (type) && (CP_AGGREGATE_TYPE_P (type)
|| is_std_init_list (type))))) || is_std_init_list (type)))))
{ {
...@@ -847,10 +853,7 @@ perform_member_init (tree member, tree init) ...@@ -847,10 +853,7 @@ perform_member_init (tree member, tree init)
persists until the constructor exits." */ persists until the constructor exits." */
unsigned i; tree t; unsigned i; tree t;
releasing_vec cleanups; releasing_vec cleanups;
if (TREE_CODE (init) == TREE_LIST) if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), type))
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
if (TREE_TYPE (init) != type)
{ {
if (BRACE_ENCLOSED_INITIALIZER_P (init) if (BRACE_ENCLOSED_INITIALIZER_P (init)
&& CP_AGGREGATE_TYPE_P (type)) && CP_AGGREGATE_TYPE_P (type))
...@@ -876,23 +879,6 @@ perform_member_init (tree member, tree init) ...@@ -876,23 +879,6 @@ perform_member_init (tree member, tree init)
{ {
if (TREE_CODE (type) == ARRAY_TYPE) if (TREE_CODE (type) == ARRAY_TYPE)
{ {
if (init)
{
/* Check to make sure the member initializer is valid and
something like a CONSTRUCTOR in: T a[] = { 1, 2 } and
if it isn't, return early to avoid triggering another
error below. */
if (maybe_reject_flexarray_init (member, init))
return;
if (TREE_CODE (init) != TREE_LIST || TREE_CHAIN (init))
init = error_mark_node;
else
init = TREE_VALUE (init);
if (BRACE_ENCLOSED_INITIALIZER_P (init))
init = digest_init (type, init, tf_warning_or_error);
}
if (init == NULL_TREE if (init == NULL_TREE
|| same_type_ignoring_top_level_qualifiers_p (type, || same_type_ignoring_top_level_qualifiers_p (type,
TREE_TYPE (init))) TREE_TYPE (init)))
...@@ -962,16 +948,10 @@ perform_member_init (tree member, tree init) ...@@ -962,16 +948,10 @@ perform_member_init (tree member, tree init)
/*using_new=*/false, /*using_new=*/false,
/*complain=*/true); /*complain=*/true);
} }
else if (TREE_CODE (init) == TREE_LIST)
/* There was an explicit member initialization. Do some work
in that case. */
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
maybe_warn_list_ctor (member, init); maybe_warn_list_ctor (member, init);
/* Reject a member initializer for a flexible array member. */ if (init)
if (init && !maybe_reject_flexarray_init (member, init))
finish_expr_stmt (cp_build_modify_expr (input_location, decl, finish_expr_stmt (cp_build_modify_expr (input_location, decl,
INIT_EXPR, init, INIT_EXPR, init,
tf_warning_or_error)); tf_warning_or_error));
......
// PR c++/86917
// { dg-do compile { target c++11 } }
struct A
{
constexpr A () : c (0) {}
static const A z;
unsigned c;
};
struct B
{ // This should really be target { ! c++2a }
typedef A W[4]; // { dg-error "paren" "" { target *-*-* } .+1 }
constexpr B () : w ({ A::z, A::z, A::z, A::z }) {} // { dg-error "constant" }
W w;
};
struct C
{
C ();
B w[1];
};
C::C () { }
...@@ -15,9 +15,9 @@ private: ...@@ -15,9 +15,9 @@ private:
}; };
SomeClass::SomeClass() SomeClass::SomeClass()
: member({ : member{
[INDEX1] = { .field = 0 }, [INDEX1] = { .field = 0 },
[INDEX2] = { .field = 1 } [INDEX2] = { .field = 1 }
}) }
{ {
} }
...@@ -13,9 +13,9 @@ private: ...@@ -13,9 +13,9 @@ private:
}; };
SomeClass::SomeClass() SomeClass::SomeClass()
: member({ : member{
[INDEX1] = { .field = 0 }, [INDEX1] = { .field = 0 },
[INDEX2] = { .field = 1 } [INDEX2] = { .field = 1 }
}) }
{ {
} }
...@@ -13,9 +13,9 @@ private: ...@@ -13,9 +13,9 @@ private:
}; };
SomeClass::SomeClass() SomeClass::SomeClass()
: member({ : member{
[INDEX1] = { .field = 0 }, // { dg-error "constant expression" } [INDEX1] = { .field = 0 }, // { dg-error "constant expression" }
[INDEX2] = { .field = 1 } // { dg-error "constant expression" } [INDEX2] = { .field = 1 } // { dg-error "constant expression" }
}) }
{ {
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
class A { class A {
public: public:
A() : argc(0), argv() { }; A() : argc(0), argv() { }; // { dg-error "flexible array" }
private: private:
int argc; int argc;
char* argv[]; char* argv[];
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
struct A struct A
{ {
constexpr A() : i(), x() {} constexpr A() : i(), x() {} // { dg-error "flexible" }
int i; int i;
char x[]; char x[];
}; };
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
struct Foo { explicit Foo(int) { } }; struct Foo { explicit Foo(int) { } };
struct Goo { struct Goo {
Goo() : x(Foo(4), Foo(5)) { } // { dg-error "array" } Goo() : x(Foo(4), Foo(5)) { } // { dg-error "" }
Foo x[2]; Foo x[2];
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment