2
0
mirror of git://gcc.gnu.org/git/gcc.git synced 2025-03-22 19:11:18 +08:00

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.
This commit is contained in:
Jason Merrill 2020-02-04 14:21:59 -05:00
parent c422cec54a
commit a1c9c9ff06
10 changed files with 65 additions and 44 deletions

@ -1,3 +1,11 @@
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>
* coroutines.cc (find_promise_type): Delete unused forward

@ -826,7 +826,12 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain)
return true;
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))
{
/* 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,
unsigned HOST_WIDE_INT i;
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
constructor of the element type. We only need to handle class types
here, as for a constructor to be constexpr, all members must be

@ -801,6 +801,17 @@ perform_member_init (tree member, tree init)
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)
{
/* mem() means value-initialization. */
@ -832,12 +843,7 @@ perform_member_init (tree member, tree init)
}
else if (init
&& (TYPE_REF_P (type)
/* Pre-digested NSDMI. */
|| (((TREE_CODE (init) == CONSTRUCTOR
&& TREE_TYPE (init) == type)
/* { } mem-initializer. */
|| (TREE_CODE (init) == TREE_LIST
&& DIRECT_LIST_INIT_P (TREE_VALUE (init))))
|| (TREE_CODE (init) == CONSTRUCTOR
&& (CP_AGGREGATE_TYPE_P (type)
|| is_std_init_list (type)))))
{
@ -847,10 +853,7 @@ perform_member_init (tree member, tree init)
persists until the constructor exits." */
unsigned i; tree t;
releasing_vec cleanups;
if (TREE_CODE (init) == TREE_LIST)
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
if (TREE_TYPE (init) != type)
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), type))
{
if (BRACE_ENCLOSED_INITIALIZER_P (init)
&& CP_AGGREGATE_TYPE_P (type))
@ -876,23 +879,6 @@ perform_member_init (tree member, tree init)
{
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
|| same_type_ignoring_top_level_qualifiers_p (type,
TREE_TYPE (init)))
@ -962,16 +948,10 @@ perform_member_init (tree member, tree init)
/*using_new=*/false,
/*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);
/* Reject a member initializer for a flexible array member. */
if (init && !maybe_reject_flexarray_init (member, init))
if (init)
finish_expr_stmt (cp_build_modify_expr (input_location, decl,
INIT_EXPR, init,
tf_warning_or_error));

@ -0,0 +1,24 @@
// 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:
};
SomeClass::SomeClass()
: member({
: member{
[INDEX1] = { .field = 0 },
[INDEX2] = { .field = 1 }
})
}
{
}

@ -13,9 +13,9 @@ private:
};
SomeClass::SomeClass()
: member({
: member{
[INDEX1] = { .field = 0 },
[INDEX2] = { .field = 1 }
})
}
{
}

@ -13,9 +13,9 @@ private:
};
SomeClass::SomeClass()
: member({
: member{
[INDEX1] = { .field = 0 }, // { dg-error "constant expression" }
[INDEX2] = { .field = 1 } // { dg-error "constant expression" }
})
}
{
}

@ -3,7 +3,7 @@
class A {
public:
A() : argc(0), argv() { };
A() : argc(0), argv() { }; // { dg-error "flexible array" }
private:
int argc;
char* argv[];

@ -4,7 +4,7 @@
struct A
{
constexpr A() : i(), x() {}
constexpr A() : i(), x() {} // { dg-error "flexible" }
int i;
char x[];
};

@ -2,6 +2,6 @@
struct Foo { explicit Foo(int) { } };
struct Goo {
Goo() : x(Foo(4), Foo(5)) { } // { dg-error "array" }
Goo() : x(Foo(4), Foo(5)) { } // { dg-error "" }
Foo x[2];
};