PR c++/71912 - [6/7 regression] flexible array in struct in union rejected

gcc/cp/ChangeLog:

	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.

gcc/testsuite/ChangeLog:

	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.

From-SVN: r241143
This commit is contained in:
Martin Sebor 2016-10-13 16:26:36 -06:00
parent 253abb2a15
commit 9603204722
10 changed files with 895 additions and 105 deletions

View File

@ -1,3 +1,13 @@
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>
@ -39,6 +49,7 @@
* decl.c (mark_inline_variable): New.
>>>>>>> .r241142
2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
* decl2.c: Include memmodel.h.

View File

@ -147,11 +147,12 @@ 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, 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 *);
@ -6692,52 +6693,147 @@ 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;
/* 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)
{
/* Find the next non-static data member if it exists. */
for (next = fld;
(next = DECL_CHAIN (next))
&& TREE_CODE (next) != FIELD_DECL; );
/* 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;
tree fldtype = TREE_TYPE (fld);
if (TREE_CODE (fld) != TYPE_DECL
&& RECORD_OR_UNION_TYPE_P (fldtype)
&& TYPE_UNNAMED_P (fldtype))
for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld))
{
if (fld == error_mark_node)
return;
/* 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)))
{
/* 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);
/* 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))
{
@ -6748,8 +6844,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. */
@ -6765,13 +6861,16 @@ 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
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
{
@ -6782,16 +6881,39 @@ 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;
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. */
@ -6799,49 +6921,70 @@ find_flexarrays (tree t, flexmems_t *fmem)
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);
}
@ -6854,7 +6997,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
@ -6862,18 +7006,20 @@ 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[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);
@ -6887,7 +7033,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, /*base_p=*/true);
}
if (fmem == &flexmems)
@ -6904,17 +7050,26 @@ 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, /*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);
}
}

View File

@ -25,6 +25,19 @@
* 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
@ -1853,6 +1866,12 @@
* 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.

View File

@ -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';

View File

@ -0,0 +1,213 @@
// 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" }
};

View File

@ -0,0 +1,343 @@
// { 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;
};

View File

@ -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[];

View File

@ -64,19 +64,29 @@ struct D5: E1, E2, NE { char 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 { };
@ -194,16 +204,27 @@ struct NE2: NE { };
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 { };

View File

@ -281,15 +281,15 @@ struct S_S_S_x {
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" }
@ -300,7 +300,7 @@ struct Anon2 {
ASSERT_AT_END (Anon2, good);
struct Anon3 {
struct {
struct { // { dg-warning "invalid use" }
struct {
int n;
int good[0]; // { dg-warning "zero-size array" }

View File

@ -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 Reference> class K : public I<any_iterator<Reference> >
{