gcc/
2015-11-20 Martin Sebor <msebor@redhat.com>
PR c++/42121
* c/c-decl.c (grokdeclarator): Mention type size in a diagnostic.
(finish_struct): Same.
gcc/cp/
2015-11-20 Martin Sebor <msebor@redhat.com>
PR c++/42121
* cp/class.c (layout_class_type): Mention type size in a diagnostic.
(all_bases_empty_p, field_nonempty_p, check_flexarrays): New helper
functions.
(finish_struct_1): Call check_flexarrays.
* cp/decl.c (compute_array_index_type): Add argument. Enhance
diagnostic.
(grokdeclarator): Reject flexible array members in unions.
Distinguish flexible array members from zero-size arrays.
gcc/testsuite/
2015-11-20 Martin Sebor <msebor@redhat.com>
PR c++/42121
* g++.dg/ext/flexary2.C: Adjust and enhance.
* g++.dg/ext/flexary3.C: Adjust.
* g++.dg/ext/flexary3.C: New test.
* g++.dg/torture/pr64280.C: Adjust.
* g++.dg/torture/pr64312.C: Adjust.
* g++.dg/parse/pr43765.C: Adjust.
* g++.dg/torture/pr64280.C: Adjust.
@@ -5868,10 +5868,12 @@ grokdeclarator (const struct c_declarator *declarator,
&& !int_fits_type_p (size, index_type))
{
if (name)
- error_at (loc, "size of array %qE is too large",
- name);
+ error_at (loc, "size of array %qE is too large "
+ "(%qE bytes)",
+ name, size);
else
- error_at (loc, "size of unnamed array is too large");
+ error_at (loc, "size of unnamed array is too large"
+ " (%qE bytes)", size);
type = error_mark_node;
continue;
}
@@ -7701,7 +7703,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
&& 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));
/* Give bit-fields their proper types and rewrite the type of array fields
with scalar component if the enclosing type has reverse storage order. */
@@ -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. */
@@ -6531,7 +6532,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);
@@ -6598,12 +6599,196 @@ sorted_fields_type_new (int n)
}
+/* Return true when all base classes of class T (a class type) are
+ empty, false otherwise. */
+
+static bool
+all_bases_empty_p (tree t)
+{
+ int i;
+ tree binfo;
+ tree base_binfo;
+
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ gcc_assert (COMPLETE_TYPE_P (basetype));
+
+ if (!is_empty_class (basetype))
+ return false;
+ }
+
+ return true;
+}
+
+/* Helper of finish_struct_1. 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 TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+ || !tree_int_cst_equal (size_zero_node, TYPE_SIZE (type));
+ }
+ return false;
+}
+
+/* Check to make sure any definitions of flexible array members
+ and zero-size arrays in a chain of FIELDS are valid, and
+ diagnose those that aren't. T denotes a struct, class, or
+ union whose fields are being checked. SEEN_FIELD is used
+ internally by recursive invocations of the function to set
+ the pointed-to object to true when a declaration of a non-
+ empty non-static data member precedes the declaration of
+ a flexible array member or a zero-size array.
+*/
+
+static tree
+check_flexarrays (tree t, tree fields, bool *seen_field)
+{
+ /* inform (DECL_SOURCE_LOCATION (fields), */
+ /* "entering %s with fields = %qD", __func__, fields); */
+
+ /* Members of anonymous structs and unions are considered to be members
+ of the containing struct or union. */
+ if (TYPE_ANONYMOUS_P (t))
+ return NULL_TREE;
+
+ /* Unlike the C front end, the C++ front end sets the upper bound
+ of a flexible array member to SIZE_MAX. Precompute that value
+ up front to avoid recomputing it on each iteration. */
+ tree size_max_node =
+ int_const_binop (MINUS_EXPR, size_zero_node, size_one_node);
+
+ /* Iterate over struct members, looking for definitions of non-static
+ flexible array members and zero-size arrays and determine whether
+ each is valid. */
+ for (tree fld = fields, next, f; fld;
+ *seen_field = *seen_field || field_nonempty_p (f), fld = next)
+ {
+ next = DECL_CHAIN (fld);
+
+ /* Use f below to check the current field, or to substitute
+ for it the flexible array member or zero-size array of
+ the anonymous struct it represents. */
+ f = fld;
+
+ const_tree fldtype = TREE_TYPE (f);
+ if (TREE_CODE (f) != TYPE_DECL
+ && RECORD_OR_UNION_TYPE_P (fldtype)
+ && TYPE_ANONYMOUS_P (fldtype))
+ {
+ /* Descend into the anonymous struct or union and check
+ its fields. The recursive call to the function will
+ either return 0 or the flexible array member whose
+ validity depends on whether any non-static data members
+ are declared in the enclosing struct. */
+ tree flexarray =
+ check_flexarrays (t, TYPE_FIELDS (fldtype), seen_field);
+ if (flexarray)
+ {
+ f = flexarray;
+ fldtype = TREE_TYPE (flexarray);
+ }
+ }
+
+ /* Skip anything that's not a (non-static) data member. */
+ if (TREE_CODE (f) != FIELD_DECL)
+ continue;
+
+ /* Skip non-arrays. */
+ if (TREE_CODE (fldtype) != ARRAY_TYPE || !DECL_CHAIN (f))
+ continue;
+
+ /* Determine the array's domain type. */
+ const_tree dom = TYPE_DOMAIN (fldtype);
+ if (!dom)
+ continue;
+
+ /* Determine the upper bound of the array. */
+ const_tree upbnd = TYPE_MAX_VALUE (dom);
+ if (!upbnd)
+ continue;
+
+ /* In C++, flexible array members and zero-size arrays have
+ an upper bound of SIZE_MAX. Skip those whose upper bound
+ is less than that. */
+ if (!tree_int_cst_equal (size_max_node, upbnd))
+ continue;
+
+ /* Flag is clear for zero-size arrays, set for flexible array
+ members. */
+ if (0 == DECL_LANG_FLAG_1 (f))
+ {
+ const char *msg = 0;
+
+ if (next && TREE_CODE (next) == FIELD_DECL)
+ msg = G_("zero-size array member %qD not at end of %q#T");
+ else if (!*seen_field && all_bases_empty_p (t))
+ msg = G_("zero-size array member %qD in an otherwise empty %q#T");
+
+ if (msg && pedwarn (DECL_SOURCE_LOCATION (f), OPT_Wpedantic,
+ msg, f, t))
+ inform (input_location, "%q#T declared here",
+ DECL_FIELD_CONTEXT (f));
+ }
+ else
+ {
+ const char *msg = 0;
+
+ if (next && TREE_CODE (next) == FIELD_DECL)
+ msg = G_("flexible array member %qD not at end of %q#T");
+ else if (!*seen_field && all_bases_empty_p (t))
+ {
+ /* When f is a member of anonymous struct, return
+ the (possibly invalid) flexible array member to
+ the (recursive) caller to determine whether it
+ is followed by any other data members in the
+ containing struct. */
+ if (DECL_CONTEXT (fld) != t)
+ return f;
+
+ msg = G_("flexible array member %qD in an otherwise empty %q#T");
+ }
+
+ if (msg)
+ {
+ /* Clear the flag specifically set for this purpose
+ only when a diagnostic is issued but leave it set
+ for prior (recursive) calls to the function so that
+ the appropriate message can be issued. */
+ DECL_LANG_FLAG_1 (f) = 0;
+ error_at (DECL_SOURCE_LOCATION (f), msg, f, t);
+ inform (input_location, "%q#T declared here",
+ DECL_FIELD_CONTEXT (f));
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* 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)
{
+ {
+ bool dummy = false;
+ check_flexarrays (t, TYPE_FIELDS (t), &dummy);
+ }
+
tree x;
/* A TREE_LIST. The TREE_VALUE of each node is a FUNCTION_DECL. */
tree virtuals = NULL_TREE;
@@ -8614,10 +8614,18 @@ fold_sizeof_expr (tree t)
name of the thing being declared. */
tree
-compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
+compute_array_index_type (tree name, tree size,
+ tsubst_flags_t complain)
{
tree itype;
tree osize = size;
+ bool flexarray = false;
+
+ if (NULL_TREE == size)
+ {
+ flexarray = true;
+ size = size_zero_node;
+ }
if (error_operand_p (size))
return error_mark_node;
@@ -8739,11 +8747,12 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
return error_mark_node;
else if (in_system_header_at (input_location))
/* Allow them in system headers because glibc uses them. */;
- else if (name)
- pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array %qD", name);
else
- pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array");
+ pedwarn (input_location, OPT_Wpedantic,
+ flexarray ? "flexible array members are a C++ extension"
+ : "ISO C++ forbids zero-size arrays");
}
+
}
else if (TREE_CONSTANT (size)
/* We don't allow VLAs at non-function scopes, or during
@@ -9182,6 +9191,8 @@ grokdeclarator (const cp_declarator *declarator,
source_location saved_loc = input_location;
const char *errmsg;
tree reqs = NULL_TREE;
+ /* Is the declarator a flexible array member? */
+ bool flexarray = false;
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
@@ -10888,7 +10899,7 @@ grokdeclarator (const cp_declarator *declarator,
}
{
- tree decl;
+ tree decl = NULL_TREE;
if (decl_context == PARM)
{
@@ -10912,11 +10923,20 @@ 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,
+ if (TREE_CODE (ctype) == UNION_TYPE
+ || TREE_CODE (ctype) == QUAL_UNION_TYPE)
+ {
+ error ("flexible array member in union");
+ type = error_mark_node;
+ }
+ else
+ {
+ flexarray = true;
+ 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)
{
/* Happens when declaring arrays of sizes which
@@ -11404,6 +11424,9 @@ grokdeclarator (const cp_declarator *declarator,
if (!processing_template_decl)
cp_apply_type_quals_to_decl (type_quals, decl);
+ if (flexarray)
+ DECL_LANG_FLAG_1 (decl) = 1;
+
return decl;
}
}
@@ -1,4 +1,10 @@
-// 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 {
@@ -7,5 +13,10 @@ struct A {
struct B {
B() {}
- A a[];
+ 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
};
@@ -1,10 +1,19 @@
-// 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.
+
// { dg-options "" }
-struct s { char c[]; };
+struct s {
+ char c[]; // { dg-error "flexible array member .* in an otherwise empty" }
+};
int main()
{
- struct s s = { .c = 0 }; // { dg-error "initializer" }
+ struct s s = { .c = 0 }; // { dg-error "invalid initializer" }
return 0;
}
new file mode 100644
@@ -0,0 +1,370 @@
+// 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.
+
+struct Sx {
+ int a[]; // { dg-error "flexible array member" }
+};
+
+// Verify that non-data members or static data members don't suppress
+// the diagnostic.
+struct Sx2 {
+ int a[]; // { dg-error "flexible array member" }
+ typedef int I;
+};
+
+struct Sx3 {
+ typedef int I;
+ int a[]; // { dg-error "flexible array member" }
+};
+
+struct Sx4 {
+ int a[]; // { dg-error "flexible array member" }
+ enum E { e };
+};
+
+struct Sx5 {
+ enum E { e };
+ int a[]; // { dg-error "flexible array member" }
+};
+
+struct Sx6 {
+ int a[]; // { dg-error "flexible array member" }
+ static int i;
+};
+
+int Sx6::i;
+
+struct Sx7 {
+ static int i;
+ int a[]; // { dg-error "flexible array member" }
+};
+
+int Sx7::i;
+
+struct Sx8 {
+ int a[]; // { dg-error "flexible array member" }
+ Sx8 () { }
+};
+
+struct Sx9 {
+ Sx9 () { }
+ int a[]; // { dg-error "flexible array member" }
+};
+
+struct Sx10 {
+ int a[]; // { dg-error "flexible array member" }
+ virtual ~Sx10 () { }
+};
+
+struct Sx11 {
+ virtual ~Sx11 () { }
+ int a[]; // { dg-error "flexible array member" }
+};
+
+struct Sx12 {
+ int a[]; // { dg-error "flexible array member" }
+ virtual void foo () = 0;
+};
+
+struct Sx13 {
+ virtual void foo () = 0;
+ int a[]; // { dg-error "flexible array member" }
+};
+
+struct Sx14 {
+ int a[][1]; // { dg-error "flexible array member" }
+};
+
+struct Sx15 {
+ typedef int A[];
+ A a; // { dg-error "flexible array member" }
+};
+
+// 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 "flexible array member" }
+};
+
+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];
+};
+
+struct Sx18 {
+ int a_x []; // { dg-error "flexible array member" }
+ struct S { };
+};
+
+struct Sx19 {
+ struct S { };
+ int a_x []; // { dg-error "flexible array member" }
+};
+
+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 [];
+};
+
+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 [];
+};
+
+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[];
+ };
+};
+
+struct Anon2 {
+ struct {
+ int n;
+ struct {
+ int good[];
+ };
+ };
+};
+
+struct Anon3 {
+ struct {
+ struct {
+ int n;
+ int 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[];
+};
+
+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 a1[0];
+ int ax[]; // { dg-error "flexible array member" }
+};
+
+struct S_a0_i_ax {
+ int a1[0];
+ int i;
+ int ax[];
+};
+
+struct Si_a0_ax {
+ int i;
+ int a1[0];
+ int ax[];
+};
+
+struct S_u_ax {
+ struct {
+ // An empty struct is in C++ treated as if it had a single
+ // member of type char. Arguably, though, since neither
+ // the struct nor the member has a name, the flexible array
+ // member should be diagnosed because its size cannot easily
+ // be stored in the contaning object. This seems like too
+ // much of a corner case to worry about.
+ };
+ int ax[]; // no warning because of the above
+};
+
+struct S_u0_ax {
+ union { } u[0];
+ int ax[]; // { dg-error "flexible array member" }
+};
+
+struct S_a1_s2 {
+ int a[1];
+ int b[2];
+};
+
+union U_i_ax {
+ int i;
+ int a[]; // { dg-error "flexible array member in union" }
+};
+
+union U_i_a0 {
+ int i;
+ int a[0];
+};
+
+template <class T>
+struct ST: 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 Empty { };
+
+STx_1<Empty<0> > stx_empty_1;
+STIx<Empty<0>, 0> stix_empty_1;
+
+struct EmptyBase1: Empty<0>, Empty<1> { };
+struct EmptyBase2: Empty<2>, Empty<3> { };
+struct EmptyDerived: EmptyBase1, EmptyBase2
+{
+ char a[]; // { dg-error "flexible array member" }
+};
+
+struct NonEmpty { int i; };
+struct NonEmptyBase: NonEmpty { };
+struct NonEmptyDerived: NonEmptyBase { };
+
+struct FinalDerived: EmptyBase1, EmptyBase2, NonEmpty, Empty<4>
+{
+ char a[]; // okay
+};
@@ -3,12 +3,13 @@
struct SomeType
{
+ int n;
const char *values[];
};
const char *temp[] = {"607", "612", 0};
SomeType vals[] =
{
- { values : temp, },
+ { 0, values : temp, },
0
}; // { dg-error "invalid" }
@@ -15,7 +15,7 @@ public:
typedef int jmp_buf[];
struct C
{
- jmp_buf cond_;
+ jmp_buf cond_; // { dg-error "flexible array member" }
};
class F
{
@@ -43,6 +43,7 @@ protected:
class F
{
public:
+ int nelems;
int elems[];
int *
m_fn1 ()