+2016-10-13 Martin Sebor <msebor@redhat.com>
+
+ 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.
+ (diagnose_invalid_flexarray): New functions.
+
2016-10-13 Jakub Jelinek <jakub@redhat.com>
Jason Merrill <jason@redhat.com>
* decl.c (mark_inline_variable): New.
+>>>>>>> .r241142
2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
* decl2.c: Include memmodel.h.
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, 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 *);
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;
+ /* The first non-static non-empty data member 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
+ of which the struct containing the flexible array member or zero-length
+ array is a member, or NULL when no such union exists. This element is
+ only used during searching, not for diagnosing problems. AFTER[0]
+ refers to the first such data member that is not a member of such
+ a union. */
+ tree after[2];
+
+ /* Refers to a struct (not union) in which the struct of which the flexible
+ array is member is defined. Used to diagnose strictly (according to C)
+ invalid uses of the latter structs. */
+ tree enclosing;
};
/* 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. */
+ array, in that order of preference, among members of class T (but not
+ 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 in which the flexible array member
+ (or zero-length array) is defined if one such union exists, otherwise
+ to NULL.
+ Similarly, PSTR is set to a data member of the outermost struct of
+ which the flexible array is a member if one such struct 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 */,
+ tree pstr /* = 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_UNNAMED_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);
+ /* Is FLD a typedef for an anonymous struct? */
+
+ /* FIXME: Note that typedefs (as well as arrays) need to be fully
+ handled elsewhere so that errors like the following are detected
+ as well:
+ typedef struct { int i, a[], j; } S; // bug c++/72753
+ S s [2]; // bug c++/68489
+ */
+ if (TREE_CODE (fld) == TYPE_DECL
+ && DECL_IMPLICIT_TYPEDEF_P (fld)
+ && CLASS_TYPE_P (TREE_TYPE (fld))
+ && anon_aggrname_p (DECL_NAME (fld)))
+ {
+ /* Check the nested unnamed type referenced via a typedef
+ independently of FMEM (since it's not a data member of
+ the enclosing class). */
+ check_flexarrays (TREE_TYPE (fld));
continue;
}
- /* 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. */
+ if (DECL_ARTIFICIAL (fld) || TREE_CODE (fld) != FIELD_DECL)
continue;
- /* Skip virtual table pointers. */
- if (DECL_ARTIFICIAL (fld))
- continue;
+ /* Type of the member. */
+ tree fldtype = TREE_TYPE (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 = fldtype;
+ while (TREE_CODE (eltype) == ARRAY_TYPE
+ || TREE_CODE (eltype) == POINTER_TYPE
+ || TREE_CODE (eltype) == REFERENCE_TYPE)
+ eltype = TREE_TYPE (eltype);
+
+ if (RECORD_OR_UNION_TYPE_P (eltype))
+ {
+ if (fmem->array && !fmem->after[bool (pun)])
+ {
+ /* Once the member after the flexible array has been found
+ we're done. */
+ fmem->after[bool (pun)] = fld;
+ break;
+ }
+
+ if (eltype == fldtype || TYPE_UNNAMED_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;
+
+ /* 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_AGGR_TYPE_P (eltype))
+ fmem->first = NULL_TREE;
+
+ find_flexarrays (eltype, fmem, false, pun,
+ !pstr && TREE_CODE (t) == RECORD_TYPE ? fld : pstr);
+
+ if (fmem->array != array)
+ continue;
+
+ if (first && !array && !ANON_AGGR_TYPE_P (eltype))
+ {
+ /* 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;
+ }
+ }
if (field_nonempty_p (fld))
{
/* 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. */
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
- member has already been seen. */
- fmem->array = fld;
+ {
+ /* Remember the first zero-length array unless a flexible array
+ member has already been seen. */
+ fmem->array = fld;
+ fmem->enclosing = pstr;
+ }
}
else
{
reset the after pointer. */
if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
{
+ fmem->after[bool (pun)] = NULL_TREE;
fmem->array = fld;
- fmem->after = NULL_TREE;
+ fmem->enclosing = pstr;
}
}
else
- fmem->array = fld;
+ {
+ fmem->array = fld;
+ fmem->enclosing = pstr;
+ }
}
}
}
+/* Diagnose a strictly (by the C standard) invalid use of a struct with
+ a flexible array member (or the zero-length array extension). */
+
+static void
+diagnose_invalid_flexarray (const flexmems_t *fmem)
+{
+ if (fmem->array && fmem->enclosing
+ && pedwarn (location_of (fmem->enclosing), OPT_Wpedantic,
+ TYPE_DOMAIN (TREE_TYPE (fmem->array))
+ ? G_("invalid use of %q#T with a zero-size array "
+ "in %q#D")
+ : G_("invalid use of %q#T with a flexible array member "
+ "in %q#T"),
+ DECL_CONTEXT (fmem->array),
+ DECL_CONTEXT (fmem->enclosing)))
+ inform (DECL_SOURCE_LOCATION (fmem->array),
+ "array member %q#D declared here", fmem->array);
+}
+
/* Issue diagnostics for invalid flexible array members or zero-length
arrays that are not the last elements of the containing class or its
base classes or that are its sole members. */
static void
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_UNNAMED_P (t) || !fmem->array)
+ if (!fmem->array)
return;
+ if (fmem->first && !fmem->after[0])
+ {
+ diagnose_invalid_flexarray (fmem);
+ return;
+ }
+
+ /* Has a diagnostic been issued? */
+ bool diagd = false;
+
const char *msg = 0;
if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
{
- if (fmem->after)
+ if (fmem->after[0])
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");
- if (msg && pedwarn (DECL_SOURCE_LOCATION (fmem->array),
- OPT_Wpedantic, msg, fmem->array, t))
+ if (msg)
+ {
+ location_t loc = DECL_SOURCE_LOCATION (fmem->array);
- inform (location_of (t), "in the definition of %q#T", t);
+ if (pedwarn (loc, OPT_Wpedantic, msg, fmem->array, t))
+ {
+ inform (location_of (t), "in the definition of %q#T", t);
+ diagd = true;
+ }
+ }
}
else
{
- if (fmem->after)
+ if (fmem->after[0])
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 (msg)
{
- error_at (DECL_SOURCE_LOCATION (fmem->array), msg,
- fmem->array, t);
+ location_t loc = DECL_SOURCE_LOCATION (fmem->array);
+ diagd = true;
+
+ error_at (loc, 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.
+ 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 (fmem->after
- && (DECL_CONTEXT (fmem->after) != DECL_CONTEXT (fmem->array)))
- inform (DECL_SOURCE_LOCATION (fmem->after),
+ if (fmem->after[0]
+ && ((DECL_CONTEXT (fmem->after[0])
+ != DECL_CONTEXT (fmem->array))))
+ {
+ inform (DECL_SOURCE_LOCATION (fmem->after[0]),
"next member %q#D declared here",
- fmem->after);
-
- inform (location_of (t), "in the definition of %q#T", t);
+ fmem->after[0]);
+ inform (location_of (t), "in the definition of %q#T", t);
+ }
}
}
+
+ if (!diagd && fmem->array && fmem->enclosing)
+ diagnose_invalid_flexarray (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
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[0])
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);
continue;
/* Check the base class. */
- check_flexarrays (BINFO_TYPE (base_binfo), fmem);
+ check_flexarrays (BINFO_TYPE (base_binfo), fmem, /*base_p=*/true);
}
if (fmem == &flexmems)
/* Check the virtual base class. */
tree basetype = TREE_TYPE (base_binfo);
- check_flexarrays (basetype, fmem);
+ check_flexarrays (basetype, fmem, /*base_p=*/true);
}
}
- /* Search the members of the current (derived) class. */
- find_flexarrays (t, fmem);
+ /* Is the type unnamed (and therefore a member of it potentially
+ an anonymous struct or union)? */
+ bool maybe_anon_p = TYPE_UNNAMED_P (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 || !maybe_anon_p)
+ find_flexarrays (t, fmem, base_p || fam != fmem->array);
+
+ if (fmem == &flexmems && !maybe_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);
}
}
* gcc.target/arm/scd42-2.c: Fix existing logic to skip if -mcpu
is incompatible with Xscale.
+2016-10-13 Martin Sebor <msebor@redhat.com>
+
+ PR c++/71912
+ * g++.dg/ext/flexary4.C: Adjust.
+ * g++.dg/ext/flexary5.C: Same.
+ * g++.dg/ext/flexary9.C: Same.
+ * g++.dg/ext/flexary19.C: New test.
+ * g++.dg/ext/flexary18.C: New test.
+ * 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.
+
2016-10-13 Martin Sebor <msebor@redhat.com>
* gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Cast 0 to wint_t
* gcc.target/msp430/function-attributes-2.c: New test.
* gcc.target/msp430/function-attributes-3.c: New test.
+2015-04-18 Martin Sebor <msebor@redhat.com>
+
+ * gfortran.dg/pr32627.f03 (strptr): Change size to match the number
+ of non-nul characters.
+ * gfortran.dg/substr_6.f90: Make the NUL character visible on stdout
+
2016-09-13 Jakub Jelinek <jakub@redhat.com>
* g++.dg/cpp0x/gen-attrs-61.C: New test.
#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;
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\
/* 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];
}
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)
{
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);
hash_table[hval % HASH_SIZE] = e;
}
+/* Output a single type. */
void
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';
--- /dev/null
+// PR c++/71912 - [6/7 regression] flexible array in struct in union rejected
+// { dg-do compile }
+// { dg-additional-options "-Wpedantic -Wno-error=pedantic" }
+
+#if __cplusplus
+
+namespace pr71912 {
+
+#endif
+
+struct foo {
+ int a;
+ char s[]; // { dg-message "array member .char pr71912::foo::s \\\[\\\]. declared here" }
+};
+
+struct bar {
+ double d;
+ char t[];
+};
+
+struct baz {
+ union {
+ struct foo f;
+ struct bar b;
+ }
+ // The definition of struct foo is fine but the use of struct foo
+ // in the definition of u below is what's invalid and must be clearly
+ // diagnosed.
+ u; // { dg-warning "invalid use of .struct pr71912::foo. with a flexible array member in .struct pr71912::baz." }
+};
+
+struct xyyzy {
+ union {
+ struct {
+ int a;
+ char s[]; // { dg-message "declared here" }
+ } f;
+ struct {
+ double d;
+ char t[];
+ } b;
+ } u; // { dg-warning "invalid use" }
+};
+
+struct baz b;
+struct xyyzy x;
+
+#if __cplusplus
+
+}
+
+#endif
+
+// 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;
+ int n2;
+};
+
+union UnionStruct2 {
+ struct { int n1, a1[]; } s1;
+ struct { int n2, a2[]; } s2;
+ int n3;
+};
+
+union UnionStruct3 {
+ struct { int n1, a1[]; } s1;
+ struct { double n2, a2[]; } s2;
+ char n3;
+};
+
+union UnionStruct4 {
+ struct { int n1, a1[]; } s1;
+ struct { struct { int n2, a2[]; } s2; } s3;
+ char n3;
+};
+
+union UnionStruct5 {
+ struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "invalid use" }
+ struct { double n2, a2[]; } s3;
+ char n3;
+};
+
+union UnionStruct6 {
+ struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "invalid use" }
+ struct { struct { int n2, a2[]; } s3; } s4;
+ char n3;
+};
+
+union UnionStruct7 {
+ struct { int n1, a1[]; } s1;
+ struct { double n2, a2[]; } s2;
+ struct { struct { int n3, a3[]; } s3; } s4;
+};
+
+union UnionStruct8 {
+ struct { int n1, a1[]; } s1;
+ struct { struct { int n2, a2[]; } s2; } s3;
+ struct { struct { int n3, a3[]; } s4; } s5;
+};
+
+union UnionStruct9 {
+ struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "invalid use" }
+ struct { struct { int n2, a2[]; } s3; } s4;
+ struct { struct { int n3, a3[]; } s5; } s6;
+};
+
+struct StructUnion1 {
+ union {
+ struct { int n1, a1[]; } s1; // { dg-message "declared here" }
+ struct { double n2, a2[]; } s2;
+ char n3;
+ } u; // { dg-warning "invalid use" }
+};
+
+// 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-message "declared here" }
+ } u1;
+ union { struct { int n2, a2[]; } s2; } u2;
+ } u; // { dg-warning "invalid use" }
+};
+
+struct StructUnion6 {
+ union {
+ struct { int n1, a1[]; } s1; // { dg-message "declared here" }
+ union { struct { int n2, a2[]; } s2; } u2;
+ } u; // { dg-warning "invalid use" }
+};
+
+struct StructUnion7 {
+ union {
+ union {
+ struct { double n2, a2[]; } s2; // { dg-message "declared here" }
+ } u2;
+ struct { int n1, a1[]; } s1;
+ } u; // { dg-warning "invalid use" }
+};
+
+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; } s2; // { dg-message "next member" }
+};
+
+struct StructUnion9 { // { dg-message "in the definition" }
+ struct A1 {
+ union B1 {
+ union C1 {
+ struct Sx1 { int n1, a1[]; } sx1; // { dg-error "not at end" }
+ } c1;
+ union D1 {
+ struct Sx2 { double n2, a2[]; } sx2;
+ } d1;
+ } b1; // { dg-warning "invalid use" }
+ } a1;
+
+ struct A2 {
+ union B2 {
+ union C2 {
+ struct Sx3 { int n3, a3[]; } sx3; // { dg-message "declared here" }
+ } c2;
+ union D2 { struct Sx4 { double n4, a4[]; } sx4; } d2;
+ } b2; // { dg-warning "invalid use" }
+ } a2; // { dg-message "next member" }
+};
--- /dev/null
+// { 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++ anonymous
+// 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 { // { dg-warning "invalid use" }
+ // A flexible array as a sole member of an anonymous struct is
+ // rejected with an error in C mode but emits just a pedantic
+ // warning in C++. Other than excessive pedantry there is no
+ // reason to reject it.
+ 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[]; // { dg-message "declared here" }
+ } s; // { dg-warning "invalid use" }
+};
+
+struct S19
+{
+ int i;
+
+ struct { // { dg-warning "invalid use" }
+ int j, a[]; // { dg-message "declared here" }
+ }; // { dg-warning "anonymous struct" }
+};
+
+struct S20
+{
+ static int i;
+ typedef int A[];
+
+ struct {
+ int j;
+ A a; // { dg-message "declared here" }
+ } s; // { dg-warning "invalid use" }
+};
+
+struct S21
+{
+ static int i;
+ typedef int A[];
+
+ struct { // { dg-warning "invalid use" }
+ int j;
+ A a; // { dg-message "declared here" }
+ }; // { 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[]; // { dg-message "declared here" }
+ } s; // { dg-warning "invalid use" }
+
+ // 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 <class>
+ 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[];
+};
+
+// Verify that the notes printed along with the warnings point to the types
+// or members they should point to and mention the correct relationships
+// with the flexible array members.
+namespace Notes
+{
+union A
+{
+ struct {
+ struct {
+ int i, a[]; // { dg-message "declared here" }
+ } c; // { dg-warning "invalid use" }
+ } d;
+ int j;
+};
+
+union B
+{
+ struct {
+ struct { // { dg-warning "invalid use" }
+ int i, a[]; // { dg-message "declared here" }
+ }; // { dg-warning "anonymous struct" }
+ }; // { dg-warning "anonymous struct" }
+ int j;
+};
+
+}
+
+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;
+};
+
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 {
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;
int n;
};
-
struct Six {
int i;
int a[];
ASSERT_AT_END (D5, a); // { dg-warning "offsetof within non-standard-layout" }
-struct A2x {
+struct A2x_1 {
size_t n;
- size_t a[]; // { dg-error "not at end of .struct D6.| D7.| D8." }
+ size_t a[]; // { dg-error "not at end of .struct D6." }
+};
+
+struct A2x_2 {
+ size_t n;
+ size_t a[]; // { dg-error "not at end of .struct D7." }
+};
+
+struct A2x_3 {
+ size_t n;
+ size_t a[]; // { dg-error "not at end of .struct D8." }
};
// Verify that the flexible array member in A2x above is diagnosed
// for each of the three struct defintions below which also derive
// from another struct with a flexible array member.
-struct D6: A2x, E1, A1x { };
-struct D7: E1, A2x, E2, A1x { };
-struct D8: E1, E2, A2x, A1x { };
+struct D6: A2x_1, E1, A1x { };
+struct D7: E1, A2x_2, E2, A1x { };
+struct D8: E1, E2, A2x_3, A1x { };
-struct DA2x: A2x { };
+struct DA2x: A2x_1 { };
struct D9: DA2x, E1, E2 { };
struct D28: NE1, AA6x { };
struct D29: AA6x, NE1 { };
-// Verify that a flexible array member in a virtual base class is not
-// diagnosed.
struct A7x {
size_t n;
- size_t a[];
+ size_t a[]; // { dg-error "flexible array member .A7x::a. not at end of .struct D33." }
};
+// Verify that a flexible array member in a virtual base class is not
+// diagnosed.
struct DA7xV1: virtual A7x { };
struct DA7xV2: virtual A7x { };
struct D30: DA7xV1, DA7xV2 { };
struct D31: DA7xV1, DA7xV2 { };
struct D32: D30, D31 { };
+
+// Verify the diagnostic when the flexible array is in an anonymous struct.
+struct A8x {
+ struct { // { dg-message "next member .A8x::<unnamed struct> A8x::<anonymous>. declared here" }
+ size_t n;
+ size_t a[];
+ };
+};
+
+struct D33: // { dg-message "in the definition of .struct D33." }
+ A7x, A8x { };
struct Anon1 {
int n;
- struct {
- int good[0]; // { dg-warning "zero-size array" }
+ struct { // { dg-warning "invalid use \[^\n\r\]* with a zero-size array" }
+ int good[0]; // { dg-warning "forbids zero-size array" }
}; // { dg-warning "anonymous struct" }
};
ASSERT_AT_END (Anon1, good);
struct Anon2 {
- struct {
+ struct { // { dg-warning "invalid use" }
int n;
struct {
int good[0]; // { dg-warning "zero-size array" }
ASSERT_AT_END (Anon2, good);
struct Anon3 {
- struct {
+ struct { // { dg-warning "invalid use" }
struct {
int n;
int good[0]; // { dg-warning "zero-size array" }
{
public:
int nelems;
- int elems[];
+ int elems[]; // { dg-error "not at end" }
int *
m_fn1 ()
{
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 Reference> class K : public I<any_iterator<Reference> >
{