On 1/4/19 10:22 PM, Jason Merrill wrote: > Hmm, I'm uncomfortable with starting to pass in the decl just for the sake of > deciding whether this diagnostic should be a pedwarn or error. In general, > because of copy elision, we can't know at this point what we're initializing, > so I'd rather not pretend we can. Instead, maybe add a > LOOKUP_ALLOW_FLEXARY_INIT flag that you can add to the flags argument in the > call from store_init_value? >
Okay, I reworked the patch, to pass a bit in the flags, it was a bit more complicated than anticipated, because it is necessary to pass the flag thru process_init_constructor and friends to the recursive invocation of digest_init_r. It turned out that digest_nsdmi_init did not need to change, since it is always wrong to use flexarray init there. I added a new test case (flexary32.C) to exercises a few cases where non static direct member intializers are allowed to use flexarrays (in static members) and where that would be wrong (in automatic members). So that seems to work. New version of the patch is attached. Bootstrapped and reg-tested on x86_64-pc-linux-gnu. Is it OK for trunk? Thanks Bernd.
gcc/cp: 2019-01-05 Bernd Edlinger <bernd.edlin...@hotmail.de> PR c++/88261 PR c++/69696 * cp-tree.h (LOOKUP_ALLOW_FLEXARRAY_INIT): New flag value. * typeck2.c (digest_init_r): Raise an error for non-static initialization of a flexible array member. (process_init_constructor, massage_init_elt, process_init_constructor_array, process_init_constructor_record, process_init_constructor_union, process_init_constructor): Add the flags parameter and pass it thru. (store_init_value): Pass LOOKUP_ALLOW_FLEXARRAY_INIT parameter to digest_init_flags for static decls. gcc/testsuite: 2019-01-05 Bernd Edlinger <bernd.edlin...@hotmail.de> PR c++/88261 PR c++/69696 * gcc.dg/array-6.c: Move from here ... * c-c++-common/array-6.c: ... to here and add some more test coverage. * g++.dg/ext/flexary32.C: New test. * g++.dg/ext/flexary3.C: Adjust test. * g++.dg/ext/flexary12.C: Likewise. * g++.dg/ext/flexary13.C: Likewise. * g++.dg/ext/flexary15.C: Likewise. * g++.dg/warn/Wplacement-new-size-1.C: Likewise. * g++.dg/warn/Wplacement-new-size-2.C: Likewise. * g++.dg/warn/Wplacement-new-size-6.C: Likewise. Index: gcc/cp/cp-tree.h Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 267569) +++ gcc/cp/cp-tree.h (working copy) @@ -5454,6 +5454,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T #define LOOKUP_NO_NON_INTEGRAL (LOOKUP_NO_RVAL_BIND << 1) /* Used for delegating constructors in order to diagnose self-delegation. */ #define LOOKUP_DELEGATING_CONS (LOOKUP_NO_NON_INTEGRAL << 1) +/* Allow initialization of a flexible array members. */ +#define LOOKUP_ALLOW_FLEXARRAY_INIT (LOOKUP_DELEGATING_CONS << 1) #define LOOKUP_NAMESPACES_ONLY(F) \ (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES)) Index: gcc/cp/typeck2.c =================================================================== --- gcc/cp/typeck2.c (revision 267569) +++ gcc/cp/typeck2.c (working copy) @@ -35,7 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "gcc-rich-location.h" static tree -process_init_constructor (tree type, tree init, int nested, +process_init_constructor (tree type, tree init, int nested, int flags, tsubst_flags_t complain); @@ -817,8 +817,12 @@ store_init_value (tree decl, tree init, vec<tree, if (flags & LOOKUP_ALREADY_DIGESTED) value = init; else - /* Digest the specified initializer into an expression. */ - value = digest_init_flags (type, init, flags, tf_warning_or_error); + { + if (TREE_STATIC (decl)) + flags |= LOOKUP_ALLOW_FLEXARRAY_INIT; + /* Digest the specified initializer into an expression. */ + value = digest_init_flags (type, init, flags, tf_warning_or_error); + } if (TREE_CODE (type) == ARRAY_TYPE && TYPE_STRING_FLAG (TREE_TYPE (type)) @@ -1068,8 +1072,18 @@ digest_init_r (tree type, tree init, int nested, i { if (nested && !TYPE_DOMAIN (type)) /* C++ flexible array members have a null domain. */ - pedwarn (loc, OPT_Wpedantic, - "initialization of a flexible array member"); + { + if (flags & LOOKUP_ALLOW_FLEXARRAY_INIT) + pedwarn (loc, OPT_Wpedantic, + "initialization of a flexible array member"); + else + { + if (complain & tf_error) + error_at (loc, "non-static initialization of" + " a flexible array member"); + return error_mark_node; + } + } tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type)); if (char_type_p (typ1) @@ -1193,7 +1207,8 @@ digest_init_r (tree type, tree init, int nested, i if (BRACE_ENCLOSED_INITIALIZER_P (stripped_init) && !TYPE_NON_AGGREGATE_CLASS (type)) - return process_init_constructor (type, stripped_init, nested, complain); + return process_init_constructor (type, stripped_init, nested, flags, + complain); else { if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE) @@ -1291,9 +1306,12 @@ picflag_from_initializer (tree init) /* Adjust INIT for going into a CONSTRUCTOR. */ static tree -massage_init_elt (tree type, tree init, int nested, tsubst_flags_t complain) +massage_init_elt (tree type, tree init, int nested, int flags, + tsubst_flags_t complain) { - init = digest_init_r (type, init, nested ? 2 : 1, LOOKUP_IMPLICIT, complain); + flags &= LOOKUP_ALLOW_FLEXARRAY_INIT; + flags |= LOOKUP_IMPLICIT; + init = digest_init_r (type, init, nested ? 2 : 1, flags, complain); /* Strip a simple TARGET_EXPR when we know this is an initializer. */ if (SIMPLE_TARGET_EXPR_P (init)) init = TARGET_EXPR_INITIAL (init); @@ -1311,11 +1329,11 @@ static tree which describe the initializers. */ static int -process_init_constructor_array (tree type, tree init, int nested, +process_init_constructor_array (tree type, tree init, int nested, int flags, tsubst_flags_t complain) { unsigned HOST_WIDE_INT i, len = 0; - int flags = 0; + int picflags = 0; bool unbounded = false; constructor_elt *ce; vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init); @@ -1365,7 +1383,8 @@ static int ce->index = error_mark_node; gcc_assert (ce->value); ce->value - = massage_init_elt (TREE_TYPE (type), ce->value, nested, complain); + = massage_init_elt (TREE_TYPE (type), ce->value, nested, flags, + complain); gcc_checking_assert (ce->value == error_mark_node @@ -1373,7 +1392,7 @@ static int (strip_array_types (TREE_TYPE (type)), strip_array_types (TREE_TYPE (ce->value))))); - flags |= picflag_from_initializer (ce->value); + picflags |= picflag_from_initializer (ce->value); } /* No more initializers. If the array is unbounded, we are done. Otherwise, @@ -1389,7 +1408,8 @@ static int we can't rely on the back end to do it for us, so make the initialization explicit by list-initializing from T{}. */ next = build_constructor (init_list_type_node, NULL); - next = massage_init_elt (TREE_TYPE (type), next, nested, complain); + next = massage_init_elt (TREE_TYPE (type), next, nested, flags, + complain); if (initializer_zerop (next)) /* The default zero-initialization is fine for us; don't add anything to the CONSTRUCTOR. */ @@ -1406,7 +1426,7 @@ static int if (next) { - flags |= picflag_from_initializer (next); + picflags |= picflag_from_initializer (next); if (len > i+1 && (initializer_constant_valid_p (next, TREE_TYPE (next)) == null_pointer_node)) @@ -1426,7 +1446,7 @@ static int } CONSTRUCTOR_ELTS (init) = v; - return flags; + return picflags; } /* Subroutine of process_init_constructor, which will process an initializer @@ -1434,7 +1454,7 @@ static int the initializers. */ static int -process_init_constructor_record (tree type, tree init, int nested, +process_init_constructor_record (tree type, tree init, int nested, int flags, tsubst_flags_t complain) { vec<constructor_elt, va_gc> *v = NULL; @@ -1449,7 +1469,7 @@ static int gcc_assert (!TYPE_POLYMORPHIC_P (type)); restart: - int flags = 0; + int picflags = 0; unsigned HOST_WIDE_INT idx = 0; int designator_skip = -1; /* Generally, we will always have an index for each initializer (which is @@ -1517,7 +1537,7 @@ static int if (ce) { gcc_assert (ce->value); - next = massage_init_elt (type, next, nested, complain); + next = massage_init_elt (type, next, nested, flags, complain); ++idx; } } @@ -1546,7 +1566,8 @@ static int for us, so build up TARGET_EXPRs. If the type in question is a class, just build one up; if it's an array, recurse. */ next = build_constructor (init_list_type_node, NULL); - next = massage_init_elt (TREE_TYPE (field), next, nested, complain); + next = massage_init_elt (TREE_TYPE (field), next, nested, flags, + complain); /* Warn when some struct elements are implicitly initialized. */ if ((complain & tf_warning) @@ -1597,7 +1618,7 @@ static int /* If this is a bitfield, now convert to the lowered type. */ if (type != TREE_TYPE (field)) next = cp_convert_and_check (TREE_TYPE (field), next, complain); - flags |= picflag_from_initializer (next); + picflags |= picflag_from_initializer (next); CONSTRUCTOR_APPEND_ELT (v, field, next); } @@ -1653,7 +1674,7 @@ static int } CONSTRUCTOR_ELTS (init) = v; - return flags; + return picflags; } /* Subroutine of process_init_constructor, which will process a single @@ -1661,7 +1682,7 @@ static int which describe the initializer. */ static int -process_init_constructor_union (tree type, tree init, int nested, +process_init_constructor_union (tree type, tree init, int nested, int flags, tsubst_flags_t complain) { constructor_elt *ce; @@ -1749,7 +1770,7 @@ static int if (ce->value && ce->value != error_mark_node) ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, nested, - complain); + flags, complain); return picflag_from_initializer (ce->value); } @@ -1769,40 +1790,43 @@ static int of error. */ static tree -process_init_constructor (tree type, tree init, int nested, +process_init_constructor (tree type, tree init, int nested, int flags, tsubst_flags_t complain) { - int flags; + int picflags; gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init)); if (TREE_CODE (type) == ARRAY_TYPE || VECTOR_TYPE_P (type)) - flags = process_init_constructor_array (type, init, nested, complain); + picflags = process_init_constructor_array (type, init, nested, flags, + complain); else if (TREE_CODE (type) == RECORD_TYPE) - flags = process_init_constructor_record (type, init, nested, complain); + picflags = process_init_constructor_record (type, init, nested, flags, + complain); else if (TREE_CODE (type) == UNION_TYPE) - flags = process_init_constructor_union (type, init, nested, complain); + picflags = process_init_constructor_union (type, init, nested, flags, + complain); else gcc_unreachable (); - if (flags & PICFLAG_ERRONEOUS) + if (picflags & PICFLAG_ERRONEOUS) return error_mark_node; TREE_TYPE (init) = type; if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == NULL_TREE) cp_complete_array_type (&TREE_TYPE (init), init, /*do_default=*/0); - if (flags & PICFLAG_SIDE_EFFECTS) + if (picflags & PICFLAG_SIDE_EFFECTS) { TREE_CONSTANT (init) = false; TREE_SIDE_EFFECTS (init) = true; } - else if (flags & PICFLAG_NOT_ALL_CONSTANT) + else if (picflags & PICFLAG_NOT_ALL_CONSTANT) /* Make sure TREE_CONSTANT isn't set from build_constructor. */ TREE_CONSTANT (init) = false; else { TREE_CONSTANT (init) = 1; - if (!(flags & PICFLAG_NOT_ALL_SIMPLE)) + if (!(picflags & PICFLAG_NOT_ALL_SIMPLE)) TREE_STATIC (init) = 1; } return init; Index: gcc/testsuite/c-c++-common/array-6.c =================================================================== --- gcc/testsuite/c-c++-common/array-6.c (revision 267569) +++ gcc/testsuite/c-c++-common/array-6.c (working copy) @@ -16,3 +16,32 @@ void foo() struct str d = (struct str) { 2, "d" }; /* { dg-error "(non-static)|(near initialization)" } */ struct str e = (struct str) { d.len, "e" }; /* { dg-error "(non-static)|(initialization)" } */ } + +struct str f = { 0, {} }; + +void bar() +{ + static struct str g = { 0, {} }; + struct str h = { 0, {} }; /* { dg-error "(non-static)|(near initialization)" } */ + struct str i = (struct str) { 0, {} }; /* { dg-error "(non-static)|(near initialization)" } */ + struct str j = (struct str) { i.len, {} }; /* { dg-error "(non-static)|(initialization)" } */ +} + +struct str k = { 0 }; + +void baz() +{ + static struct str l = { 0 }; + struct str m = { 0 }; + struct str n = (struct str) { 0 }; + struct str o = (struct str) { n.len }; +} + +struct str p = {}; + +void qux() +{ + static struct str q = {}; + struct str r = {}; + struct str s = (struct str) {}; +} Index: gcc/testsuite/g++.dg/ext/flexary12.C =================================================================== --- gcc/testsuite/g++.dg/ext/flexary12.C (revision 267569) +++ gcc/testsuite/g++.dg/ext/flexary12.C (working copy) @@ -12,7 +12,7 @@ struct A { void f1 () { // This is the meat of the test from c++/69290: - struct A a + static struct A a = { "c" }; // { dg-error "invalid conversion from .const char\\*. to .int." } (void)&a; @@ -27,13 +27,13 @@ struct B { void f2 () { - struct B b1 + static struct B b1 = { 0, "c" }; // { dg-error "invalid conversion from .const char\\*. to .int." } (void)&b1; const char s[] = "c"; - struct B b2 + static struct B b2 = { 0, s }; // { dg-error "invalid conversion from .const char\\*. to .int." } (void)&b2; @@ -57,7 +57,7 @@ struct C { void f3 () { - struct C<double> cd + static struct C<double> cd = { "c" }; // { dg-error "cannot convert .const char\\*. to .double." } (void)&cd; Index: gcc/testsuite/g++.dg/ext/flexary13.C =================================================================== --- gcc/testsuite/g++.dg/ext/flexary13.C (revision 267569) +++ gcc/testsuite/g++.dg/ext/flexary13.C (working copy) @@ -19,33 +19,33 @@ int main () ASSERT (s.n == 0); } { - Ax s = + static Ax s = { 0, { } }; // dg-warning "initialization of a flexible array member" } ASSERT (s.n == 0); } { - Ax s = + static Ax s = { 1, { 2 } }; // dg-warning "initialization of a flexible array member" } ASSERT (s.n == 1 && s.a [0] == 2); } { - Ax s = + static Ax s = { 2, { 3, 4 } }; // dg-warning "initialization of a flexible array member" } ASSERT (s.n = 2 && s.a [0] == 3 && s.a [1] == 4); } { - Ax s = + static Ax s = { 123, i }; // dg-warning "initialization of a flexible array member" } ASSERT (s.n == 123 && s.a [0] == i); } { - Ax s = + static Ax s = { 456, { i } }; // dg-warning "initialization of a flexible array member" } ASSERT (s.n == 456 && s.a [0] == i); } { int j = i + 1, k = j + 1; - Ax s = + static Ax s = { 3, { i, j, k } }; // dg-warning "initialization of a flexible array member" } ASSERT (s.n == 3 && s.a [0] == i && s.a [1] == j && s.a [2] == k); } Index: gcc/testsuite/g++.dg/ext/flexary15.C =================================================================== --- gcc/testsuite/g++.dg/ext/flexary15.C (revision 267569) +++ gcc/testsuite/g++.dg/ext/flexary15.C (working copy) @@ -10,5 +10,5 @@ struct S { void foo (const char *a) { - const S s = { 1, { a, "b" } }; // { dg-warning "invalid conversion" } + static const S s = { 1, { a, "b" } }; // { dg-warning "invalid conversion" } } Index: gcc/testsuite/g++.dg/ext/flexary3.C =================================================================== --- gcc/testsuite/g++.dg/ext/flexary3.C (revision 267569) +++ gcc/testsuite/g++.dg/ext/flexary3.C (working copy) @@ -17,5 +17,6 @@ struct s { int main() { struct s s = { .c = 0 }; // { dg-error "initializer" } + // { dg-error "non-static initialization of a flexible array member" "" { target *-*-* } .-1 } return 0; } Index: gcc/testsuite/g++.dg/ext/flexary32.C =================================================================== --- gcc/testsuite/g++.dg/ext/flexary32.C (revision 0) +++ gcc/testsuite/g++.dg/ext/flexary32.C (working copy) @@ -0,0 +1,19 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-options -Wno-pedantic } */ + +struct str { int len; char s[]; }; + +struct foo { + str x = {3, {1,2,3}}; /* { dg-error "(non-static)|(initialization)" } */ + foo() {} +}; + +struct bar { + static constexpr str x = {3, {1,2,3}}; + bar() {} +}; + +struct baz { + str x = {3}; + baz() {} +}; Index: gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C (revision 267569) +++ gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C (working copy) @@ -28,7 +28,7 @@ void fAx (Ax *px, Ax &rx) void fAx2 () { - Ax ax2 = { 1, { 2, 3 } }; + static Ax ax2 = { 1, { 2, 3 } }; new (ax2.a) Int16; new (ax2.a) Int32; // { dg-warning "placement" } @@ -82,7 +82,7 @@ void fBx (BAx *pbx, BAx &rbx) void fBx1 () { - BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } }; + static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } }; new (bax1.ax.a) char; // { dg-warning "placement" } new (bax1.ax.a) char[2]; // { dg-warning "placement" } Index: gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C (revision 267569) +++ gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C (working copy) @@ -33,13 +33,13 @@ void fAx (Ax *px, Ax &rx) void fAx2 () { // Initialization of non-static objects with flexible array members - // isn't allowed in C and should perhaps be disallowed in C++ as + // isn't allowed in C and had to be be disallowed in C++ as // well to avoid c++/69696 - incorrect initialization of block-scope // flexible array members. - Ax ax2 = { 1, { 2, 3 } }; + Ax ax2 = { 1, { 2, 3 } }; // { dg-error "non-static initialization of a flexible array member" } - new (ax2.a) Int16; - new (ax2.a) Int16[1]; + new (ax2.a) Int16; // { dg-warning "placement" } + new (ax2.a) Int16[1]; // { dg-warning "placement" } new (ax2.a) Int16[2]; // { dg-warning "placement" } new (ax2.a) Int32; // { dg-warning "placement" } new (ax2.a) Int32[2]; // { dg-warning "placement" } @@ -140,7 +140,7 @@ void fBx (BAx *pbx, BAx &rbx) void fBx1 () { - BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } }; + static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } }; new (bax1.ax.a) char; // { dg-warning "placement" } new (bax1.ax.a) char[2]; // { dg-warning "placement" } Index: gcc/testsuite/g++.dg/warn/Wplacement-new-size-6.C =================================================================== --- gcc/testsuite/g++.dg/warn/Wplacement-new-size-6.C (revision 267569) +++ gcc/testsuite/g++.dg/warn/Wplacement-new-size-6.C (working copy) @@ -15,7 +15,7 @@ struct BAx { int i; Ax ax; }; void fBx1 () { - BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } }; // { dg-error "initialization of flexible array member in a nested context" } + static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } }; // { dg-error "initialization of flexible array member in a nested context" } new (bax1.ax.a) char; // { dg-warning "placement" } new (bax1.ax.a) char[2]; // { dg-warning "placement" } @@ -25,7 +25,7 @@ void fBx1 () void fBx2 () { - BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } }; // { dg-error "initialization of flexible array member in a nested context" } + static BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } }; // { dg-error "initialization of flexible array member in a nested context" } new (bax2.ax.a) char; // { dg-warning "placement" } new (bax2.ax.a) char[2]; // { dg-warning "placement" } @@ -37,7 +37,7 @@ void fBx2 () void fBx3 () { - BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; // { dg-error "initialization of flexible array member in a nested context" } + static BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; // { dg-error "initialization of flexible array member in a nested context" } new (bax2.ax.a) char; // { dg-warning "placement" } new (bax2.ax.a) char[2]; // { dg-warning "placement" } Index: gcc/testsuite/gcc.dg/array-6.c =================================================================== --- gcc/testsuite/gcc.dg/array-6.c (revision 267569) +++ gcc/testsuite/gcc.dg/array-6.c (working copy) @@ -1,18 +0,0 @@ -/* PR c/5597 */ -/* { dg-do compile } */ -/* { dg-options "" } */ - -/* Verify that GCC forbids non-static initialization of - flexible array members. */ - -struct str { int len; char s[]; }; - -struct str a = { 2, "a" }; - -void foo() -{ - static struct str b = { 2, "b" }; - struct str c = { 2, "c" }; /* { dg-error "(non-static)|(near initialization)" } */ - struct str d = (struct str) { 2, "d" }; /* { dg-error "(non-static)|(near initialization)" } */ - struct str e = (struct str) { d.len, "e" }; /* { dg-error "(non-static)|(initialization)" } */ -}