From patchwork Tue Sep 20 17:01:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 672365 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3sdpxw3q2Lz9svs for ; Wed, 21 Sep 2016 03:04:04 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=o3yiJHCG; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=CS2osw7faP3H9BULA YmADKASDqyJ64LhG37UvvPRukQs9W5iXJ+qF5GwGwv0GSaheB4hElnPTKqXmT/Bb oV57cZ6yiq59hYPZe7FZKH7O0apHe6NV3MeWmHU27YMXFuDYDFo80gDdydSzLcCd 2eRdd8OB3exEPJjrYDAFA4EMsU= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=GMj09HNC880yahCFIhG9YLV 6ho4=; b=o3yiJHCGTkpQuqobLYuVrdPp/IW/fSE1NMSuJotkrupUw1zYHBu1OSI yl0V5kV4ErAyDC7okS45zc1Yh2VfwKMZPaTSnD8+pGD/IRLyHf1+MBzNVMZMca6m IrjbBtDSqQJb4xDkEqucfw6atjxpkai9qMTk3IlsXtUNYh1uTtWw= Received: (qmail 115005 invoked by alias); 20 Sep 2016 17:02:07 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 114880 invoked by uid 89); 20 Sep 2016 17:02:07 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=Members, highest, relationships, xs X-HELO: mail-qk0-f172.google.com Received: from mail-qk0-f172.google.com (HELO mail-qk0-f172.google.com) (209.85.220.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 20 Sep 2016 17:01:56 +0000 Received: by mail-qk0-f172.google.com with SMTP id t7so21351766qkh.2 for ; Tue, 20 Sep 2016 10:01:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:subject:to:references:cc:message-id:date :user-agent:mime-version:in-reply-to; bh=SRV9coFPV8469KWDdxJe/D4hwa0pSjZWCBUqUXew02s=; b=Akaptiq4R/xD+c6aWCU6IaoQ9b2cmQW/FI/MIeBnAGdepVpfEulyAWurMlw6mmTs93 eVBDieAEVPjJfuUzaocca+t8x1FPaadlZmWxQD6v9KsXEhbFaL+INMblHn00lAbz3Swv DQqn5/ska/7vedLhtQNLfOOkXJ02Cxd+JISMGW1sBeOKN6a//12awYCFEUtx5HgOoGgX RMl2/wB8gUESmfV40aCo23v0UUScJv13+gPLMAVzOxIiQc5Bqxt4rUUawydYohRdUf7g MXDzBa1cmANb5vL33TOEHAaQK2crqA0IefSJAAVuX/xylqrJJypyFd7+kGolOYo9lwY2 5orw== X-Gm-Message-State: AE9vXwPgTfsOWOCAzKGPw6lcSg7LWUy6Pzy/chwkCLucPlisVgHHDYZAd1FIi0R5BmPlyA== X-Received: by 10.55.214.68 with SMTP id t65mr37058423qki.216.1474390914074; Tue, 20 Sep 2016 10:01:54 -0700 (PDT) Received: from [192.168.0.26] (75-166-199-51.hlrn.qwest.net. [75.166.199.51]) by smtp.gmail.com with ESMTPSA id u9sm16576833qtb.28.2016.09.20.10.01.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 20 Sep 2016 10:01:53 -0700 (PDT) From: Martin Sebor Subject: Re: [PATCH] accept flexible arrays in struct in unions (c++/71912 - [6/7 regression]) To: Jason Merrill References: <57927079.5080400@gmail.com> <5793A6F4.2090900@gmail.com> <69dc2b8d-1841-92b7-20ed-6e0a899435f2@redhat.com> <579BE53E.7070002@gmail.com> <6a6e323e-dbbb-f903-2492-e8ed26e01d65@redhat.com> <579E5F1E.8060603@gmail.com> <57A109E6.8010809@gmail.com> <57A15341.9070702@gmail.com> <73604cac-ed57-8811-aaf7-232cab86ac2d@gmail.com> Cc: Gcc Patch List Message-ID: <5f633d7d-e730-cbc1-5c71-b7ab5dea7840@gmail.com> Date: Tue, 20 Sep 2016 11:01:50 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 In-Reply-To: X-IsSubscribed: yes On 09/16/2016 12:19 PM, Jason Merrill wrote: > On 09/14/2016 01:03 PM, Martin Sebor wrote: >> Attached is an updated patch that does away with the "overlapping" >> warning and instead issues the same warnings as the C front end >> (though with more context). >> >> In struct flexmems_t I've retained the NEXT array even though only >> the first element is used to diagnose problems. The second element >> is used by the find_flexarrays function to differentiate structs >> with flexible array members in unions (which are valid) from those >> in structs (which are not). >> >> FWIW, I think this C restriction on structs is unnecessary and will >> propose to remove it so that's valid to define a struct that contains >> another struct (possibly recursively) with a flexible array member. >> I.e., I think this should be made valid in C (and accepted without >> the pedantic warning that GCC, and with this patch also G++, issues): > > Agreed. This is now N2083: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2083.htm > >> + /* Is FLD a typedef for an anonymous struct? */ >> + bool anon_type_p >> + = (TREE_CODE (fld) == TYPE_DECL >> + && DECL_IMPLICIT_TYPEDEF_P (fld) >> + && anon_aggrname_p (DECL_NAME (fld))); > > We talked earlier about handling typedefs in > cp_parser_{simple,single}_declaration, so that we catch > > typedef struct { int a[]; } B; > > or at least adding a FIXME comment here explaining that looking at > typedefs is a temporary hack. I've added a FIXME comment. > >> + /* Type of the member. */ >> + tree fldtype = TREE_CODE (fld) == FIELD_DECL ? TREE_TYPE (fld) >> : fld; > > Why set "fldtype" to be a TYPE_DECL rather than its type? I'm not sure I understand the question but (IIRC) the purpose of this code is to detect invalid uses of flexible array members in typedefs such as this: struct S { typedef struct { int i, a[]; } X2 [2]; }; Sadly, it doesn't do anything for struct X { int i, a[]; }; struct S { typedef struct X X2 [2]; }; >> + /* Determine the type of the array element or object referenced >> + by the member so that it can be checked for flexible array >> + members if it hasn't been yet. */ >> + tree eltype = TREE_CODE (fld) == FIELD_DECL ? fldtype : >> TREE_TYPE (fld); > > Given the above, this seems equivalent to > > tree eltype = TREE_TYPE (fld); Yes. > >> + if (RECORD_OR_UNION_TYPE_P (eltype)) >> + { > ... >> + if (fmem->array && !fmem->after[bool (pun)]) >> + { >> + /* Once the member after the flexible array has been found >> + we're done. */ >> + fmem->after[bool (pun)] = fld; >> + break; >> + } > ... >> if (field_nonempty_p (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->array && !fmem->after[bool (pun)]) >> fmem->after[bool (pun)] = fld; >> } > > Can we do this in one place rather than two? You mean merge the two assignments to fmem->after[bool (pun)] into one? I'm not sure. There's quite a bit of conditional logic in between them, including a recursive call that might set fmem. What would be gained by rewriting it all to merge the two assignments? If it could be done I worry that I'd just end up duplicating the conditions instead. > >> + if (eltype == fldtype || TYPE_UNNAMED_P (eltype)) > > This is excluding arrays, so we don't diagnose, say, > >> struct A >> { >> int i; >> int ar[]; >> }; >> >> struct B { >> A a[2]; >> }; > > Should we complain elsewhere about an array of a class with a flexible > array member? Yes, there are outstanding gaps/bugs that remain to be fixed. I tried to limit this fix to not much more than the reported regression. I did end up tightening other things up as I found more gaps during testing (though I probably should have resisted). Sometimes I find it hard to know where to stop but I feel like I need to draw the line somewhere. I of course agree that the outstanding bugs should be fixed as well but I'd prefer to do it in a separate change. >> + /* Does the field represent an anonymous struct? */ >> + bool anon_p = !DECL_NAME (fld) && ANON_AGGR_TYPE_P >> (eltype); > > You don't need to check DECL_NAME; ANON_AGGR_TYPE_P by itself indicates > that we're dealing with an anonymous struct/union. Thanks, I've removed the variable. > >> Similarly, PSTR is set to the outermost struct of which T is a member >> if one such struct exists, otherwise to NULL. */ > ... >> find_flexarrays (eltype, fmem, false, pun, >> !pstr && TREE_CODE (t) == RECORD_TYPE ? >> fld : pstr); > ... >> +diagnose_invalid_flexarray (const flexmems_t *fmem) >> +{ >> + if (fmem->array && fmem->enclosing >> + && pedwarn (location_of (fmem->enclosing), OPT_Wpedantic, >> + TYPE_DOMAIN (TREE_TYPE (fmem->array)) >> + ? G_("invalid use of %q#T with a zero-size array " >> + "in %q#D") >> + : G_("invalid use of %q#T with a flexible array >> member " >> + "in %q#T"), >> + DECL_CONTEXT (fmem->array), >> + DECL_CONTEXT (fmem->enclosing))) > > PSTR is documented to be the outermost struct, PSTR is set to a data member of the outermost struct of which the flexible array is a member. I've updated the comment to make it clearer. > but it (and thus > fmem->enclosing) end up being a data member of that outermost struct, > which is why you need to take its DECL_CONTEXT. What's the advantage of > doing that over passing t itself to the recursive call? I need the data member because I want to point the diagnostic at it, not at the struct of which it's a member. For example, in struct S { struct X { int i, a[]; } *p, x; }; I want to point at the x because it is the problem, like this: warning: invalid use of ‘struct S::X’ with a flexible array member in struct S’ [-Wpedantic] x; ^ not at struct X, which is not incorrect in and of itself, and neither is p. The diagnostic makes use of x's DECL_CONTEXT to print the name of x's type because that's where the flexible array is defined (or in which it's nested). > >> + /* The context of the flexible array member. Either the struct >> + in which it's declared or, for anonymous structs and unions, >> + the struct/union of which the array is effectively a member. */ >> + tree fmemctx = anon_context (fmem->array); >> + bool anon_p = fmemctx != DECL_CONTEXT (fmem->array); >> + if (!anon_p) >> + fmemctx = t; > > Why do you need to do something different here based on anon_p? I don't > see why that would affect whether we want to look through intermediate > non-anonymous classes. In code like this: struct X { int n, a[]; }; struct Y { int n, b[]; }; struct D: X, Y { }; The test above make the diagnostic point to the context of the invalid flexible array member, or Y::b, rather than that of X. Without it, we end up with: error: flexible array member ‘X::a’ not at end of ‘struct X’ rather than with error: flexible array member ‘X::a’ not at end of ‘struct D’ > >> + check_flexarrays (basetype, fmem, true); > > Please decorate boolean literal arguments like this with the name of the > parameter, e.g. /*base_p*/true. Sure. I should mention that Jeff recently advised against it in another review, so it would be nice to adopt the same convention throughout and document it (I'm happy to add it to the Wiki once it has been agreed on): https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00354.html FWIW, I haven't found mentioning the formal argument in a comment a useful or consistent convention. Other arguments' names aren't mentioned, and the bool argument's name cannot be mentioned when it has a default value. On the other hand, a convention I do find useful (though not one that seems to be used in GCC) is indicating in a comment in the definition of a function the value of the default argument in functions declared to take one. > >> + bool maybe_anon_p = anon_aggrname_p (TYPE_IDENTIFIER (t)); > > Now we can use TYPE_UNNAMED_P. Okay, thanks. Attached is a revision of the patch with the changes discussed above. Martin PR c++/71912 - [6/7 regression] flexible array in struct in union rejected gcc/cp/ChangeLog: PR c++/71912 * class.c (struct flexmems_t): Add members. (find_flexarrays): Add arguments. Correct handling of anonymous structs. (diagnose_flexarrays): Adjust to issue warnings in addition to errors. (check_flexarrays): Add argument. (anon_context, diagnose_invalid_flexarray): New functions. gcc/testsuite/ChangeLog: PR c++/71912 * g++.dg/ext/flexary4.C: Adjust. * g++.dg/ext/flexary5.C: Same. * g++.dg/ext/flexary9.C: Same. * g++.dg/ext/flexary19.C: New test. * g++.dg/ext/flexary18.C: New test. * g++.dg/torture/pr64312.C: Add a dg-error directive to an ill-formed regression test. * g++.dg/compat/struct-layout-1_generate.c (subfield): Add argument. Avoid generating a flexible array member in an array. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f7147e6..28171ea 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -147,11 +147,12 @@ 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. */ +/* Used by find_flexarrays and related functions. */ 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 find_flexarrays (tree, flexmems_t *, bool = false, + tree = NULL_TREE, tree = NULL_TREE); +static void check_flexarrays (tree, flexmems_t * = NULL, bool = false); static void check_bases (tree, int *, int *); static void check_bases_and_members (tree); static tree create_vtable_ptr (tree, tree *); @@ -6711,53 +6712,160 @@ field_nonempty_p (const_tree fld) return false; } -/* Used by find_flexarrays and related. */ -struct flexmems_t { +/* Used by find_flexarrays and related functions. */ + +struct flexmems_t +{ /* The first flexible array member or non-zero array member found - in order of layout. */ + in the 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; + /* The first non-static non-empty data member following either + the flexible array member, if found, or the zero-length array member + otherwise. AFTER[1] refers to the first such data member of a union + of which the struct containing the flexible array member or zero-length + array is a member, or NULL when no such union exists. This element is + only used during searching, not for diagnosing problems. AFTER[0] + refers to the first such data member that is not a member of such + a union. */ + tree after[2]; + + /* Refers to a struct (not union) in which the struct of which the flexible + array is member is defined. Used to diagnose strictly (according to C) + invalid uses of the latter structs. */ + tree enclosing; }; /* 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. */ + array, in that order of preference, among members of class T (but not + its base classes), and set members of FMEM accordingly. + BASE_P is true if T is a base class of another class. + PUN is set to the outermost union in which the flexible array member + (or zero-length array) is defined if one such union exists, otherwise + to NULL. + Similarly, PSTR is set to a data member of the outermost struct of + which the flexible array is a member if one such struct exists, + otherwise to NULL. */ static void -find_flexarrays (tree t, flexmems_t *fmem) +find_flexarrays (tree t, flexmems_t *fmem, bool base_p, + tree pun /* = NULL_TREE */, + tree pstr /* = NULL_TREE */) { - 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; ); + /* Set the "pointer" to the outermost enclosing union if not set + yet and maintain it for the remainder of the recursion. */ + if (!pun && TREE_CODE (t) == UNION_TYPE) + pun = t; - tree fldtype = TREE_TYPE (fld); - if (TREE_CODE (fld) != TYPE_DECL - && RECORD_OR_UNION_TYPE_P (fldtype) - && TYPE_UNNAMED_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; - } + for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld)) + { + if (fld == error_mark_node) + return; - /* Skip anything that's not a (non-static) data member. */ - if (TREE_CODE (fld) != FIELD_DECL) + /* Is FLD a typedef for an anonymous struct? */ + + /* FIXME: Note that typedefs (as well as arrays) need to be fully + handled elsewhere so that errors like the following are detected + as well: + typedef struct { int i, a[], j; } S; // bug c++/72753 + S s [2]; // bug c++/68489 + */ + bool anon_type_p + = (TREE_CODE (fld) == TYPE_DECL + && DECL_IMPLICIT_TYPEDEF_P (fld) + && anon_aggrname_p (DECL_NAME (fld))); + + /* Skip anything that's GCC-generated or not a (non-static) data + member or typedef. */ + if ((DECL_ARTIFICIAL (fld) && !anon_type_p) + || (TREE_CODE (fld) != FIELD_DECL && TREE_CODE (fld) != TYPE_DECL)) continue; - /* Skip virtual table pointers. */ - if (DECL_ARTIFICIAL (fld)) + /* Type of the member. */ + tree fldtype = TREE_CODE (fld) == FIELD_DECL ? TREE_TYPE (fld) : fld; + if (fldtype == error_mark_node) + return; + + /* Determine the type of the array element or object referenced + by the member so that it can be checked for flexible array + members if it hasn't been yet. */ + tree eltype = TREE_TYPE (fld); + if (eltype == error_mark_node) + return; + + while (TREE_CODE (eltype) == ARRAY_TYPE + || TREE_CODE (eltype) == POINTER_TYPE + || TREE_CODE (eltype) == REFERENCE_TYPE) + eltype = TREE_TYPE (eltype); + + if (TREE_CODE (fld) == TYPE_DECL + && TYPE_CANONICAL (eltype) == TYPE_CANONICAL (t)) continue; + if (RECORD_OR_UNION_TYPE_P (eltype)) + { + if (anon_type_p) + { + /* Check the nested unnamed type referenced via a typedef + independently of FMEM (since it's not a data member of + the enclosing class). */ + check_flexarrays (eltype); + continue; + } + + if (fmem->array && !fmem->after[bool (pun)]) + { + /* Once the member after the flexible array has been found + we're done. */ + fmem->after[bool (pun)] = fld; + break; + } + + if (eltype == fldtype || TYPE_UNNAMED_P (eltype)) + { + /* Descend into the non-static member struct or union and try + to find a flexible array member or zero-length array among + its members. This is only necessary for anonymous types + and types in whose context the current type T has not been + defined (the latter must not be checked again because they + are already in the process of being checked by one of the + recursive calls). */ + + tree first = fmem->first; + tree array = fmem->array; + + /* If this member isn't anonymous and a prior non-flexible array + member has been seen in one of the enclosing structs, clear + the FIRST member since it doesn't contribute to the flexible + array struct's members. */ + if (first && !array && !ANON_AGGR_TYPE_P (eltype)) + fmem->first = NULL_TREE; + + find_flexarrays (eltype, fmem, false, pun, + !pstr && TREE_CODE (t) == RECORD_TYPE ? fld : pstr); + + if (fmem->array != array) + continue; + + if (first && !array && !ANON_AGGR_TYPE_P (eltype)) + { + /* Restore the FIRST member reset above if no flexible + array member has been found in this member's struct. */ + fmem->first = first; + } + + /* If the member struct contains the first flexible array + member, or if this member is a base class, continue to + the next member and avoid setting the FMEM->NEXT pointer + to point to it. */ + if (base_p) + continue; + } + else if (TREE_CODE (fld) == TYPE_DECL) + continue; + } + if (field_nonempty_p (fld)) { /* Remember the first non-static data member. */ @@ -6767,8 +6875,8 @@ find_flexarrays (tree t, flexmems_t *fmem) /* 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; + if (fmem->array && !fmem->after[bool (pun)]) + fmem->after[bool (pun)] = fld; } /* Skip non-arrays. */ @@ -6784,13 +6892,16 @@ find_flexarrays (tree t, flexmems_t *fmem) 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; + if (!fmem->after[bool (pun)]) + fmem->after[bool (pun)] = fld; } else if (integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype)))) - /* Remember the first zero-length array unless a flexible array - member has already been seen. */ - fmem->array = fld; + { + /* Remember the first zero-length array unless a flexible array + member has already been seen. */ + fmem->array = fld; + fmem->enclosing = pstr; + } } else { @@ -6801,16 +6912,55 @@ find_flexarrays (tree t, flexmems_t *fmem) reset the after pointer. */ if (TYPE_DOMAIN (TREE_TYPE (fmem->array))) { + fmem->after[bool (pun)] = NULL_TREE; fmem->array = fld; - fmem->after = NULL_TREE; + fmem->enclosing = pstr; } } else - fmem->array = fld; + { + fmem->array = fld; + fmem->enclosing = pstr; + } } } } +/* Return the type in which the member T is effectively declared. + This is either the member's enclosing struct for ordinary members, + or for anonymous structs and unions, the first non-anonymous struct + or union they are declared in. */ + +static tree +anon_context (tree t) +{ + if (TREE_CODE (t) == FIELD_DECL) + return anon_context (DECL_CONTEXT (t)); + + bool anon_p = ANON_AGGR_TYPE_P (t); + + return anon_p ? anon_context (TYPE_CONTEXT (t)) : t; +} + +/* Diagnose a strictly (by the C standard) invalid use of a struct with + a flexible array member (or the zero-length array extension). */ + +static void +diagnose_invalid_flexarray (const flexmems_t *fmem) +{ + if (fmem->array && fmem->enclosing + && pedwarn (location_of (fmem->enclosing), OPT_Wpedantic, + TYPE_DOMAIN (TREE_TYPE (fmem->array)) + ? G_("invalid use of %q#T with a zero-size array " + "in %q#D") + : G_("invalid use of %q#T with a flexible array member " + "in %q#T"), + DECL_CONTEXT (fmem->array), + DECL_CONTEXT (fmem->enclosing))) + inform (DECL_SOURCE_LOCATION (fmem->array), + "array member %q#D declared here", fmem->array); +} + /* 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. */ @@ -6818,49 +6968,78 @@ find_flexarrays (tree t, flexmems_t *fmem) 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_UNNAMED_P (t) || !fmem->array) + if (!fmem->array) return; + if (fmem->first && !fmem->after[0]) + { + diagnose_invalid_flexarray (fmem); + return; + } + + /* The context of the flexible array member. Either the struct + in which it's declared or, for anonymous structs and unions, + the struct/union of which the array is effectively a member. */ + tree fmemctx = anon_context (fmem->array); + if (fmemctx == DECL_CONTEXT (fmem->array)) + fmemctx = t; + + /* Has a diagnostic been issued? */ + bool diagd = false; + const char *msg = 0; if (TYPE_DOMAIN (TREE_TYPE (fmem->array))) { - if (fmem->after) + if (fmem->after[0]) 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)) + if (msg) + { + location_t loc = DECL_SOURCE_LOCATION (fmem->array); - inform (location_of (t), "in the definition of %q#T", t); + if (pedwarn (loc, OPT_Wpedantic, + msg, fmem->array, fmemctx)) + { + inform (location_of (t), "in the definition of %q#T", fmemctx); + diagd = true; + } + } } else { - if (fmem->after) + if (fmem->after[0]) 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); + location_t loc = DECL_SOURCE_LOCATION (fmem->array); + diagd = true; + + error_at (loc, msg, fmem->array, fmemctx); /* In the unlikely event that the member following the flexible - array member is declared in a different class, point to it. + array member is declared in a different class, or the member + overlaps another member of a common union, 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), + if (fmem->after[0] + && ((DECL_CONTEXT (fmem->after[0]) + != DECL_CONTEXT (fmem->array)))) + { + inform (DECL_SOURCE_LOCATION (fmem->after[0]), "next member %q#D declared here", - fmem->after); - - inform (location_of (t), "in the definition of %q#T", t); + fmem->after[0]); + inform (location_of (t), "in the definition of %q#T", t); + } } } + + if (!diagd && fmem->array && fmem->enclosing) + diagnose_invalid_flexarray (fmem); } @@ -6873,7 +7052,8 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem) that fails the checks. */ static void -check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) +check_flexarrays (tree t, flexmems_t *fmem /* = NULL */, + bool base_p /* = false */) { /* Initialize the result of a search for flexible array and zero-length array members. Avoid doing any work if the most interesting FMEM data @@ -6881,18 +7061,20 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) flexmems_t flexmems = flexmems_t (); if (!fmem) fmem = &flexmems; - else if (fmem->array && fmem->first && fmem->after) + else if (fmem->array && fmem->first && fmem->after[0]) return; + tree fam = fmem->array; + /* 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); + check_flexarrays (basetype, fmem, true); } /* Recursively check the base classes. */ - int nbases = BINFO_N_BASE_BINFOS (TYPE_BINFO (t)); + int nbases = TYPE_BINFO (t) ? BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) : 0; for (int i = 0; i < nbases; ++i) { tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (t), i); @@ -6906,7 +7088,7 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) continue; /* Check the base class. */ - check_flexarrays (BINFO_TYPE (base_binfo), fmem); + check_flexarrays (BINFO_TYPE (base_binfo), fmem, /*base_p=*/true); } if (fmem == &flexmems) @@ -6923,17 +7105,26 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */) /* Check the virtual base class. */ tree basetype = TREE_TYPE (base_binfo); - check_flexarrays (basetype, fmem); + check_flexarrays (basetype, fmem, /*base_p=*/true); } } - /* Search the members of the current (derived) class. */ - find_flexarrays (t, fmem); + /* Is the type unnamed (and therefore a member of it potentially + an anonymous struct or union)? */ + bool maybe_anon_p = TYPE_UNNAMED_P (t); - if (fmem == &flexmems) + /* Search the members of the current (possibly derived) class, skipping + unnamed structs and unions since those could be anonymous. */ + if (fmem != &flexmems || !maybe_anon_p) + find_flexarrays (t, fmem, base_p || fam != fmem->array); + + if (fmem == &flexmems && !maybe_anon_p) { - /* Issue diagnostics for invalid flexible and zero-length array members - found in base classes or among the members of the current class. */ + /* Issue diagnostics for invalid flexible and zero-length array + members found in base classes or among the members of the current + class. Ignore anonymous structs and unions whose members are + considered to be members of the enclosing class and thus will + be diagnosed when checking it. */ diagnose_flexarrays (t, fmem); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 531cd21e..4571fe7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -4,6 +4,12 @@ of non-nul characters. * gfortran.dg/substr_6.f90: Make the NUL character visible on stdout +2015-04-18 Martin Sebor + + * gfortran.dg/pr32627.f03 (strptr): Change size to match the number + of non-nul characters. + * gfortran.dg/substr_6.f90: Make the NUL character visible on stdout + 2016-09-13 Jakub Jelinek PR c++/77553 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 9fab3a8..b102306 100644 --- a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c +++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c @@ -495,7 +495,16 @@ struct types attrib_array_types[] = { #define HASH_SIZE 32749 static struct entry *hash_table[HASH_SIZE]; -static int idx, limidx, output_one, short_enums; +/* The index of the current type being output. */ +static int idx; + +/* The maximum index of the type(s) to output. */ +static int limidx; + +/* Set to non-zero to output a single type in response to the -i option + (which sets LIMIDX to the index of the type to output. */ +static int output_one; +static int short_enums; static const char *destdir; static const char *srcdir; static const char *srcdir_safe; @@ -535,6 +544,7 @@ switchfiles (int fields) fputs ("failed to create test files\n", stderr); exit (1); } + for (i = 0; i < NDG_OPTIONS; i++) fprintf (outfile, dg_options[i], "", srcdir_safe); fprintf (outfile, "\n\ @@ -607,9 +617,14 @@ getrandll (void) /* 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*/ + prevents subsequent fields from being generated (a flexible array member + must be the last member of the struct it's defined in). ARRAY is non- + zero when the enclosing structure is part of an array. In that case, + avoid generating a flexible array member as a subfield (such a member + would be invalid). */ + int -subfield (struct entry *e, char *letter, int *flex) +subfield (struct entry *e, char *letter, int *flex, int array) { int i, type; char buf[20]; @@ -664,7 +679,14 @@ subfield (struct entry *e, char *letter, int *flex) } for (i = 1; !*flex && i <= e[0].len; ) - i += subfield (e + i, letter, flex); + { + /* Avoid generating flexible array members if the enclosing + type is an array. */ + int array + = (e[0].etype == ETYPE_STRUCT_ARRAY + || e[0].etype == ETYPE_UNION_ARRAY); + i += subfield (e + i, letter, flex, array); + } switch (type) { @@ -685,7 +707,7 @@ subfield (struct entry *e, char *letter, int *flex) case ETYPE_ARRAY: if (e[0].etype == ETYPE_ARRAY) { - if (e[0].arr_len == 255) + if (!array && e[0].arr_len == 255) { *flex = 1; snprintf (buf, 20, "%c[]", *letter); @@ -1141,6 +1163,7 @@ e_insert (struct entry *e) hash_table[hval % HASH_SIZE] = e; } +/* Output a single type. */ void output (struct entry *e) { @@ -1169,7 +1192,7 @@ output (struct entry *e) int flex = 0; for (i = 1; i <= e[0].len; ) - i += subfield (e + i, &c, &flex); + i += subfield (e + i, &c, &flex, 0); fputs (",", outfile); c = 'a'; diff --git a/gcc/testsuite/g++.dg/ext/flexary17.C b/gcc/testsuite/g++.dg/ext/flexary17.C new file mode 100644 index 0000000..b44e512 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary17.C @@ -0,0 +1,63 @@ + +// PR c++/68489 - arrays of flexible array members are silently accepted +// { dg-do compile } +// { dg-options "-Wno-error=pedantic" } + +struct S1 { + struct X1 { int n, a []; } x [1]; +}; + +struct S2 { + struct X2 { int n, a []; } x [2]; // { dg-error "not at end" } +}; + +struct S3 { + struct X3 { int n, a []; } x [0]; // { dg-error "not at end" } +}; + +struct S4 { + struct Y4 { + struct X4 { int n, a []; } x; + } y [1]; +}; + +struct S5 { + struct Y5 { + struct X5 { int n, a []; } x; // { dg-error "not at end" } + } y [2]; +}; + +struct S6 { + struct Y6 { + struct X6 { int n, a []; } x; // { dg-error "not at end" } + } y [0]; +}; + +struct S7 { + struct Z7 { + struct Y7 { + struct X7 { int n, a []; } x; + } y; + } z [1]; +}; + +struct S8 { + struct Z8 { + struct Y8 { + struct X8 { int n, a []; } x; // { dg-error "not at end" } + } y; + } z [2]; +}; + +struct S9 { + struct Z9 { + struct Y9 { + struct X9 { int n, a []; } x; // { dg-error "not at end" } + } y; + } z [0]; +}; + + +struct X { + int n, a[]; +} x [2]; // { dg-error "not at end" "PR c++/68489" { xfail *-*-*-* } } diff --git a/gcc/testsuite/g++.dg/ext/flexary18.C b/gcc/testsuite/g++.dg/ext/flexary18.C new file mode 100644 index 0000000..4353425 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary18.C @@ -0,0 +1,213 @@ +// PR c++/71912 - [6/7 regression] flexible array in struct in union rejected +// { dg-do compile } +// { dg-additional-options "-Wpedantic -Wno-error=pedantic" } + +#if __cplusplus + +namespace pr71912 { + +#endif + +struct foo { + int a; + char s[]; // { dg-message "array member .char pr71912::foo::s \\\[\\\]. declared here" } +}; + +struct bar { + double d; + char t[]; +}; + +struct baz { + union { + struct foo f; + struct bar b; + } + // The definition of struct foo is fine but the use of struct foo + // in the definition of u below is what's invalid and must be clearly + // diagnosed. + u; // { dg-warning "invalid use of .struct pr71912::foo. with a flexible array member in .struct pr71912::baz." } +}; + +struct xyyzy { + union { + struct { + int a; + char s[]; // { dg-message "declared here" } + } f; + struct { + double d; + char t[]; + } b; + } u; // { dg-warning "invalid use" } +}; + +struct baz b; +struct xyyzy x; + +#if __cplusplus + +} + +#endif + +// The following definitions aren't strictly valid but, like those above, +// are accepted for compatibility with GCC (in C mode). They are benign +// in that the flexible array member is at the highest offset within +// the outermost type and doesn't overlap with other members except for +// those of the union. +union UnionStruct1 { + struct { int n1, a[]; } s; + int n2; +}; + +union UnionStruct2 { + struct { int n1, a1[]; } s1; + struct { int n2, a2[]; } s2; + int n3; +}; + +union UnionStruct3 { + struct { int n1, a1[]; } s1; + struct { double n2, a2[]; } s2; + char n3; +}; + +union UnionStruct4 { + struct { int n1, a1[]; } s1; + struct { struct { int n2, a2[]; } s2; } s3; + char n3; +}; + +union UnionStruct5 { + struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "invalid use" } + struct { double n2, a2[]; } s3; + char n3; +}; + +union UnionStruct6 { + struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "invalid use" } + struct { struct { int n2, a2[]; } s3; } s4; + char n3; +}; + +union UnionStruct7 { + struct { int n1, a1[]; } s1; + struct { double n2, a2[]; } s2; + struct { struct { int n3, a3[]; } s3; } s4; +}; + +union UnionStruct8 { + struct { int n1, a1[]; } s1; + struct { struct { int n2, a2[]; } s2; } s3; + struct { struct { int n3, a3[]; } s4; } s5; +}; + +union UnionStruct9 { + struct { struct { int n1, a1[]; } s1; } s2; // { dg-warning "invalid use" } + struct { struct { int n2, a2[]; } s3; } s4; + struct { struct { int n3, a3[]; } s5; } s6; +}; + +struct StructUnion1 { + union { + struct { int n1, a1[]; } s1; // { dg-message "declared here" } + struct { double n2, a2[]; } s2; + char n3; + } u; // { dg-warning "invalid use" } +}; + +// The following are invalid and rejected. +struct StructUnion2 { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + } u; + char n3; // { dg-message "next member" } +}; + +struct StructUnion3 { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + struct { double n2, a2[]; } s2; + } u; + char n3; // { dg-message "next member" } +}; + +struct StructUnion4 { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + } u1; + union { + struct { double n2, a2[]; } s2; + } u2; // { dg-message "next member" } +}; + +struct StructUnion5 { + union { + union { + struct { int n1, a1[]; } s1; // { dg-message "declared here" } + } u1; + union { struct { int n2, a2[]; } s2; } u2; + } u; // { dg-warning "invalid use" } +}; + +struct StructUnion6 { + union { + struct { int n1, a1[]; } s1; // { dg-message "declared here" } + union { struct { int n2, a2[]; } s2; } u2; + } u; // { dg-warning "invalid use" } +}; + +struct StructUnion7 { + union { + union { + struct { double n2, a2[]; } s2; // { dg-message "declared here" } + } u2; + struct { int n1, a1[]; } s1; + } u; // { dg-warning "invalid use" } +}; + +struct StructUnion8 { + struct { + union { + union { + struct { int n1, a1[]; } s1; // { dg-error "not at end" } + } u1; + union { + struct { double n2, a2[]; } s2; + } u2; + } u; + } s1; + + struct { + union { + union { + struct { int n1, a1[]; } s1; + } u1; + union { + struct { double n2, a2[]; } s2; + } u2; + } u; } s2; // { dg-message "next member" } +}; + +struct StructUnion9 { // { dg-message "in the definition" } + struct A1 { + union B1 { + union C1 { + struct Sx1 { int n1, a1[]; } sx1; // { dg-error "not at end" } + } c1; + union D1 { + struct Sx2 { double n2, a2[]; } sx2; + } d1; + } b1; // { dg-warning "invalid use" } + } a1; + + struct A2 { + union B2 { + union C2 { + struct Sx3 { int n3, a3[]; } sx3; // { dg-message "declared here" } + } c2; + union D2 { struct Sx4 { double n4, a4[]; } sx4; } d2; + } b2; // { dg-warning "invalid use" } + } a2; // { dg-message "next member" } +}; diff --git a/gcc/testsuite/g++.dg/ext/flexary19.C b/gcc/testsuite/g++.dg/ext/flexary19.C new file mode 100644 index 0000000..27d08ec --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flexary19.C @@ -0,0 +1,343 @@ +// { dg-do compile } +// { dg-additional-options "-Wpedantic -Wno-error=pedantic" } + +// Verify that flexible array members are recognized as either valid +// or invalid in anonymous structs (a G++ extension) and C++ anonymous +// unions as well as in structs and unions that look anonymous but +// aren't. +struct S1 +{ + int i; + + // The following declares a named data member of an unnamed struct + // (i.e., it is not an anonymous struct). + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S2 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[1]; +}; + +struct S3 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[]; +}; + +struct S4 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[2]; +}; + +struct S5 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[1][2]; +}; + +struct S6 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s[][2]; +}; + +struct S7 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } *s; +}; + +struct S8 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s; +}; + +struct S9 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } *s[1]; +}; + +struct S10 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } *s[]; +}; + +struct S11 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s[1]; +}; + +struct S12 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s[]; +}; + +struct S13 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } **s[2]; +}; + +struct S14 +{ + int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } &s; +}; + +struct S15 +{ + int i; + + typedef struct { + int a[]; // { dg-error "in an otherwise empty" } + } T15; +}; + +struct S16 +{ + int i; + + struct { // { dg-warning "invalid use" } + // A flexible array as a sole member of an anonymous struct is + // rejected with an error in C mode but emits just a pedantic + // warning in C++. Other than excessive pedantry there is no + // reason to reject it. + int a[]; + }; // { dg-warning "anonymous struct" } +}; + +struct S17 +{ + int i; + + union { // anonymous union + int a[]; // { dg-error "flexible array member in union" } + }; +}; + +struct S18 +{ + int i; + + struct { + int j, a[]; // { dg-message "declared here" } + } s; // { dg-warning "invalid use" } +}; + +struct S19 +{ + int i; + + struct { // { dg-warning "invalid use" } + int j, a[]; // { dg-message "declared here" } + }; // { dg-warning "anonymous struct" } +}; + +struct S20 +{ + static int i; + typedef int A[]; + + struct { + int j; + A a; // { dg-message "declared here" } + } s; // { dg-warning "invalid use" } +}; + +struct S21 +{ + static int i; + typedef int A[]; + + struct { // { dg-warning "invalid use" } + int j; + A a; // { dg-message "declared here" } + }; // { dg-warning "anonymous struct" } +}; + +struct S22 +{ + struct S22S { + static int i; + + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S23 +{ + struct { + static int i; // { dg-error "static data member" } + + int a[]; // { dg-error "in an otherwise empty" } + }; // { dg-warning "anonymous struct" } +}; + +struct S24 +{ + static int i; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S25 +{ + int i; + + struct { + int j, a[]; // { dg-message "declared here" } + } s; // { dg-warning "invalid use" } + + // Verify that a static data member of the enclosing class doesn't + // cause infinite recursion or some such badness. + static S25 s2; +}; + +struct S26 +{ + template + struct S26S { + static int a; + }; + + struct { + int a[]; // { dg-error "in an otherwise empty" } + } s; +}; + +struct S27 +{ + S27 *p; + int a[]; +}; + +struct S28 +{ + struct A { + struct B { + S28 *ps28; + A *pa; + B *pb; + } b, *pb; + A *pa; + } a, *pa; + + S28::A *pa2; + S28::A::B *pb; + + int flexarray[]; +}; + +// Verify that the notes printed along with the warnings point to the types +// or members they should point to and mention the correct relationships +// with the flexible array members. +namespace Notes +{ +union A +{ + struct { + struct { + int i, a[]; // { dg-message "declared here" } + } c; // { dg-warning "invalid use" } + } d; + int j; +}; + +union B +{ + struct { + struct { // { dg-warning "invalid use" } + int i, a[]; // { dg-message "declared here" } + }; // { dg-warning "anonymous struct" } + }; // { dg-warning "anonymous struct" } + int j; +}; + +} + +typedef struct Opaque* P29; +struct S30 { P29 p; }; +struct S31 { S30 s; }; + +typedef struct { } S32; +typedef struct { S32 *ps32; } S33; +typedef struct +{ + S33 *ps33; +} S34; + +struct S35 +{ + struct A { + int i1, a1[]; + }; + + struct B { + int i2, a2[]; + }; + + typedef struct { + int i3, a3[]; + } C; + + typedef struct { + int i4, a4[]; + } D; + + typedef A A2; + typedef B B2; + typedef C C2; + typedef D D2; +}; + diff --git a/gcc/testsuite/g++.dg/ext/flexary4.C b/gcc/testsuite/g++.dg/ext/flexary4.C index 97ec625..29d6bdd 100644 --- a/gcc/testsuite/g++.dg/ext/flexary4.C +++ b/gcc/testsuite/g++.dg/ext/flexary4.C @@ -102,31 +102,28 @@ struct Sx17 { 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 +// An empty struct is treated as if it had a single member of type +// char but the member cannot be accessed. 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 { }; + struct { /* empty */ } 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. +// Anonymous structs are a G++ extension. Members of anonymous structs +// are treated as if they were declared in the enclosing class. struct Sx19 { - struct S { }; - union U { }; - int a_x []; // { dg-error "in an otherwise empty" } + struct { int i; }; // anonymous struct + int a_x []; }; -// Unlike in the case above, a named member of an anonymous struct -// prevents a subsequent flexible array member from being diagnosed. +// Unlike in the case above, a named struct is not anonymous and +// so doesn't contribute its member to that of the enclosing struct. struct Sx20 { - struct S { } s; - int a_x []; + struct S { int i; }; + int a_x []; // { dg-error "in an otherwise empty" } }; struct Sx21 { @@ -298,6 +295,15 @@ struct Anon1 { ASSERT_AT_END (Anon1, good); +struct NotAnon1 { + int n; + // The following is not an anonymous struct -- the type is unnamed + // but the object has a name. + struct { + int bad[]; // { dg-error "otherwise empty" } + } name; +}; + struct Anon2 { struct { int n; @@ -352,7 +358,6 @@ struct Anon7 { int n; }; - struct Six { int i; int a[]; diff --git a/gcc/testsuite/g++.dg/ext/flexary5.C b/gcc/testsuite/g++.dg/ext/flexary5.C index 3e76d3e..db1b060 100644 --- a/gcc/testsuite/g++.dg/ext/flexary5.C +++ b/gcc/testsuite/g++.dg/ext/flexary5.C @@ -64,19 +64,29 @@ struct D5: E1, E2, NE { char a[]; }; ASSERT_AT_END (D5, a); // { dg-warning "offsetof within non-standard-layout" } -struct A2x { +struct A2x_1 { size_t n; - size_t a[]; // { dg-error "not at end of .struct D6.| D7.| D8." } + size_t a[]; // { dg-error "not at end of .struct D6." } +}; + +struct A2x_2 { + size_t n; + size_t a[]; // { dg-error "not at end of .struct D7." } +}; + +struct A2x_3 { + size_t n; + size_t a[]; // { dg-error "not at end of .struct 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 D6: A2x_1, E1, A1x { }; +struct D7: E1, A2x_2, E2, A1x { }; +struct D8: E1, E2, A2x_3, A1x { }; -struct DA2x: A2x { }; +struct DA2x: A2x_1 { }; struct D9: DA2x, E1, E2 { }; diff --git a/gcc/testsuite/g++.dg/ext/flexary9.C b/gcc/testsuite/g++.dg/ext/flexary9.C index 3228542..07eb966 100644 --- a/gcc/testsuite/g++.dg/ext/flexary9.C +++ b/gcc/testsuite/g++.dg/ext/flexary9.C @@ -281,15 +281,15 @@ struct S_S_S_x { struct Anon1 { int n; - struct { - int good[0]; // { dg-warning "zero-size array" } + struct { // { dg-warning "invalid use \[^\n\r\]* with a zero-size array" } + int good[0]; // { dg-warning "forbids zero-size array" } }; // { dg-warning "anonymous struct" } }; ASSERT_AT_END (Anon1, good); struct Anon2 { - struct { + struct { // { dg-warning "invalid use" } int n; struct { int good[0]; // { dg-warning "zero-size array" } @@ -300,7 +300,7 @@ struct Anon2 { ASSERT_AT_END (Anon2, good); struct Anon3 { - struct { + struct { // { dg-warning "invalid use" } struct { int n; int good[0]; // { dg-warning "zero-size array" } diff --git a/gcc/testsuite/g++.dg/torture/pr64312.C b/gcc/testsuite/g++.dg/torture/pr64312.C index 85211f2..c7a56d7 100644 --- a/gcc/testsuite/g++.dg/torture/pr64312.C +++ b/gcc/testsuite/g++.dg/torture/pr64312.C @@ -44,7 +44,7 @@ class F { public: int nelems; - int elems[]; + int elems[]; // { dg-error "not at end" } int * m_fn1 () { @@ -88,7 +88,7 @@ public: m_impl->~any_incrementable_iterator_interface (); } G m_buffer; - any_incrementable_iterator_interface *m_impl; + any_incrementable_iterator_interface *m_impl; // { dg-message "next member" } }; template class K : public I > {