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