+2015-12-15 Martin Sebor <msebor@redhat.com>
+
+ c++/42121
+ * tree-chkp.c (chkp_find_bound_slots_1): Handle flexible array
+ members.
+ * tree.c (type_contains_placeholder_1): Avoid assuming type has
+ a non-null domain or an upper bound to handle flexible array
+ members.
+ * varasm.c (output_constructor_regular_field): Same.
+ (output_constructor): Set min_index to integer_zero_node rather
+ than null when a type has no domain to avoid crashing later.
+
2015-12-15 Nathan Sidwell <nathan@acm.org>
* config/nvptx/nvptx.c (write_one_arg): Rename to ...
+2015-12-15 Martin Sebor <msebor@redhat.com>
+
+ c++/42121
+ c++/68478
+ c++/68613
+ c++/68689
+ c++/68710
+ * class.c (walk_subobject_offsets): Avoid assuming type domain
+ is non-null or has an upper bound.
+ (layout_class_type): Include type size in error message.
+ (flexmems_t): New type.
+ (field_nonempty_p, find_flexarrays, diagnose_flexarrays)
+ (check_flexarrays): New functions.
+ (finish_struct_1): Call check_flexarrays.
+ * decl.c (compute_array_index_type): Distinguish flexible array
+ members from zero-length arrays.
+ (grokdeclarator): Reject flexible array members in unions. Avoid
+ rejecting members of incomplete types that are flexible array members.
+ * error.c (dump_type_suffix): Handle flexible array members with null
+ upper bound.
+ * init.c (perform_member_init): Same.
+ * pt.c (instantiate_class_template_1): Allow flexible array members.
+ (tsubst): Handle flexible array members with null upper bound.
+ * typeck2.c (digest_init_r): Warn for initialization of flexible
+ array members.
+ (process_init_constructor_record): Handle flexible array members.
+
2015-12-15 Patrick Palka <ppalka@gcc.gnu.org>
PR c++/21802
#include "convert.h"
#include "dumpfile.h"
#include "gimplify.h"
+#include "intl.h"
/* The number of nested classes being processed. If we are not in the
scope of any class, this is zero. */
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. */
+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 check_bases (tree, int *, int *);
static void check_bases_and_members (tree);
static tree create_vtable_ptr (tree, tree *);
/* Avoid recursing into objects that are not interesting. */
if (!CLASS_TYPE_P (element_type)
- || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type))
+ || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type)
+ || !domain
+ /* Flexible array members have no upper bound. */
+ || !TYPE_MAX_VALUE (domain))
return 0;
/* Step through each of the elements in the array. */
cant_have_const_ctor = 0;
no_const_asn_ref = 0;
- /* Check all the base-classes. */
- check_bases (t, &cant_have_const_ctor,
- &no_const_asn_ref);
+ /* Check all the base-classes and set FMEM members to point to arrays
+ of potential interest. */
+ check_bases (t, &cant_have_const_ctor, &no_const_asn_ref);
/* Deduce noexcept on destructors. This needs to happen after we've set
triviality flags appropriately for our bases. */
&& TREE_CODE (TYPE_SIZE_UNIT (t)) == INTEGER_CST
&& !TREE_OVERFLOW (TYPE_SIZE_UNIT (t))
&& !valid_constant_size_p (TYPE_SIZE_UNIT (t)))
- error ("type %qT is too large", t);
+ error ("size of type %qT is too large (%qE bytes)", t, TYPE_SIZE_UNIT (t));
/* Warn about bases that can't be talked about due to ambiguity. */
warn_about_ambiguous_bases (t);
return sft;
}
+/* Helper of find_flexarrays. Return true when FLD refers to a non-static
+ class data member of non-zero size, otherwise false. */
+
+static inline bool
+field_nonempty_p (const_tree fld)
+{
+ if (TREE_CODE (fld) == ERROR_MARK)
+ return false;
+
+ tree type = TREE_TYPE (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 false;
+}
+
+/* Used by find_flexarrays and related. */
+struct flexmems_t {
+ /* The first flexible array member or non-zero array member found
+ in 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;
+};
+
+/* 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. */
+
+static void
+find_flexarrays (tree t, flexmems_t *fmem)
+{
+ 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; );
+
+ tree fldtype = TREE_TYPE (fld);
+ if (TREE_CODE (fld) != TYPE_DECL
+ && RECORD_OR_UNION_TYPE_P (fldtype)
+ && TYPE_ANONYMOUS_P (fldtype))
+ {
+ /* Members of anonymous structs and unions are treated as if
+ they were members of the containing class. Descend into
+ the anonymous struct or union and find a flexible array
+ member or zero-length array among its fields. */
+ find_flexarrays (fldtype, fmem);
+ continue;
+ }
+
+ /* Skip anything that's not a (non-static) data member. */
+ if (TREE_CODE (fld) != FIELD_DECL)
+ continue;
+
+ /* Skip virtual table pointers. */
+ if (DECL_ARTIFICIAL (fld))
+ continue;
+
+ if (field_nonempty_p (fld))
+ {
+ /* Remember the first non-static data member. */
+ if (!fmem->first)
+ fmem->first = fld;
+
+ /* Remember the first non-static data member after the flexible
+ array member, if one has been found, or the zero-length array
+ if it has been found. */
+ if (!fmem->after && fmem->array)
+ fmem->after = fld;
+ }
+
+ /* Skip non-arrays. */
+ if (TREE_CODE (fldtype) != ARRAY_TYPE)
+ continue;
+
+ /* Determine the upper bound of the array if it has one. */
+ tree dom = TYPE_DOMAIN (fldtype);
+
+ if (dom && TYPE_MAX_VALUE (dom))
+ {
+ if (fmem->array)
+ {
+ /* Make a record of the zero-length array if either one
+ 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;
+ }
+ else if (integer_all_onesp (TYPE_MAX_VALUE (dom)))
+ /* Remember the first zero-length array unless a flexible array
+ member has already been seen. */
+ fmem->array = fld;
+ }
+ else
+ {
+ /* Flexible array members have no upper bound. */
+ if (fmem->array)
+ {
+ /* Replace the zero-length array if it's been stored and
+ reset the after pointer. */
+ dom = TYPE_DOMAIN (TREE_TYPE (fmem->array));
+ if (dom && TYPE_MAX_VALUE (dom))
+ {
+ fmem->array = fld;
+ fmem->after = NULL_TREE;
+ }
+ }
+ else
+ fmem->array = fld;
+ }
+ }
+}
+
+/* Issue diagnostics for invalid flexible array members or zero-length
+ arrays that are not the last elements of the containing class or its
+ base classes or that are its sole members. */
+
+static void
+diagnose_flexarrays (tree t, const flexmems_t *fmem)
+{
+ /* Members of anonymous structs and unions are considered to be members
+ of the containing struct or union. */
+ if (TYPE_ANONYMOUS_P (t) || !fmem->array)
+ return;
+
+ const char *msg = 0;
+
+ const_tree dom = TYPE_DOMAIN (TREE_TYPE (fmem->array));
+ if (dom && TYPE_MAX_VALUE (dom))
+ {
+ if (fmem->after)
+ 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))
+
+ inform (location_of (t), "in the definition of %q#T", t);
+ }
+ else
+ {
+ if (fmem->after)
+ 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);
+
+ /* In the unlikely event that the member following the flexible
+ array member is declared in a different class, 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),
+ "next member %q#D declared here",
+ fmem->after);
+
+ inform (location_of (t), "in the definition of %q#T", t);
+ }
+ }
+}
+
+
+/* Recursively check to make sure that any flexible array or zero-length
+ array members of class T or its bases are valid (i.e., not the sole
+ non-static data member of T and, if one exists, that it is the last
+ non-static data member of T and its base classes. FMEM is expected
+ to be initially null and is used internally by recursive calls to
+ the function. Issue the appropriate diagnostics for the array member
+ that fails the checks. */
+
+static void
+check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
+{
+ /* Initialize the result of a search for flexible array and zero-length
+ array members. Avoid doing any work if the most interesting FMEM data
+ have already been populated. */
+ flexmems_t flexmems = flexmems_t ();
+ if (!fmem)
+ fmem = &flexmems;
+ else if (fmem->array && fmem->first && fmem->after)
+ return;
+
+ /* 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);
+ }
+
+ /* Recursively check the base classes. */
+ int nbases = BINFO_N_BASE_BINFOS (TYPE_BINFO (t));
+ for (int i = 0; i < nbases; ++i)
+ {
+ tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (t), i);
+
+ /* The primary base class was already checked above. */
+ if (base_binfo == CLASSTYPE_PRIMARY_BINFO (t))
+ continue;
+
+ /* Virtual base classes are at the end. */
+ if (BINFO_VIRTUAL_P (base_binfo))
+ continue;
+
+ /* Check the base class. */
+ check_flexarrays (BINFO_TYPE (base_binfo), fmem);
+ }
+
+ if (fmem == &flexmems)
+ {
+ /* Check virtual base classes only once per derived class.
+ I.e., this check is not performed recursively for base
+ classes. */
+ int i;
+ tree base_binfo;
+ vec<tree, va_gc> *vbases;
+ for (vbases = CLASSTYPE_VBASECLASSES (t), i = 0;
+ vec_safe_iterate (vbases, i, &base_binfo); i++)
+ {
+ /* Check the virtual base class. */
+ tree basetype = TREE_TYPE (base_binfo);
+
+ check_flexarrays (basetype, fmem);
+ }
+ }
+
+ /* Search the members of the current (derived) class. */
+ find_flexarrays (t, fmem);
+
+ if (fmem == &flexmems)
+ {
+ /* Issue diagnostics for invalid flexible and zero-length array members
+ found in base classes or among the members of the current class. */
+ diagnose_flexarrays (t, fmem);
+ }
+}
/* Perform processing required when the definition of T (a class type)
- is complete. */
+ is complete. Diagnose invalid definitions of flexible array members
+ and zero-size arrays. */
void
finish_struct_1 (tree t)
needs a mode. */
compute_record_mode (CLASSTYPE_AS_BASE (t));
+ /* With the layout complete, check for flexible array members and
+ zero-length arrays that might overlap other members in the final
+ layout. */
+ check_flexarrays (t);
+
virtuals = modify_all_vtables (t, nreverse (virtuals));
/* If necessary, create the primary vtable for this class. */
}
/* Given the SIZE (i.e., number of elements) in an array, compute an
- appropriate index type for the array. If non-NULL, NAME is the
- name of the thing being declared. */
+ appropriate index type for the array. When SIZE is null, the array
+ is a flexible array member. If non-NULL, NAME is the name of
+ the entity being declared. */
tree
compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
tree itype;
tree osize = size;
+ if (size == NULL_TREE)
+ return build_index_type (NULL_TREE);
+
if (error_operand_p (size))
return error_mark_node;
}
{
- tree decl;
+ tree decl = NULL_TREE;
if (decl_context == PARM)
{
if (!staticp && TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) == NULL_TREE)
{
- tree itype = compute_array_index_type (dname, integer_zero_node,
- tf_warning_or_error);
- type = build_cplus_array_type (TREE_TYPE (type), itype);
+ if (TREE_CODE (ctype) == UNION_TYPE
+ || TREE_CODE (ctype) == QUAL_UNION_TYPE)
+ {
+ error ("flexible array member in union");
+ type = error_mark_node;
+ }
+ else
+ {
+ tree itype = compute_array_index_type (dname, NULL_TREE,
+ tf_warning_or_error);
+ type = build_cplus_array_type (TREE_TYPE (type), itype);
+ }
}
if (type == error_mark_node)
|| !COMPLETE_TYPE_P (TREE_TYPE (type))
|| initialized == 0))
{
- if (unqualified_id)
+ if (TREE_CODE (type) != ARRAY_TYPE
+ || !COMPLETE_TYPE_P (TREE_TYPE (type)))
{
- error ("field %qD has incomplete type %qT",
- unqualified_id, type);
- cxx_incomplete_type_inform (strip_array_types (type));
- }
- else
- error ("name %qT has incomplete type", type);
+ if (unqualified_id)
+ {
+ error ("field %qD has incomplete type %qT",
+ unqualified_id, type);
+ cxx_incomplete_type_inform (strip_array_types (type));
+ }
+ else
+ error ("name %qT has incomplete type", type);
- type = error_mark_node;
- decl = NULL_TREE;
+ type = error_mark_node;
+ decl = NULL_TREE;
+ }
}
else
{
case ARRAY_TYPE:
pp_maybe_space (pp);
pp_cxx_left_bracket (pp);
- if (TYPE_DOMAIN (t))
+ if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t)))
{
tree dtype = TYPE_DOMAIN (t);
tree max = TYPE_MAX_VALUE (dtype);
|| same_type_ignoring_top_level_qualifiers_p (type,
TREE_TYPE (init)))
{
- init = build_vec_init_expr (type, init, tf_warning_or_error);
- init = build2 (INIT_EXPR, type, decl, init);
- finish_expr_stmt (init);
+ if (TYPE_DOMAIN (type) && TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ {
+ /* Initialize the array only if it's not a flexible
+ array member (i.e., if it has an upper bound). */
+ init = build_vec_init_expr (type, init, tf_warning_or_error);
+ init = build2 (INIT_EXPR, type, decl, init);
+ finish_expr_stmt (init);
+ }
}
else
error ("invalid initializer for array member %q#D", member);
if (can_complete_type_without_circularity (rtype))
complete_type (rtype);
- if (!COMPLETE_TYPE_P (rtype))
+ if (TREE_CODE (r) == FIELD_DECL
+ && TREE_CODE (rtype) == ARRAY_TYPE
+ && COMPLETE_TYPE_P (TREE_TYPE (rtype))
+ && !COMPLETE_TYPE_P (rtype))
+ {
+ /* Flexible array mmembers of elements
+ of complete type have an incomplete type
+ and that's okay. */
+ }
+ else if (!COMPLETE_TYPE_P (rtype))
{
cxx_incomplete_type_error (r, rtype);
TREE_TYPE (r) = error_mark_node;
if (t == integer_type_node)
return t;
- if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
- && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
- return t;
+ if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST)
+ {
+ if (!TYPE_MAX_VALUE (t))
+ return compute_array_index_type (NULL_TREE, NULL_TREE, complain);
+
+ if (TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
+ return t;
+ }
{
tree max, omax = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
them if they were present. */
if (code == ARRAY_TYPE)
{
+ if (nested
+ && (!TYPE_DOMAIN (type) || !TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+ {
+ /* Flexible array members do not have an upper bound. */
+ pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wpedantic,
+ "initialization of a flexible array member");
+ }
+
tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
if (char_type_p (typ1)
/*&& init */
init = copy_node (init);
TREE_TYPE (init) = type;
}
- if (TYPE_DOMAIN (type) != 0 && TREE_CONSTANT (TYPE_SIZE (type)))
+ if (TYPE_DOMAIN (type)
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+ && TREE_CONSTANT (TYPE_SIZE (type)))
{
+ /* Not a flexible array member. */
int size = TREE_INT_CST_LOW (TYPE_SIZE (type));
size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
/* In C it is ok to subtract 1 from the length of the string
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree domain = TYPE_DOMAIN (type);
- if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
- len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
+ /* Flexible array members have no upper bound. */
+ tree maxval = domain ? TYPE_MAX_VALUE (domain) : NULL_TREE;
+ if (domain && maxval && TREE_CONSTANT (maxval))
+ len = wi::ext (wi::to_offset (maxval)
- wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
TYPE_PRECISION (TREE_TYPE (domain)),
TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
}
else
{
- if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
+ const_tree fldtype = TREE_TYPE (field);
+ if (TREE_CODE (fldtype) == REFERENCE_TYPE)
{
if (complain & tf_error)
error ("member %qD is uninitialized reference", field);
else
return PICFLAG_ERRONEOUS;
}
- else if (CLASSTYPE_REF_FIELDS_NEED_INIT (TREE_TYPE (field)))
+ else if (CLASSTYPE_REF_FIELDS_NEED_INIT (fldtype))
{
if (complain & tf_error)
error ("member %qD with uninitialized reference fields", field);
}
/* Warn when some struct elements are implicitly initialized
- to zero. */
- if ((complain & tf_warning)
+ to zero. However, avoid issuing the warning for flexible
+ array members since they need not have any elements. */
+ if ((TREE_CODE (fldtype) != ARRAY_TYPE
+ || (TYPE_DOMAIN (fldtype)
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype))))
+ && (complain & tf_warning)
&& !EMPTY_CONSTRUCTOR_P (init))
warning (OPT_Wmissing_field_initializers,
"missing initializer for member %qD", field);
- if (!zero_init_p (TREE_TYPE (field))
+ if (!zero_init_p (fldtype)
|| skipped < 0)
next = build_zero_init (TREE_TYPE (field), /*nelts=*/NULL_TREE,
/*static_storage_p=*/false);
+2015-12-15 Martin Sebor <msebor@redhat.com>
+
+ c++/42121
+ c++/68478
+ c++/68613
+ c++/68689
+ c++/68710
+ * g++.dg/compat/struct-layout-1_generate.c: Avoid generating
+ further fields after the first flexible array member.
+ * g++.dg/ext/flexary2.C: Expect a sole flexible array member
+ to be rejected. Add a test case exercising zero-length array.
+ * g++.dg/ext/flexary3.C: Expect a sole flexible array member
+ to be rejected.
+ * g++.dg/ext/flexary.h: New file.
+ * g++.dg/ext/flexary4.C: New file.
+ * g++.dg/ext/flexary5.C: New file.
+ * g++.dg/ext/flexary6.C: New file.
+ * g++.dg/ext/flexary7.C: New file.
+ * g++.dg/ext/flexary8.C: New file.
+ * g++.dg/other/dump-ada-spec-2.C: Adjust to reflect flexible
+ array members.
+ * g++.dg/parse/pr43765.C: Add a member to make a struct with
+ a flexible array member valid. Adjust expected error message.
+ * g++.dg/torture/pr64280.C: Expect a sole flexible array member
+ to be rejected.
+ * g++.dg/torture/pr64312.C: Add a member to make a struct with
+ a flexible array member valid.
+ * g++.dg/ubsan/object-size-1.C: Adjust expected diagnostic.
+
2015-12-15 Marek Polacek <polacek@redhat.com>
PR c/68907
return ret;
}
+/* 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*/
int
-subfield (struct entry *e, char *letter)
+subfield (struct entry *e, char *letter, int *flex)
{
int i, type;
char buf[20];
if (e[0].etype == ETYPE_STRUCT_ARRAY || e[0].etype == ETYPE_UNION_ARRAY)
{
if (e[0].arr_len == 255)
- snprintf (buf, 20, "%c[]", *letter);
+ {
+ *flex = 1;
+ snprintf (buf, 20, "%c[]", *letter);
+ }
else
snprintf (buf, 20, "%c[%d]", *letter, e[0].arr_len);
/* If this is an array type, do not put aligned attributes on
break;
}
- for (i = 1; i <= e[0].len; )
- i += subfield (e + i, letter);
+ for (i = 1; !*flex && i <= e[0].len; )
+ i += subfield (e + i, letter, flex);
switch (type)
{
if (e[0].etype == ETYPE_ARRAY)
{
if (e[0].arr_len == 255)
- snprintf (buf, 20, "%c[]", *letter);
+ {
+ *flex = 1;
+ snprintf (buf, 20, "%c[]", *letter);
+ }
else
snprintf (buf, 20, "%c[%d]", *letter, e[0].arr_len);
}
else
fprintf (outfile, "U(%d,", idx);
c = 'a';
+
+ int flex = 0;
for (i = 1; i <= e[0].len; )
- i += subfield (e + i, &c);
+ i += subfield (e + i, &c, &flex);
+
fputs (",", outfile);
c = 'a';
for (i = 1; i <= e[0].len; )
--- /dev/null
+// Definitions of helper macros for tests of flexible array members.
+
+#if __cplusplus < 201102L
+# define _CAT(x, y) x ## y
+# define CAT(x, y) _CAT (x, y)
+
+// Generate a struct with a unique name containing a bitfield
+// of size that must evaluate to a non-zero value, otherwise
+// generate a compiler error.
+# define ASSERT(expr) \
+ struct CAT (FAM_Assert, __LINE__) { unsigned asrt: 0 != (expr); }
+#else
+// In C++ 11 and beyond, use static_assert.
+# define ASSERT(expr) static_assert (expr, #expr)
+#endif
+
+// Macro to verify that a flexible array member is allocated
+// at the very end of the containing struct.
+#define ASSERT_AT_END(T, m) \
+ ASSERT (__builtin_offsetof (T, m) == sizeof (T))
+
+typedef __SIZE_TYPE__ size_t;
-// PR c++/46688
+// PR c++/46688 - [4.6 Regression] g++ requires a function declaration
+// when it should not
+// Note that although the definition of struct B in the test case for
+// c++/46688 was thought to be valid, it is, in fact, invalid, in C and
+// as noted in c++/42121, should be treated as invalid in C++ as well.
+// The test verifies that gcc detects and reports the right error.
+
// { dg-options "" }
struct A {
- A(int);
+ A(int);
};
struct B {
- B() {}
- A a[];
+ B() {}
+ A a[]; // { dg-error "extension|flexible array .* in an otherwise empty" }
+};
+
+struct C {
+ C() {}
+ A a[0]; // -Wpedantic warning: ISO C++ forbids zero-size arrays
};
+
-// PR c++/54441
+// PR c++/54441 - [4.7/4.8 Regression] Infinite loop with brace initializer
+// on zero-length array
+// Note that although the definition of struct s in the test case for
+// c++/54441 was accepted as valid, it is, in fact, invalid in C, and
+// as noted in c++/42121, should be treated as invalid in C++ as well.
+// The test verifies that gcc detects, reports, and handles both errors
+// gracefully.
+// Note also that the error(s) issued for the invalid initializer depend
+// on c++/55606.
+
// { dg-options "" }
-struct s { char c[]; };
+struct s {
+ char c[]; // { dg-error "flexible array member .* in an otherwise empty" }
+};
int main()
{
--- /dev/null
+// PR c++/42121 - g++ should warn or error on internal 0 size array in struct
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Flexible array members are a feature of C99 (and newer) not provided
+// by C++ 2014 and prior. G++ supports both the C99/C11 kind of flexible
+// array members and pre-C99 zero-size arrays (defining an array of size
+// zero). Since both features are provided for compatibility with C,
+// G++ allows them in the same contexts as in C.
+
+#include "flexary.h"
+
+struct Sx {
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+// Verify that non-data members or static data members either before
+// or after a flexible array member in an otherwise empty struct don't
+// suppress the diagnostic.
+struct Sx2 {
+ int a[]; // { dg-error "in an otherwise empty" }
+ typedef int I;
+};
+
+struct Sx3 {
+ typedef int I;
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx4 {
+ int a[]; // { dg-error "in an otherwise empty" }
+ enum E { e };
+};
+
+struct Sx5 {
+ enum E { e };
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx6 {
+ int a[]; // { dg-error "in an otherwise empty" }
+ static int i;
+};
+
+struct Sx7 {
+ static int i;
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx8 {
+ int a[]; // { dg-error "in an otherwise empty" }
+ Sx8 () { }
+};
+
+struct Sx9 {
+ Sx9 () { }
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx10 {
+ int a[]; // { dg-error "in an otherwise empty" }
+ virtual ~Sx10 () { }
+};
+
+struct Sx11 {
+ virtual ~Sx11 () { }
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx12 {
+ int a[]; // { dg-error "in an otherwise empty" }
+ virtual void foo () = 0;
+};
+
+struct Sx13 {
+ virtual void foo () = 0;
+ int a[]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx14 {
+ int a[][1]; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx15 {
+ typedef int A[];
+ A a; // { dg-error "in an otherwise empty" }
+};
+
+// Verify also that a zero-size array doesn't suppress the diagnostic.
+struct Sx16 {
+ // a_0 below is diagnosed with -Wpedantic only and emits
+ // warning: ISO C++ forbids zero-size arrays
+ int a_0 [0];
+ int a_x []; // { dg-error "in an otherwise empty" }
+};
+
+struct Sx17 {
+ int a_x []; // { dg-error "flexible array member" }
+
+ // a_0 below is diagnosed with -Wpedantic only and emits
+ // warning: ISO C++ forbids zero-size arrays
+ 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
+// 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 { };
+};
+
+// 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.
+struct Sx19 {
+ struct S { };
+ union U { };
+ int a_x []; // { dg-error "in an otherwise empty" }
+};
+
+// Unlike in the case above, a named member of an anonymous struct
+// prevents a subsequent flexible array member from being diagnosed.
+struct Sx20 {
+ struct S { } s;
+ int a_x [];
+};
+
+struct Sx21 {
+ int a_x []; // { dg-error "not at end" }
+ struct S { } s;
+};
+
+struct Sx22 {
+ int a_x []; // { dg-error "not at end" }
+ union { int i; };
+};
+
+struct Sx23 {
+ union { int i; };
+ int a_x [];
+};
+
+struct Sx24 {
+ struct S;
+ S a_x []; // { dg-error "incomplete type" }
+};
+
+struct Sx25 {
+ struct S { };
+ S a_x []; // { dg-error "flexible array member" }
+};
+
+struct Sx26 {
+ struct { }
+ a_x []; // { dg-error "flexible array member" }
+};
+
+struct Sx27 {
+ int i;
+ struct { }
+ a_x [];
+};
+
+ASSERT_AT_END (Sx27, a_x);
+
+struct Sx28 {
+ struct { }
+ a_x []; // { dg-error "not at end" }
+ int i;
+};
+
+struct Sx29 {
+ // Pointer to an array of unknown size.
+ int (*a_x)[];
+};
+
+struct Sx30 {
+ // Reference to an array of unknown size.
+ int (&a_x)[];
+};
+
+struct Sx31 {
+ int a []; // { dg-error "not at end" }
+ unsigned i: 1;
+};
+
+struct Sx32 {
+ unsigned i: 1;
+ int a [];
+};
+
+ASSERT_AT_END (Sx32, a);
+
+struct Sx33 {
+ int a []; // { dg-error "otherwise empty" }
+ friend int foo ();
+};
+
+struct Sx34 {
+ friend int foo ();
+ int a []; // { dg-error "otherwise empty" }
+};
+
+// Verify that intervening non-field declarations of members other
+// than non-static data members don't affect the diagnostics.
+struct Sx35 {
+ int a[]; // { dg-error "not at end" }
+ typedef int I;
+ int n;
+};
+
+struct Sx36 {
+ int n;
+ typedef int I;
+ int a[];
+};
+
+ASSERT_AT_END (Sx36, a);
+
+struct Sx37 {
+ int a[]; // { dg-error "not at end" }
+ enum E { };
+ int n;
+};
+
+struct Sx38 {
+ int n;
+ enum E { };
+ int a[];
+};
+
+ASSERT_AT_END (Sx38, a);
+
+struct Sx39 {
+ int a[]; // { dg-error "not at end" }
+ struct S;
+ int n;
+};
+
+struct Sx40 {
+ int n;
+ struct S;
+ int a[];
+};
+
+ASSERT_AT_END (Sx40, a);
+
+struct Sx41 {
+ int a[]; // { dg-error "not at end" }
+ static int i;
+ int n;
+};
+
+struct Sx42 {
+ int n;
+ static int i;
+ int a[];
+};
+
+ASSERT_AT_END (Sx42, a);
+
+struct Sx43 {
+ int a[]; // { dg-error "not at end" }
+ Sx43 ();
+ int n;
+};
+
+struct Sx44 {
+ int n;
+ Sx44 ();
+ int a[];
+};
+
+ASSERT_AT_END (Sx44, a);
+
+struct S_S_S_x {
+ struct A {
+ struct B {
+ int a[]; // { dg-error "flexible array member" }
+ } b;
+ } a;
+};
+
+// Since members of an anonymous struct or union are considered to be
+// members of the enclosing union the below defintions are valid and
+// must be accepted.
+
+struct Anon1 {
+ int n;
+ struct {
+ int good[];
+ };
+};
+
+ASSERT_AT_END (Anon1, good);
+
+struct Anon2 {
+ struct {
+ int n;
+ struct {
+ int good[];
+ };
+ };
+};
+
+ASSERT_AT_END (Anon2, good);
+
+struct Anon3 {
+ struct {
+ struct {
+ int n;
+ int good[];
+ };
+ };
+};
+
+ASSERT_AT_END (Anon3, good);
+
+struct Anon4 {
+ struct {
+ int in_empty_struct[]; // { dg-error "in an otherwise empty" }
+ };
+};
+
+struct Anon5 {
+ struct {
+ int not_at_end[]; // { dg-error "not at end" }
+ };
+ int n;
+};
+
+struct Anon6 {
+ struct {
+ struct {
+ int not_at_end[]; // { dg-error "not at end" }
+ };
+ int n;
+ };
+};
+
+
+struct Anon7 {
+ struct {
+ struct {
+ int not_at_end[]; // { dg-error "not at end" }
+ };
+ };
+ int n;
+};
+
+
+struct Six {
+ int i;
+ int a[];
+};
+
+ASSERT_AT_END (Six, a);
+
+class Cx {
+ int a[]; // { dg-error "flexible array member" }
+};
+
+class Cix {
+ int i;
+ int a[];
+};
+
+struct Sxi {
+ int a[]; // { dg-error "not at end" }
+ int i;
+};
+
+struct S0 {
+ int a[0];
+};
+
+struct S0i {
+ int a[0];
+ int i;
+};
+
+struct S_a0_ax {
+ int a0[0];
+ int ax[]; // { dg-error "flexible array member" }
+};
+
+struct S_a0_i_ax {
+ int a0[0];
+ int i;
+ int ax[];
+};
+
+ASSERT_AT_END (S_a0_i_ax, ax);
+
+struct Si_a0_ax {
+ int i;
+ int a0[0];
+ int ax[];
+};
+
+ASSERT_AT_END (Si_a0_ax, ax);
+
+struct Si_ax_a0 {
+ int i;
+ int ax[]; // { dg-error "not at end" }
+ int a0[0];
+};
+
+struct S_u0_ax {
+ union { } u[0];
+ int ax[]; // { dg-error "flexible array member" }
+};
+
+struct S_a1_s2 {
+ int a[1];
+ int b[2];
+};
--- /dev/null
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Test to verify flexible array members handling in base and derived
+// classes.
+
+#include "flexary.h"
+
+template <class T>
+struct S_no_diag: T {
+ char a[]; // cannot be diagnosed unless/until T is known
+};
+
+template <class T>
+struct STx_1: T {
+ char a[]; // { dg-error "flexible array member" }
+};
+
+template <class T, int I>
+struct STI: T {
+ char a[I]; // cannot be diagnosed unless/until T and I are known
+};
+
+template <class T, int I>
+struct STIx: T {
+ char a[I];
+};
+
+template <int> struct E { };
+
+STx_1<E<0> > stx_empty_1;
+STIx<E<0>, 0> stix_empty_1;
+
+// Verify that a sole flexible array member in a class with all empty
+// base classes is diagnosed.
+struct E1: E<0>, E<1> { };
+struct E2: E<2>, E<3> { };
+struct D1: E1, E2
+{
+ char a[]; // { dg-error "flexible array member" }
+};
+
+struct NE { size_t i; };
+
+struct A1x { int n, a[]; };
+struct D2: A1x, E1, E2 { };
+
+// Verify that the offset of the flexible array member is equal
+// to the size of each of the valid structs.
+ASSERT_AT_END (D2, a);
+
+struct D3: E1, A1x, E2 { };
+
+ASSERT_AT_END (D3, a);
+
+struct D4: E1, E2, A1x { };
+
+ASSERT_AT_END (D4, a);
+
+// Class with non-static data members and at least one base class
+// with such a member is not a standard layout class. The warning
+// below is benign since GCC computes the expected value.
+struct D5: E1, E2, NE { char a[]; };
+
+ASSERT_AT_END (D5, a); // { dg-warning "offsetof within non-standard-layout" }
+
+struct A2x {
+ size_t n;
+ size_t a[]; // { dg-error "not at end of .struct D6.| D7.| 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 DA2x: A2x { };
+
+struct D9: DA2x, E1, E2 { };
+
+ASSERT_AT_END (D9, a);
+
+struct D10: E1, DA2x, E2 { };
+
+ASSERT_AT_END (D10, a);
+
+struct D11: E1, E2, DA2x { };
+
+ASSERT_AT_END (D11, a);
+
+struct A3x {
+ size_t n;
+ size_t a[]; // { dg-error "not at end of .struct D12.| D13.| D14.| D15." }
+};
+
+// Verify that the flexible array member in A3x above is diagnosed
+// for each of the three struct defintions below which also derive
+// from another struct with a non-static member.
+struct D12: A3x, E1, NE { };
+struct D13: E1, A3x, NE { };
+struct D14: E1, E2, A3x, NE { };
+struct D15: E1, E2, NE, A3x { };
+
+struct A4x {
+ A4x ();
+ ~A4x ();
+
+ size_t n;
+ struct AS {
+ AS (int);
+ ~AS ();
+ size_t i;
+ } a[];
+};
+
+struct D16: A4x, E1, E2 { };
+
+ASSERT_AT_END (D16, a);
+
+struct D17: E1, A4x, E2 { };
+
+ASSERT_AT_END (D17, a);
+
+struct D18: E1, E2, A4x { };
+
+ASSERT_AT_END (D18, a);
+
+struct DA4x: A4x { };
+
+struct D19: DA4x, E1, E2 { };
+
+ASSERT_AT_END (D19, a);
+
+struct D20: E1, DA4x, E2 { };
+
+ASSERT_AT_END (D20, a);
+
+struct D21: E1, E2, DA4x { };
+
+ASSERT_AT_END (D21, a);
+
+
+struct A5x {
+ A5x (int);
+ virtual ~A5x ();
+
+ size_t n;
+ struct AS {
+ AS (int);
+ ~AS ();
+ size_t i;
+ } a[];
+};
+
+struct D22: A5x, E1, E2 { };
+
+ASSERT_AT_END (D22, a); // { dg-warning "offsetof within non-standard-layout" }
+
+struct D23: E1, A5x, E2 { };
+
+ASSERT_AT_END (D23, a); // { dg-warning "offsetof within non-standard-layout" }
+
+struct D24: E1, E2, A5x { };
+
+ASSERT_AT_END (D24, a); // { dg-warning "offsetof within non-standard-layout" }
+
+struct DA5x: A5x { };
+
+struct D25: DA5x, E1, E2 { };
+
+ASSERT_AT_END (D25, a); // { dg-warning "offsetof within non-standard-layout" }
+
+struct D26: E1, DA5x, E2 { };
+
+ASSERT_AT_END (D26, a); // { dg-warning "offsetof within non-standard-layout" }
+
+struct D27: E1, E2, DA5x { };
+
+ASSERT_AT_END (D27, a); // { dg-warning "offsetof within non-standard-layout" }
+
+// Verfify that a flexible array member is diagnosed even when deep
+// in the base class hierarchy.
+struct A6x {
+ size_t n;
+ size_t a[]; // { dg-error "not at end of .struct D28.| D29." }
+};
+
+struct AA6x: A6x { };
+struct NE1: NE { };
+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[];
+};
+
+struct DA7xV1: virtual A7x { };
+struct DA7xV2: virtual A7x { };
+
+struct D30: DA7xV1, DA7xV2 { };
+struct D31: DA7xV1, DA7xV2 { };
+struct D32: D30, D31 { };
--- /dev/null
+// PR c++/68478 - flexible array members have complete type
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Test to verify that attempting to use a flexible array member where
+// a complete type is required is rejected.
+
+struct A {
+ int n;
+ int a[];
+ enum {
+ e = sizeof a // { dg-error "invalid application of .sizeof. to incomplete type" }
+ };
+};
+
+struct B {
+ int n;
+ typedef int A[];
+ A a;
+ enum {
+ e = sizeof a // { dg-error "invalid application of .sizeof. to incomplete type" }
+ };
+};
--- /dev/null
+// PR c++/68613 - initializer-string for array of chars is too long error
+// on flexible array member
+// { dg-do compile }
+// { dg-options "-Wpedantic -Wno-error=pedantic" }
+
+struct FlexChar {
+ int n;
+ char a[];
+};
+
+struct FlexChar ac =
+ { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" }
+
+
+#if !__cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+
+struct FlexWchar {
+ int n;
+ wchar_t a[];
+};
+
+struct FlexWchar awc =
+ { 3, { L"ab" } }; // { dg-warning "initialization of a flexible array member" }
+
+
+struct FlexInt {
+ int n;
+ int a[];
+};
+
+// Verify that no warning is issued for the case when a flexible array
+// member is not initialized (i.e., that a -Wmissing-field-initializer
+// isn't issued) because such arrays need not have any elements.
+struct FlexInt ai0 =
+ { 0 };
+
+struct FlexInt ai0_ =
+ { 0, { } }; // { dg-warning "initialization of a flexible array member" }
+
+struct FlexInt ai2 =
+ { 2, { 1, 2 } }; // { dg-warning "initialization of a flexible array member" }
+
+
+#if __cplusplus
+
+template <class T>
+struct FlexT {
+ int n;
+ T a[];
+};
+
+struct FlexT<char> atc =
+ { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" }
+
+#endif
--- /dev/null
+// 68689 - flexible array members in unions accepted in C++
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+union U_i_ax {
+ int i;
+ int a[]; // { dg-error "flexible array member in union" }
+};
+
+struct SU1 {
+ union {
+ int a[]; // { dg-error "flexible array member in union" }
+ };
+};
+
+struct SU2 {
+ int n;
+ union {
+ int a[]; // { dg-error "flexible array member in union" }
+ };
+};
+
+struct SU3 {
+ union {
+ int n;
+ int a[]; // { dg-error "flexible array member in union" }
+ };
+};
+
+union U_i_a0 {
+ int i;
+ int a[0];
+};
--- /dev/null
+// { dg-do compile }
+// { dg-options "-Wpedantic -Wno-error=pedantic" }
+
+#include "flexary.h"
+
+struct Sx {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+// Verify that non-data members or static data members either before
+// or after a zero-length array in an otherwise empty struct don't
+// suppress the diagnostic.
+struct Sx2 {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+ typedef int I;
+};
+
+struct Sx3 {
+ typedef int I;
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx4 {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+ enum E { e };
+};
+
+struct Sx5 {
+ enum E { e };
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx6 {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+ static int i;
+};
+
+struct Sx7 {
+ static int i;
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx8 {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+ Sx8 () { }
+};
+
+struct Sx9 {
+ Sx9 () { }
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx10 {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+ virtual ~Sx10 () { }
+};
+
+struct Sx11 {
+ virtual ~Sx11 () { }
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx12 {
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+ virtual void foo () = 0;
+};
+
+struct Sx13 {
+ virtual void foo () = 0;
+ int a[0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx14 {
+ int a[0][1]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx15 {
+ typedef int A[0]; // { dg-warning "zero-size" }
+ A a; // { dg-warning "in an otherwise empty" }
+};
+
+// Verify also that a zero-size array doesn't suppress the diagnostic.
+struct Sx16 {
+ int a_0 [0]; // { dg-warning "zero-size|in an otherwise empty" }
+ int a_x [0]; // { dg-warning "zero-size array" }
+};
+
+struct Sx17 {
+ int a_x [0]; // { dg-warning "zero-size|in an otherwise empty" }
+ int a_0 [0]; // { dg-warning "zero-size array" }
+};
+
+// 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
+// containing a zero-length array followed by an empty struct
+// is diagnosed to prevent the former subobject from sharing space
+// with the latter.
+struct Sx18 {
+ int a_x [0]; // { dg-warning "zero-size array" }
+ struct S { };
+};
+
+// Anonymous structs and unions are another GCC extension. Since
+// they cannot be named and thus used to store the size of a zero
+// length array member, a struct containing both is diagnosed as
+// if the zero-length array appeared alone.
+struct Sx19 {
+ struct S { };
+ union U { };
+ int a_x [0]; // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+// Unlike in the case above, a named member of an anonymous struct
+// prevents a subsequent zero-length array from being diagnosed.
+struct Sx20 {
+ struct S { } s;
+ int a_x [0]; // { dg-warning "zero-size array" }
+};
+
+struct Sx21 {
+ int a_x [0]; // { dg-warning "zero-size array|not at end" }
+ struct S { } s;
+};
+
+struct Sx22 {
+ int a_x [0]; // { dg-warning "zero-size array|not at end" }
+ union { int i; };
+};
+
+struct Sx23 {
+ union { int i; };
+ int a_x [0]; // { dg-warning "zero-size array" }
+};
+
+// The following causes an incomplete type error error and a zero-size
+// array warning.
+struct Sx24 {
+ struct S;
+ S a_x [0]; // { dg-message "incomplete type|zero-size array" }
+};
+
+struct Sx25 {
+ struct S { };
+ S a_x [0]; // { dg-warning "zero-size array" }
+};
+
+struct Sx26 {
+ struct { }
+ a_x [0]; // { dg-warning "zero-size array" }
+};
+
+struct Sx27 {
+ int i;
+ struct { }
+ a_x [0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx27, a_x);
+
+struct Sx28 {
+ struct { }
+ a_x [0]; // { dg-warning "zero-size array|not at end" }
+ int i;
+};
+
+struct Sx29 {
+ // Pointer to an array of zero size.
+ int (*a_x)[0]; // { dg-warning "zero-size array" }
+};
+
+struct Sx30 {
+ // Reference to an array of zero size.
+ int (&a_x)[0]; // { dg-warning "zero-size array" }
+};
+
+struct Sx31 {
+ int a [0]; // { dg-warning "zero-size array|not at end" }
+ unsigned i: 1;
+};
+
+struct Sx32 {
+ unsigned i: 1;
+ int a [0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx32, a);
+
+struct Sx33 {
+ int a [0]; // { dg-warning "zero-size array|otherwise empty" }
+ friend int foo ();
+};
+
+struct Sx34 {
+ friend int foo ();
+ int a [0]; // { dg-warning "zero-size array|otherwise empty" }
+};
+
+// Verify that intervening non-field declarations of members other
+// than non-static data members don't affect the diagnostics.
+struct Sx35 {
+ int a[0]; // { dg-warning "zero-size array|not at end" }
+ typedef int I;
+ int n;
+};
+
+struct Sx36 {
+ int n;
+ typedef int I;
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx36, a);
+
+struct Sx37 {
+ int a[0]; // { dg-warning "zero-size array|not at end" }
+ enum E { };
+ int n;
+};
+
+struct Sx38 {
+ int n;
+ enum E { };
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx38, a);
+
+struct Sx39 {
+ int a[0]; // { dg-warning "zero-size array|not at end" }
+ struct S;
+ int n;
+};
+
+struct Sx40 {
+ int n;
+ struct S;
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx40, a);
+
+struct Sx41 {
+ int a[0]; // { dg-warning "zero-size array|not at end" }
+ static int i;
+ int n;
+};
+
+struct Sx42 {
+ int n;
+ static int i;
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx42, a);
+
+struct Sx43 {
+ int a[0]; // { dg-warning "zero-size array|not at end" }
+ Sx43 ();
+ int n;
+};
+
+struct Sx44 {
+ int n;
+ Sx44 ();
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx44, a);
+
+struct S_S_S_x {
+ struct A {
+ struct B {
+ int a[0]; // { dg-warning "zero-size array" }
+ } b;
+ } a;
+};
+
+// Since members of an anonymous struct or union are considered to be
+// members of the enclosing union the below defintions are valid and
+// must be accepted.
+
+struct Anon1 {
+ int n;
+ struct {
+ int good[0]; // { dg-warning "zero-size array" }
+ }; // { dg-warning "anonymous struct" }
+};
+
+ASSERT_AT_END (Anon1, good);
+
+struct Anon2 {
+ struct {
+ int n;
+ struct {
+ int good[0]; // { dg-warning "zero-size array" }
+ }; // { dg-warning "anonymous struct" }
+ }; // { dg-warning "anonymous struct" }
+};
+
+ASSERT_AT_END (Anon2, good);
+
+struct Anon3 {
+ struct {
+ struct {
+ int n;
+ int good[0]; // { dg-warning "zero-size array" }
+ }; // { dg-warning "anonymous struct" }
+ }; // { dg-warning "anonymous struct" }
+};
+
+ASSERT_AT_END (Anon3, good);
+
+struct Anon4 {
+ struct {
+ int in_empty_struct[0]; // { dg-warning "zero-size array|in an otherwise empty" }
+ }; // { dg-warning "anonymous struct" }
+};
+
+struct Anon5 {
+ struct {
+ int not_at_end[0]; // { dg-warning "zero-size array|not at end" }
+ }; // { dg-warning "anonymous struct" }
+ int n;
+};
+
+struct Anon6 {
+ struct {
+ struct {
+ int not_at_end[0]; // { dg-warning "zero-size array|not at end" }
+ }; // { dg-warning "anonymous struct" }
+ int n;
+ }; // { dg-warning "anonymous struct" }
+};
+
+
+struct Anon7 {
+ struct {
+ struct {
+ int not_at_end[0]; // { dg-warning "zero-size array|not at end" }
+ }; // { dg-warning "anonymous struct" }
+ }; // { dg-warning "anonymous struct" }
+ int n;
+};
+
+
+struct Six {
+ int i;
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Six, a);
+
+class Cx {
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+class Cix {
+ int i;
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+struct Sxi {
+ int a[0]; // { dg-warning "zero-size array|not at end" }
+ int i;
+};
+
+struct S0 {
+ int a[0]; // { dg-warning "zero-size array" }
+};
+
+struct S0i {
+ int a[0]; // { dg-warning "zero-size array" }
+ int i;
+};
+
+struct S_a0_ax {
+ int a1[0]; // { dg-warning "zero-size array" }
+ int ax[0]; // { dg-warning "zero-size array" }
+};
+
+struct S_a0_i_ax {
+ int a1[0]; // { dg-warning "zero-size array" }
+ int i;
+ int ax[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (S_a0_i_ax, ax);
+
+struct Si_a0_ax {
+ int i;
+ int a1[0]; // { dg-warning "zero-size array" }
+ int ax[0]; // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Si_a0_ax, ax);
+
+struct S_u0_ax {
+ union { } u[0]; // { dg-warning "zero-size array" }
+ int ax[0]; // { dg-warning "zero-size array" }
+};
+
+struct S_a1_s2 {
+ int a[1];
+ int b[2];
+};
__extension__ unsigned char data[];
};
-/* { dg-final { scan-ada-spec "array \\(0 .. -1\\)" } } */
+/* { dg-final { scan-ada-spec "array \\(0 .. 0\\)" } } */
/* { dg-final { cleanup-ada-spec } } */
struct SomeType
{
+ int n;
const char *values[];
};
const char *temp[] = {"607", "612", 0};
SomeType vals[] =
{
- { values : temp, },
+ { 0, values : temp, },
0
- }; // { dg-error "invalid" }
+ }; // { dg-error "GNU-style designated initializer for an array|cannot convert" }
+// (note the error above is on the wrong line)
+
typedef int jmp_buf[];
struct C
{
- jmp_buf cond_;
+ jmp_buf cond_; // { dg-error "flexible array member" }
};
class F
{
class F
{
public:
+ int nelems;
int elems[];
int *
m_fn1 ()
// { dg-do compile }
-// { dg-options "-fsanitize=undefined -fpermissive" }
+// { dg-options "-Wpedantic -Wno-error=pedantic -fsanitize=undefined -fpermissive" }
struct T { int c; char d[]; };
-struct T t = { 1, "a" }; // { dg-warning "initializer-string for array of chars is too long" }
+struct T t = { 1, "a" }; // { dg-warning "initialization of a flexible array member " }
int
baz (int i)
offs + field_offs);
}
}
- else if (TREE_CODE (type) == ARRAY_TYPE)
+ else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
{
+ /* The object type is an array of complete type, i.e., other
+ than a flexible array. */
tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
tree etype = TREE_TYPE (type);
HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype));
|| CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
case ARRAY_TYPE:
- /* We have already checked the component type above, so just check the
- domain type. */
- return type_contains_placeholder_p (TYPE_DOMAIN (type));
+ /* We have already checked the component type above, so just check
+ the domain type. Flexible array members have a null domain. */
+ return TYPE_DOMAIN (type) ?
+ type_contains_placeholder_p (TYPE_DOMAIN (type)) : false;
case RECORD_TYPE:
case UNION_TYPE:
but we cannot do this until the deprecated support for
initializing zero-length array members is removed. */
if (TREE_CODE (TREE_TYPE (local->field)) == ARRAY_TYPE
- && TYPE_DOMAIN (TREE_TYPE (local->field))
- && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field))))
+ && (!TYPE_DOMAIN (TREE_TYPE (local->field))
+ || !TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field)))))
{
fieldsize = array_size_for_constructor (local->val);
- /* Given a non-empty initialization, this field had
- better be last. */
- gcc_assert (!fieldsize || !DECL_CHAIN (local->field));
+ /* Given a non-empty initialization, this field had better
+ be last. Given a flexible array member, the next field
+ on the chain is a TYPE_DECL of the enclosing struct. */
+ const_tree next = DECL_CHAIN (local->field);
+ gcc_assert (!fieldsize || !next || TREE_CODE (next) != FIELD_DECL);
}
else
fieldsize = tree_to_uhwi (DECL_SIZE_UNIT (local->field));
if (TREE_CODE (local.type) == ARRAY_TYPE && TYPE_DOMAIN (local.type))
local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
else
- local.min_index = NULL_TREE;
+ local.min_index = integer_zero_node;
local.total_bytes = 0;
local.byte_buffer_in_use = outer != NULL;