@@ -5945,12 +5945,13 @@ catenate_strings (const char *lhs, const char *rhs_start, int rhs_size)
return result;
}
-/* Issue the error given by GMSGID, indicating that it occurred before
- TOKEN, which had the associated VALUE. */
+/* Issue the error given by GMSGID at RICHLOC, indicating that it occurred
+ before TOKEN, which had the associated VALUE. */
void
c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
- tree value, unsigned char token_flags)
+ tree value, unsigned char token_flags,
+ rich_location *richloc)
{
#define catenate_messages(M1, M2) catenate_strings ((M1), (M2), sizeof (M2))
@@ -5991,7 +5992,7 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
else
message = catenate_messages (gmsgid, " before %s'\\x%x'");
- error (message, prefix, val);
+ error_at_rich_loc (richloc, message, prefix, val);
free (message);
message = NULL;
}
@@ -6019,7 +6020,7 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
else if (token_type == CPP_NAME)
{
message = catenate_messages (gmsgid, " before %qE");
- error (message, value);
+ error_at_rich_loc (richloc, message, value);
free (message);
message = NULL;
}
@@ -6032,16 +6033,16 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
else if (token_type < N_TTYPES)
{
message = catenate_messages (gmsgid, " before %qs token");
- error (message, cpp_type2name (token_type, token_flags));
+ error_at_rich_loc (richloc, message, cpp_type2name (token_type, token_flags));
free (message);
message = NULL;
}
else
- error (gmsgid);
+ error_at_rich_loc (richloc, gmsgid);
if (message)
{
- error (message);
+ error_at_rich_loc (richloc, message);
free (message);
}
#undef catenate_messages
@@ -7996,4 +7997,163 @@ c_flt_eval_method (bool maybe_c11_only_p)
return c_ts18661_flt_eval_method ();
}
+/* An enum for get_missing_token_insertion_kind for describing the best
+ place to insert a missing token, if there is one. */
+
+enum missing_token_insertion_kind
+{
+ MTIK_IMPOSSIBLE,
+ MTIK_INSERT_BEFORE_NEXT,
+ MTIK_INSERT_AFTER_PREV
+};
+
+/* Given a missing token of TYPE, determine if it is reasonable to
+ emit a fix-it hint suggesting the insertion of the token, and,
+ if so, where the token should be inserted relative to other tokens.
+
+ For example, it only makes sense to do this for values of TYPE that
+ are symbols.
+
+ Some symbols should go before the next token, e.g. in:
+ if flag)
+ we want to insert the missing '(' immediately before "flag",
+ giving:
+ if (flag)
+ rather than:
+ if( flag)
+ These use MTIK_INSERT_BEFORE_NEXT.
+
+ Other symbols should go after the previous token, e.g. in:
+ if (flag
+ do_something ();
+ we want to insert the missing ')' immediately after the "flag",
+ giving:
+ if (flag)
+ do_something ();
+ rather than:
+ if (flag
+ )do_something ();
+ These use MTIK_INSERT_AFTER_PREV. */
+
+static enum missing_token_insertion_kind
+get_missing_token_insertion_kind (enum cpp_ttype type)
+{
+ switch (type)
+ {
+ /* Insert missing "opening" brackets immediately
+ before the next token. */
+ case CPP_OPEN_SQUARE:
+ case CPP_OPEN_PAREN:
+ return MTIK_INSERT_BEFORE_NEXT;
+
+ /* Insert other missing symbols immediately after
+ the previous token. */
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ case CPP_SEMICOLON:
+ case CPP_COMMA:
+ case CPP_COLON:
+ return MTIK_INSERT_AFTER_PREV;
+
+ /* Other kinds of token don't get fix-it hints. */
+ default:
+ return MTIK_IMPOSSIBLE;
+ }
+}
+
+/* Given RICHLOC, a location for a diagnostic describing a missing token
+ of kind TOKEN_TYPE, potentially add a fix-it hint suggesting the
+ insertion of the token.
+
+ The location of the attemped fix-it hint depends on TOKEN_TYPE:
+ it will either be:
+ (a) immediately after PREV_TOKEN_LOC, or
+
+ (b) immediately before the primary location within RICHLOC (taken to
+ be that of the token following where the token was expected).
+
+ If we manage to add a fix-it hint, then the location of the
+ fix-it hint is likely to be more useful as the primary location
+ of the diagnostic than that of the following token, so we swap
+ these locations.
+
+ For example, given this bogus code:
+ 123456789012345678901234567890
+ 1 | int missing_semicolon (void)
+ 2 | {
+ 3 | return 42
+ 4 | }
+
+ we will emit:
+
+ "expected ';' before '}'"
+
+ RICHLOC's primary location is at the closing brace, so before "swapping"
+ we would emit the error at line 4 column 1:
+
+ 123456789012345678901234567890
+ 3 | return 42 |< fix-it hint emitted for this line
+ | ; |
+ 4 | } |< "expected ';' before '}'" emitted at this line
+ | ^ |
+
+ It's more useful for the location of the diagnostic to be at the
+ fix-it hint, so we swap the locations, so the primary location
+ is at the fix-it hint, with the old primary location inserted
+ as a secondary location, giving this, with the error at line 3
+ column 12:
+
+ 123456789012345678901234567890
+ 3 | return 42 |< "expected ';' before '}'" emitted at this line,
+ | ^ | with fix-it hint
+ 4 | ; |
+ | } |< secondary range emitted here
+ | ~ |. */
+
+void
+maybe_suggest_missing_token_insertion (rich_location *richloc,
+ enum cpp_ttype token_type,
+ location_t prev_token_loc)
+{
+ gcc_assert (richloc);
+
+ enum missing_token_insertion_kind mtik
+ = get_missing_token_insertion_kind (token_type);
+
+ switch (mtik)
+ {
+ default:
+ gcc_unreachable ();
+ break;
+
+ case MTIK_IMPOSSIBLE:
+ return;
+
+ case MTIK_INSERT_BEFORE_NEXT:
+ /* Attempt to add the fix-it hint before the primary location
+ of RICHLOC. */
+ richloc->add_fixit_insert_before (cpp_type2name (token_type, 0));
+ break;
+
+ case MTIK_INSERT_AFTER_PREV:
+ /* Attempt to add the fix-it hint after PREV_TOKEN_LOC. */
+ richloc->add_fixit_insert_after (prev_token_loc,
+ cpp_type2name (token_type, 0));
+ break;
+ }
+
+ /* If we were successful, use the fix-it hint's location as the
+ primary location within RICHLOC, adding the old primary location
+ back as a secondary location. */
+ if (!richloc->seen_impossible_fixit_p ())
+ {
+ fixit_hint *hint = richloc->get_last_fixit_hint ();
+ location_t hint_loc = hint->get_start_loc ();
+ location_t old_loc = richloc->get_loc ();
+
+ richloc->set_range (line_table, 0, hint_loc, true);
+ richloc->add_range (old_loc, false);
+ }
+}
+
#include "gt-c-family-c-common.h"
@@ -1124,7 +1124,8 @@ extern void builtin_define_with_int_value (const char *, HOST_WIDE_INT);
extern void builtin_define_type_sizeof (const char *, tree);
extern void c_stddef_cpp_builtins (void);
extern void fe_file_change (const line_map_ordinary *);
-extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char);
+extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char,
+ rich_location *richloc);
/* In c-ppoutput.c */
extern void init_pp_output (FILE *);
@@ -1554,6 +1555,10 @@ excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);
extern int c_flt_eval_method (bool ts18661_p);
extern void add_no_sanitize_value (tree node, unsigned int flags);
+extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
+ enum cpp_ttype token_type,
+ location_t prev_token_loc);
+
#if CHECKING_P
namespace selftest {
extern void c_format_c_tests (void);
@@ -206,6 +206,9 @@ struct GTY(()) c_parser {
/* Buffer to hold all the tokens from parsing the vector attribute for the
SIMD-enabled functions (formerly known as elemental functions). */
vec <c_token, va_gc> *cilk_simd_fn_tokens;
+
+ /* Location of the most-recently consumed token. */
+ location_t previous_token_loc;
};
/* Return a pointer to the Nth token in PARSERs tokens_buf. */
@@ -770,6 +773,7 @@ c_parser_consume_token (c_parser *parser)
gcc_assert (parser->tokens[0].type != CPP_EOF);
gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
+ parser->previous_token_loc = parser->tokens[0].location;
if (parser->tokens != &parser->tokens_buf[0])
parser->tokens++;
else if (parser->tokens_avail == 2)
@@ -850,14 +854,17 @@ c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind,
MESSAGE (specified by the caller) is usually of the form "expected
OTHER-TOKEN".
+ Use RICHLOC as the location of the diagnostic.
+
Do not issue a diagnostic if still recovering from an error.
??? This is taken from the C++ parser, but building up messages in
this way is not i18n-friendly and some other approach should be
used. */
-void
-c_parser_error (c_parser *parser, const char *gmsgid)
+static void
+c_parser_error_richloc (c_parser *parser, const char *gmsgid,
+ rich_location *richloc)
{
c_token *token = c_parser_peek_token (parser);
if (parser->error)
@@ -879,9 +886,6 @@ c_parser_error (c_parser *parser, const char *gmsgid)
}
}
- /* 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);
c_parse_error (gmsgid,
/* Because c_parse_error does not understand
CPP_KEYWORD, keywords are treated like
@@ -891,18 +895,39 @@ c_parser_error (c_parser *parser, const char *gmsgid)
token, we need to pass 0 here and we will not get
the source spelling of some tokens but rather the
canonical spelling. */
- token->value, /*flags=*/0);
+ token->value, /*flags=*/0, richloc);
+}
+
+/* As c_parser_error_richloc, but issue the message at the
+ location of PARSER's next token, or at input_location
+ if the next token is EOF. */
+
+void
+c_parser_error (c_parser *parser, const char *gmsgid)
+{
+ c_token *token = c_parser_peek_token (parser);
+ c_parser_set_source_position_from_token (token);
+ rich_location richloc (line_table, input_location);
+ c_parser_error_richloc (parser, gmsgid, &richloc);
}
/* If the next token is of the indicated TYPE, consume it. Otherwise,
issue the error MSGID. If MSGID is NULL then a message has already
been produced and no message will be produced this time. Returns
- true if found, false otherwise. */
+ true if found, false otherwise.
+
+ If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly
+ one type (e.g. "expected %<)%>") and thus it may be reasonable to
+ attempt to generate a fix-it hint for the problem.
+ Otherwise msgid describes multiple token types (e.g.
+ "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to
+ generate a fix-it hint. */
bool
c_parser_require (c_parser *parser,
enum cpp_ttype type,
- const char *msgid)
+ const char *msgid,
+ bool type_is_unique)
{
if (c_parser_next_token_is (parser, type))
{
@@ -911,7 +936,14 @@ c_parser_require (c_parser *parser,
}
else
{
- c_parser_error (parser, msgid);
+ rich_location richloc (line_table,
+ c_parser_peek_token (parser)->location);
+ /* Potentially supply a fix-it hint, suggesting to add the
+ missing token immediately after the *previous* token. */
+ if (!parser->error && type_is_unique)
+ maybe_suggest_missing_token_insertion (&richloc, type,
+ parser->previous_token_loc);
+ c_parser_error_richloc (parser, msgid, &richloc);
return false;
}
}
@@ -3798,7 +3830,7 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
return get_parm_info (false, expr);
}
if (!c_parser_require (parser, CPP_COMMA,
- "expected %<;%>, %<,%> or %<)%>"))
+ "expected %<;%>, %<,%> or %<)%>", false))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
return NULL;
@@ -6177,7 +6209,8 @@ c_parser_asm_statement (c_parser *parser)
if (!c_parser_require (parser, CPP_COLON,
is_goto
? G_("expected %<:%>")
- : G_("expected %<:%> or %<)%>")))
+ : G_("expected %<:%> or %<)%>"),
+ is_goto))
goto error_close_paren;
/* Once past any colon, we're no longer a simple asm. */
@@ -136,7 +136,7 @@ extern c_token * c_parser_peek_token (c_parser *parser);
extern c_token * c_parser_peek_2nd_token (c_parser *parser);
extern c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n);
extern bool c_parser_require (c_parser *parser, enum cpp_ttype type,
- const char *msgid);
+ const char *msgid, bool type_is_unique=true);
extern void c_parser_error (c_parser *parser, const char *gmsgid);
extern void c_parser_consume_token (c_parser *parser);
extern void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type,
@@ -2804,12 +2804,13 @@ cp_parser_error (cp_parser* parser, const char* gmsgid)
}
}
+ rich_location richloc (line_table, input_location);
c_parse_error (gmsgid,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
identifiers. */
(token->type == CPP_KEYWORD ? CPP_NAME : token->type),
- token->u.value, token->flags);
+ token->u.value, token->flags, &richloc);
}
}
@@ -27758,6 +27759,39 @@ cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers)
return decl_spec_seq_has_spec_p (decl_specifiers, ds_friend);
}
+/* Attempt to convert TOKEN_DESC from a required_token to an
+ enum cpp_ttype, returning CPP_EOF if there is no good conversion. */
+
+static enum cpp_ttype
+get_required_cpp_ttype (required_token token_desc)
+{
+ switch (token_desc)
+ {
+ case RT_SEMICOLON:
+ return CPP_SEMICOLON;
+ case RT_OPEN_PAREN:
+ return CPP_OPEN_PAREN;
+ case RT_CLOSE_BRACE:
+ return CPP_CLOSE_BRACE;
+ case RT_OPEN_BRACE:
+ return CPP_OPEN_BRACE;
+ case RT_CLOSE_SQUARE:
+ return CPP_CLOSE_SQUARE;
+ case RT_OPEN_SQUARE:
+ return CPP_OPEN_SQUARE;
+ case RT_COMMA:
+ return CPP_COMMA;
+ case RT_COLON:
+ return CPP_COLON;
+ case RT_CLOSE_PAREN:
+ return CPP_CLOSE_PAREN;
+
+ default:
+ /* Use CPP_EOF as a "no completions possible" code. */
+ return CPP_EOF;
+ }
+}
+
/* Issue an error message indicating that TOKEN_DESC was expected.
If KEYWORD is true, it indicated this function is called by
cp_parser_require_keword and the required token can only be
@@ -27768,163 +27802,185 @@ cp_parser_required_error (cp_parser *parser,
required_token token_desc,
bool keyword)
{
+ if (cp_parser_simulate_error (parser))
+ return;
+
+ const char *gmsgid = NULL;
switch (token_desc)
{
case RT_NEW:
- cp_parser_error (parser, "expected %<new%>");
- return;
+ gmsgid = G_("expected %<new%>");
+ break;
case RT_DELETE:
- cp_parser_error (parser, "expected %<delete%>");
- return;
+ gmsgid = G_("expected %<delete%>");
+ break;
case RT_RETURN:
- cp_parser_error (parser, "expected %<return%>");
- return;
+ gmsgid = G_("expected %<return%>");
+ break;
case RT_WHILE:
- cp_parser_error (parser, "expected %<while%>");
- return;
+ gmsgid = G_("expected %<while%>");
+ break;
case RT_EXTERN:
- cp_parser_error (parser, "expected %<extern%>");
- return;
+ gmsgid = G_("expected %<extern%>");
+ break;
case RT_STATIC_ASSERT:
- cp_parser_error (parser, "expected %<static_assert%>");
- return;
+ gmsgid = G_("expected %<static_assert%>");
+ break;
case RT_DECLTYPE:
- cp_parser_error (parser, "expected %<decltype%>");
- return;
+ gmsgid = G_("expected %<decltype%>");
+ break;
case RT_OPERATOR:
- cp_parser_error (parser, "expected %<operator%>");
- return;
+ gmsgid = G_("expected %<operator%>");
+ break;
case RT_CLASS:
- cp_parser_error (parser, "expected %<class%>");
- return;
+ gmsgid = G_("expected %<class%>");
+ break;
case RT_TEMPLATE:
- cp_parser_error (parser, "expected %<template%>");
- return;
+ gmsgid = G_("expected %<template%>");
+ break;
case RT_NAMESPACE:
- cp_parser_error (parser, "expected %<namespace%>");
- return;
+ gmsgid = G_("expected %<namespace%>");
+ break;
case RT_USING:
- cp_parser_error (parser, "expected %<using%>");
- return;
+ gmsgid = G_("expected %<using%>");
+ break;
case RT_ASM:
- cp_parser_error (parser, "expected %<asm%>");
- return;
+ gmsgid = G_("expected %<asm%>");
+ break;
case RT_TRY:
- cp_parser_error (parser, "expected %<try%>");
- return;
+ gmsgid = G_("expected %<try%>");
+ break;
case RT_CATCH:
- cp_parser_error (parser, "expected %<catch%>");
- return;
+ gmsgid = G_("expected %<catch%>");
+ break;
case RT_THROW:
- cp_parser_error (parser, "expected %<throw%>");
- return;
+ gmsgid = G_("expected %<throw%>");
+ break;
case RT_LABEL:
- cp_parser_error (parser, "expected %<__label__%>");
- return;
+ gmsgid = G_("expected %<__label__%>");
+ break;
case RT_AT_TRY:
- cp_parser_error (parser, "expected %<@try%>");
- return;
+ gmsgid = G_("expected %<@try%>");
+ break;
case RT_AT_SYNCHRONIZED:
- cp_parser_error (parser, "expected %<@synchronized%>");
- return;
+ gmsgid = G_("expected %<@synchronized%>");
+ break;
case RT_AT_THROW:
- cp_parser_error (parser, "expected %<@throw%>");
- return;
+ gmsgid = G_("expected %<@throw%>");
+ break;
case RT_TRANSACTION_ATOMIC:
- cp_parser_error (parser, "expected %<__transaction_atomic%>");
- return;
+ gmsgid = G_("expected %<__transaction_atomic%>");
+ break;
case RT_TRANSACTION_RELAXED:
- cp_parser_error (parser, "expected %<__transaction_relaxed%>");
- return;
+ gmsgid = G_("expected %<__transaction_relaxed%>");
+ break;
default:
break;
}
- if (!keyword)
+
+ if (!gmsgid && !keyword)
{
switch (token_desc)
{
case RT_SEMICOLON:
- cp_parser_error (parser, "expected %<;%>");
- return;
+ gmsgid = G_("expected %<;%>");
+ break;
case RT_OPEN_PAREN:
- cp_parser_error (parser, "expected %<(%>");
- return;
+ gmsgid = G_("expected %<(%>");
+ break;
case RT_CLOSE_BRACE:
- cp_parser_error (parser, "expected %<}%>");
- return;
+ gmsgid = G_("expected %<}%>");
+ break;
case RT_OPEN_BRACE:
- cp_parser_error (parser, "expected %<{%>");
- return;
+ gmsgid = G_("expected %<{%>");
+ break;
case RT_CLOSE_SQUARE:
- cp_parser_error (parser, "expected %<]%>");
- return;
+ gmsgid = G_("expected %<]%>");
+ break;
case RT_OPEN_SQUARE:
- cp_parser_error (parser, "expected %<[%>");
- return;
+ gmsgid = G_("expected %<[%>");
+ break;
case RT_COMMA:
- cp_parser_error (parser, "expected %<,%>");
- return;
+ gmsgid = G_("expected %<,%>");
+ break;
case RT_SCOPE:
- cp_parser_error (parser, "expected %<::%>");
- return;
+ gmsgid = G_("expected %<::%>");
+ break;
case RT_LESS:
- cp_parser_error (parser, "expected %<<%>");
- return;
+ gmsgid = G_("expected %<<%>");
+ break;
case RT_GREATER:
- cp_parser_error (parser, "expected %<>%>");
- return;
+ gmsgid = G_("expected %<>%>");
+ break;
case RT_EQ:
- cp_parser_error (parser, "expected %<=%>");
- return;
+ gmsgid = G_("expected %<=%>");
+ break;
case RT_ELLIPSIS:
- cp_parser_error (parser, "expected %<...%>");
- return;
+ gmsgid = G_("expected %<...%>");
+ break;
case RT_MULT:
- cp_parser_error (parser, "expected %<*%>");
- return;
+ gmsgid = G_("expected %<*%>");
+ break;
case RT_COMPL:
- cp_parser_error (parser, "expected %<~%>");
- return;
+ gmsgid = G_("expected %<~%>");
+ break;
case RT_COLON:
- cp_parser_error (parser, "expected %<:%>");
- return;
+ gmsgid = G_("expected %<:%>");
+ break;
case RT_COLON_SCOPE:
- cp_parser_error (parser, "expected %<:%> or %<::%>");
- return;
+ gmsgid = G_("expected %<:%> or %<::%>");
+ break;
case RT_CLOSE_PAREN:
- cp_parser_error (parser, "expected %<)%>");
- return;
+ gmsgid = G_("expected %<)%>");
+ break;
case RT_COMMA_CLOSE_PAREN:
- cp_parser_error (parser, "expected %<,%> or %<)%>");
- return;
+ gmsgid = G_("expected %<,%> or %<)%>");
+ break;
case RT_PRAGMA_EOL:
- cp_parser_error (parser, "expected end of line");
- return;
+ gmsgid = G_("expected end of line");
+ break;
case RT_NAME:
- cp_parser_error (parser, "expected identifier");
- return;
+ gmsgid = G_("expected identifier");
+ break;
case RT_SELECT:
- cp_parser_error (parser, "expected selection-statement");
- return;
+ gmsgid = G_("expected selection-statement");
+ break;
case RT_ITERATION:
- cp_parser_error (parser, "expected iteration-statement");
- return;
+ gmsgid = G_("expected iteration-statement");
+ break;
case RT_JUMP:
- cp_parser_error (parser, "expected jump-statement");
- return;
+ gmsgid = G_("expected jump-statement");
+ break;
case RT_CLASS_KEY:
- cp_parser_error (parser, "expected class-key");
- return;
+ gmsgid = G_("expected class-key");
+ break;
case RT_CLASS_TYPENAME_TEMPLATE:
- cp_parser_error (parser,
- "expected %<class%>, %<typename%>, or %<template%>");
- return;
+ gmsgid = G_("expected %<class%>, %<typename%>, or %<template%>");
+ break;
default:
gcc_unreachable ();
}
}
- else
- gcc_unreachable ();
+
+ if (gmsgid)
+ {
+ /* Emulate rest of cp_parser_error. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ cp_lexer_set_source_position_from_token (token);
+
+ rich_location richloc (line_table, input_location);
+
+ /* Potentially supply a fix-it hint, suggesting to add the
+ missing token immediately after the *previous* token. */
+ enum cpp_ttype ttype = get_required_cpp_ttype (token_desc);
+ location_t prev_token_loc
+ = cp_lexer_previous_token (parser->lexer)->location;
+ maybe_suggest_missing_token_insertion (&richloc, ttype, prev_token_loc);
+
+ c_parse_error (gmsgid,
+ (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+ token->u.value, token->flags, &richloc);
+ }
}
@@ -7,5 +7,5 @@ int main (void)
array2[:] = array2[: ; /* { dg-error "expected ']'" } */
- return 0;
-} /* { dg-error "expected ';' before" "" { target c } } */
+ return 0; /* { dg-error "expected ';' before" "" { target c } } */
+}
@@ -7,6 +7,7 @@ int main (void)
array2[:] = array2[1:2:] ; /* { dg-error "expected expression before" "" { target c } } */
/* { dg-error "expected primary-expression before" "" { target c++ } .-1 } */
+ /* { dg-error "expected ';' before" "" { target c } .-2 } */
- return 0; /* { dg-error "expected ';' before" "" { target c } } */
+ return 0;
}
@@ -7,6 +7,7 @@ int main (void)
array2[:] = array2[1: :] ; /* { dg-error "expected expression before" "" { target c } } */
/* { dg-error "expected primary-expression before" "" { target c++ } .-1 } */
+ /* { dg-error "expected ';' before" "" { target c } .-2 } */
- return 0; /* { dg-error "expected ';' before" "" { target c } } */
+ return 0;
}
@@ -7,4 +7,5 @@ double f(double * A, double * B)
return __sec_reduce_add((B[0:500])(; /* { dg-error "called object" "" { target c } } */
/* { dg-error "expected expression before ';' token" "" { target c } .-1 } */
/* { dg-error "expected primary-expression before ';' token" "" { target c++ } .-2 } */
-} /* { dg-error "expected" "" { target c } } */
+/* { dg-error "expected" "" { target c } .-3 } */
+}
@@ -156,34 +156,34 @@ f4 (int x)
{
do
#pragma omp barrier /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp flush /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp taskwait /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp taskyield /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
#pragma omp parallel
{
do
#pragma omp cancel parallel /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
#pragma omp parallel
{
do
#pragma omp cancellation point parallel /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
#pragma omp for ordered(1)
for (i = 0; i < 16; i++)
@@ -191,28 +191,28 @@ f4 (int x)
{
do
#pragma omp ordered depend(source) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp ordered depend(sink: i-1) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
}
{
do
#pragma omp target enter data map(to:i) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp target update to(i) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp target exit data map(from:i) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
}
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+extern int foo (void);
+extern int bar (void);
+
+void missing_close_paren (void)
+{
+ if (foo ()
+ && bar () /* { dg-error "16: expected '\\)' before '.' token" } */
+ {
+ /* { dg-begin-multiline-output "" }
+ && bar ()
+ ^
+ )
+ {
+ ~
+ { dg-end-multiline-output "" } */
+ }
+} /* { dg-error "1: expected" } */
+ /* { dg-begin-multiline-output "" }
+ }
+ ^
+ { dg-end-multiline-output "" } */
+
+
+int missing_colon_in_ternary (int flag)
+{
+ return flag ? 42 0; /* { dg-error "expected ':' before numeric constant" } */
+ /* { dg-begin-multiline-output "" }
+ return flag ? 42 0;
+ ^~
+ :
+ { dg-end-multiline-output "" } */
+}
@@ -26,5 +26,5 @@ main()
}
// { dg-error "exponent has no digits" "exponent has no digits" { target *-*-* } 21 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 14 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 25 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 13 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 24 }
@@ -22,5 +22,5 @@ struct bar;
int main()
{
foo<ns::bar> f;
- adl::swap(f, f)
-} // { dg-error "" }
+ adl::swap(f, f) // { dg-error "expected ';'" }
+} // { dg-error "expected '.'" "expected end of namespace" }
new file mode 100644
@@ -0,0 +1,58 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+extern int foo (void);
+
+void missing_open_paren (void)
+{
+ if foo ()) /* { dg-error "expected '\\(' before 'foo'" } */
+ {
+ }
+ /* { dg-begin-multiline-output "" }
+ if foo ())
+ ^~~
+ (
+ { dg-end-multiline-output "" } */
+}
+
+
+void missing_close_square (void)
+{
+ const char test [42; /* { dg-error "22: expected ']' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ const char test [42;
+ ^
+ ]
+ { dg-end-multiline-output "" } */
+}
+
+int missing_semicolon (void)
+{
+ return 42 /* { dg-error "expected ';'" } */
+}
+/* { dg-begin-multiline-output "" }
+ return 42
+ ^
+ ;
+ }
+ ~
+ { dg-end-multiline-output "" } */
+
+
+int missing_colon_in_switch (int val)
+{
+ switch (val)
+ {
+ case 42 /* { dg-error "expected ':' before 'return'" } */
+ return 42;
+ /* { dg-begin-multiline-output "" }
+ case 42
+ ^
+ :
+ return 42;
+ ~~~~~~
+ { dg-end-multiline-output "" } */
+
+ default:
+ return val;
+ }
+}
@@ -7,7 +7,7 @@
void init ()
{
- do { } while (0)
- obj = 0; // { dg-error "expected|not declared" }
+ do { } while (0) // { dg-error "expected ';'" }
+ obj = 0; // { dg-error "not declared" }
}
@@ -52,7 +52,7 @@ void func(void)
Foo[:B> k1; // { dg-bogus "cannot begin|alternate spelling" "smart error should not be triggered here" }
// { dg-error "6:missing template arguments before" "template" { target *-*-* } 51 }
// { dg-error "9:expected primary-expression before ':' token" "primary" { target *-*-* } 51 }
-// { dg-error "9:expected '\]' before ':' token" "backslash" { target *-*-* } 51 }
+// { dg-error "8:expected '\]' before ':' token" "backslash" { target *-*-* } 51 }
// { dg-error "6:missing template arguments before" "template" { target *-*-* } 52 }
// { dg-error "7:expected primary-expression before ':' token" "primary" { target *-*-* } 52 }
// { dg-error "7:expected '\]' before ':' token" "backslash" { target *-*-* } 52 }
@@ -4,5 +4,5 @@
// does not.
int f(int x,
#pragma interface // { dg-error "not allowed here" }
- // The parser gets confused and issues an error on the next line.
- int y); // { dg-bogus "" "" { xfail *-*-* } }
+ // { dg-bogus "expected identifier" "" { xfail *-*-* } .-1 }
+ int y);
@@ -1,4 +1,4 @@
// PR c++/12132
inline template <int> void foo () {} // { dg-error "<" }
-void abort (); // { dg-error ";" }
+void abort (); // { dg-error ";" "" { target *-*-* } .-1 }
new file mode 100644
@@ -0,0 +1,71 @@
+/* { dg-options "-fdiagnostics-show-caret -Wno-switch-unreachable" } */
+
+extern int foo (void);
+
+void missing_open_paren (void)
+{
+ if foo ()) /* { dg-line missing_open_paren } */
+ {
+ }
+ /* { dg-error "expected '\\(' before 'foo'" "" { target c } missing_open_paren } */
+ /* { dg-begin-multiline-output "" }
+ if foo ())
+ ^~~
+ (
+ { dg-end-multiline-output "" } */
+ /* { dg-error "expected statement before '\\)' token" "" { target c } missing_open_paren } */
+ /* { dg-begin-multiline-output "" }
+ if foo ())
+ ^
+ { dg-end-multiline-output "" } */
+}
+
+void missing_close_square (void)
+{
+ const char test [42; /* { dg-error "22: expected ']' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ const char test [42;
+ ^
+ ]
+ { dg-end-multiline-output "" } */
+}
+
+int missing_semicolon (void)
+{
+ return 42 /* { dg-error "expected ';'" } */
+}
+/* { dg-begin-multiline-output "" }
+ return 42
+ ^
+ ;
+ }
+ ~
+ { dg-end-multiline-output "" } */
+
+
+/* We don't offer a fix-it hint for this case in C, as it could be
+ colon or ellipsis.
+ TODO: we could be smarter about error-recovery here; given the
+ return perhaps we could assume a missing colon. */
+
+int missing_colon_in_switch (int val)
+{
+ switch (val)
+ {
+ case 42
+ return 42; /* { dg-error "expected ':' or '...' before 'return'" } */
+ /* { dg-begin-multiline-output "" }
+ return 42;
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+
+ default:
+ return val;
+ }
+}
+
+/* { dg-begin-multiline-output "" }
+ int dummy;
+ ^~~
+ { dg-end-multiline-output "" } */
+int dummy;/* { dg-error "expected declaration or statement at end of input" "" { target c } } */
new file mode 100644
@@ -0,0 +1,50 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+/* A sequence of bogus _Static_assert.
+ We can offer fix-it hints for some of these, but not all. */
+
+void test_static_assert_1 (void)
+{
+ _Static_assert sizeof(int) >= sizeof(char); /* { dg-error "expected '\\(' before 'sizeof'" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert sizeof(int) >= sizeof(char);
+ ^~~~~~
+ (
+ { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_2 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char); /* { dg-error "expected ',' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert(sizeof(int) >= sizeof(char);
+ ^
+ ,
+ { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_3 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char),; /* { dg-error "expected string literal before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert(sizeof(int) >= sizeof(char),;
+ ^
+ { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_4 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char), "msg"; /* { dg-error "expected '\\)' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert(sizeof(int) >= sizeof(char), "msg";
+ ^
+ )
+ { dg-end-multiline-output "" } */
+}
+
+/* The final one is correct. */
+
+void test_static_assert_5 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char), "msg");
+}
@@ -3,5 +3,5 @@ f (int x)
{
double e = 1;
e = 1;
- return (e)
-} /* { dg-error "parse error|syntax error|expected" } */
+ return (e) /* { dg-error "parse error|syntax error|expected" } */
+}
@@ -27,6 +27,6 @@ static void up(int sem){
printf("%s had processes sleeping on it!\n",
({ "MUTEX ", "BARB_SEM 1", "BARB_SEM 2", "CUST_SEM 1",
"CUST_SEM 2", "WAIT_SEM 1", "WAIT_SEM 2", "WAIT_SEM 3",
- "WAIT_SEM 4"} /* { dg-error "parse error|syntax error|expected" } */
- [( sb.sem_num )]) ); /* { dg-error "expected" } */
+ "WAIT_SEM 4"} /* { dg-error "expected" } */
+ [( sb.sem_num )]) );
}
@@ -11,15 +11,15 @@ void test (id object)
@throw object; /* Ok */
@throw; /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */
@throw (object); /* Ok. */
- @throw (id)0
-} /* { dg-error "expected" } */
+ @throw (id)0 /* { dg-error "expected" } */
+}
void test2 (id object)
{
@throw object); /* { dg-error "expected" } */
@throw (...); /* { dg-error "expected" } */
@throw (); /* { dg-error "expected" } */
- @throw
+ @throw /* { dg-error "expected" } */
} /* { dg-error "expected" } */
void test3 (id object1, id object2)
@@ -1,19 +1,19 @@
/* { dg-do compile } */
@interface A
-{
+{ /* { dg-error "xpected" } */
] /* { dg-error "xpected" } */
}
@end
@interface B
-{
+{ /* { dg-error "xpected" } */
]; /* { dg-error "xpected" } */
}
@end
@interface C
-{
+{ /* { dg-error "xpected" } */
]; /* { dg-error "xpected" } */
int x;
}
@@ -21,7 +21,7 @@
@interface D
{
- (
+ ( /* { dg-error "xpected" } */
} /* { dg-error "xpected" } */
@end
@@ -11,8 +11,8 @@ void test (id object)
@throw object; /* Ok */
@throw; /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */
@throw (object); /* Ok. */
- @throw (id)0
-} /* { dg-error "expected" } */
+ @throw (id)0 /* { dg-error "expected" } */
+}
void test2 (id object)
{