From b8cfdc96d67a3252cf2548ebd4f6d4f3064f7902 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 28 Feb 2018 18:57:38 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@258080 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 9 +++ gcc/cp/parser.c | 132 +++++++++++++++++++++++++++++++---- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/cpp0x/pr84609.C | 9 +++ 4 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr84609.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5d8a6dba227..40d7f873abf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2018-02-28 Jakub Jelinek + 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. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e02d4bf1710..359460cd4d8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bfdc0f18645..afe8cf974b5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-02-28 Jakub Jelinek + + PR c++/84609 + * g++.dg/cpp0x/pr84609.C: New test. + 2018-02-28 Martin Sebor 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 index 00000000000..057219280a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr84609.C @@ -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" } +}; -- 2.11.4.GIT