From 62e1c6780d7794bd000a15b2fdbfa65dd63a223c Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 12 Oct 2017 17:49:35 +0000 Subject: [PATCH] C/C++: add fix-it hints for various missing symbols The patch improves our C/C++ frontends' handling of missing symbols, by making c_parser_require and cp_parser_require use "better" locations for the diagnostic, and insert fix-it hints, under certain circumstances (see the comments in the patch for full details). For example, for this code with a missing semicolon: $ cat test.c int missing_semicolon (void) { return 42 } trunk currently emits: test.c:4:1: error: expected ';' before '}' token } ^ This patch adds a fix-it hint for the missing semicolon, and puts the error at the location of the missing semicolon, printing the followup token as a secondary location: test.c:3:12: error: expected ';' before '}' token return 42 ^ ; } ~ More examples can be seen in the test cases. gcc/c-family/ChangeLog: * c-common.c (enum missing_token_insertion_kind): New enum. (get_missing_token_insertion_kind): New function. (maybe_suggest_missing_token_insertion): New function. * c-common.h (maybe_suggest_missing_token_insertion): New decl. gcc/c/ChangeLog: * c-parser.c (c_parser_require): Add "type_is_unique" param and use it to guard calls to maybe_suggest_missing_token_insertion. (c_parser_parms_list_declarator): Override default value of new "type_is_unique" param to c_parser_require. (c_parser_asm_statement): Likewise. * c-parser.h (c_parser_require): Add "type_is_unique" param, defaulting to true. gcc/cp/ChangeLog: * parser.c (get_required_cpp_ttype): New function. (cp_parser_error_1): Call it, using the result to call maybe_suggest_missing_token_insertion. gcc/testsuite/ChangeLog: * c-c++-common/cilk-plus/AN/parser_errors.c: Update expected output to reflect changes to reported locations of missing symbols. * c-c++-common/cilk-plus/AN/parser_errors2.c: Likewise. * c-c++-common/cilk-plus/AN/parser_errors3.c: Likewise. * c-c++-common/cilk-plus/AN/pr61191.c: Likewise. * c-c++-common/gomp/pr63326.c: Likewise. * c-c++-common/missing-close-symbol.c: Likewise, also update for new fix-it hints. * c-c++-common/missing-symbol.c: Likewise, also add test coverage for missing colon in ternary operator. * g++.dg/cpp1y/digit-sep-neg.C: Likewise. * g++.dg/cpp1y/pr65202.C: Likewise. * g++.dg/missing-symbol-2.C: New test case. * g++.dg/other/do1.C: Update expected output to reflect changes to reported locations of missing symbols. * g++.dg/parse/error11.C: Likewise. * g++.dg/template/error11.C: Likewise. * gcc.dg/missing-symbol-2.c: New test case. * gcc.dg/missing-symbol-3.c: New test case. * gcc.dg/noncompile/940112-1.c: Update expected output to reflect changes to reported locations of missing symbols. * gcc.dg/noncompile/971104-1.c: Likewise. * obj-c++.dg/exceptions-6.mm: Likewise. * obj-c++.dg/pr48187.mm: Likewise. * objc.dg/exceptions-6.m: Likewise. From-SVN: r253690 --- gcc/c-family/ChangeLog | 7 + gcc/c-family/c-common.c | 158 ++++++++++++++++++ gcc/c-family/c-common.h | 3 + gcc/c/ChangeLog | 10 ++ gcc/c/c-parser.c | 25 ++- gcc/c/c-parser.h | 3 +- gcc/cp/ChangeLog | 6 + gcc/cp/parser.c | 51 +++++- gcc/testsuite/ChangeLog | 29 ++++ .../c-c++-common/cilk-plus/AN/parser_errors.c | 4 +- .../cilk-plus/AN/parser_errors2.c | 3 +- .../cilk-plus/AN/parser_errors3.c | 3 +- .../c-c++-common/cilk-plus/AN/pr61191.c | 3 +- gcc/testsuite/c-c++-common/gomp/pr63326.c | 22 +-- .../c-c++-common/missing-close-symbol.c | 2 + gcc/testsuite/c-c++-common/missing-symbol.c | 35 ++-- gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C | 4 +- gcc/testsuite/g++.dg/cpp1y/pr65202.C | 4 +- gcc/testsuite/g++.dg/missing-symbol-2.C | 58 +++++++ gcc/testsuite/g++.dg/other/do1.C | 4 +- gcc/testsuite/g++.dg/parse/error11.C | 2 +- gcc/testsuite/g++.dg/template/error11.C | 2 +- gcc/testsuite/gcc.dg/missing-symbol-2.c | 71 ++++++++ gcc/testsuite/gcc.dg/missing-symbol-3.c | 50 ++++++ gcc/testsuite/gcc.dg/noncompile/940112-1.c | 4 +- gcc/testsuite/gcc.dg/noncompile/971104-1.c | 4 +- gcc/testsuite/obj-c++.dg/exceptions-6.mm | 6 +- gcc/testsuite/obj-c++.dg/pr48187.mm | 8 +- gcc/testsuite/objc.dg/exceptions-6.m | 4 +- 29 files changed, 528 insertions(+), 57 deletions(-) create mode 100644 gcc/testsuite/g++.dg/missing-symbol-2.C create mode 100644 gcc/testsuite/gcc.dg/missing-symbol-2.c create mode 100644 gcc/testsuite/gcc.dg/missing-symbol-3.c diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index da40ab31002..ee6fc87dd6f 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2017-10-12 David Malcolm + + * c-common.c (enum missing_token_insertion_kind): New enum. + (get_missing_token_insertion_kind): New function. + (maybe_suggest_missing_token_insertion): New function. + * c-common.h (maybe_suggest_missing_token_insertion): New decl. + 2017-10-11 Nathan Sidwell * c-opts.c (add_prefixed_path): Change chain to incpath_kind. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 09594e44e6c..dfcfb196028 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -7946,6 +7946,164 @@ 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. + + 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 attempted 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); + } +} + #if CHECKING_P namespace selftest { diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index da6a0be9200..7e1877e8d16 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1550,6 +1550,9 @@ extern int c_flt_eval_method (bool ts18661_p); extern void add_no_sanitize_value (tree node, unsigned int flags); extern void maybe_add_include_fixit (rich_location *, const char *); +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 { diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index baf57c1f95a..1f697f17f99 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,13 @@ +2017-10-12 David Malcolm + + * c-parser.c (c_parser_require): Add "type_is_unique" param and + use it to guard calls to maybe_suggest_missing_token_insertion. + (c_parser_parms_list_declarator): Override default value of new + "type_is_unique" param to c_parser_require. + (c_parser_asm_statement): Likewise. + * c-parser.h (c_parser_require): Add "type_is_unique" param, + defaulting to true. + 2017-10-11 Nathan Sidwell * c-decl.c (grokdeclarator): Check HAS_DECL_ASSEMBLER_NAME_P too. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index a622e2a89c9..6b843247911 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1041,13 +1041,21 @@ get_matching_symbol (enum cpp_ttype type) If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it within any error as the location of an "opening" token matching the close token TYPE (e.g. the location of the '(' when TYPE is - CPP_CLOSE_PAREN). */ + CPP_CLOSE_PAREN). + + 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, - location_t matching_location) + location_t matching_location, + bool type_is_unique) { if (c_parser_next_token_is (parser, type)) { @@ -1059,6 +1067,13 @@ c_parser_require (c_parser *parser, location_t next_token_loc = c_parser_peek_token (parser)->location; gcc_rich_location richloc (next_token_loc); + /* Potentially supply a fix-it hint, suggesting to add the + missing token immediately after the *previous* token. + This may move the primary location within richloc. */ + if (!parser->error && type_is_unique) + maybe_suggest_missing_token_insertion (&richloc, type, + parser->last_token_location); + /* If matching_location != UNKNOWN_LOCATION, highlight it. Attempt to consolidate diagnostics by printing it as a secondary range within the main diagnostic. */ @@ -3975,7 +3990,8 @@ 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 %<)%>", + UNKNOWN_LOCATION, false)) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL; @@ -6429,7 +6445,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 %<)%>"), + UNKNOWN_LOCATION, is_goto)) goto error_close_paren; /* Once past any colon, we're no longer a simple asm. */ diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h index 01a7b724081..21e40541ce6 100644 --- a/gcc/c/c-parser.h +++ b/gcc/c/c-parser.h @@ -137,7 +137,8 @@ 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, - location_t matching_location = UNKNOWN_LOCATION); + location_t matching_location = UNKNOWN_LOCATION, + bool type_is_unique=true); extern bool 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, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4c78cc0a01b..717411582b3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2017-10-12 David Malcolm + + * parser.c (get_required_cpp_ttype): New function. + (cp_parser_error_1): Call it, using the result to call + maybe_suggest_missing_token_insertion. + 2017-10-12 David Malcolm * parser.c (get_matching_symbol): Move to before... diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b668b59d9ae..810e2b7f72e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2788,6 +2788,40 @@ get_matching_symbol (required_token token_desc) } } +/* 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; + } +} + + /* Subroutine of cp_parser_error and cp_parser_required_error. Issue a diagnostic of the form @@ -2799,9 +2833,12 @@ get_matching_symbol (required_token token_desc) This bypasses the check for tentative passing, and potentially adds material needed by cp_parser_required_error. - If MISSING_TOKEN_DESC is not RT_NONE, and MATCHING_LOCATION is not - UNKNOWN_LOCATION, then we have an unmatched symbol at - MATCHING_LOCATION; highlight this secondary location. */ + If MISSING_TOKEN_DESC is not RT_NONE, then potentially add fix-it hints + suggesting insertion of the missing token. + + Additionally, if MATCHING_LOCATION is not UNKNOWN_LOCATION, then we + have an unmatched symbol at MATCHING_LOCATION; highlight this secondary + location. */ static void cp_parser_error_1 (cp_parser* parser, const char* gmsgid, @@ -2840,6 +2877,14 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid, if (missing_token_desc != RT_NONE) { + /* Potentially supply a fix-it hint, suggesting to add the + missing token immediately after the *previous* token. + This may move the primary location within richloc. */ + enum cpp_ttype ttype = get_required_cpp_ttype (missing_token_desc); + location_t prev_token_loc + = cp_lexer_previous_token (parser->lexer)->location; + maybe_suggest_missing_token_insertion (&richloc, ttype, prev_token_loc); + /* If matching_location != UNKNOWN_LOCATION, highlight it. Attempt to consolidate diagnostics by printing it as a secondary range within the main diagnostic. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a910f8aeac1..79642b88d82 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,32 @@ +2017-10-12 David Malcolm + + * c-c++-common/cilk-plus/AN/parser_errors.c: Update expected + output to reflect changes to reported locations of missing + symbols. + * c-c++-common/cilk-plus/AN/parser_errors2.c: Likewise. + * c-c++-common/cilk-plus/AN/parser_errors3.c: Likewise. + * c-c++-common/cilk-plus/AN/pr61191.c: Likewise. + * c-c++-common/gomp/pr63326.c: Likewise. + * c-c++-common/missing-close-symbol.c: Likewise, also update for + new fix-it hints. + * c-c++-common/missing-symbol.c: Likewise, also add test coverage + for missing colon in ternary operator. + * g++.dg/cpp1y/digit-sep-neg.C: Likewise. + * g++.dg/cpp1y/pr65202.C: Likewise. + * g++.dg/missing-symbol-2.C: New test case. + * g++.dg/other/do1.C: Update expected output to reflect + changes to reported locations of missing symbols. + * g++.dg/parse/error11.C: Likewise. + * g++.dg/template/error11.C: Likewise. + * gcc.dg/missing-symbol-2.c: New test case. + * gcc.dg/missing-symbol-3.c: New test case. + * gcc.dg/noncompile/940112-1.c: Update expected output to reflect + changes to reported locations of missing symbols. + * gcc.dg/noncompile/971104-1.c: Likewise. + * obj-c++.dg/exceptions-6.mm: Likewise. + * obj-c++.dg/pr48187.mm: Likewise. + * objc.dg/exceptions-6.m: Likewise. + 2017-10-12 Martin Sebor PR other/82301 diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c index 18816e0ec6f..fd4fe5419b6 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c @@ -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 } } */ +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c index 2bb91343a79..d003d7cc2bb 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.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; } diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c index 9270007050e..14256e9579e 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c @@ -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; } diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c index a9a9d6601bc..8c32ad9a267 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c @@ -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 } */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr63326.c b/gcc/testsuite/c-c++-common/gomp/pr63326.c index e319f497011..3e627237c43 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr63326.c +++ b/gcc/testsuite/c-c++-common/gomp/pr63326.c @@ -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++ } } */ } diff --git a/gcc/testsuite/c-c++-common/missing-close-symbol.c b/gcc/testsuite/c-c++-common/missing-close-symbol.c index 85b96f28ef8..abeb83748c1 100644 --- a/gcc/testsuite/c-c++-common/missing-close-symbol.c +++ b/gcc/testsuite/c-c++-common/missing-close-symbol.c @@ -12,6 +12,7 @@ void test_static_assert_same_line (void) /* { dg-begin-multiline-output "" } _Static_assert(sizeof(int) >= sizeof(char), "msg"; ~ ^ + ) { dg-end-multiline-output "" } */ } @@ -25,6 +26,7 @@ void test_static_assert_different_line (void) /* { dg-begin-multiline-output "" } "msg"; ^ + ) { dg-end-multiline-output "" } */ /* { dg-begin-multiline-output "" } _Static_assert(sizeof(int) >= sizeof(char), diff --git a/gcc/testsuite/c-c++-common/missing-symbol.c b/gcc/testsuite/c-c++-common/missing-symbol.c index 33a501b9988..326b9faad7a 100644 --- a/gcc/testsuite/c-c++-common/missing-symbol.c +++ b/gcc/testsuite/c-c++-common/missing-symbol.c @@ -5,15 +5,14 @@ extern int bar (void); int missing_close_paren_in_switch (int i) { - switch (i /* { dg-message "10: to match this '\\('" } */ - { /* { dg-error "5: expected '\\)' before '.' token" } */ - /* { dg-begin-multiline-output "" } - { - ^ - { dg-end-multiline-output "" } */ + switch (i /* { dg-error "12: expected '\\)' before '.' token" } */ + { /* { dg-begin-multiline-output "" } switch (i - ^ + ~ ^ + ) + { + ~ { dg-end-multiline-output "" } */ case 0: @@ -30,21 +29,33 @@ int missing_close_paren_in_switch (int i) void missing_close_paren_in_if (void) { if (foo () /* { dg-line start_of_if } */ - && bar () - { /* { dg-error "5: expected '\\)' before '.' token" } */ + && bar () /* { dg-error "16: expected '\\)' before '.' token" } */ + { /* { dg-begin-multiline-output "" } + && bar () + ^ + ) { - ^ + ~ { dg-end-multiline-output "" } */ /* { dg-message "6: to match this '\\('" "" { target *-*-* } start_of_if } */ /* { dg-begin-multiline-output "" } if (foo () ^ - { dg-end-multiline-output "" } */ + { 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 "" } */ +} diff --git a/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C b/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C index 833fab7c50b..727e74e2e10 100644 --- a/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C +++ b/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C @@ -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 } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr65202.C b/gcc/testsuite/g++.dg/cpp1y/pr65202.C index 602b264b302..7ce4895a134 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr65202.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr65202.C @@ -22,5 +22,5 @@ struct bar; int main() { foo f; - adl::swap(f, f) -} // { dg-error "" } + adl::swap(f, f) // { dg-error "expected ';'" } +} // { dg-error "expected '.'" "expected end of namespace" } diff --git a/gcc/testsuite/g++.dg/missing-symbol-2.C b/gcc/testsuite/g++.dg/missing-symbol-2.C new file mode 100644 index 00000000000..4a119f8e9ad --- /dev/null +++ b/gcc/testsuite/g++.dg/missing-symbol-2.C @@ -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; + } +} diff --git a/gcc/testsuite/g++.dg/other/do1.C b/gcc/testsuite/g++.dg/other/do1.C index b3a9daf9056..db65e7de301 100644 --- a/gcc/testsuite/g++.dg/other/do1.C +++ b/gcc/testsuite/g++.dg/other/do1.C @@ -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" } } diff --git a/gcc/testsuite/g++.dg/parse/error11.C b/gcc/testsuite/g++.dg/parse/error11.C index d118c19deb8..1a49d6edb12 100644 --- a/gcc/testsuite/g++.dg/parse/error11.C +++ b/gcc/testsuite/g++.dg/parse/error11.C @@ -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 } diff --git a/gcc/testsuite/g++.dg/template/error11.C b/gcc/testsuite/g++.dg/template/error11.C index 3a469fd1a8c..16402988a87 100644 --- a/gcc/testsuite/g++.dg/template/error11.C +++ b/gcc/testsuite/g++.dg/template/error11.C @@ -1,4 +1,4 @@ // PR c++/12132 inline template void foo () {} // { dg-error "<" } -void abort (); // { dg-error ";" } +void abort (); // { dg-error ";" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/gcc.dg/missing-symbol-2.c b/gcc/testsuite/gcc.dg/missing-symbol-2.c new file mode 100644 index 00000000000..7ee795dfcc5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/missing-symbol-2.c @@ -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 } } */ diff --git a/gcc/testsuite/gcc.dg/missing-symbol-3.c b/gcc/testsuite/gcc.dg/missing-symbol-3.c new file mode 100644 index 00000000000..e2d00dfa03f --- /dev/null +++ b/gcc/testsuite/gcc.dg/missing-symbol-3.c @@ -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"); +} diff --git a/gcc/testsuite/gcc.dg/noncompile/940112-1.c b/gcc/testsuite/gcc.dg/noncompile/940112-1.c index bb5e0f66c85..0a9e07dcaf9 100644 --- a/gcc/testsuite/gcc.dg/noncompile/940112-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/940112-1.c @@ -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" } */ +} diff --git a/gcc/testsuite/gcc.dg/noncompile/971104-1.c b/gcc/testsuite/gcc.dg/noncompile/971104-1.c index 39e00c60fc2..4a04dad7747 100644 --- a/gcc/testsuite/gcc.dg/noncompile/971104-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/971104-1.c @@ -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 )]) ); } diff --git a/gcc/testsuite/obj-c++.dg/exceptions-6.mm b/gcc/testsuite/obj-c++.dg/exceptions-6.mm index 58882fed8b7..6f6ba783ea7 100644 --- a/gcc/testsuite/obj-c++.dg/exceptions-6.mm +++ b/gcc/testsuite/obj-c++.dg/exceptions-6.mm @@ -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) diff --git a/gcc/testsuite/obj-c++.dg/pr48187.mm b/gcc/testsuite/obj-c++.dg/pr48187.mm index 750710b1f24..99677a56244 100644 --- a/gcc/testsuite/obj-c++.dg/pr48187.mm +++ b/gcc/testsuite/obj-c++.dg/pr48187.mm @@ -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 diff --git a/gcc/testsuite/objc.dg/exceptions-6.m b/gcc/testsuite/objc.dg/exceptions-6.m index 58882fed8b7..74be98d39fa 100644 --- a/gcc/testsuite/objc.dg/exceptions-6.m +++ b/gcc/testsuite/objc.dg/exceptions-6.m @@ -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) { -- 2.30.2