Joseph noticed that we were wrongly accepting multiple attributes without
commas.  Thus fixed by breaking out of the loop when parsing the attributes --
if we don't see a comma after an attribute, then the next tokens must be )); if
not, then the attribute is invalid.  I've also added a few more comments.

(I think it would be nicer to model the code after C++ and introduce
c_parser_attributes_list, but the following is enough to fix the bug.)

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

2015-10-20  Marek Polacek  <pola...@redhat.com>

        PR c/67964
        * c-parser.c (c_parser_attributes): Break out of the loop if the
        token after an attribute isn't a comma.

        * gcc.dg/pr67964.c: New test.

diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 704ebc6..e7b8440 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -3965,7 +3965,9 @@ c_parser_attributes (c_parser *parser)
       /* ??? Follow the C++ parser rather than using the
         lex_untranslated_string kludge.  */
       parser->lex_untranslated_string = true;
+      /* Consume the `__attribute__' keyword.  */
       c_parser_consume_token (parser);
+      /* Look for the two `(' tokens.  */
       if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
        {
          parser->lex_untranslated_string = false;
@@ -3993,17 +3995,24 @@ c_parser_attributes (c_parser *parser)
          attr_name = c_parser_attribute_any_word (parser);
          if (attr_name == NULL)
            break;
-         if (is_cilkplus_vector_p (attr_name))           
+         if (is_cilkplus_vector_p (attr_name))
            {
              c_token *v_token = c_parser_peek_token (parser);
              c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
+             /* If the next token isn't a comma, we're done.  */
+             if (!c_parser_next_token_is (parser, CPP_COMMA))
+               break;
              continue;
            }
          c_parser_consume_token (parser);
          if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
            {
              attr = build_tree_list (attr_name, NULL_TREE);
+             /* Add this attribute to the list.  */
              attrs = chainon (attrs, attr);
+             /* If the next token isn't a comma, we're done.  */
+             if (!c_parser_next_token_is (parser, CPP_COMMA))
+               break;
              continue;
            }
          c_parser_consume_token (parser);
@@ -4062,8 +4071,13 @@ c_parser_attributes (c_parser *parser)
                                         "expected %<)%>");
              return attrs;
            }
+         /* Add this attribute to the list.  */
          attrs = chainon (attrs, attr);
+         /* If the next token isn't a comma, we're done.  */
+         if (!c_parser_next_token_is (parser, CPP_COMMA))
+           break;
        }
+      /* Look for the two `)' tokens.  */
       if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
        c_parser_consume_token (parser);
       else
diff --git gcc/testsuite/gcc.dg/pr67964.c gcc/testsuite/gcc.dg/pr67964.c
index e69de29..095b50f 100644
--- gcc/testsuite/gcc.dg/pr67964.c
+++ gcc/testsuite/gcc.dg/pr67964.c
@@ -0,0 +1,21 @@
+/* PR c/67964 */
+/* { dg-do compile } */
+
+extern int fn0 (void) __attribute__ ((const const)); /* { dg-error "expected" 
} */
+extern int fn1 (void) __attribute__ ((const, const));
+extern int fn2 (void) __attribute__ ((optimize (0) const)); /* { dg-error 
"expected" } */
+extern int fn3 (void) __attribute__ ((optimize (0), const));
+/* We allow starting/trailing comma.  */
+extern int fn4 (void) __attribute__ ((, const));
+extern int fn5 (void) __attribute__ ((const, ));
+extern int fn6 (void) __attribute__ ((,,,, const,,,,, ));
+extern int fn7 (void) __attribute__ ((,));
+extern int fn8 (void) __attribute__ ((__noreturn__ __noreturn__)); /* { 
dg-error "expected" } */
+extern int fn9 (void) __attribute__ ((__noreturn__, __noreturn__));
+extern int fn10 (void) __attribute__ ((__cold__ __pure__ __noclone__)); /* { 
dg-error "expected" } */
+extern int fn11 (void) __attribute__ ((__cold__, __pure__ __noclone__)); /* { 
dg-error "expected" } */
+int i;
+int ii;
+extern int a __attribute__ ((alias ("i") unused)); /* { dg-error "expected" } 
*/
+extern int a2 __attribute__ ((alias ("i" "i")));
+struct A { char p[6]; } __attribute__((__packed__ packed)); /* { dg-error 
"expected" } */

        Marek

Reply via email to