On Wed, Sep 27, 2017 at 07:55:20AM -0700, Nathan Sidwell wrote:
> Jakub,
> > The following patch implements P0386R1 - NSDMIs for bit-fields.
> > While working on that, I've discovered our parser mishandles attributes
> > on bitfields, already C++11 says:
> > identifier[opt] attribute-specifier-seq[opt] : constant-expression
> > in the grammar, but we actually parsed
> > identifier[opt] : constant-expression attribute-specifier-seq[opt]
> 
> I'm sorry for my tardiness.  It think the patch would be better broken
> apart:
>       1) fix the parsing bug you found and move to (ab)using
> DECL_BIT_FIELD_REPRESENTATIVE
> 
>       2) the new c++2a feature

I don't see the first half of 1) related to second half thereof, the
DECL_BIT_FIELD_REPRESENTATIVE is unrelated to the parsing bug, and a needed
precondition of 2).

Therefore, I'm going to split the patch into 4 patches, one the
parsing bug (make sure we allow attributes where the standard allows them),
attached below, including pedwarn.  Note we already error for the old
spot when using C++11 [[ ]] attributes there, like int a : 8 [[gnu::packed]];
because when parsing the width expression we see [ after 8 and so it could
be say 8[var] or similar, but error out because [[ must not appear in that
spot.  But alignas there didn't result in error, neither __attribute__.
The other patches will follow, second patch will be
DECL_BIT_FIELD_REPRESENTATIVE, third one the Make-lang.in tweak and fourth
one, to be rewritten tomorrow on top of the rest will be the new c++2a
feature.

The following has been bootstrapped/regtested on x86_64-linux and i686-linux
(together with the Make-lang.in patch, but without the second and fourth
patch), ok for trunk?

As I said on IRC, I hope [[/__attribute__/alignas early is rare enough that
the tentative parsing shouldn't be a big deal, if it is, we could add some
cheaper function that allows us to skip over attributes (return a peek
offset after the attributes given a starting peek offset).

2017-09-28  Jakub Jelinek  <ja...@redhat.com>

cp/
        * parser.c (cp_parser_member_declaration): Parse attributes before
        colon of a bitfield in addition to after colon.
testsuite/
        * g++.dg/ext/bitfield7.C: New test.
        * g++.dg/ext/bitfield8.C: New test.
        * g++.dg/ext/bitfield9.C: New test.

--- gcc/cp/parser.c.jj  2017-09-22 20:51:48.181537880 +0200
+++ gcc/cp/parser.c     2017-09-27 17:50:15.082792676 +0200
@@ -23443,35 +23443,64 @@ cp_parser_member_declaration (cp_parser*
        {
          tree attributes = NULL_TREE;
          tree first_attribute;
+         bool is_bitfld = false;
+         bool named_bitfld = false;
 
          /* Peek at the next token.  */
          token = cp_lexer_peek_token (parser->lexer);
 
+         if (cp_next_tokens_can_be_attribute_p (parser)
+             || (token->type == CPP_NAME
+                 && cp_nth_tokens_can_be_attribute_p (parser, 2)
+                 && (named_bitfld = true)))
+           {
+             cp_parser_parse_tentatively (parser);
+             if (named_bitfld)
+               cp_lexer_consume_token (parser->lexer);
+             cp_parser_attributes_opt (parser);
+             token = cp_lexer_peek_token (parser->lexer);
+             is_bitfld = cp_lexer_next_token_is (parser->lexer, CPP_COLON);
+             cp_parser_abort_tentative_parse (parser);
+           }
+
          /* Check for a bitfield declaration.  */
-         if (token->type == CPP_COLON
+         if (is_bitfld
+             || token->type == CPP_COLON
              || (token->type == CPP_NAME
-                 && cp_lexer_peek_nth_token (parser->lexer, 2)->type
-                 == CPP_COLON))
+                 && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)
+                 && (named_bitfld = true)))
            {
              tree identifier;
              tree width;
+             tree late_attributes = NULL_TREE;
 
-             /* Get the name of the bitfield.  Note that we cannot just
-                check TOKEN here because it may have been invalidated by
-                the call to cp_lexer_peek_nth_token above.  */
-             if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
+             if (named_bitfld)
                identifier = cp_parser_identifier (parser);
              else
                identifier = NULL_TREE;
 
+             /* Look for attributes that apply to the bitfield.  */
+             attributes = cp_parser_attributes_opt (parser);
+
              /* Consume the `:' token.  */
              cp_lexer_consume_token (parser->lexer);
+
              /* Get the width of the bitfield.  */
-             width
-               = cp_parser_constant_expression (parser);
+             width = cp_parser_constant_expression (parser);
+
+             /* Look for attributes that apply to the bitfield after
+                the `:' token and width.  This is where GCC used to
+                parse attributes in the past, pedwarn if there is
+                a std attribute.  */
+             if (cp_next_tokens_can_be_std_attribute_p (parser))
+               pedwarn (input_location, OPT_Wpedantic,
+                        "ISO C++ allows bit-field attributes only before "
+                        "the %<:%> token");
+
+             late_attributes = cp_parser_attributes_opt (parser);
+
+             attributes = chainon (attributes, late_attributes);
 
-             /* Look for attributes that apply to the bitfield.  */
-             attributes = cp_parser_attributes_opt (parser);
              /* Remember which attributes are prefix attributes and
                 which are not.  */
              first_attribute = attributes;
--- gcc/testsuite/g++.dg/ext/bitfield7.C.jj     2017-09-27 17:37:11.118154267 
+0200
+++ gcc/testsuite/g++.dg/ext/bitfield7.C        2017-09-27 17:37:11.118154267 
+0200
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-options "-Wno-packed-bitfield-compat -mno-ms-bitfields" { target { 
i?86-*-mingw* x86_64-*-mingw* } } } */
+
+struct t /* { dg-message "note: offset of packed bit-field 't::b' has changed 
in GCC 4.4" "" { target pcc_bitfield_type_matters } } */
+{
+  char a:4;
+  char b __attribute__ ((packed)) : 8;
+  char c:4;
+};
+
+int assrt[sizeof (struct t) == 2 ? 1 : -1];
--- gcc/testsuite/g++.dg/ext/bitfield8.C.jj     2017-09-27 17:37:11.118154267 
+0200
+++ gcc/testsuite/g++.dg/ext/bitfield8.C        2017-09-27 17:37:11.118154267 
+0200
@@ -0,0 +1,12 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "" } */
+/* { dg-options "-Wno-packed-bitfield-compat -mno-ms-bitfields" { target { 
i?86-*-mingw* x86_64-*-mingw* } } } */
+
+struct t /* { dg-message "note: offset of packed bit-field 't::b' has changed 
in GCC 4.4" "" { target pcc_bitfield_type_matters } } */
+{
+  char a:4;
+  char b [[gnu::packed]] : 8;
+  char c:4;
+};
+
+int assrt[sizeof (struct t) == 2 ? 1 : -1];
--- gcc/testsuite/g++.dg/ext/bitfield9.C.jj     2017-09-27 18:00:54.903153797 
+0200
+++ gcc/testsuite/g++.dg/ext/bitfield9.C        2017-09-27 18:20:24.823186005 
+0200
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-pedantic" }
+
+struct S
+{
+  char a:4;
+  char b:8 alignas(int);       // { dg-warning "ISO C\\+\\+ allows bit-field 
attributes only before the ':' token" }
+  char c:8 [[gnu::aligned(8)]];        // { dg-warning "ISO C\\+\\+ allows 
bit-field attributes only before the ':' token" }
+                               // { dg-error "two consecutive '\\\[' shall 
only introduce an attribute before '\\\[' token" "" { target *-*-* } .-1 }
+};


        Jakub

Reply via email to