re PR c++/84609 (internal compiler error: in cp_parser_abort_tentative_parse, at...
authorJakub Jelinek <jakub@redhat.com>
Wed, 28 Feb 2018 18:57:38 +0000 (19:57 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 28 Feb 2018 18:57:38 +0000 (19:57 +0100)
PR c++/84609
* parser.c (cp_parser_attributes_opt): Formatting fix.
(cp_parser_skip_balanced_tokens, cp_parser_skip_gnu_attributes_opt,
cp_parser_skip_std_attribute_spec_seq, cp_parser_skip_attributes_opt):
New functions.
(cp_parser_member_declaration): Use cp_parser_skip_attributes_opt
instead of tentative parse to peek over optional attribute tokens
to check for CPP_COLON after them.

* g++.dg/cpp0x/pr84609.C: New test.

From-SVN: r258080

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/pr84609.C [new file with mode: 0644]

index 5d8a6db..40d7f87 100644 (file)
@@ -1,5 +1,14 @@
 2018-02-28  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/84609
+       * parser.c (cp_parser_attributes_opt): Formatting fix.
+       (cp_parser_skip_balanced_tokens, cp_parser_skip_gnu_attributes_opt,
+       cp_parser_skip_std_attribute_spec_seq, cp_parser_skip_attributes_opt):
+       New functions.
+       (cp_parser_member_declaration): Use cp_parser_skip_attributes_opt
+       instead of tentative parse to peek over optional attribute tokens
+       to check for CPP_COLON after them.
+
        PR c++/83871
        PR c++/83503
        * pt.c (INCLUDE_STRING): Remove define.
index e02d4bf..359460c 100644 (file)
@@ -2393,6 +2393,8 @@ static tree cp_parser_std_attribute_spec
   (cp_parser *);
 static tree cp_parser_std_attribute_spec_seq
   (cp_parser *);
+static size_t cp_parser_skip_attributes_opt
+  (cp_parser *, size_t);
 static bool cp_parser_extension_opt
   (cp_parser *, int *);
 static void cp_parser_label_declaration
@@ -23628,7 +23630,6 @@ cp_parser_member_declaration (cp_parser* parser)
          tree attributes = NULL_TREE;
          tree first_attribute;
          tree initializer;
-         bool is_bitfld = false;
          bool named_bitfld = false;
 
          /* Peek at the next token.  */
@@ -23636,26 +23637,22 @@ cp_parser_member_declaration (cp_parser* parser)
 
          /* The following code wants to know early if it is a bit-field
             or some other declaration.  Attributes can appear before
-            the `:' token, but are hopefully rare enough that the
-            simplicity of the tentative lookup pays off.  */
+            the `:' token.  Skip over them without consuming any tokens
+            to peek if they are followed by `:'.  */
          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);
+             size_t n
+               = cp_parser_skip_attributes_opt (parser, 1 + named_bitfld);
+             token = cp_lexer_peek_nth_token (parser->lexer, n);
            }
 
          /* Check for a bitfield declaration.  */
-         if (is_bitfld
-             || token->type == CPP_COLON
+         if (token->type == CPP_COLON
              || (token->type == CPP_NAME
+                 && token == cp_lexer_peek_token (parser->lexer)
                  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)
                  && (named_bitfld = true)))
            {
@@ -24919,7 +24916,7 @@ static tree
 cp_parser_attributes_opt (cp_parser *parser)
 {
   if (cp_next_tokens_can_be_gnu_attribute_p (parser))
-      return cp_parser_gnu_attributes_opt (parser);
+    return cp_parser_gnu_attributes_opt (parser);
   return cp_parser_std_attribute_spec_seq (parser);
 }
 
@@ -25462,6 +25459,115 @@ cp_parser_std_attribute_spec_seq (cp_parser *parser)
   return attr_specs;
 }
 
+/* Skip a balanced-token starting at Nth token (with 1 as the next token),
+   return index of the first token after balanced-token, or N on failure.  */
+
+static size_t
+cp_parser_skip_balanced_tokens (cp_parser *parser, size_t n)
+{
+  size_t orig_n = n;
+  int nparens = 0, nbraces = 0, nsquares = 0;
+  do
+    switch (cp_lexer_peek_nth_token (parser->lexer, n++)->type)
+      {
+      case CPP_EOF:
+      case CPP_PRAGMA_EOL:
+       /* Ran out of tokens.  */
+       return orig_n;
+      case CPP_OPEN_PAREN:
+       ++nparens;
+       break;
+      case CPP_OPEN_BRACE:
+       ++nbraces;
+       break;
+      case CPP_OPEN_SQUARE:
+       ++nsquares;
+       break;
+      case CPP_CLOSE_PAREN:
+       --nparens;
+       break;
+      case CPP_CLOSE_BRACE:
+       --nbraces;
+       break;
+      case CPP_CLOSE_SQUARE:
+       --nsquares;
+       break;
+      default:
+       break;
+      }
+  while (nparens || nbraces || nsquares);
+  return n;
+}
+
+/* Skip GNU attribute tokens starting at Nth token (with 1 as the next token),
+   return index of the first token after the GNU attribute tokens, or N on
+   failure.  */
+
+static size_t
+cp_parser_skip_gnu_attributes_opt (cp_parser *parser, size_t n)
+{
+  while (true)
+    {
+      if (!cp_lexer_nth_token_is_keyword (parser->lexer, n, RID_ATTRIBUTE)
+         || !cp_lexer_nth_token_is (parser->lexer, n + 1, CPP_OPEN_PAREN)
+         || !cp_lexer_nth_token_is (parser->lexer, n + 2, CPP_OPEN_PAREN))
+       break;
+
+      size_t n2 = cp_parser_skip_balanced_tokens (parser, n + 2);
+      if (n2 == n + 2)
+       break;
+      if (!cp_lexer_nth_token_is (parser->lexer, n2, CPP_CLOSE_PAREN))
+       break;
+      n = n2 + 1;
+    }
+  return n;
+}
+
+/* Skip standard C++11 attribute tokens starting at Nth token (with 1 as the
+   next token), return index of the first token after the standard C++11
+   attribute tokens, or N on failure.  */
+
+static size_t
+cp_parser_skip_std_attribute_spec_seq (cp_parser *parser, size_t n)
+{
+  while (true)
+    {
+      if (cp_lexer_nth_token_is (parser->lexer, n, CPP_OPEN_SQUARE)
+         && cp_lexer_nth_token_is (parser->lexer, n + 1, CPP_OPEN_SQUARE))
+       {
+         size_t n2 = cp_parser_skip_balanced_tokens (parser, n + 1);
+         if (n2 == n + 1)
+           break;
+         if (!cp_lexer_nth_token_is (parser->lexer, n2, CPP_CLOSE_SQUARE))
+           break;
+         n = n2 + 1;
+       }
+      else if (cp_lexer_nth_token_is_keyword (parser->lexer, n, RID_ALIGNAS)
+              && cp_lexer_nth_token_is (parser->lexer, n + 1, CPP_OPEN_PAREN))
+       {
+         size_t n2 = cp_parser_skip_balanced_tokens (parser, n + 1);
+         if (n2 == n + 1)
+           break;
+         n = n2;
+       }
+      else
+       break;
+    }
+  return n;
+}
+
+/* Skip standard C++11 or GNU attribute tokens starting at Nth token (with 1
+   as the next token), return index of the first token after the attribute
+   tokens, or N on failure.  */
+
+static size_t
+cp_parser_skip_attributes_opt (cp_parser *parser, size_t n)
+{
+  if (cp_nth_tokens_can_be_gnu_attribute_p (parser, n))
+    return cp_parser_skip_gnu_attributes_opt (parser, n);
+  return cp_parser_skip_std_attribute_spec_seq (parser, n);
+}
+
 /* Parse an optional `__extension__' keyword.  Returns TRUE if it is
    present, and FALSE otherwise.  *SAVED_PEDANTIC is set to the
    current value of the PEDANTIC flag, regardless of whether or not
index bfdc0f1..afe8cf9 100644 (file)
@@ -1,3 +1,8 @@
+2018-02-28  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/84609
+       * g++.dg/cpp0x/pr84609.C: New test.
+
 2018-02-28  Martin Sebor  <msebor@redhat.com>
 
        PR testsuite/84617
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr84609.C b/gcc/testsuite/g++.dg/cpp0x/pr84609.C
new file mode 100644 (file)
index 0000000..0572192
--- /dev/null
@@ -0,0 +1,9 @@
+// PR c++/84609
+// { dg-do compile { target c++11 } }
+
+struct S {
+  int s __attribute__((aligned([](char *) {})));       // { dg-error "requested alignment is not an integer constant" }
+  int t [[gnu::aligned([](char *) {})]];               // { dg-error "requested alignment is not an integer constant" }
+  int u __attribute__((aligned([](char *) {}))) : 2;   // { dg-error "requested alignment is not an integer constant" }
+  int v [[gnu::aligned([](char *) {})]] : 4;           // { dg-error "requested alignment is not an integer constant" }
+};