diff options
author | Nathan Sidwell <nathan@acm.org> | 2020-07-15 06:00:10 -0700 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2020-07-15 06:05:41 -0700 |
commit | f0d0be62db5ba030283fa8189211830d09dfb467 (patch) | |
tree | 820947e511b6978f67725536c91b30755a344166 /gcc | |
parent | e0685fadb6aa7c9cc895bc14cbbe2b9026fa3a94 (diff) | |
download | gcc-f0d0be62db5ba030283fa8189211830d09dfb467.zip gcc-f0d0be62db5ba030283fa8189211830d09dfb467.tar.gz gcc-f0d0be62db5ba030283fa8189211830d09dfb467.tar.bz2 |
c++: error recovery & pragmas
Parser error recovery can get confused by the tokens within a deferred
pragma, as treats those as regular tokens. This adjusts the recovery
so that the pragma is treated as a unit. Also, the preprocessor now
ensures that we never have an EOF token inside a pragma -- the pragma
is always closed first.
gcc/cp/
* parser.c (cp_parser_skip_to_closing_parenthesis_1): Deal with
meeting a deferred pragma.
(cp_parser_skip_to_end_of_statement): Likewise.
(cp_parser_skip_to_end_of_block_or_statement): Likewise.
(cp_parser_skip_to_pragma_eol): We should never meet EOF.
(cp_parser_omp_declare_simd): Likewise.
(cp_parser_omp_declare_reduction, cp_parser_oacc_routine)
(pragma_lex): Likewise.
gcc/testsuite/
* g++.dg/parse/pragma-recovery.C: New.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/parser.c | 47 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/pragma-recovery.C | 32 |
2 files changed, 64 insertions, 15 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 08cfd23..1532431 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3689,6 +3689,11 @@ cp_parser_skip_to_closing_parenthesis_1 (cp_parser *parser, condop_depth--; break; + case CPP_PRAGMA: + /* We fell into a pragma. Skip it, and continue. */ + cp_parser_skip_to_pragma_eol (parser, token); + continue; + default: break; } @@ -3780,6 +3785,13 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser) ++nesting_depth; break; + case CPP_PRAGMA: + /* We fell into a pragma. Skip it, and continue or return. */ + cp_parser_skip_to_pragma_eol (parser, token); + if (!nesting_depth) + return; + continue; + default: break; } @@ -3855,6 +3867,13 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser) nesting_depth++; break; + case CPP_PRAGMA: + /* Skip it, and continue or return. */ + cp_parser_skip_to_pragma_eol (parser, token); + if (!nesting_depth) + return; + continue; + default: break; } @@ -3921,8 +3940,15 @@ cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok) parser->lexer->in_pragma = false; do - token = cp_lexer_consume_token (parser->lexer); - while (token->type != CPP_PRAGMA_EOL && token->type != CPP_EOF); + { + /* The preprocessor makes sure that a PRAGMA_EOL token appears + before an EOF token, even when the EOF is on the pragma line. + We should never get here without being inside a deferred + pragma. */ + gcc_checking_assert (cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)); + token = cp_lexer_consume_token (parser->lexer); + } + while (token->type != CPP_PRAGMA_EOL); /* Ensure that the pragma is not parsed again. */ cp_lexer_purge_tokens_after (parser->lexer, pragma_tok); @@ -41470,11 +41496,8 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, } /* Store away all pragma tokens. */ - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - parser->omp_declare_simd->error_seen = true; cp_parser_require_pragma_eol (parser, pragma_tok); struct cp_token_cache *cp = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); @@ -42534,11 +42557,8 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, { if (cp == NULL) { - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - goto fail; cp = cp_token_cache_new (first_token, cp_lexer_peek_nth_token (parser->lexer, 2)); @@ -43017,11 +43037,8 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, else /* No optional '( name )'. */ { /* Store away all pragma tokens. */ - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - parser->oacc_routine->error_seen = true; cp_parser_require_pragma_eol (parser, pragma_tok); struct cp_token_cache *cp = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); @@ -44014,7 +44031,7 @@ pragma_lex (tree *value, location_t *loc) if (loc) *loc = tok->location; - if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) + if (ret == CPP_PRAGMA_EOL) ret = CPP_EOF; else if (ret == CPP_STRING) *value = cp_parser_string_literal (the_parser, false, false); diff --git a/gcc/testsuite/g++.dg/parse/pragma-recovery.C b/gcc/testsuite/g++.dg/parse/pragma-recovery.C new file mode 100644 index 0000000..cc9d323 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/pragma-recovery.C @@ -0,0 +1,32 @@ +/* { dg-additional-options -fopenmp } */ +/* { dg-require-effective-target fopenmp } */ + +// Make sure error recovery doesn't get confused by tokens inside a +// deferred pragma. +// OpenMP is a convenient deferred pragma insertion mechanism. + +void foo () +{ + 1 * "" // { dg-error "invalid" } +#pragma omp atomic { + ; + + } + +void bar () +{ + 1 * "" // { dg-error "invalid" } +#pragma omp atomic } + ; + + } + +void baz () +{ + 1 * "" // { dg-error "invalid" } +#pragma omp atomic ; + 0; + + + } + |