public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: David Malcolm <dmalcolm@redhat.com>
To: Bernd Schmidt <bschmidt@redhat.com>
Cc: gcc-patches@gcc.gnu.org, Joseph Myers <joseph@codesourcery.com>,
	       Jason Merrill <jason@redhat.com>,
	David Malcolm <dmalcolm@redhat.com>
Subject: [PATCH] Better error recovery for merge-conflict markers (v4)
Date: Wed, 09 Dec 2015 16:39:00 -0000	[thread overview]
Message-ID: <1449680327-43788-1-git-send-email-dmalcolm@redhat.com> (raw)
In-Reply-To: <563A0E7D.3070804@redhat.com>

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&regrtested 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 <typename T>
+struct foo
+{
+  T t;
+};
+
+foo <foo <foo <foo <foo <foo <foo <int
+>>>>>>> f;
+// The above line is valid C++11, and isn't a patch conflict marker
-- 
1.8.5.3

  reply	other threads:[~2015-12-09 16:39 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-30 15:02 [PATCH] Better error messages for merge-conflict markers (v3) David Malcolm
2015-11-02 22:52 ` Jeff Law
2015-11-03  4:05   ` Trevor Saunders
2015-11-04 13:56 ` Bernd Schmidt
2015-12-09 16:39   ` David Malcolm [this message]
2015-12-09 17:44     ` [PATCH] Better error recovery for merge-conflict markers (v4) Bernd Schmidt
2015-12-09 20:18       ` Jeff Law
2015-12-16 18:23       ` David Malcolm
2015-12-15 19:11   ` [PATCH] Better error recovery for merge-conflict markers (v5) David Malcolm
2015-12-15 23:52     ` Bernd Schmidt
2015-12-16 18:33       ` David Malcolm
2015-12-09 23:50 ` [PATCH] Better error messages for merge-conflict markers (v3) Martin Sebor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1449680327-43788-1-git-send-email-dmalcolm@redhat.com \
    --to=dmalcolm@redhat.com \
    --cc=bschmidt@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    --cc=joseph@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).