From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 98747 invoked by alias); 21 Nov 2015 22:17:26 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 97451 invoked by uid 89); 21 Nov 2015 22:17:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=AWL,BAYES_50,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-qg0-f52.google.com Received: from mail-qg0-f52.google.com (HELO mail-qg0-f52.google.com) (209.85.192.52) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sat, 21 Nov 2015 22:17:21 +0000 Received: by qgea14 with SMTP id a14so94406725qge.0 for ; Sat, 21 Nov 2015 14:17:19 -0800 (PST) X-Received: by 10.140.234.66 with SMTP id f63mr21233397qhc.61.1448144239109; Sat, 21 Nov 2015 14:17:19 -0800 (PST) Received: from [192.168.0.26] (97-124-162-152.hlrn.qwest.net. [97.124.162.152]) by smtp.gmail.com with ESMTPSA id c67sm1347346qgd.29.2015.11.21.14.17.17 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 21 Nov 2015 14:17:18 -0800 (PST) Message-ID: <5650ED6B.2040404@gmail.com> Date: Sat, 21 Nov 2015 22:26:00 -0000 From: Martin Sebor User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Gcc Patch List Subject: [PATCH] c++/42121 - diagnose invalid flexible array members Content-Type: multipart/mixed; boundary="------------060108050900050603090206" X-IsSubscribed: yes X-SW-Source: 2015-11/txt/msg02596.txt.bz2 This is a multi-part message in MIME format. --------------060108050900050603090206 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1493 Bug 42121 - g++ should warn or error on internal 0 size array in struct, is a request to diagnose declarations of flexible array members that aren't last in the enclosing struct, such as in the following: struct S { int a; char b[]; // invalid int c; }; The C front end diagnoses such cases because they are invalid in standard C. Comment 8 on the bug points out that flexible array members should not be treated identically to zero-size arrays (they're not in C). The attached patch implements the requested diagnostic, keeping comment 8 in mind. It also issues a diagnostic for flexible array members in unions (which are also diagnosed as invalid in C mode). The patch found a number of instances of invalid flexible array members in the C++ test suites. I corrected them. Since the C++ front end doesn't distinguish between flexible array members and zero-size arrays (both are considered to have an upper bound of SIZE_MAX), and since determining whether or not a declaration of such a member is valid cannot be done until the whole containing struct has been processed, the patch makes use one of the DECL_LANG_FLAGs to temporarily remember which is which (I somewhat arbitrarily picked DECL_LANG_FLAG_1), before clearing it. There might be a better flag to use, and it might be appropriate to define a descriptive macro for this purpose in cp-tree.h, along the same lines as the macros already defined for other such purposes. Martin --------------060108050900050603090206 Content-Type: text/x-patch; name="gcc-42121.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="gcc-42121.patch" Content-length: 22892 gcc/ 2015-11-20 Martin Sebor PR c++/42121 * c/c-decl.c (grokdeclarator): Mention type size in a diagnostic. (finish_struct): Same. gcc/cp/ 2015-11-20 Martin Sebor 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 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. diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 7b9ab8a..e55471f 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -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. */ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 216a301..4803f55 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. */ @@ -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; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 675342e..ba3daf3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; } } diff --git a/gcc/testsuite/g++.dg/ext/flexary2.C b/gcc/testsuite/g++.dg/ext/flexary2.C index 4855b3f..dcd1bde 100644 --- a/gcc/testsuite/g++.dg/ext/flexary2.C +++ b/gcc/testsuite/g++.dg/ext/flexary2.C @@ -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 }; diff --git a/gcc/testsuite/g++.dg/ext/flexary3.C b/gcc/testsuite/g++.dg/ext/flexary3.C index 906877b..5c4a658 100644 --- a/gcc/testsuite/g++.dg/ext/flexary3.C +++ b/gcc/testsuite/g++.dg/ext/flexary3.C @@ -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; } diff --git a/gcc/testsuite/g++.dg/ext/flexary4.C b/gcc/testsuite/g++.dg/ext/flexary4.C new file mode 100644 index 0000000..dd001f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary4.C @@ -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 +struct ST: 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 Empty { }; + +STx_1 > stx_empty_1; +STIx, 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 +}; diff --git a/gcc/testsuite/g++.dg/parse/pr43765.C b/gcc/testsuite/g++.dg/parse/pr43765.C index 0b341dd..e115aa5 100644 --- a/gcc/testsuite/g++.dg/parse/pr43765.C +++ b/gcc/testsuite/g++.dg/parse/pr43765.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/torture/pr64280.C b/gcc/testsuite/g++.dg/torture/pr64280.C index 6ea3148..e756e02 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 dc3e95d..85211f2 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 () --------------060108050900050603090206--