From patchwork Wed Dec 9 16:58:47 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 554712 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 982C5140297 for ; Thu, 10 Dec 2015 03:39:42 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=uzmiSx6r; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=EiBypAUhkh2HUx3LNnsKJbSeV8ty/CmH0i8pvmCctr7h/wEJh0pC0 QZl9wcm+oTPoafCxTl6sRR3YRRA1ir9ienlmsRVeyx4locV6lfH3gHk5Q806pjU8 LTIeyCxrzYmZSGUH5WRBy+cscQ/9YxPz+pvPQQ5i6W/QlmbXScomik= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=nQjH4bWAKjijgY5lETKdUCgbd5g=; b=uzmiSx6rf/I8JZuNKSSP vS3/yx52HeewAXvFzRwjlmTKZBoEWGlph4IWLKxPd34p7eW73qrjJ1rRqeNWsbBR yk3Kj1tKPFpxWgalGFCkf9GsN5tavnJPvDQUFl+Inmip7FhqmJ5kPg60zQx7uA9R qmTDur0i5luh+Se4G6nZSLA= Received: (qmail 37499 invoked by alias); 9 Dec 2015 16:39:34 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 37488 invoked by uid 89); 9 Dec 2015 16:39:33 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.8 required=5.0 tests=AWL, BAYES_40, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 09 Dec 2015 16:39:30 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id E16F0C0A8480; Wed, 9 Dec 2015 16:39:27 +0000 (UTC) Received: from c64.redhat.com (vpn-236-44.phx2.redhat.com [10.3.236.44]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tB9GdQUC001240; Wed, 9 Dec 2015 11:39:26 -0500 From: David Malcolm To: Bernd Schmidt Cc: gcc-patches@gcc.gnu.org, Joseph Myers , Jason Merrill , David Malcolm Subject: [PATCH] Better error recovery for merge-conflict markers (v4) Date: Wed, 9 Dec 2015 11:58:47 -0500 Message-Id: <1449680327-43788-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <563A0E7D.3070804@redhat.com> References: <563A0E7D.3070804@redhat.com> X-IsSubscribed: yes On Wed, 2015-11-04 at 14:56 +0100, Bernd Schmidt wrote: > On 10/30/2015 04:16 PM, David Malcolm wrote: > > The idea is to more gracefully handle merger conflict markers > > in the source code being compiled. Specifically, in the C and > > C++ frontends, if we're about to emit an error, see if the > > source code is at a merger conflict marker, and if so, emit > > a more specific message, so that the user gets this: > > > > foo.c:1:1: error: source file contains patch conflict marker > > <<<<<<< HEAD > > ^ > > > > It's something of a "fit and finish" cosmetic item, but these > > things add up. > > This seems like fairly low impact but also low cost, so I'm fine with it > in principle. I wonder whether the length of the marker is the same > across all versions of patch (and VC tools)? It's hardcoded for GNU patch: http://git.savannah.gnu.org/cgit/patch.git/tree/src/merge.c which hardcodes e.g.: fputs (outstate->after_newline + "\n<<<<<<<\n", fp); I don't know if it's hardcoded for CVS or Subversion, but both have documentation showing that format: ftp://ftp.gnu.org/old-gnu/Manuals/cvs/html_node/cvs_38.html http://svnbook.red-bean.com/en/1.7/svn.tour.cycle.html#svn.tour.cycle.resolve It's the default of git: http://git.kernel.org/cgit/git/git.git/tree/Documentation/merge-config.txt (config option "merge.conflictStyle") This git commit (to git) seems to have generalized it to support a "conflict-marker-size" attribute: https://github.com/git/git/commit/8588567c96490b8d236b1bc13f9bcb0dfa118efe Mercurial uses them; the format appears to be a keyword-argument in: https://selenic.com/hg/file/tip/mercurial/simplemerge.py#l91 but it's hardcoded in this regex in filemerge.py: if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(), Bazaar uses them; see e.g.: http://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev/view/head:/bzrlib/tests/test_merge3.py (I couldn't easily tell if they're configurable) FWIW, Perforce appears to use a different format; http://www.perforce.com/perforce/doc.current/manuals/p4guide/chapter.resolve.html has an example showing: >>>> ORIGINAL file#n (text from the original version) ==== THEIR file#m (text from their file) ==== YOURS file (text from your file) <<<< From what I can tell, Perforce is the outlier here. > > +static bool > > +c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind) > > +{ > > + 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; > > + return true; > > +} > > Just thinking out loud - I guess it would be too much to hope for to > share lexers between frontends so that we need only one copy of this? Probably :( > > +extern short some_var; /* this line would lead to a warning */ > > Would or does? I don't see anything suppressing it? It's skipped in error-handling. c_parser_declaration_or_fndef has: 1794 declarator = c_parser_declarator (parser, 1795 specs->typespec_kind != ctsk_none, 1796 C_DTR_NORMAL, &dummy); 1797 if (declarator == NULL) 1798 { [...snip...] 1807 c_parser_skip_to_end_of_block_or_statement (parser); The call to c_parser_declarator fails, and when issuing: 3465 c_parser_error (parser, "expected identifier or %<(%>"); we emit the "conflict marker" wording error for the error. Then at line 1807 we skip, discarding everything up to the ";" in that decl. Would a better wording be: extern short some_var; /* This line would lead to a warning due to the duplicate name, but it is skipped when handling the conflict marker. */ > There seems to be no testcase verifying what happens if the marker is > not at the start of the line (IMO it should not be interpreted as a marker). The v3 patch actually reported them as markers regardless of location. The v4 patch now verifies that they are at the start of the line; I've added test coverage for this (patch-conflict-markers-11.c). That said, it's not clear they're always at the beginning of a line; this bazaar bug indicates that CVS (and bazaar) can emit them mid-line: https://bugs.launchpad.net/bzr/+bug/36399 I noticed a visual glitch with the v3 patch now that we have range information for tokens: with caret-printing, we get just the first token within the marker underlined: <<<<<<< HEAD ^~ which looks strange (especially with the underlined chars colorized). Hence in the v4 patch I've added a location tweak so that it underline/colorizes *all* of the marker: <<<<<<< HEAD ^~~~~~~ Wording-wise, should it be "merge conflict marker", rather than "patch conflict marker"? Clang spells it: "error: version control conflict marker in file" http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-recovery.html#merge_conflicts Maybe I should simply use that wording? > It would be good to have buy-in from the frontend maintainers (Joseph > commented on v1 and as far as I can see you've addressed his feedback). > If you do not hear back from them by the end of the week, I'll approve > it if the start-of-line thing is sorted. (clearly over a week by now; I got bogged down in the C++ FE expression ranges; sorry). > Bernd Rebased on top of r231445 (from yesterday). Successfully bootstrapped®rtested on x86_64-pc-linux-gnu. Adds 82 new PASSes to g++.sum and 27 new PASSes to gcc.sum. OK for trunk? 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 patch conflict markers and report them as such. gcc/cp/ChangeLog: * parser.c (cp_lexer_peek_conflict_marker): New function. (cp_parser_error): Detect patch conflict markers and report them as such. gcc/testsuite/ChangeLog: * c-c++-common/patch-conflict-markers-1.c: New testcase. * c-c++-common/patch-conflict-markers-2.c: Likewise. * c-c++-common/patch-conflict-markers-3.c: Likewise. * c-c++-common/patch-conflict-markers-4.c: Likewise. * c-c++-common/patch-conflict-markers-5.c: Likewise. * c-c++-common/patch-conflict-markers-6.c: Likewise. * c-c++-common/patch-conflict-markers-7.c: Likewise. * c-c++-common/patch-conflict-markers-8.c: Likewise. * c-c++-common/patch-conflict-markers-9.c: Likewise. * c-c++-common/patch-conflict-markers-10.c: Likewise. * c-c++-common/patch-conflict-markers-11.c: Likewise. * g++.dg/patch-conflict-markers-1.C: Likewise. --- gcc/c-family/c-common.h | 4 ++ gcc/c-family/c-lex.c | 26 ++++++++ gcc/c/c-parser.c | 72 +++++++++++++++++++++- gcc/cp/parser.c | 53 ++++++++++++++++ .../c-c++-common/patch-conflict-markers-1.c | 9 +++ .../c-c++-common/patch-conflict-markers-10.c | 23 +++++++ .../c-c++-common/patch-conflict-markers-11.c | 14 +++++ .../c-c++-common/patch-conflict-markers-2.c | 2 + .../c-c++-common/patch-conflict-markers-3.c | 11 ++++ .../c-c++-common/patch-conflict-markers-4.c | 11 ++++ .../c-c++-common/patch-conflict-markers-5.c | 11 ++++ .../c-c++-common/patch-conflict-markers-6.c | 38 ++++++++++++ .../c-c++-common/patch-conflict-markers-7.c | 6 ++ .../c-c++-common/patch-conflict-markers-8.c | 4 ++ .../c-c++-common/patch-conflict-markers-9.c | 8 +++ gcc/testsuite/g++.dg/patch-conflict-markers-1.C | 13 ++++ 16 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-1.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-10.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-11.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-2.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-3.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-4.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-5.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-6.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-7.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-8.c create mode 100644 gcc/testsuite/c-c++-common/patch-conflict-markers-9.c create mode 100644 gcc/testsuite/g++.dg/patch-conflict-markers-1.C diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index ef64e6b..2183565 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1089,6 +1089,10 @@ extern void c_genericize (tree); extern int c_gimplify_expr (tree *, gimple_seq *, gimple_seq *); extern tree c_build_bind_expr (location_t, tree, tree); +/* In c-lex.c. */ +extern enum cpp_ttype +conflict_marker_get_final_tok_kind (enum cpp_ttype tok1_kind); + /* In c-pch.c */ extern void pch_init (void); extern void pch_cpp_save_state (void); diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index 9c86ba7..6e0205b 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -1263,3 +1263,29 @@ lex_charconst (const cpp_token *token) return value; } + +/* Helper function for c_parser_peek_conflict_marker + and cp_lexer_peek_conflict_marker. + Given a possible patch conflict marker token of kind TOK1_KIND + consisting of a pair of characters, get the token kind for the + standalone final character. */ + +enum cpp_ttype +conflict_marker_get_final_tok_kind (enum cpp_ttype tok1_kind) +{ + switch (tok1_kind) + { + default: gcc_unreachable (); + case CPP_LSHIFT: + /* "<<" and '<' */ + return CPP_LESS; + + case CPP_EQ_EQ: + /* "==" and '=' */ + return CPP_EQ; + + case CPP_RSHIFT: + /* ">>" and '>' */ + return CPP_GREATER; + } +} diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 124c30b..87ceeff 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,20 @@ 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) +{ + 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 +843,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 patch conflict marker, peek successor tokens to determine + if we actually do have a patch conflict marker. + Specifically, we consider a run of 7 '<', '=' or '>' characters + at the start of a line as a patch 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 +904,20 @@ c_parser_error (c_parser *parser, const char *gmsgid) parser->error = true; if (!gmsgid) return; + + /* If this is actually a patch 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, "source file contains patch conflict marker"); + 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); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a420cf1..a904e8d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2689,6 +2689,46 @@ cp_parser_is_keyword (cp_token* token, enum rid keyword) return token->keyword == keyword; } +/* Helper function for cp_parser_error. + Having peeked a token of kind TOK1_KIND that might signify + a patch conflict marker, peek successor tokens to determine + if we actually do have a patch conflict marker. + Specifically, we consider a run of 7 '<', '=' or '>' characters + at the start of a line as a patch conflict marker. + These come through the lexer as three pairs and a single, + e.g. three CPP_LSHIFT tokens ("<<") and a CPP_LESS token ('<'). + If it returns true, *OUT_LOC is written to with the location/range + of the marker. */ + +static bool +cp_lexer_peek_conflict_marker (cp_lexer *lexer, enum cpp_ttype tok1_kind, + location_t *out_loc) +{ + cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2); + if (token2->type != tok1_kind) + return false; + cp_token *token3 = cp_lexer_peek_nth_token (lexer, 3); + if (token3->type != tok1_kind) + return false; + cp_token *token4 = cp_lexer_peek_nth_token (lexer, 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 = cp_lexer_peek_token (lexer)->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; +} + /* If not parsing tentatively, issue a diagnostic of the form FILE:LINE: MESSAGE before TOKEN where TOKEN is the next token in the input stream. MESSAGE @@ -2713,6 +2753,19 @@ cp_parser_error (cp_parser* parser, const char* gmsgid) return; } + /* If this is actually a patch conflict marker, report it as such. */ + if (token->type == CPP_LSHIFT + || token->type == CPP_RSHIFT + || token->type == CPP_EQ_EQ) + { + location_t loc; + if (cp_lexer_peek_conflict_marker (parser->lexer, token->type, &loc)) + { + error_at (loc, "source file contains patch conflict marker"); + return; + } + } + c_parse_error (gmsgid, /* Because c_parser_error does not understand CPP_KEYWORD, keywords are treated like diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-1.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-1.c new file mode 100644 index 0000000..71e9fa7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-1.c @@ -0,0 +1,9 @@ +int p; + +<<<<<<< HEAD /* { dg-error "patch conflict marker" } */ +extern int some_var; +======= /* { dg-error "patch conflict marker" } */ +extern short some_var; /* this line would lead to a warning */ +>>>>>>> Some commit message /* { dg-error "patch conflict marker" } */ + +int q; diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-10.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-10.c new file mode 100644 index 0000000..839c0a6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-10.c @@ -0,0 +1,23 @@ +/* { dg-options "-fdiagnostics-show-caret" } */ + +<<<<<<< HEAD /* { dg-error "patch conflict marker" } */ +/* { dg-begin-multiline-output "" } + <<<<<<< HEAD + ^~~~~~~ + { dg-end-multiline-output "" } */ + +extern int some_var; + +======= /* { dg-error "patch conflict marker" } */ +/* { dg-begin-multiline-output "" } + ======= + ^~~~~~~ + { dg-end-multiline-output "" } */ + +extern short some_var; /* this line would lead to a warning */ + +>>>>>>> Some commit message /* { dg-error "patch conflict marker" } */ +/* { dg-begin-multiline-output "" } + >>>>>>> + ^~~~~~~ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-11.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-11.c new file mode 100644 index 0000000..8771453 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-11.c @@ -0,0 +1,14 @@ +/* Verify that we only report conflict markers at the start of lines. */ +int p; + + <<<<<<< HEAD /* { dg-error "expected identifier|expected unqualified-id" } */ + +int q; + + ======= /* { dg-error "expected identifier|expected unqualified-id" } */ + +int r; + + >>>>>>> Some commit message /* { dg-error "expected identifier|expected unqualified-id" } */ + +int s; diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-2.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-2.c new file mode 100644 index 0000000..79030ee --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-2.c @@ -0,0 +1,2 @@ +/* This should not be flagged as a patch conflict marker. */ +const char *msg = "<<<<<<< "; diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-3.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-3.c new file mode 100644 index 0000000..be956b2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-3.c @@ -0,0 +1,11 @@ +/* Ensure we can handle unterminated conflict markers. */ + +int p; + +<<<<<<< HEAD /* { dg-error "patch conflict marker" } */ + +int q; + +<<<<<<< HEAD /* { dg-error "patch conflict marker" } */ + +int r; diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-4.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-4.c new file mode 100644 index 0000000..ec3730c --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-4.c @@ -0,0 +1,11 @@ +/* Ensure we can handle mismatched conflict markers. */ + +int p; + +>>>>>>> Some commit message /* { dg-error "patch conflict marker" } */ + +int q; + +>>>>>>> Some other commit message /* { dg-error "patch conflict marker" } */ + +int r; diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-5.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-5.c new file mode 100644 index 0000000..816a97e --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-5.c @@ -0,0 +1,11 @@ +/* Ensure we can handle mismatched conflict markers. */ + +int p; + +======= /* { dg-error "patch conflict marker" } */ + +int q; + +======= /* { dg-error "patch conflict marker" } */ + +int r; diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-6.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-6.c new file mode 100644 index 0000000..74ea2d5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-6.c @@ -0,0 +1,38 @@ +/* Branch coverage of patch conflict marker detection: + none of these should be reported as patch conflict markers. */ + +int a0; + +<< HEAD /* { dg-error "expected" } */ + +int a1; + +<<<< HEAD /* { dg-error "expected" } */ + +int a2; + +<<<<<< HEAD /* { dg-error "expected" } */ + +int b0; + +== HEAD /* { dg-error "expected" } */ + +int b1; + +==== HEAD /* { dg-error "expected" } */ + +int b2; + +====== HEAD /* { dg-error "expected" } */ + +int c0; + +>> HEAD /* { dg-error "expected" } */ + +int c1; + +>>>> HEAD /* { dg-error "expected" } */ + +int c2; + +>>>>>> HEAD /* { dg-error "expected" } */ diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-7.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-7.c new file mode 100644 index 0000000..2b5d4e6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-7.c @@ -0,0 +1,6 @@ +/* It's valid to stringize the "<<<<<<<"; don't + report it as a patch conflict marker. */ +#define str(s) #s +const char *s = str( +<<<<<<< +); diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-8.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-8.c new file mode 100644 index 0000000..90d75b0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-8.c @@ -0,0 +1,4 @@ +/* A macro that's never expanded shouldn't be reported as a patch + conflict marker. */ +#define foo \ +<<<<<<< diff --git a/gcc/testsuite/c-c++-common/patch-conflict-markers-9.c b/gcc/testsuite/c-c++-common/patch-conflict-markers-9.c new file mode 100644 index 0000000..5c1e663 --- /dev/null +++ b/gcc/testsuite/c-c++-common/patch-conflict-markers-9.c @@ -0,0 +1,8 @@ +/* It's valid to have +<<<<<<< + inside both + comments (as above), and within string literals. */ +const char *s = "\ +<<<<<<<"; + +/* The above shouldn't be reported as errors. */ diff --git a/gcc/testsuite/g++.dg/patch-conflict-markers-1.C b/gcc/testsuite/g++.dg/patch-conflict-markers-1.C new file mode 100644 index 0000000..ae19193 --- /dev/null +++ b/gcc/testsuite/g++.dg/patch-conflict-markers-1.C @@ -0,0 +1,13 @@ +/* Ensure that we don't complain about patch conflict markers on + valid template argument lists, valid in C++11 onwards. */ +// { dg-options "-std=c++11" } + +template +struct foo +{ + T t; +}; + +foo >>>>>> f; +// The above line is valid C++11, and isn't a patch conflict marker