@@ -141,8 +141,8 @@ static bool accessible_nvdtor_p (tree);
/* 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);
@@ -7362,11 +7362,9 @@ field_nonempty_p (const_tree fld)
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)
+ && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+ || !integer_zerop (TYPE_SIZE (type))));
return false;
}
@@ -7378,8 +7376,9 @@ struct flexmems_t
/* 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
@@ -7400,24 +7399,50 @@ struct flexmems_t
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. */
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;
+ if (TREE_CODE (t) == UNION_TYPE)
+ pun = true;
- for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld))
+ 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; fld = DECL_CHAIN (fld))
+ if (fld == error_mark_node)
+ return;
+ else if (DECL_ARTIFICIAL (fld) || TREE_CODE (fld) != FIELD_DECL)
+ 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;
@@ -7462,11 +7487,11 @@ find_flexarrays (tree t, flexmems_t *fme
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;
}
@@ -7480,32 +7505,43 @@ find_flexarrays (tree t, flexmems_t *fme
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 will have nested_p set,
+ it looks just 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;
@@ -7516,13 +7552,13 @@ find_flexarrays (tree t, flexmems_t *fme
{
/* 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. */
@@ -7538,8 +7574,8 @@ find_flexarrays (tree t, flexmems_t *fme
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))))
{
@@ -7558,13 +7594,13 @@ find_flexarrays (tree t, flexmems_t *fme
{
/* 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
{
@@ -7585,15 +7621,14 @@ diagnose_invalid_flexarray (const flexme
{
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);
}
}
@@ -7662,8 +7697,8 @@ diagnose_flexarrays (tree t, const flexm
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",
@@ -7756,14 +7791,12 @@ check_flexarrays (tree t, flexmems_t *fm
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)
@@ -272,7 +272,7 @@ struct S_S_S_x {
struct A {
struct B {
int a[0]; // { dg-warning "zero-size array" }
- } b;
+ } b; // { dg-warning "invalid use" }
} a;
};
@@ -210,7 +210,7 @@ struct S22
static int i;
int a[]; // { dg-warning "in an otherwise empty" }
- } s;
+ } s; // { dg-warning "invalid use" }
};
struct S23
@@ -0,0 +1,26 @@
+// PR c++/117516
+// { dg-do compile }
+// { dg-options "-Wpedantic -Wno-error=pedantic" }
+
+struct A { int a; char b[]; int c; }; // { dg-warning "forbids flexible array member" }
+ // { dg-error "flexible array member 'A::b' not at end of 'struct A'" "" { target *-*-* } .-1 }
+struct B { struct A d; struct A e[]; struct A f; }; // { dg-warning "forbids flexible array member" }
+ // { dg-error "flexible array member 'B::e' not at end of 'struct B'" "" { target *-*-* } .-1 }
+struct C { struct B g; struct B h[]; struct B i; }; // { dg-warning "forbids flexible array member" }
+ // { dg-error "flexible array member 'C::h' not at end of 'struct C'" "" { target *-*-* } .-1 }
+struct D { struct C j; };
+D k;
+struct E { int l; struct { int m; int n[]; int o; } p; int q; }; // { dg-warning "forbids flexible array member" }
+ // { dg-error "flexible array member 'E::<unnamed struct>::n' not at end of 'struct E'" "" { target *-*-* } .-1 }
+struct F {};
+struct G { int r[]; }; // { dg-warning "forbids flexible array member" }
+ // { dg-warning "flexible array member 'G::r' in an otherwise empty 'struct G' is a GCC extension" "" { target *-*-* } .-1 }
+struct H { int s; int t[]; }; // { dg-warning "forbids flexible array member" }
+ // { dg-error "flexible array member 'H::t' not at end of 'struct K'" "" { target *-*-* } .-1 }
+ // { dg-message "array member 'int H::t \\\[\\\]' declared here" "" { target *-*-* } .-2 }
+#if __cplusplus >= 202002L
+struct I { [[no_unique_address]] F u; [[no_unique_address]] F v; int w[]; }; // { dg-warning "forbids flexible array member" "" { target c++20 } }
+#endif
+struct J { int x; struct H y; }; // { dg-warning "invalid use of 'struct H' with a flexible array member in 'struct J'" }
+struct K { int z; struct H aa; int ab; }; // { dg-message "next member 'int K::ab' declared here" }
+ // { dg-message "in the definition of 'struct K'" "" { target *-*-* } .-1 }
@@ -0,0 +1,21 @@
+// PR c++/117516
+// { dg-do compile }
+
+struct S10 { char a; };
+#define A(m, n) struct S##m { struct S##n a, b; };
+#define B(m) A(m##1, m##0) A(m##2, m##1) A(m##3, m##2) A(m##4, m##3) \
+ A(m##5, m##4) A(m##6, m##5) A(m##7, m##6) A(m##8, m##7)
+B(1)
+#define S20 S18
+B(2)
+#define S30 S28
+B(3)
+#define S40 S38
+A(41, 40) A(42, 41) A(43, 42)
+
+int
+main ()
+{
+ struct S43 s;
+ __builtin_memset (&s, 0, sizeof (s));
+}