Hi!

During the OpenMP directives using C++ attribute syntax work, I've noticed
that cp_parser_statement when parsing various block declarations that do
not allow attribute-specifier-seq at the start rolls back the attributes
only if std_attrs is non-NULL (i.e. some attributes have been parsed),
but doesn't roll back if some tokens were parsed as attribute-specifier-seq,
but didn't yield any attributes (e.g. [[]][[]][[]][[]]), which means
we accept those empty attributes even in places where they don't appear
in the grammar.

The following patch fixes that by instead checking if there are any
tokens to roll back.  This makes the parsing handle the first
function the same as the second one (where some attribute appears).

The testcase contains two xfails, using namespace ... apparently
allows attributes at the start and the attributes shall appeartain to
using in that case.  To be fixed incrementally.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2021-07-30  Jakub Jelinek  <ja...@redhat.com>

        * parser.c (cp_parser_statement): Rollback attributes not just
        when std_attrs is non-NULL, but whenever
        cp_parser_std_attribute_spec_seq parsed any tokens.

        * g++.dg/cpp0x/gen-attrs-76.C: New test.

--- gcc/cp/parser.c.jj  2021-07-30 11:19:39.431614703 +0200
+++ gcc/cp/parser.c     2021-07-30 12:22:16.995130642 +0200
@@ -11909,6 +11909,7 @@ cp_parser_statement (cp_parser* parser,
   cp_token *token;
   location_t statement_location, attrs_loc;
   bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
+  bool has_std_attrs;
 
  restart:
   if (if_p != NULL)
@@ -11917,7 +11918,8 @@ cp_parser_statement (cp_parser* parser,
   statement = NULL_TREE;
 
   saved_token_sentinel saved_tokens (parser->lexer);
-  attrs_loc = cp_lexer_peek_token (parser->lexer)->location;
+  token = cp_lexer_peek_token (parser->lexer);
+  attrs_loc = token->location;
   if (c_dialect_objc ())
     /* In obj-c++, seeing '[[' might be the either the beginning of
        c++11 attributes, or a nested objc-message-expression.  So
@@ -11931,6 +11933,7 @@ cp_parser_statement (cp_parser* parser,
       if (!cp_parser_parse_definitely (parser))
        std_attrs = NULL_TREE;
     }
+  has_std_attrs = cp_lexer_peek_token (parser->lexer) != token;
 
   if (std_attrs && (flag_openmp || flag_openmp_simd))
     std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs);
@@ -11999,7 +12002,7 @@ cp_parser_statement (cp_parser* parser,
 
        case RID_NAMESPACE:
          /* This must be a namespace alias definition.  */
-         if (std_attrs != NULL_TREE)
+         if (has_std_attrs)
            {
              /* Attributes should be parsed as part of the
                 declaration, so let's un-parse them.  */
@@ -12104,7 +12107,7 @@ cp_parser_statement (cp_parser* parser,
     {
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
        {
-         if (std_attrs != NULL_TREE)
+         if (has_std_attrs)
            /* Attributes should be parsed as part of the declaration,
               so let's un-parse them.  */
            saved_tokens.rollback();
@@ -12116,7 +12119,7 @@ cp_parser_statement (cp_parser* parser,
          if (cp_parser_parse_definitely (parser))
            return;
          /* It didn't work, restore the post-attribute position.  */
-         if (std_attrs)
+         if (has_std_attrs)
            cp_lexer_set_token_position (parser->lexer, statement_token);
        }
       /* All preceding labels have been parsed at this point.  */
--- gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C.jj        2021-07-30 
12:16:59.472477365 +0200
+++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C   2021-07-30 12:21:32.440740569 
+0200
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-attributes" }
+
+namespace N {}
+namespace O { typedef int T; };
+
+void
+foo ()
+{
+  [[]] asm ("");                               // { dg-error "expected" }
+  [[]] __extension__ asm ("");                 // { dg-error "expected" }
+  __extension__ [[]] asm ("");                 // { dg-error "expected" }
+  [[]] namespace M = ::N;                      // { dg-error "expected" }
+  [[]] using namespace N;                      // { dg-bogus "expected" "" { 
xfail *-*-* } }
+  [[]] using O::T;                             // { dg-error "expected" }
+  [[]] __label__ foo;                          // { dg-error "expected" }
+  [[]] static_assert (true, "");               // { dg-error "expected" }
+}
+
+void
+bar ()
+{
+  [[gnu::unused]] asm ("");                    // { dg-error "expected" }
+  [[gnu::unused]] __extension__ asm ("");      // { dg-error "expected" }
+  __extension__ [[gnu::unused]] asm ("");      // { dg-error "expected" }
+  [[gnu::unused]] namespace M = ::N;           // { dg-error "expected" }
+  [[gnu::unused]] using namespace N;           // { dg-bogus "expected" "" { 
xfail *-*-* } }
+  [[gnu::unused]] using O::T;                  // { dg-error "expected" }
+  [[gnu::unused]] __label__ foo;               // { dg-error "expected" }
+  [[gnu::unused]] static_assert (true, "");    // { dg-error "expected" }
+}

        Jakub

Reply via email to