+2015-12-16 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.h (conflict_marker_get_final_tok_kind): New prototype.
+ * c-lex.c (conflict_marker_get_final_tok_kind): New function.
+
2015-12-15 Ilya Verbin <ilya.verbin@intel.com>
* c-common.c (c_common_attribute_table): Handle "omp declare target
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);
return value;
}
+
+/* Helper function for c_parser_peek_conflict_marker
+ and cp_lexer_peek_conflict_marker.
+ Given a possible 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;
+ }
+}
+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
/* 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.
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
}
}
+/* 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.
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);
+2015-12-16 David Malcolm <dmalcolm@redhat.com>
+
+ * parser.c (cp_lexer_peek_conflict_marker): New function.
+ (cp_parser_error): Detect conflict markers and report them as
+ such.
+
2015-12-15 Martin Sebor <msebor@redhat.com>
c++/42121
return token->keyword == keyword;
}
+/* Helper function for cp_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 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
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 (cp_lexer_peek_conflict_marker (parser->lexer, token->type, &loc))
+ {
+ error_at (loc, "version control conflict marker in file");
+ return;
+ }
+ }
+
c_parse_error (gmsgid,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
+2015-12-16 David Malcolm <dmalcolm@redhat.com>
+
+ * 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.
+
2015-12-16 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/cast-function-1.c (bar): Update column numbers.
--- /dev/null
+int p;
+
+<<<<<<< HEAD /* { dg-error "conflict marker" } */
+extern int some_var;
+======= /* { dg-error "conflict marker" } */
+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. */
+>>>>>>> Some commit message /* { dg-error "conflict marker" } */
+
+int q;
--- /dev/null
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+<<<<<<< HEAD /* { dg-error "conflict marker" } */
+/* { dg-begin-multiline-output "" }
+ <<<<<<< HEAD
+ ^~~~~~~
+ { dg-end-multiline-output "" } */
+
+extern int some_var;
+
+======= /* { dg-error "conflict marker" } */
+/* { dg-begin-multiline-output "" }
+ =======
+ ^~~~~~~
+ { dg-end-multiline-output "" } */
+
+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. */
+
+>>>>>>> Some commit message /* { dg-error "conflict marker" } */
+/* { dg-begin-multiline-output "" }
+ >>>>>>>
+ ^~~~~~~
+ { dg-end-multiline-output "" } */
--- /dev/null
+/* 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;
--- /dev/null
+/* This should not be flagged as a conflict marker. */
+const char *msg = "<<<<<<< ";
--- /dev/null
+/* Ensure we can handle unterminated conflict markers. */
+
+int p;
+
+<<<<<<< HEAD /* { dg-error "conflict marker" } */
+
+int q;
+
+<<<<<<< HEAD /* { dg-error "conflict marker" } */
+
+int r;
--- /dev/null
+/* Ensure we can handle mismatched conflict markers. */
+
+int p;
+
+>>>>>>> Some commit message /* { dg-error "conflict marker" } */
+
+int q;
+
+>>>>>>> Some other commit message /* { dg-error "conflict marker" } */
+
+int r;
--- /dev/null
+/* Ensure we can handle mismatched conflict markers. */
+
+int p;
+
+======= /* { dg-error "conflict marker" } */
+
+int q;
+
+======= /* { dg-error "conflict marker" } */
+
+int r;
--- /dev/null
+/* Branch coverage of conflict marker detection:
+ none of these should be reported as 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" } */
--- /dev/null
+/* It's valid to stringize the "<<<<<<<"; don't
+ report it as a conflict marker. */
+#define str(s) #s
+const char *s = str(
+<<<<<<<
+);
--- /dev/null
+/* A macro that's never expanded shouldn't be reported as a
+ conflict marker. */
+#define foo \
+<<<<<<<
--- /dev/null
+/* 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. */
--- /dev/null
+/* Ensure that we don't complain about 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 conflict marker