PR c++/71912 - [6/7 regression] flexible array in struct in union rejected gcc/cp/ChangeLog: 2016-07-29 Martin Sebor PR c++/71912 * class.c (struct flexmems_t): Add members. (find_flexarrays): Add arguments. Correct handling of anonymous structs. (diagnose_flexarrays): Adjust to issue warnings in addition to errors. (check_flexarrays): Add argument. gcc/testsuite/ChangeLog: 2016-07-29 Martin Sebor PR c++/71912 * g++.dg/ext/flexary19.C: New test. * g++.dg/ext/flexary18.C: New test. * g++.dg/ext/flexary4.C: Correct the handling of anonymous structs. * g++.dg/torture/pr64312.C: Add a dg-error directive to an ill-formed regression test. * g++.dg/compat/struct-layout-1_generate.c (subfield): Add argument. Avoid generating a flexible array member in an array. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index b2db7f8..ebaee58 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -147,11 +147,11 @@ static void check_methods (tree); static void remove_zero_width_bit_fields (tree); static bool accessible_nvdtor_p (tree); -/* Used by find_flexarrays and related. */ +/* Used by find_flexarrays and related functions. */ struct flexmems_t; -static void find_flexarrays (tree, flexmems_t *); static void diagnose_flexarrays (tree, const flexmems_t *); -static void check_flexarrays (tree, flexmems_t * = NULL); +static void find_flexarrays (tree, flexmems_t *, bool = false, tree = NULL_TREE); +static void check_flexarrays (tree, flexmems_t * = NULL, bool = false); static void check_bases (tree, int *, int *); static void check_bases_and_members (tree); static tree create_vtable_ptr (tree, tree *); @@ -6688,53 +6688,161 @@ field_nonempty_p (const_tree fld) return false; } -/* Used by find_flexarrays and related. */ -struct flexmems_t { +/* Used by find_flexarrays and related functions. */ + +struct flexmems_t +{ /* The first flexible array member or non-zero array member found - in order of layout. */ + in the order of layout. */ tree array; /* First non-static non-empty data member in the class or its bases. */ tree first; - /* First non-static non-empty data member following either the flexible - array member, if found, or the zero-length array member. */ - tree after; + /* A pair of the first non-static non-empty data members following + either the flexible array member, if found, or the zero-length + array member otherwise. AFTER[1] refers to the first such data + member of a union that the struct containing the flexible array + member or zero-length array is a member, or NULL when no such + union exists. AFTER[0] refers to the first such data member that + is not a member of such a union. + For example, in the following, the flexible array member + S::U::X::a overlaps S::U::Y::i and so AFTER[1] is set to refer to + the latter. This potential problem is indepenent of union U's + membership in struct S. In addition, in the definition of struct + S, S::U::x::a is followed by S::z, and so AFTER[0] is set to refer + to the latter. The two problems result in two diagnostics, the + first one being a pedantic warning and the second a hard error. + + struct S { + union U { + struct X { int i, a[]; } x; + struct Y { long i, a[]; } y; + } u; + int z; + }; + */ + tree after[2]; + + /* The type in which an anonymous struct or union containing ARRAY + is defined or null if no such anonymous struct or union exists. */ + tree anonctx; }; /* Find either the first flexible array member or the first zero-length array, in that order or preference, among members of class T (but not - its base classes), and set members of FMEM accordingly. */ + its base classes), and set members of FMEM accordingly. + BASE_P is true if T is a base class of another class. + PUN is set to the outermost union of which T is a member if one such + union exists, otherwise to NULL. */ static void -find_flexarrays (tree t, flexmems_t *fmem) +find_flexarrays (tree t, flexmems_t *fmem, bool base_p, + tree pun /* = NULL_TREE */) { - for (tree fld = TYPE_FIELDS (t), next; fld; fld = next) + /* Set the "pointer" to the outermost enclosing union if not set + yet and maintain it for the remainder of the recursion. */ + if (!pun && TREE_CODE (t) == UNION_TYPE) + pun = t; + + for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld)) { - /* Find the next non-static data member if it exists. */ - for (next = fld; - (next = DECL_CHAIN (next)) - && TREE_CODE (next) != FIELD_DECL; ); + if (fld == error_mark_node) + return; - tree fldtype = TREE_TYPE (fld); - if (TREE_CODE (fld) != TYPE_DECL - && RECORD_OR_UNION_TYPE_P (fldtype) - && TYPE_ANONYMOUS_P (fldtype)) - { - /* Members of anonymous structs and unions are treated as if - they were members of the containing class. Descend into - the anonymous struct or union and find a flexible array - member or zero-length array among its fields. */ - find_flexarrays (fldtype, fmem); - continue; - } + /* Is FLD a typedef for an anonymous struct? */ + bool anon_type_p + = (TREE_CODE (fld) == TYPE_DECL + && DECL_IMPLICIT_TYPEDEF_P (fld) + && anon_aggrname_p (DECL_NAME (fld))); - /* Skip anything that's not a (non-static) data member. */ - if (TREE_CODE (fld) != FIELD_DECL) + /* Skip anything that's GCC-generated or not a (non-static) data + member or typedef. */ + if ((DECL_ARTIFICIAL (fld) && !anon_type_p) + || (TREE_CODE (fld) != FIELD_DECL && TREE_CODE (fld) != TYPE_DECL)) continue; - /* Skip virtual table pointers. */ - if (DECL_ARTIFICIAL (fld)) + /* Type of the member. */ + tree fldtype = TREE_CODE (fld) == FIELD_DECL ? TREE_TYPE (fld) : fld; + if (fldtype == error_mark_node) + return; + + /* Determine the type of the array element or object referenced + by the member so that it can be checked for flexible array + members if it hasn't been yet. */ + tree eltype = TREE_CODE (fld) == FIELD_DECL ? fldtype : TREE_TYPE (fld); + if (eltype == error_mark_node) + return; + + while (TREE_CODE (eltype) == ARRAY_TYPE + || TREE_CODE (eltype) == POINTER_TYPE + || TREE_CODE (eltype) == REFERENCE_TYPE) + eltype = TREE_TYPE (eltype); + + if (TREE_CODE (fld) == TYPE_DECL + && TYPE_CANONICAL (eltype) == TYPE_CANONICAL (t)) continue; + if (RECORD_OR_UNION_TYPE_P (eltype)) + { + if (anon_type_p) + { + /* Check the nested unnamed type referenced via a typedef + independently of FMEM (since it's not a data member of + the enclising class). */ + check_flexarrays (eltype); + continue; + } + + if (eltype == fldtype || TYPE_ANONYMOUS_P (eltype)) + { + /* Descend into the non-static member struct or union and try + to find a flexible array member or zero-length array among + its members. This is only necessary for anonymous types + and types in whose context the current type T has not been + defined (the latter must not be checked again because they + are already in the process of being checked by one of the + recursive calls). */ + + tree first = fmem->first; + tree array = fmem->array; + + /* Does the field represent an anonymous struct? */ + bool anon_p = !DECL_NAME (fld) && ANON_AGGR_TYPE_P (eltype); + + /* If this member isn't anonymous and a prior non-flexible array + member has been seen in one of the enclosing structs, clear + the FIRST member since it doesn't contribute to the flexible + array struct's members. */ + if (first && !array && !anon_p) + fmem->first = NULL_TREE; + + find_flexarrays (eltype, fmem, false, pun); + + if (fmem->array != array) + { + /* If the member struct contains the first flexible array + member, store the enclosing struct if it is anonymous. */ + if (anon_p) + fmem->anonctx = t; + continue; + } + else if (first && !array && !anon_p) + { + /* Restore the FIRST member reset above if no flexible + array member has been found in this member's struct. */ + fmem->first = first; + } + + /* If the member struct contains the first flexible array + member, or if this member is a base class, continue to + the next member and avoid setting the FMEM->NEXT pointer + to point to it. */ + if (base_p) + continue; + } + else if (TREE_CODE (fld) == TYPE_DECL) + continue; + } + if (field_nonempty_p (fld)) { /* Remember the first non-static data member. */ @@ -6744,8 +6852,8 @@ find_flexarrays (tree t, flexmems_t *fmem) /* Remember the first non-static data member after the flexible array member, if one has been found, or the zero-length array if it has been found. */ - if (!fmem->after && fmem->array) - fmem->after = fld; + if (fmem->array && !fmem->after[bool (pun)]) + fmem->after[bool (pun)] = fld; } /* Skip non-arrays. */ @@ -6761,8 +6869,8 @@ find_flexarrays (tree t, flexmems_t *fmem) such field or a flexible array member has been seen to handle the pathological and unlikely case of multiple such members. */ - if (!fmem->after) - fmem->after = fld; + if (!fmem->after[bool (pun)]) + fmem->after[bool (pun)] = fld; } else if (integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype)))) /* Remember the first zero-length array unless a flexible array @@ -6778,8 +6886,8 @@ find_flexarrays (tree t, flexmems_t *fmem) reset the after pointer. */ if (TYPE_DOMAIN (TREE_TYPE (fmem->array))) { + fmem->after[bool (pun)] = NULL_TREE; fmem->array = fld; - fmem->after = NULL_TREE; } } else @@ -6797,47 +6905,109 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem) { /* Members of anonymous structs and unions are considered to be members of the containing struct or union. */ - if (TYPE_ANONYMOUS_P (t) || !fmem->array) + if (!fmem->array) return; - const char *msg = 0; + /* Issue errors first, and when no errors are found, then warnings + for flexible array members of structs in unions. */ + for (int in_union = false; in_union != 2; ++in_union) { - if (TYPE_DOMAIN (TREE_TYPE (fmem->array))) - { - if (fmem->after) - msg = G_("zero-size array member %qD not at end of %q#T"); - else if (!fmem->first) - msg = G_("zero-size array member %qD in an otherwise empty %q#T"); + /* The context of the flexible array member. Either the struct + in which it's declared or, for anonymous structs and unions, + the struct/union of which the array is effectively a member. */ + tree fmemctx = fmem->anonctx ? fmem->anonctx : t; - if (msg && pedwarn (DECL_SOURCE_LOCATION (fmem->array), - OPT_Wpedantic, msg, fmem->array, t)) + const char *msg = 0; - inform (location_of (t), "in the definition of %q#T", t); - } - else - { - if (fmem->after) - msg = G_("flexible array member %qD not at end of %q#T"); - else if (!fmem->first) - msg = G_("flexible array member %qD in an otherwise empty %q#T"); + if (TYPE_DOMAIN (TREE_TYPE (fmem->array))) + { + if (fmem->after[in_union]) + msg = (in_union + ? G_("zero-size array member %qD belonging to %q#T") + : G_("zero-size array member %qD not at end of %q#T")); + else if (!fmem->first) + msg = G_("zero-size array member %qD in an otherwise empty %q#T"); + + if (msg) + { + location_t loc = DECL_SOURCE_LOCATION (fmem->array); - if (msg) - { - error_at (DECL_SOURCE_LOCATION (fmem->array), msg, - fmem->array, t); - - /* In the unlikely event that the member following the flexible - array member is declared in a different class, point to it. - Otherwise it should be obvious. */ - if (fmem->after - && (DECL_CONTEXT (fmem->after) != DECL_CONTEXT (fmem->array))) - inform (DECL_SOURCE_LOCATION (fmem->after), - "next member %q#D declared here", - fmem->after); - - inform (location_of (t), "in the definition of %q#T", t); - } - } + if (!TREE_NO_WARNING (fmem->array) + && pedwarn (loc, OPT_Wpedantic, + msg, fmem->array, fmemctx)) + { + inform (location_of (t), "in the definition of %q#T", fmemctx); + + /* Prevent the same flexible array member from being diagnosed + more than once if it happens to be nested in more than one + union and overlap with another member. This avoids multiple + warnings for perverse cases like the following where + U::U1::X::a1 would otherwise be diagnosed first when finishing + the definition of U, followed by S::U1::X::a1 when completing + the definition of S: + struct S { + union U { + union U1 { struct X { int n1, a1[]; } x1; } u1; + union U2 { struct X { int n2, a2[]; } x1; } u2; + } u; + } s; + */ + TREE_NO_WARNING (fmem->array) = 1; + } + } + } + else + { + if (fmem->after[in_union]) + msg = (in_union + ? G_("flexible array member %qD belonging to %q#T") + : G_("flexible array member %qD not at end of %q#T")); + else if (!fmem->first) + msg = G_("flexible array member %qD in an otherwise empty %q#T"); + + if (msg) + { + location_t loc = DECL_SOURCE_LOCATION (fmem->array); + + /* Has a diagnostic been issued? */ + bool diagd = true; + + /* A union containing a struct with a flexible array member, + followed by another member (of the union) is diagnosed + with a warning for compatibility with GCC (C mode), even + though it's not valid accoding to C11. */ + if (in_union) + { + diagd = (TREE_NO_WARNING (fmem->array) + ? false : pedwarn (loc, OPT_Wpedantic, + msg, fmem->array, fmemctx)); + } + else + error_at (loc, msg, fmem->array, fmemctx); + + TREE_NO_WARNING (fmem->array) = 1; + + /* In the unlikely event that the member following the flexible + array member is declared in a different class, or the member + overlaps another member of a common union, point to it. + Otherwise it should be obvious. */ + if (diagd) + { + if (fmem->after[in_union] + && (in_union + || (DECL_CONTEXT (fmem->after[in_union]) + != DECL_CONTEXT (fmem->array)))) + { + inform (DECL_SOURCE_LOCATION (fmem->after[in_union]), + (in_union ? "overlaps member %q#D declared here" + : "next member %q#D declared here"), + fmem->after[in_union]); + inform (location_of (t), "in the definition of %q#T", t); + } + } + } + } + } } @@ -6850,7 +7020,8 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem) that fails the checks. */ static void -check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) +check_flexarrays (tree t, flexmems_t *fmem /* = NULL */, + bool base_p /* = false */) { /* Initialize the result of a search for flexible array and zero-length array members. Avoid doing any work if the most interesting FMEM data @@ -6858,18 +7029,21 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) flexmems_t flexmems = flexmems_t (); if (!fmem) fmem = &flexmems; - else if (fmem->array && fmem->first && fmem->after) + else if (fmem->array && fmem->first + && fmem->after[false] && fmem->after[true]) return; + tree fam = fmem->array; + /* Recursively check the primary base class first. */ if (CLASSTYPE_HAS_PRIMARY_BASE_P (t)) { tree basetype = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (t)); - check_flexarrays (basetype, fmem); + check_flexarrays (basetype, fmem, true); } /* Recursively check the base classes. */ - int nbases = BINFO_N_BASE_BINFOS (TYPE_BINFO (t)); + int nbases = TYPE_BINFO (t) ? BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) : 0; for (int i = 0; i < nbases; ++i) { tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (t), i); @@ -6883,7 +7057,7 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) continue; /* Check the base class. */ - check_flexarrays (BINFO_TYPE (base_binfo), fmem); + check_flexarrays (BINFO_TYPE (base_binfo), fmem, true); } if (fmem == &flexmems) @@ -6900,17 +7074,24 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) /* Check the virtual base class. */ tree basetype = TREE_TYPE (base_binfo); - check_flexarrays (basetype, fmem); + check_flexarrays (basetype, fmem, true); } } - /* Search the members of the current (derived) class. */ - find_flexarrays (t, fmem); + bool anon_p = TYPE_ANONYMOUS_P (t) || anon_aggrname_p (TYPE_IDENTIFIER (t)); - if (fmem == &flexmems) + /* Search the members of the current (possibly derived) class, skipping + unnamed structs and unions since those could be anonymous. */ + if (fmem != &flexmems || !anon_p) + find_flexarrays (t, fmem, base_p || fam != fmem->array); + + if (fmem == &flexmems && !anon_p) { - /* Issue diagnostics for invalid flexible and zero-length array members - found in base classes or among the members of the current class. */ + /* Issue diagnostics for invalid flexible and zero-length array + members found in base classes or among the members of the current + class. Ignore anonymous structs and unions whose members are + considered to be members of the enclosing class and thus will + be diagnosed when checking it. */ diagnose_flexarrays (t, fmem); } } diff --git a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c index 9fab3a8..b102306 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c @@ -495,7 +495,16 @@ struct types attrib_array_types[] = { #define HASH_SIZE 32749 static struct entry *hash_table[HASH_SIZE]; -static int idx, limidx, output_one, short_enums; +/* The index of the current type being output. */ +static int idx; + +/* The maximum index of the type(s) to output. */ +static int limidx; + +/* Set to non-zero to output a single type in response to the -i option + (which sets LIMIDX to the index of the type to output. */ +static int output_one; +static int short_enums; static const char *destdir; static const char *srcdir; static const char *srcdir_safe; @@ -535,6 +544,7 @@ switchfiles (int fields) fputs ("failed to create test files\n", stderr); exit (1); } + for (i = 0; i < NDG_OPTIONS; i++) fprintf (outfile, dg_options[i], "", srcdir_safe); fprintf (outfile, "\n\ @@ -607,9 +617,14 @@ getrandll (void) /* Generate a subfield. The object pointed to by FLEX is set to a non-zero value when the generated field is a flexible array member. When set, it - prevents subsequent fields from being generated (a flexible array mem*/ + prevents subsequent fields from being generated (a flexible array member + must be the last member of the struct it's defined in). ARRAY is non- + zero when the enclosing structure is part of an array. In that case, + avoid generating a flexible array member as a subfield (such a member + would be invalid). */ + int -subfield (struct entry *e, char *letter, int *flex) +subfield (struct entry *e, char *letter, int *flex, int array) { int i, type; char buf[20]; @@ -664,7 +679,14 @@ subfield (struct entry *e, char *letter, int *flex) } for (i = 1; !*flex && i <= e[0].len; ) - i += subfield (e + i, letter, flex); + { + /* Avoid generating flexible array members if the enclosing + type is an array. */ + int array + = (e[0].etype == ETYPE_STRUCT_ARRAY + || e[0].etype == ETYPE_UNION_ARRAY); + i += subfield (e + i, letter, flex, array); + } switch (type) { @@ -685,7 +707,7 @@ subfield (struct entry *e, char *letter, int *flex) case ETYPE_ARRAY: if (e[0].etype == ETYPE_ARRAY) { - if (e[0].arr_len == 255) + if (!array && e[0].arr_len == 255) { *flex = 1; snprintf (buf, 20, "%c[]", *letter); @@ -1141,6 +1163,7 @@ e_insert (struct entry *e) hash_table[hval % HASH_SIZE] = e; } +/* Output a single type. */ void output (struct entry *e) { @@ -1169,7 +1192,7 @@ output (struct entry *e) int flex = 0; for (i = 1; i <= e[0].len; ) - i += subfield (e + i, &c, &flex); + i += subfield (e + i, &c, &flex, 0); fputs (",", outfile); c = 'a'; diff --git a/gcc/testsuite/g++.dg/ext/flexary18.C b/gcc/testsuite/g++.dg/ext/flexary18.C new file mode 100644 index 0000000..5478a87 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary18.C @@ -0,0 +1,217 @@ +// PR c++/71912 - [6/7 regression] flexible array in struct in union rejected +// { dg-do compile } +// { dg-additional-options "-Wpedantic -Wno-error=pedantic" } + +namespace pr71912 { + +struct foo { + int a; + char s[]; // { dg-warning "flexible array member" } +}; + +struct bar { + double d; // { dg-message "overlaps member" } + char t[]; +}; + +struct baz { // { dg-message "in the definition" } + union { + struct foo f; + struct bar b; + } u; +}; + +struct xyyzy { // { dg-message "in the definition" } + union { + struct { + int a; + char s[]; // { dg-warning "flexible array member" } + } f; + struct { + double d; // { dg-message "overlaps member" } + char t[]; + } b; + } u; +}; + +struct baz b; +struct xyyzy x; + +} + +// The following definitions aren't strictly valid but, like those above, +// are accepted for compatibility with GCC (in C mode). They are benign +// in that the flexible array member is at the highest offset within +// the outermost type and doesn't overlap with other members except for +// those of the union. +union UnionStruct1 { + struct { int n1, a[]; } s; // { dg-warning "flexible array member" } + int n2; // { dg-message "overlaps" } +}; + +union UnionStruct2 { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array member" } + struct { int n2, a2[]; } s2; // { dg-message "overlaps" } + int n3; +}; + +union UnionStruct3 { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array member" } + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + char n3; +}; + +union UnionStruct4 { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array member" } + struct { + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + } s3; + char n3; +}; + +union UnionStruct5 { + struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "flexible array" } + struct { double n2, a2[]; } s3; // { dg-message "overlaps" } + char n3; +}; + +union UnionStruct6 { + struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "flexible array" } + struct { + struct { double n2, a2[]; } s3; // { dg-message "overlaps" } + } s4; + char n3; +}; + +union UnionStruct7 { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array" } + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + struct { struct { int n3, a3[]; } s3; } s4; +}; + +union UnionStruct8 { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array" } + struct { + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + } s3; + struct { struct { int n3, a3[]; } s4; } s5; +}; + +union UnionStruct9 { + struct { struct { int n1, a1[]; } s1; } s2;// { dg-warning "flexible array" } + struct { + struct { double n2, a2[]; } s3; // { dg-message "overlaps" } + } s4; + struct { struct { int n3, a3[]; } s5; } s6; +}; + +struct StructUnion1 { + union { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array" } + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + char n3; + } u; +}; + +// The following are invalid and rejected. +struct StructUnion2 { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + } u; + char n3; // { dg-message "next member" } +}; + +struct StructUnion3 { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + struct { double n2, a2[]; } s2; + } u; + char n3; // { dg-message "next member" } +}; + +struct StructUnion4 { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + } u1; + union { + struct { double n2, a2[]; } s2; + } u2; // { dg-message "next member" } +}; + +struct StructUnion5 { + union { + union { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array" } + } u1; + union { + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + } u2; + } u; +}; + +struct StructUnion6 { + union { + struct { int n1, a1[]; } s1; // { dg-warning "flexible array" } + union { + struct { double n2, a2[]; } s2; // { dg-message "overlaps" } + } u2; + } u; +}; + +struct StructUnion7 { + union { + union { + struct { double n2, a2[]; } s2; // { dg-warning "flexible array" } + } u2; + struct { int n1, a1[]; } s1; // { dg-message "overlaps" } + } u; +}; + +struct StructUnion8 { + struct { + union { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + } u1; + union { + struct { double n2, a2[]; } s2; + } u2; + } u; + } s1; + + struct { + union { + union { + struct { int n1, a1[]; } s1; + } u1; + union { + struct { double n2, a2[]; } s2; + } u2; + } u; // { dg-message "next member" } + } s2; +}; + +struct StructUnion9 { // { dg-message "in the definition" } + struct A1 { + union B1 { + union C1 { + struct Sx1 { int n1, a1[]; } sx1; // { dg-error "not at end" } + // { dg-warning "flexible array" "" { target *-*-*-* } 198 } + } c1; + union D1 { + struct Sx2 { double n2, a2[]; } sx2; + } d1; + } b1; + } a1; + + struct A2 { + union B2 { // { dg-message "in the definition" } + union C2 { + struct Sx3 { int n3, a3[]; } sx3; // { dg-warning "flexible array" } + } c2; + union D2 { + struct Sx3 { double n4, a4[]; } sx4;// { dg-message "overlaps member" } + } d2; + } b2; // { dg-message "next member" } + } a2; +}; diff --git a/gcc/testsuite/g++.dg/ext/flexary19.C b/gcc/testsuite/g++.dg/ext/flexary19.C new file mode 100644 index 0000000..dfc72d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary19.C @@ -0,0 +1,312 @@ +// { dg-do compile } +// { dg-additional-options "-Wpedantic -Wno-error=pedantic" } + +// Verify that flexible array members are recognized as either valid +// or invalid in anonymous structs (a G++ extension) and C++Nanonymous +// unions as well as in structs and unions that look anonymous but +// aren't. +struct S1 +{ + int i; + + // The following declares a named data member of an unnamed struct + // (i.e., it is not an anonymous struct). + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S2 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[1]; +}; + +struct S3 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[]; +}; + +struct S4 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[2]; +}; + +struct S5 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[1][2]; +}; + +struct S6 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[][2]; +}; + +struct S7 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } *s; +}; + +struct S8 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s; +}; + +struct S9 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } *s[1]; +}; + +struct S10 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } *s[]; +}; + +struct S11 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s[1]; +}; + +struct S12 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s[]; +}; + +struct S13 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s[2]; +}; + +struct S14 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } &s; +}; + +struct S15 +{ + int i; + + typedef struct { + int a[]; // { dg-error "in an otherwise empty" } + } T15; +}; + +struct S16 +{ + int i; + + struct { + int a[]; + }; // { dg-warning "anonymous struct" } +}; + +struct S17 +{ + int i; + + union { // anonymous union + int a[]; // { dg-error "flexible array member in union" } + }; +}; + +struct S18 +{ + int i; + + struct { + int j, a[]; + } s; +}; + +struct S19 +{ + int i; + + struct { + int j, a[]; + }; // { dg-warning "anonymous struct" } +}; + +struct S20 +{ + static int i; + typedef int A[]; + + struct { + int j; + A a; + } s; +}; + +struct S21 +{ + static int i; + typedef int A[]; + + struct { + int j; + A a; + }; // { dg-warning "anonymous struct" } +}; + +struct S22 +{ + struct S22S { + static int i; + + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S23 +{ + struct { + static int i; // { dg-error "static data member" } + + int a[]; // { dg-error "in an otherwise empty" } + }; // { dg-warning "anonymous struct" } +}; + +struct S24 +{ + static int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S25 +{ + int i; + + struct { + int j, a[]; + } s; + + // Verify that a static data member of the enclosing class doesn't + // cause infinite recursion or some such badness. + static S25 s2; +}; + +struct S26 +{ + template + struct S26S { + static int a; + }; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S27 +{ + S27 *p; + int a[]; +}; + +struct S28 +{ + struct A { + struct B { + S28 *ps28; + A *pa; + B *pb; + } b, *pb; + A *pa; + } a, *pa; + + S28::A *pa2; + S28::A::B *pb; + + int flexarray[]; +}; + +typedef struct Opaque* P29; +struct S30 { P29 p; }; +struct S31 { S30 s; }; + +typedef struct { } S32; +typedef struct { S32 *ps32; } S33; +typedef struct +{ + S33 *ps33; +} S34; + +struct S35 +{ + struct A { + int i1, a1[]; + }; + + struct B { + int i2, a2[]; + }; + + typedef struct { + int i3, a3[]; + } C; + + typedef struct { + int i4, a4[]; + } D; + + typedef A A2; + typedef B B2; + typedef C C2; + typedef D D2; +}; + diff --git a/gcc/testsuite/g++.dg/ext/flexary4.C b/gcc/testsuite/g++.dg/ext/flexary4.C index 97ec625..29d6bdd 100644 --- a/gcc/testsuite/g++.dg/ext/flexary4.C +++ b/gcc/testsuite/g++.dg/ext/flexary4.C @@ -102,31 +102,28 @@ struct Sx17 { int a_0 [0]; }; -// Empty structs are a GCC extension that (in C++ only) is treated -// as if it had a single member of type char. Therefore, a struct +// An empty struct is treated as if it had a single member of type +// char but the member cannot be accessed. Therefore, a struct // containing a flexible array member followed by an empty struct // is diagnosed to prevent the former subobject from sharing space // with the latter. struct Sx18 { int a_x []; // { dg-error "flexible array member" } - struct S { }; + struct { /* empty */ } s; }; -// Anonymous structs and unions are another GCC extension. Since -// they cannot be named and thus used to store the size of a flexible -// array member, a struct containing both is diagnosed as if -// the flexible array member appeared alone. +// Anonymous structs are a G++ extension. Members of anonymous structs +// are treated as if they were declared in the enclosing class. struct Sx19 { - struct S { }; - union U { }; - int a_x []; // { dg-error "in an otherwise empty" } + struct { int i; }; // anonymous struct + int a_x []; }; -// Unlike in the case above, a named member of an anonymous struct -// prevents a subsequent flexible array member from being diagnosed. +// Unlike in the case above, a named struct is not anonymous and +// so doesn't contribute its member to that of the enclosing struct. struct Sx20 { - struct S { } s; - int a_x []; + struct S { int i; }; + int a_x []; // { dg-error "in an otherwise empty" } }; struct Sx21 { @@ -298,6 +295,15 @@ struct Anon1 { ASSERT_AT_END (Anon1, good); +struct NotAnon1 { + int n; + // The following is not an anonymous struct -- the type is unnamed + // but the object has a name. + struct { + int bad[]; // { dg-error "otherwise empty" } + } name; +}; + struct Anon2 { struct { int n; @@ -352,7 +358,6 @@ struct Anon7 { int n; }; - struct Six { int i; int a[]; diff --git a/gcc/testsuite/g++.dg/torture/pr64312.C b/gcc/testsuite/g++.dg/torture/pr64312.C index 85211f2..c7a56d7 100644 --- a/gcc/testsuite/g++.dg/torture/pr64312.C +++ b/gcc/testsuite/g++.dg/torture/pr64312.C @@ -44,7 +44,7 @@ class F { public: int nelems; - int elems[]; + int elems[]; // { dg-error "not at end" } int * m_fn1 () { @@ -88,7 +88,7 @@ public: m_impl->~any_incrementable_iterator_interface (); } G m_buffer; - any_incrementable_iterator_interface *m_impl; + any_incrementable_iterator_interface *m_impl; // { dg-message "next member" } }; template class K : public I > {