/* Used by find_flexarrays and related functions. */
struct flexmems_t;
static void diagnose_flexarrays (tree, const flexmems_t *);
-static void find_flexarrays (tree, flexmems_t *, bool = false,
- tree = NULL_TREE, tree = NULL_TREE);
+static void find_flexarrays (tree, flexmems_t *, bool, bool = false,
+ bool = false, tree = NULL_TREE);
static void check_flexarrays (tree, flexmems_t * = NULL, bool = false);
static void check_bases (tree, int *, int *);
static void check_bases_and_members (tree);
if (TREE_CODE (fld) == FIELD_DECL
&& TREE_CODE (type) != ERROR_MARK
&& (DECL_NAME (fld) || RECORD_OR_UNION_TYPE_P (type)))
- {
- return TYPE_SIZE (type)
- && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
- || !tree_int_cst_equal (size_zero_node, TYPE_SIZE (type)));
- }
+ return TYPE_SIZE (type) && !integer_zerop (TYPE_SIZE (type));
return false;
}
/* The first flexible array member or non-zero array member found
in the order of layout. */
tree array;
- /* First non-static non-empty data member in the class or its bases. */
- tree first;
+ /* True if there is a non-static non-empty data member in the class or
+ its bases. */
+ bool first;
/* 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
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
+ PUN is true when inside of a union (perhaps recursively).
+ 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. */
+ otherwise to NULL. NESTED_P is true for recursive calls except ones
+ handling anonymous aggregates. Those types are expected to be diagnosed
+ on its own already and so only the last member is checked vs. what
+ follows it in the outer type. */
static void
find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
- tree pun /* = NULL_TREE */,
+ bool nested_p /* = false */, bool pun /* = false */,
tree pstr /* = NULL_TREE */)
{
- /* 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))
+ if (TREE_CODE (t) == UNION_TYPE)
+ pun = true;
+
+ tree fld = TYPE_FIELDS (t);
+ if ((base_p || nested_p) && TREE_CODE (t) == RECORD_TYPE)
+ {
+ /* In bases or in nested structures, only process the last
+ non-static data member. If we have say
+ struct A { int a; int b[]; int c; };
+ struct B { int d; int e[]; int f; };
+ struct C : A { int g; B h, i; int j; };
+ then the A::b followed by A::c should have been diagnosed
+ already when completing struct A, and B::e followed by B::f
+ when completing struct B, so no need to repeat that when completing
+ struct C. So, only look at the last member so we cover e.g.
+ struct D { int k; int l[]; };
+ struct E : D { int m; };
+ struct F { D n; int o; };
+ where flexible array member at the end of D is fine, but it isn't
+ correct that E::m in E or F::o in F follows it. */
+ tree last_fld = NULL_TREE;
+ for (; (fld = next_subobject_field (fld)); fld = DECL_CHAIN (fld))
+ if (DECL_ARTIFICIAL (fld))
+ continue;
+ else if (TREE_TYPE (fld) == error_mark_node)
+ return;
+ else if (TREE_CODE (TREE_TYPE (fld)) == ARRAY_TYPE
+ || field_nonempty_p (fld))
+ last_fld = fld;
+ fld = last_fld;
+ }
+ for (; fld; fld = DECL_CHAIN (fld))
{
if (fld == error_mark_node)
return;
if (RECORD_OR_UNION_TYPE_P (eltype))
{
- if (fmem->array && !fmem->after[bool (pun)])
+ if (fmem->array && !fmem->after[pun])
{
/* Once the member after the flexible array has been found
we're done. */
- fmem->after[bool (pun)] = fld;
+ fmem->after[pun] = fld;
break;
}
are already in the process of being checked by one of the
recursive calls). */
- tree first = fmem->first;
+ bool first = fmem->first;
tree array = fmem->array;
+ bool maybe_anon_p = TYPE_UNNAMED_P (eltype);
+ if (tree ctx = maybe_anon_p ? TYPE_CONTEXT (eltype) : NULL_TREE)
+ maybe_anon_p = RECORD_OR_UNION_TYPE_P (ctx);
/* 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;
+ fmem->first = false;
- find_flexarrays (eltype, fmem, false, pun,
- !pstr && TREE_CODE (t) == RECORD_TYPE ? fld : pstr);
+ find_flexarrays (eltype, fmem, false, !maybe_anon_p, 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 recursive call passed true to nested_p,
+ it only looked at the last field and we do not
+ want to diagnose in that case the "in otherwise empty"
+ case, just if it is followed by some other non-empty
+ member. So set fmem->first. */
+ if (!maybe_anon_p)
+ fmem->first = true;
+ 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
+ the next member and avoid setting the FMEM->AFTER pointer
to point to it. */
if (base_p)
continue;
{
/* Remember the first non-static data member. */
if (!fmem->first)
- fmem->first = fld;
+ fmem->first = true;
/* 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->array && !fmem->after[bool (pun)])
- fmem->after[bool (pun)] = fld;
+ if (fmem->array && !fmem->after[pun])
+ fmem->after[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[bool (pun)])
- fmem->after[bool (pun)] = fld;
+ if (!fmem->after[pun])
+ fmem->after[pun] = fld;
}
else if (integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype))))
{
{
/* Replace the zero-length array if it's been stored and
reset the after pointer. */
- fmem->after[bool (pun)] = NULL_TREE;
+ fmem->after[pun] = NULL_TREE;
fmem->array = fld;
fmem->enclosing = pstr;
}
- else if (!fmem->after[bool (pun)])
+ else if (!fmem->after[pun])
/* Make a record of another flexible array member. */
- fmem->after[bool (pun)] = fld;
+ fmem->after[pun] = fld;
}
else
{
{
auto_diagnostic_group d;
if (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)))
+ 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);
+ "array member %q#D declared here", fmem->array);
}
}
overlaps another member of a common union, point to it.
Otherwise it should be obvious. */
if (fmem->after[0]
- && ((DECL_CONTEXT (fmem->after[0])
- != DECL_CONTEXT (fmem->array))))
+ && (DECL_CONTEXT (fmem->after[0])
+ != DECL_CONTEXT (fmem->array)))
{
inform (DECL_SOURCE_LOCATION (fmem->after[0]),
"next member %q#D declared here",
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. 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);
- }
+ /* 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);
}
/* Perform processing required when the definition of T (a class type)