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:
parent
253abb2a15
commit
9603204722
@ -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.
|
||||
|
293
gcc/cp/class.c
293
gcc/cp/class.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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';
|
||||
|
213
gcc/testsuite/g++.dg/ext/flexary18.C
Normal file
213
gcc/testsuite/g++.dg/ext/flexary18.C
Normal 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" }
|
||||
};
|
343
gcc/testsuite/g++.dg/ext/flexary19.C
Normal file
343
gcc/testsuite/g++.dg/ext/flexary19.C
Normal 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;
|
||||
};
|
||||
|
@ -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[];
|
||||
|
@ -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 { };
|
||||
|
@ -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" }
|
||||
|
@ -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> >
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user