diff options
author | David Malcolm <dmalcolm@redhat.com> | 2015-12-16 18:15:01 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2015-12-16 18:15:01 +0000 |
commit | de67c4c37913cb4f30cc0d5163665ab8419ac2ed (patch) | |
tree | 631c0d4e81b08a923db1179b2753d0d62d53bd9c /gcc/c | |
parent | 8a69b8590383788dc5da60693b3a48f8222a2893 (diff) | |
download | gcc-de67c4c37913cb4f30cc0d5163665ab8419ac2ed.zip gcc-de67c4c37913cb4f30cc0d5163665ab8419ac2ed.tar.gz gcc-de67c4c37913cb4f30cc0d5163665ab8419ac2ed.tar.bz2 |
Better error recovery for merge-conflict markers
gcc/c-family/ChangeLog:
* c-common.h (conflict_marker_get_final_tok_kind): New prototype.
* c-lex.c (conflict_marker_get_final_tok_kind): New function.
gcc/c/ChangeLog:
* c-parser.c (struct c_parser): Expand array "tokens_buf" from 2
to 4.
(c_parser_peek_nth_token): New function.
(c_parser_peek_conflict_marker): New function.
(c_parser_error): Detect conflict markers and report them as such.
gcc/cp/ChangeLog:
* parser.c (cp_lexer_peek_conflict_marker): New function.
(cp_parser_error): Detect conflict markers and report them as
such.
gcc/testsuite/ChangeLog:
* c-c++-common/conflict-markers-1.c: New testcase.
* c-c++-common/conflict-markers-2.c: Likewise.
* c-c++-common/conflict-markers-3.c: Likewise.
* c-c++-common/conflict-markers-4.c: Likewise.
* c-c++-common/conflict-markers-5.c: Likewise.
* c-c++-common/conflict-markers-6.c: Likewise.
* c-c++-common/conflict-markers-7.c: Likewise.
* c-c++-common/conflict-markers-8.c: Likewise.
* c-c++-common/conflict-markers-9.c: Likewise.
* c-c++-common/conflict-markers-10.c: Likewise.
* c-c++-common/conflict-markers-11.c: Likewise.
* g++.dg/conflict-markers-1.C: Likewise.
From-SVN: r231712
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 75 |
2 files changed, 81 insertions, 2 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 49c3cbb..22692d4 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,5 +1,13 @@ 2015-12-16 David Malcolm <dmalcolm@redhat.com> + * c-parser.c (struct c_parser): Expand array "tokens_buf" from 2 + to 4. + (c_parser_peek_nth_token): New function. + (c_parser_peek_conflict_marker): New function. + (c_parser_error): Detect conflict markers and report them as such. + +2015-12-16 David Malcolm <dmalcolm@redhat.com> + * c-parser.c (c_parser_postfix_expression): Use EXPR_LOC_OR_LOC to preserve range information for the primary expression in the call to c_parser_postfix_expression_after_primary. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index e149e19..43c26ae 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -202,8 +202,8 @@ struct GTY(()) c_parser { /* The look-ahead tokens. */ c_token * GTY((skip)) tokens; /* Buffer for look-ahead tokens. */ - c_token tokens_buf[2]; - /* How many look-ahead tokens are available (0, 1 or 2, or + c_token tokens_buf[4]; + /* How many look-ahead tokens are available (0 - 4, or more if parsing from pre-lexed tokens). */ unsigned int tokens_avail; /* True if a syntax error is being recovered from; false otherwise. @@ -492,6 +492,23 @@ c_parser_peek_2nd_token (c_parser *parser) return &parser->tokens[1]; } +/* Return a pointer to the Nth token from PARSER, reading it + in if necessary. The N-1th token is already read in. */ + +static c_token * +c_parser_peek_nth_token (c_parser *parser, unsigned int n) +{ + /* N is 1-based, not zero-based. */ + gcc_assert (n > 0); + + if (parser->tokens_avail >= n) + return &parser->tokens[n - 1]; + gcc_assert (parser->tokens_avail == n - 1); + c_lex_one_token (parser, &parser->tokens[n - 1]); + parser->tokens_avail = n; + return &parser->tokens[n - 1]; +} + /* Return true if TOKEN can start a type name, false otherwise. */ static bool @@ -829,6 +846,46 @@ c_parser_set_source_position_from_token (c_token *token) } } +/* Helper function for c_parser_error. + Having peeked a token of kind TOK1_KIND that might signify + a conflict marker, peek successor tokens to determine + if we actually do have a conflict marker. + Specifically, we consider a run of 7 '<', '=' or '>' characters + at the start of a line as a conflict marker. + These come through the lexer as three pairs and a single, + e.g. three CPP_LSHIFT ("<<") and a CPP_LESS ('<'). + If it returns true, *OUT_LOC is written to with the location/range + of the marker. */ + +static bool +c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind, + location_t *out_loc) +{ + c_token *token2 = c_parser_peek_2nd_token (parser); + if (token2->type != tok1_kind) + return false; + c_token *token3 = c_parser_peek_nth_token (parser, 3); + if (token3->type != tok1_kind) + return false; + c_token *token4 = c_parser_peek_nth_token (parser, 4); + if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind)) + return false; + + /* It must be at the start of the line. */ + location_t start_loc = c_parser_peek_token (parser)->location; + if (LOCATION_COLUMN (start_loc) != 1) + return false; + + /* We have a conflict marker. Construct a location of the form: + <<<<<<< + ^~~~~~~ + with start == caret, finishing at the end of the marker. */ + location_t finish_loc = get_finish (token4->location); + *out_loc = make_location (start_loc, start_loc, finish_loc); + + return true; +} + /* Issue a diagnostic of the form FILE:LINE: MESSAGE before TOKEN where TOKEN is the next token in the input stream of PARSER. @@ -850,6 +907,20 @@ c_parser_error (c_parser *parser, const char *gmsgid) parser->error = true; if (!gmsgid) return; + + /* If this is actually a conflict marker, report it as such. */ + if (token->type == CPP_LSHIFT + || token->type == CPP_RSHIFT + || token->type == CPP_EQ_EQ) + { + location_t loc; + if (c_parser_peek_conflict_marker (parser, token->type, &loc)) + { + error_at (loc, "version control conflict marker in file"); + return; + } + } + /* This diagnostic makes more sense if it is tagged to the line of the token we just peeked at. */ c_parser_set_source_position_from_token (token); |