From: Martin Sebor Date: Tue, 15 Dec 2015 21:04:08 +0000 (+0000) Subject: struct-layout-1_generate.c: Avoid generating further fields after the first flexible... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7e9a3ad30076ad8a91b8f61352aa98b417191ed5;p=gcc.git struct-layout-1_generate.c: Avoid generating further fields after the first flexible array member. gcc/testsuite/ChangeLog: 2015-12-15 Martin Sebor 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. gcc/cp/ChangeLog: 2015-12-15 Martin Sebor 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. gcc/ChangeLog: 2015-12-15 Martin Sebor 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. From-SVN: r231665 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f48dfe74b0c..57f95750359 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2015-12-15 Martin Sebor + + 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 * config/nvptx/nvptx.c (write_one_arg): Rename to ... diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0598be5a2f5..a23d05f7bd2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2015-12-15 Martin Sebor + + 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 PR c++/21802 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 216a30141d4..ab9ba26cef3 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #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. */ @@ -145,6 +146,12 @@ static void build_base_fields (record_layout_info, splay_tree, tree *); 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 *); @@ -4114,7 +4121,10 @@ walk_subobject_offsets (tree type, /* 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. */ @@ -5703,9 +5713,9 @@ check_bases_and_members (tree t) 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. */ @@ -6531,7 +6541,7 @@ layout_class_type (tree t, tree *virtuals_p) && 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); @@ -6597,9 +6607,262 @@ sorted_fields_type_new (int n) 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 *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) @@ -6661,6 +6924,11 @@ 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. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 62636c9eefa..77358c4c685 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8627,8 +8627,9 @@ fold_sizeof_expr (tree t) } /* 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) @@ -8636,6 +8637,9 @@ 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; @@ -10905,7 +10909,7 @@ grokdeclarator (const cp_declarator *declarator, } { - tree decl; + tree decl = NULL_TREE; if (decl_context == PARM) { @@ -10929,9 +10933,18 @@ grokdeclarator (const cp_declarator *declarator, 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) @@ -11099,17 +11112,21 @@ grokdeclarator (const cp_declarator *declarator, || !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 { diff --git a/gcc/cp/error.c b/gcc/cp/error.c index e0ba806b32d..412d6381b16 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -875,7 +875,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags) 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); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 5ecf9fb1cad..a08f7d70b25 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -729,9 +729,14 @@ perform_member_init (tree member, tree init) || 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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a45e6df9e8b..8a39ca4861a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10026,7 +10026,16 @@ instantiate_class_template_1 (tree type) 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; @@ -12763,9 +12772,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) 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); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 839091c565e..68d2e7110b8 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1013,6 +1013,14 @@ digest_init_r (tree type, tree init, bool nested, int flags, 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 */ @@ -1051,8 +1059,11 @@ digest_init_r (tree type, tree init, bool nested, int flags, 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 @@ -1240,8 +1251,10 @@ process_init_constructor_array (tree type, tree init, 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 (); @@ -1417,14 +1430,15 @@ process_init_constructor_record (tree type, tree init, } 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); @@ -1433,13 +1447,17 @@ process_init_constructor_record (tree type, tree init, } /* 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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 17c1b661e19..7e45765159c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,32 @@ +2015-12-15 Martin Sebor + + 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 PR c/68907 diff --git a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c index 2884c25f337..9fab3a8d0f7 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c @@ -605,8 +605,11 @@ getrandll (void) 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]; @@ -625,7 +628,10 @@ subfield (struct entry *e, char *letter) 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 @@ -657,8 +663,8 @@ subfield (struct entry *e, char *letter) 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) { @@ -680,7 +686,10 @@ subfield (struct entry *e, char *letter) 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); } @@ -1157,8 +1166,11 @@ output (struct entry *e) 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; ) diff --git a/gcc/testsuite/g++.dg/ext/flexary.h b/gcc/testsuite/g++.dg/ext/flexary.h new file mode 100644 index 00000000000..a8dff7db0d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary.h @@ -0,0 +1,22 @@ +// 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; diff --git a/gcc/testsuite/g++.dg/ext/flexary2.C b/gcc/testsuite/g++.dg/ext/flexary2.C index 4855b3f5725..c0253777a1e 100644 --- a/gcc/testsuite/g++.dg/ext/flexary2.C +++ b/gcc/testsuite/g++.dg/ext/flexary2.C @@ -1,11 +1,23 @@ -// 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 }; + diff --git a/gcc/testsuite/g++.dg/ext/flexary3.C b/gcc/testsuite/g++.dg/ext/flexary3.C index 906877b11b7..c7c0e793355 100644 --- a/gcc/testsuite/g++.dg/ext/flexary3.C +++ b/gcc/testsuite/g++.dg/ext/flexary3.C @@ -1,7 +1,18 @@ -// 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() { diff --git a/gcc/testsuite/g++.dg/ext/flexary4.C b/gcc/testsuite/g++.dg/ext/flexary4.C new file mode 100644 index 00000000000..97ec62512b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary4.C @@ -0,0 +1,421 @@ +// 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]; +}; diff --git a/gcc/testsuite/g++.dg/ext/flexary5.C b/gcc/testsuite/g++.dg/ext/flexary5.C new file mode 100644 index 00000000000..3e76d3ef58d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary5.C @@ -0,0 +1,209 @@ +// { dg-do compile } +// { dg-options "-Wno-error=pedantic" } + +// Test to verify flexible array members handling in base and derived +// classes. + +#include "flexary.h" + +template +struct S_no_diag: T { + char a[]; // cannot be diagnosed unless/until T is known +}; + +template +struct STx_1: T { + char a[]; // { dg-error "flexible array member" } +}; + +template +struct STI: T { + char a[I]; // cannot be diagnosed unless/until T and I are known +}; + +template +struct STIx: T { + char a[I]; +}; + +template struct E { }; + +STx_1 > stx_empty_1; +STIx, 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 { }; diff --git a/gcc/testsuite/g++.dg/ext/flexary6.C b/gcc/testsuite/g++.dg/ext/flexary6.C new file mode 100644 index 00000000000..92677cd2aab --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary6.C @@ -0,0 +1,23 @@ +// 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" } + }; +}; diff --git a/gcc/testsuite/g++.dg/ext/flexary7.C b/gcc/testsuite/g++.dg/ext/flexary7.C new file mode 100644 index 00000000000..fdea4d44eaf --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary7.C @@ -0,0 +1,57 @@ +// 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 +struct FlexT { + int n; + T a[]; +}; + +struct FlexT atc = + { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" } + +#endif diff --git a/gcc/testsuite/g++.dg/ext/flexary8.C b/gcc/testsuite/g++.dg/ext/flexary8.C new file mode 100644 index 00000000000..7a1811deaff --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary8.C @@ -0,0 +1,33 @@ +// 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]; +}; diff --git a/gcc/testsuite/g++.dg/ext/flexary9.C b/gcc/testsuite/g++.dg/ext/flexary9.C new file mode 100644 index 00000000000..3228542177a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary9.C @@ -0,0 +1,405 @@ +// { 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]; +}; diff --git a/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C b/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C index 87c183aab66..d1af7e028fe 100644 --- a/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C +++ b/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C @@ -7,5 +7,5 @@ struct S __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 } } */ diff --git a/gcc/testsuite/g++.dg/parse/pr43765.C b/gcc/testsuite/g++.dg/parse/pr43765.C index 0b341ddb8ab..800f2c7cbbb 100644 --- a/gcc/testsuite/g++.dg/parse/pr43765.C +++ b/gcc/testsuite/g++.dg/parse/pr43765.C @@ -3,12 +3,15 @@ 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) + diff --git a/gcc/testsuite/g++.dg/torture/pr64280.C b/gcc/testsuite/g++.dg/torture/pr64280.C index 6ea31481bd5..e756e02eca1 100644 --- a/gcc/testsuite/g++.dg/torture/pr64280.C +++ b/gcc/testsuite/g++.dg/torture/pr64280.C @@ -15,7 +15,7 @@ public: typedef int jmp_buf[]; struct C { - jmp_buf cond_; + jmp_buf cond_; // { dg-error "flexible array member" } }; class F { diff --git a/gcc/testsuite/g++.dg/torture/pr64312.C b/gcc/testsuite/g++.dg/torture/pr64312.C index dc3e95dbb94..85211f25d26 100644 --- a/gcc/testsuite/g++.dg/torture/pr64312.C +++ b/gcc/testsuite/g++.dg/torture/pr64312.C @@ -43,6 +43,7 @@ protected: class F { public: + int nelems; int elems[]; int * m_fn1 () diff --git a/gcc/testsuite/g++.dg/ubsan/object-size-1.C b/gcc/testsuite/g++.dg/ubsan/object-size-1.C index e2aad4670bb..e6cdefc5c7b 100644 --- a/gcc/testsuite/g++.dg/ubsan/object-size-1.C +++ b/gcc/testsuite/g++.dg/ubsan/object-size-1.C @@ -1,9 +1,9 @@ // { 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) diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c index b666e970643..3768bc80c44 100644 --- a/gcc/tree-chkp.c +++ b/gcc/tree-chkp.c @@ -1664,8 +1664,10 @@ chkp_find_bound_slots_1 (const_tree type, bitmap have_bound, 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)); diff --git a/gcc/tree.c b/gcc/tree.c index 21c5fe1652e..66c06c992f6 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -3581,9 +3581,10 @@ type_contains_placeholder_1 (const_tree type) || 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: diff --git a/gcc/varasm.c b/gcc/varasm.c index c4c55e7cd06..643d682dc19 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -4974,13 +4974,15 @@ output_constructor_regular_field (oc_local_state *local) 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)); @@ -5196,7 +5198,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, 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;