From 32129a17506ba18a34d07145eb2c1e9f9827034f Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 10 Aug 2017 13:22:27 +0000 Subject: [PATCH] C/C++: show pertinent open token when missing a close token gcc/c/ChangeLog: * c-parser.c (c_parser_error): Rename to... (c_parser_error_richloc): ...this, making static, and adding "richloc" parameter, passing it to the c_parse_error call, rather than calling c_parser_set_source_position_from_token. (c_parser_error): Reintroduce, reimplementing in terms of the above, converting return type from void to bool. (class token_pair): New class. (struct matching_paren_traits): New struct. (matching_parens): New typedef. (struct matching_brace_traits): New struct. (matching_braces): New typedef. (get_matching_symbol): New function. (c_parser_require): Add param MATCHING_LOCATION, using it to highlight matching "opening" tokens for missing "closing" tokens. (c_parser_skip_until_found): Likewise. (c_parser_static_assert_declaration_no_semi): Convert explicit parsing of CPP_OPEN_PAREN and CPP_CLOSE_PAREN to use of class matching_parens, so that the pertinent open parenthesis is highlighted when there are problems locating the close parenthesis. (c_parser_struct_or_union_specifier): Likewise. (c_parser_typeof_specifier): Likewise. (c_parser_alignas_specifier): Likewise. (c_parser_simple_asm_expr): Likewise. (c_parser_braced_init): Likewise, for matching_braces. (c_parser_paren_condition): Likewise, for matching_parens. (c_parser_switch_statement): Likewise. (c_parser_for_statement): Likewise. (c_parser_asm_statement): Likewise. (c_parser_asm_operands): Likewise. (c_parser_cast_expression): Likewise. (c_parser_sizeof_expression): Likewise. (c_parser_alignof_expression): Likewise. (c_parser_generic_selection): Likewise. (c_parser_postfix_expression): Likewise for cases RID_VA_ARG, RID_OFFSETOF, RID_TYPES_COMPATIBLE_P, RID_AT_SELECTOR, RID_AT_PROTOCOL, RID_AT_ENCODE, reindenting as necessary. In case CPP_OPEN_PAREN, pass loc_open_paren to the c_parser_skip_until_found call. (c_parser_objc_class_definition): Use class matching_parens as above. (c_parser_objc_method_decl): Likewise. (c_parser_objc_try_catch_finally_statement): Likewise. (c_parser_objc_synchronized_statement): Likewise. (c_parser_objc_at_property_declaration): Likewise. (c_parser_oacc_wait_list): Likewise. (c_parser_omp_var_list_parens): Likewise. (c_parser_omp_clause_collapse): Likewise. (c_parser_omp_clause_default): Likewise. (c_parser_omp_clause_if): Likewise. (c_parser_omp_clause_num_threads): Likewise. (c_parser_omp_clause_num_tasks): Likewise. (c_parser_omp_clause_grainsize): Likewise. (c_parser_omp_clause_priority): Likewise. (c_parser_omp_clause_hint): Likewise. (c_parser_omp_clause_defaultmap): Likewise. (c_parser_oacc_single_int_clause): Likewise. (c_parser_omp_clause_ordered): Likewise. (c_parser_omp_clause_reduction): Likewise. (c_parser_omp_clause_schedule): Likewise. (c_parser_omp_clause_num_teams): Likewise. (c_parser_omp_clause_thread_limit): Likewise. (c_parser_omp_clause_aligned): Likewise. (c_parser_omp_clause_linear): Likewise. (c_parser_omp_clause_safelen): Likewise. (c_parser_omp_clause_simdlen): Likewise. (c_parser_omp_clause_depend): Likewise. (c_parser_omp_clause_map): Likewise. (c_parser_omp_clause_device): Likewise. (c_parser_omp_clause_dist_schedule): Likewise. (c_parser_omp_clause_proc_bind): Likewise. (c_parser_omp_clause_uniform): Likewise. (c_parser_omp_for_loop): Likewise. (c_parser_cilk_clause_vectorlength): Likewise. (c_parser_cilk_clause_linear): Likewise. (c_parser_transaction_expression): Likewise. * c-parser.h (c_parser_require): Add param matching_location with default UNKNOWN_LOCATION. (c_parser_error): Convert return type from void to bool. (c_parser_skip_until_found): Add param matching_location with default UNKNOWN_LOCATION. gcc/c-family/ChangeLog: * c-common.c (c_parse_error): Add rich_location * param, using it rather implicitly using input_location. * c-common.h (c_parse_error): Add rich_location * param. gcc/cp/ChangeLog: * parser.c (cp_parser_error): Update for new param to c_parse_error. (class token_pair): New class. (struct matching_paren_traits): New struct. (matching_parens): New typedef. (struct matching_brace_traits): New struct. (matching_braces): New typedef. (cp_parser_statement_expr): Convert explicit parsing of CPP_OPEN_PAREN and CPP_CLOSE_PAREN to use of class matching_parens, so that the pertinent open parenthesis is highlighted when there are problems locating the close parenthesis. (cp_parser_primary_expression): Likewise. (cp_parser_compound_literal_p): Remove consumption of opening paren. (cp_parser_postfix_expression): Convert explicit parsing of CPP_OPEN_PAREN and CPP_CLOSE_PAREN to use matching parens, as above. Use it to consume the opening paren previously consumed by cp_parser_compound_literal_p. (cp_parser_parenthesized_expression_list): Likewise. (cp_parser_unary_expression): Likewise. (cp_parser_new_expression): Likewise. (cp_parser_cast_expression): Likewise. (cp_parser_builtin_offsetof): Likewise. (cp_parser_trait_expr): Likewise. (cp_parser_lambda_declarator_opt): Likewise. (cp_parser_lambda_body): Likewise, for matching_braces. (cp_parser_compound_statement): Likewise. (cp_parser_selection_statement): Likewise, for matching_parens. (cp_parser_iteration_statement): Likewise. (cp_parser_already_scoped_statement): Likewise, for matching_braces. (cp_parser_linkage_specification): Likewise. (cp_parser_static_assert): Likewise, for matching_parens. (cp_parser_decltype): Likewise. (cp_parser_operator): Likewise. (cp_parser_enum_specifier): Likewise. (cp_parser_namespace_definition): Likewise. (cp_parser_direct_declarator): Likewise. (cp_parser_braced_list): Likewise. (cp_parser_class_specifier_1): Likewise, for matching_braces. (cp_parser_constant_initializer): Likewise. (cp_parser_noexcept_specification_opt): Likewise, for matching_parens. (cp_parser_exception_specification_opt): Likewise. (cp_parser_handler): Likewise. (cp_parser_asm_specification_opt): Likewise. (cp_parser_asm_operand_list): Likewise. (cp_parser_gnu_attributes_opt): Likewise. (cp_parser_std_attribute_spec): Likewise. (cp_parser_requirement_parameter_list): Likewise. (cp_parser_requirement_body): Likewise, for matching_braces. (cp_parser_compound_requirement): Likewise. (cp_parser_template_introduction): Likewise. (cp_parser_sizeof_pack): Likewise, for matching_parens. (cp_parser_sizeof_operand): Likewise; use it to consume the opening paren previously consumed by cp_parser_compound_literal_p. (get_matching_symbol): New function. (cp_parser_required_error): Add param "matching_location". Remove calls to cp_parser_error, instead setting a non-NULL gmsgid, and handling it if set by calling c_parse_error, potentially with a secondary location if matching_location was set. (cp_parser_require): Add param "matching_location", with a default value of UNKNOWN_LOCATION. (cp_parser_require_keyword): Update for new param of cp_parser_required_error. (cp_parser_objc_encode_expression): Update to class matching_parens as above. (cp_parser_objc_defs_expression): Likewise. (cp_parser_objc_protocol_expression): Likewise. (cp_parser_objc_selector_expression): Likewise. (cp_parser_objc_typename): Likewise. (cp_parser_objc_superclass_or_category): Likewise. (cp_parser_objc_try_catch_finally_statement): Likewise. (cp_parser_objc_synchronized_statement): Likewise. (cp_parser_objc_at_property_declaration): Likewise. (cp_parser_oacc_single_int_clause): Likewise. (cp_parser_oacc_shape_clause): Likewise. (cp_parser_omp_clause_collapse): Likewise. (cp_parser_omp_clause_default): Likewise. (cp_parser_omp_clause_final): Likewise. (cp_parser_omp_clause_if): Likewise. (cp_parser_omp_clause_num_threads): Likewise. (cp_parser_omp_clause_num_tasks): Likewise. (cp_parser_omp_clause_grainsize): Likewise. (cp_parser_omp_clause_priority): Likewise. (cp_parser_omp_clause_hint): Likewise. (cp_parser_omp_clause_defaultmap): Likewise. (cp_parser_omp_clause_ordered): Likewise. (cp_parser_omp_clause_schedule): Likewise. (cp_parser_omp_clause_num_teams): Likewise. (cp_parser_omp_clause_thread_limit): Likewise. (cp_parser_omp_clause_aligned): Likewise. (cp_parser_omp_clause_linear): Likewise. (cp_parser_omp_clause_safelen): Likewise. (cp_parser_omp_clause_simdlen): Likewise. (cp_parser_omp_clause_depend): Likewise. (cp_parser_omp_clause_device): Likewise. (cp_parser_omp_clause_dist_schedule): Likewise. (cp_parser_oacc_clause_async): Likewise. (cp_parser_omp_critical): Likewise. (cp_parser_omp_for_loop): Likewise. (cp_parser_omp_sections_scope): Likewise. (cp_parser_omp_declare_reduction_exprs): Likewise. Update for new param to cp_parser_required_error. (cp_parser_oacc_routine): Likewise. (cp_parser_transaction_expression): Likewise. (cp_parser_cilk_simd_vectorlength): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/missing-close-symbol.c: New test case. * c-c++-common/missing-symbol.c: New test case. * gcc.dg/unclosed-init.c: New test case. * g++.dg/diagnostic/unclosed-extern-c.C: New test case. * g++.dg/diagnostic/unclosed-function.C: New test case. * g++.dg/diagnostic/unclosed-namespace.C: New test case. * g++.dg/diagnostic/unclosed-struct.C: New test case. * g++.dg/parse/pragma2.C: Update to reflect movement of the "expected identifier" error. From-SVN: r251026 --- gcc/c-family/ChangeLog | 6 + gcc/c-family/c-common.c | 17 +- gcc/c-family/c-common.h | 3 +- gcc/c/ChangeLog | 84 ++ gcc/c/c-parser.c | 644 +++++++++----- gcc/c/c-parser.h | 8 +- gcc/cp/ChangeLog | 111 +++ gcc/cp/parser.c | 811 +++++++++++------- gcc/testsuite/ChangeLog | 12 + .../c-c++-common/missing-close-symbol.c | 33 + gcc/testsuite/c-c++-common/missing-symbol.c | 50 ++ .../g++.dg/diagnostic/unclosed-extern-c.C | 3 + .../g++.dg/diagnostic/unclosed-function.C | 3 + .../g++.dg/diagnostic/unclosed-namespace.C | 2 + .../g++.dg/diagnostic/unclosed-struct.C | 3 + gcc/testsuite/g++.dg/parse/pragma2.C | 4 +- gcc/testsuite/gcc.dg/unclosed-init.c | 3 + 17 files changed, 1279 insertions(+), 518 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/missing-close-symbol.c create mode 100644 gcc/testsuite/c-c++-common/missing-symbol.c create mode 100644 gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C create mode 100644 gcc/testsuite/g++.dg/diagnostic/unclosed-function.C create mode 100644 gcc/testsuite/g++.dg/diagnostic/unclosed-namespace.C create mode 100644 gcc/testsuite/g++.dg/diagnostic/unclosed-struct.C create mode 100644 gcc/testsuite/gcc.dg/unclosed-init.c diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 5c7454b8069..fcb4ea5169b 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2017-08-10 David Malcolm + + * c-common.c (c_parse_error): Add rich_location * param, using it + rather implicitly using input_location. + * c-common.h (c_parse_error): Add rich_location * param. + 2017-08-09 Marek Polacek * c-common.c (pointer_int_sum): Use true/false instead of 1/0. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index a9c0614b436..4dc3b338e5e 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5950,12 +5950,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)) @@ -5996,7 +5997,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; } @@ -6024,7 +6025,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; } @@ -6037,16 +6038,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 diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index b44e1bd78d6..980d39662fc 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/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 *); diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index a7cc74658d5..6e293345e99 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,87 @@ +2017-08-10 David Malcolm + + * c-parser.c (c_parser_error): Rename to... + (c_parser_error_richloc): ...this, making static, and adding + "richloc" parameter, passing it to the c_parse_error call, + rather than calling c_parser_set_source_position_from_token. + (c_parser_error): Reintroduce, reimplementing in terms of the + above, converting return type from void to bool. + (class token_pair): New class. + (struct matching_paren_traits): New struct. + (matching_parens): New typedef. + (struct matching_brace_traits): New struct. + (matching_braces): New typedef. + (get_matching_symbol): New function. + (c_parser_require): Add param MATCHING_LOCATION, using it to + highlight matching "opening" tokens for missing "closing" tokens. + (c_parser_skip_until_found): Likewise. + (c_parser_static_assert_declaration_no_semi): Convert explicit + parsing of CPP_OPEN_PAREN and CPP_CLOSE_PAREN to use of + class matching_parens, so that the pertinent open parenthesis is + highlighted when there are problems locating the close + parenthesis. + (c_parser_struct_or_union_specifier): Likewise. + (c_parser_typeof_specifier): Likewise. + (c_parser_alignas_specifier): Likewise. + (c_parser_simple_asm_expr): Likewise. + (c_parser_braced_init): Likewise, for matching_braces. + (c_parser_paren_condition): Likewise, for matching_parens. + (c_parser_switch_statement): Likewise. + (c_parser_for_statement): Likewise. + (c_parser_asm_statement): Likewise. + (c_parser_asm_operands): Likewise. + (c_parser_cast_expression): Likewise. + (c_parser_sizeof_expression): Likewise. + (c_parser_alignof_expression): Likewise. + (c_parser_generic_selection): Likewise. + (c_parser_postfix_expression): Likewise for cases RID_VA_ARG, + RID_OFFSETOF, RID_TYPES_COMPATIBLE_P, RID_AT_SELECTOR, + RID_AT_PROTOCOL, RID_AT_ENCODE, reindenting as necessary. + In case CPP_OPEN_PAREN, pass loc_open_paren to the + c_parser_skip_until_found call. + (c_parser_objc_class_definition): Use class matching_parens as + above. + (c_parser_objc_method_decl): Likewise. + (c_parser_objc_try_catch_finally_statement): Likewise. + (c_parser_objc_synchronized_statement): Likewise. + (c_parser_objc_at_property_declaration): Likewise. + (c_parser_oacc_wait_list): Likewise. + (c_parser_omp_var_list_parens): Likewise. + (c_parser_omp_clause_collapse): Likewise. + (c_parser_omp_clause_default): Likewise. + (c_parser_omp_clause_if): Likewise. + (c_parser_omp_clause_num_threads): Likewise. + (c_parser_omp_clause_num_tasks): Likewise. + (c_parser_omp_clause_grainsize): Likewise. + (c_parser_omp_clause_priority): Likewise. + (c_parser_omp_clause_hint): Likewise. + (c_parser_omp_clause_defaultmap): Likewise. + (c_parser_oacc_single_int_clause): Likewise. + (c_parser_omp_clause_ordered): Likewise. + (c_parser_omp_clause_reduction): Likewise. + (c_parser_omp_clause_schedule): Likewise. + (c_parser_omp_clause_num_teams): Likewise. + (c_parser_omp_clause_thread_limit): Likewise. + (c_parser_omp_clause_aligned): Likewise. + (c_parser_omp_clause_linear): Likewise. + (c_parser_omp_clause_safelen): Likewise. + (c_parser_omp_clause_simdlen): Likewise. + (c_parser_omp_clause_depend): Likewise. + (c_parser_omp_clause_map): Likewise. + (c_parser_omp_clause_device): Likewise. + (c_parser_omp_clause_dist_schedule): Likewise. + (c_parser_omp_clause_proc_bind): Likewise. + (c_parser_omp_clause_uniform): Likewise. + (c_parser_omp_for_loop): Likewise. + (c_parser_cilk_clause_vectorlength): Likewise. + (c_parser_cilk_clause_linear): Likewise. + (c_parser_transaction_expression): Likewise. + * c-parser.h (c_parser_require): Add param matching_location with + default UNKNOWN_LOCATION. + (c_parser_error): Convert return type from void to bool. + (c_parser_skip_until_found): Add param matching_location with + default UNKNOWN_LOCATION. + 2017-08-09 Marek Polacek * c-decl.c (build_enumerator): Use true/false instead of 1/0. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6d40a97d5f5..1402ba67204 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -850,21 +850,26 @@ 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. + Return true iff an error was actually emitted. + ??? 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 bool +c_parser_error_richloc (c_parser *parser, const char *gmsgid, + rich_location *richloc) { c_token *token = c_parser_peek_token (parser); if (parser->error) - return; + return false; parser->error = true; if (!gmsgid) - return; + return false; /* If this is actually a conflict marker, report it as such. */ if (token->type == CPP_LSHIFT @@ -875,13 +880,10 @@ c_parser_error (c_parser *parser, const char *gmsgid) if (c_parser_peek_conflict_marker (parser, token->type, &loc)) { error_at (loc, "version control conflict marker in file"); - return; + return true; } } - /* 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 +893,157 @@ 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); + return true; +} + +/* 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. */ + +bool +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); + return c_parser_error_richloc (parser, gmsgid, &richloc); +} + +/* Some tokens naturally come in pairs e.g.'(' and ')'. + This class is for tracking such a matching pair of symbols. + In particular, it tracks the location of the first token, + so that if the second token is missing, we can highlight the + location of the first token when notifying the user about the + problem. */ + +template +class token_pair +{ + public: + /* token_pair's ctor. */ + token_pair () : m_open_loc (UNKNOWN_LOCATION) {} + + /* If the next token is the opening symbol for this pair, consume it and + return true. + Otherwise, issue an error and return false. + In either case, record the location of the opening token. */ + + bool require_open (c_parser *parser) + { + c_token *token = c_parser_peek_token (parser); + if (token) + m_open_loc = token->location; + + return c_parser_require (parser, traits_t::open_token_type, + traits_t::open_gmsgid); + } + + /* Consume the next token from PARSER, recording its location as + that of the opening token within the pair. */ + + void consume_open (c_parser *parser) + { + c_token *token = c_parser_peek_token (parser); + gcc_assert (token->type == traits_t::open_token_type); + m_open_loc = token->location; + c_parser_consume_token (parser); + } + + /* If the next token is the closing symbol for this pair, consume it + and return true. + Otherwise, issue an error, highlighting the location of the + corresponding opening token, and return false. */ + + bool require_close (c_parser *parser) const + { + return c_parser_require (parser, traits_t::close_token_type, + traits_t::close_gmsgid, m_open_loc); + } + + /* Like token_pair::require_close, except that tokens will be skipped + until the desired token is found. An error message is still produced + if the next token is not as expected. */ + + void skip_until_found_close (c_parser *parser) const + { + c_parser_skip_until_found (parser, traits_t::close_token_type, + traits_t::close_gmsgid, m_open_loc); + } + + private: + location_t m_open_loc; +}; + +/* Traits for token_pair for tracking matching pairs of parentheses. */ + +struct matching_paren_traits +{ + static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN; + static const char * const open_gmsgid; + static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN; + static const char * const close_gmsgid; +}; + +const char * const matching_paren_traits::open_gmsgid = "expected %<(%>"; +const char * const matching_paren_traits::close_gmsgid = "expected %<)%>"; + +/* "matching_parens" is a token_pair class for tracking matching + pairs of parentheses. */ + +typedef token_pair matching_parens; + +/* Traits for token_pair for tracking matching pairs of braces. */ + +struct matching_brace_traits +{ + static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE; + static const char * const open_gmsgid; + static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE; + static const char * const close_gmsgid; +}; + +const char * const matching_brace_traits::open_gmsgid = "expected %<{%>"; +const char * const matching_brace_traits::close_gmsgid = "expected %<}%>"; + +/* "matching_braces" is a token_pair class for tracking matching + pairs of braces. */ + +typedef token_pair matching_braces; + +/* Get a description of the matching symbol to TYPE e.g. "(" for + CPP_CLOSE_PAREN. */ + +static const char * +get_matching_symbol (enum cpp_ttype type) +{ + switch (type) + { + default: + gcc_unreachable (); + return ""; + case CPP_CLOSE_PAREN: + return "("; + case CPP_CLOSE_BRACE: + return "{"; + } } /* 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 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). */ bool c_parser_require (c_parser *parser, enum cpp_ttype type, - const char *msgid) + const char *msgid, + location_t matching_location) { if (c_parser_next_token_is (parser, type)) { @@ -911,7 +1052,24 @@ c_parser_require (c_parser *parser, } else { - c_parser_error (parser, msgid); + location_t next_token_loc = c_parser_peek_token (parser)->location; + gcc_rich_location richloc (next_token_loc); + + /* If matching_location != UNKNOWN_LOCATION, highlight it. + Attempt to consolidate diagnostics by printing it as a + secondary range within the main diagnostic. */ + bool added_matching_location = false; + if (matching_location != UNKNOWN_LOCATION) + added_matching_location + = richloc.add_location_if_nearby (matching_location); + + if (c_parser_error_richloc (parser, msgid, &richloc)) + /* If we weren't able to consolidate matching_location, then + print it as a secondary diagnostic. */ + if (matching_location != UNKNOWN_LOCATION && !added_matching_location) + inform (matching_location, "to match this %qs", + get_matching_symbol (type)); + return false; } } @@ -940,16 +1098,22 @@ c_parser_require_keyword (c_parser *parser, desired token is found. An error message is still produced if the next token is not as expected. If MSGID is NULL then a message has already been produced and no message will be produced this - time. */ + time. + + 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). */ void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type, - const char *msgid) + const char *msgid, + location_t matching_location) { unsigned nesting_depth = 0; - if (c_parser_require (parser, type, msgid)) + if (c_parser_require (parser, type, msgid, matching_location)) return; /* Skip tokens until the desired token is found. */ @@ -2210,7 +2374,8 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) pedwarn_c99 (assert_loc, OPT_Wpedantic, "ISO C90 does not support %<_Static_assert%>"); c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return; location_t value_tok_loc = c_parser_peek_token (parser)->location; value = c_parser_expr_no_commas (parser, NULL).value; @@ -2237,7 +2402,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) parser->lex_untranslated_string = false; return; } - c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.require_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) { @@ -2922,7 +3087,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) tree name; gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) goto end_at_defs; if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) @@ -2936,8 +3102,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); goto end_at_defs; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); + parens.skip_until_found_close (parser); contents = nreverse (objc_get_class_ivars (name)); } end_at_defs: @@ -3224,7 +3389,8 @@ c_parser_typeof_specifier (c_parser *parser) c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; in_typeof++; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) { c_inhibit_evaluation_warnings--; in_typeof--; @@ -3265,7 +3431,7 @@ c_parser_typeof_specifier (c_parser *parser) if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec)) ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED); } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return ret; } @@ -3291,7 +3457,8 @@ c_parser_alignas_specifier (c_parser * parser) else pedwarn_c99 (loc, OPT_Wpedantic, "ISO C90 does not support %<_Alignas%>"); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return ret; if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) { @@ -3302,7 +3469,7 @@ c_parser_alignas_specifier (c_parser * parser) } else ret = c_parser_expr_no_commas (parser, NULL).value; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return ret; } @@ -3953,14 +4120,15 @@ c_parser_simple_asm_expr (c_parser *parser) lex_untranslated_string kludge. */ parser->lex_untranslated_string = true; c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) { parser->lex_untranslated_string = false; return NULL_TREE; } str = c_parser_asm_string_literal (parser); parser->lex_untranslated_string = false; - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + if (!parens.require_close (parser)) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; @@ -4398,7 +4566,8 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, location_t brace_loc = c_parser_peek_token (parser)->location; gcc_obstack_init (&braced_init_obstack); gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); - c_parser_consume_token (parser); + matching_braces braces; + braces.consume_open (parser); if (nested_p) { finish_implicit_inits (brace_loc, outer_obstack); @@ -4436,7 +4605,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, ret.value = error_mark_node; ret.original_code = ERROR_MARK; ret.original_type = NULL; - c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>"); + braces.skip_until_found_close (parser); pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma); obstack_free (&braced_init_obstack, NULL); return ret; @@ -5459,10 +5628,11 @@ static tree c_parser_paren_condition (c_parser *parser) { tree cond; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return error_mark_node; cond = c_parser_condition (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return cond; } @@ -5731,7 +5901,8 @@ c_parser_switch_statement (c_parser *parser, bool *if_p) c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); bool explicit_cast_p = false; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { switch_cond_loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) @@ -5746,7 +5917,7 @@ c_parser_switch_statement (c_parser *parser, bool *if_p) "%<_Cilk_spawn%> statement cannot be used as a condition for switch statement", switch_cond_loc)) expr = error_mark_node; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } else { @@ -5956,7 +6127,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep, bool *if_p) block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); cond = error_mark_node; incr = error_mark_node; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { /* Parse the initialization declaration or expression. */ object_expression = error_mark_node; @@ -6103,7 +6275,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, bool *if_p) incr = c_process_expr_stmt (loc, ce.value); } } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } save_break = c_break_label; c_break_label = NULL_TREE; @@ -6197,7 +6369,8 @@ c_parser_asm_statement (c_parser *parser) parser->lex_untranslated_string = true; ret = NULL; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) goto error; str = c_parser_asm_string_literal (parser); @@ -6255,7 +6428,7 @@ c_parser_asm_statement (c_parser *parser) } done_asm: - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + if (!parens.require_close (parser)) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); goto error; @@ -6320,7 +6493,8 @@ c_parser_asm_operands (c_parser *parser) if (str == NULL_TREE) return NULL_TREE; parser->lex_untranslated_string = false; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) { parser->lex_untranslated_string = true; return NULL_TREE; @@ -6328,7 +6502,7 @@ c_parser_asm_operands (c_parser *parser) expr = c_parser_expression (parser); mark_exp_read (expr.value); parser->lex_untranslated_string = true; - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + if (!parens.require_close (parser)) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; @@ -6940,9 +7114,10 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) struct c_type_name *type_name; struct c_expr ret; struct c_expr expr; - c_parser_consume_token (parser); + matching_parens parens; + parens.consume_open (parser); type_name = c_parser_type_name (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (type_name == NULL) { ret.value = error_mark_node; @@ -7169,10 +7344,11 @@ c_parser_sizeof_expression (c_parser *parser) /* Either sizeof ( type-name ) or sizeof unary-expression starting with a compound literal. */ struct c_type_name *type_name; - c_parser_consume_token (parser); + matching_parens parens; + parens.consume_open (parser); expr_loc = c_parser_peek_token (parser)->location; type_name = c_parser_type_name (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); finish = parser->tokens_buf[0].location; if (type_name == NULL) { @@ -7251,11 +7427,12 @@ c_parser_alignof_expression (c_parser *parser) location_t loc; struct c_type_name *type_name; struct c_expr ret; - c_parser_consume_token (parser); + matching_parens parens; + parens.consume_open (parser); loc = c_parser_peek_token (parser)->location; type_name = c_parser_type_name (parser); end_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (type_name == NULL) { struct c_expr ret; @@ -7414,7 +7591,8 @@ c_parser_generic_selection (c_parser *parser) pedwarn_c99 (generic_loc, OPT_Wpedantic, "ISO C90 does not support %<_Generic%>"); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return error_expr; c_inhibit_evaluation_warnings++; @@ -7556,7 +7734,7 @@ c_parser_generic_selection (c_parser *parser) c_parser_consume_token (parser); } - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + if (!parens.require_close (parser)) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return error_expr; @@ -7802,7 +7980,7 @@ c_parser_postfix_expression (c_parser *parser) location_t loc_close_paren = c_parser_peek_token (parser)->location; set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); + "expected %<)%>", loc_open_paren); } break; case CPP_KEYWORD: @@ -7839,7 +8017,8 @@ c_parser_postfix_expression (c_parser *parser) { location_t start_loc = loc; c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) { expr.set_error (); break; @@ -7879,25 +8058,25 @@ c_parser_postfix_expression (c_parser *parser) } break; case RID_OFFSETOF: - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - expr.set_error (); - break; - } - t1 = c_parser_type_name (parser); - if (t1 == NULL) - parser->error = true; - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - gcc_assert (parser->error); - if (parser->error) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - { + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + parser->error = true; + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + gcc_assert (parser->error); + if (parser->error) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } tree type = groktypename (t1, NULL, NULL); tree offsetof_ref; if (type == error_mark_node) @@ -8014,34 +8193,34 @@ c_parser_postfix_expression (c_parser *parser) break; } case RID_TYPES_COMPATIBLE_P: - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - expr.set_error (); - break; - } - t1 = c_parser_type_name (parser); - if (t1 == NULL) - { - expr.set_error (); - break; - } - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } - t2 = c_parser_type_name (parser); - if (t2 == NULL) - { - expr.set_error (); - break; - } { + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + { + expr.set_error (); + break; + } + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } + t2 = c_parser_type_name (parser); + if (t2 == NULL) + { + expr.set_error (); + break; + } location_t close_paren_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); + parens.skip_until_found_close (parser); tree e1, e2; e1 = groktypename (t1, NULL, NULL); e2 = groktypename (t2, NULL, NULL); @@ -8207,67 +8386,67 @@ c_parser_postfix_expression (c_parser *parser) break; } case RID_AT_SELECTOR: - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - expr.set_error (); - break; - } { + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } tree sel = c_parser_objc_selector_arg (parser); location_t close_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); + parens.skip_until_found_close (parser); expr.value = objc_build_selector_expr (loc, sel); set_c_expr_source_range (&expr, loc, close_loc); } break; case RID_AT_PROTOCOL: - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - expr.set_error (); - break; - } - if (c_parser_next_token_is_not (parser, CPP_NAME)) - { - c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.set_error (); - break; - } { + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + expr.set_error (); + break; + } tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); location_t close_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); + parens.skip_until_found_close (parser); expr.value = objc_build_protocol_expr (id); set_c_expr_source_range (&expr, loc, close_loc); } break; case RID_AT_ENCODE: - /* Extension to support C-structures in the archiver. */ - gcc_assert (c_dialect_objc ()); - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - expr.set_error (); - break; - } - t1 = c_parser_type_name (parser); - if (t1 == NULL) - { - expr.set_error (); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - break; - } { + /* Extension to support C-structures in the archiver. */ + gcc_assert (c_dialect_objc ()); + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + t1 = c_parser_type_name (parser); + if (t1 == NULL) + { + expr.set_error (); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + break; + } location_t close_loc = c_parser_peek_token (parser)->location; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); + parens.skip_until_found_close (parser); tree type = groktypename (t1, NULL, NULL); expr.value = objc_build_encode_expr (type); set_c_expr_source_range (&expr, loc, close_loc); @@ -8860,7 +9039,8 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes) /* We have a category or class extension. */ tree id2; tree proto = NULL_TREE; - c_parser_consume_token (parser); + matching_parens parens; + parens.consume_open (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) @@ -8880,7 +9060,7 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes) id2 = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!iface_p) { objc_start_category_implementation (id1, id2); @@ -9414,9 +9594,10 @@ c_parser_objc_method_decl (c_parser *parser, bool is_class_method, *attributes = NULL_TREE; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { - c_parser_consume_token (parser); + matching_parens parens; + parens.consume_open (parser); type = c_parser_objc_type_name (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } sel = c_parser_objc_selector (parser); /* If there is no selector, or a colon follows, we have an @@ -9622,7 +9803,8 @@ c_parser_objc_try_catch_finally_statement (c_parser *parser) bool seen_open_paren = false; c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) seen_open_paren = true; if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { @@ -9645,7 +9827,7 @@ c_parser_objc_try_catch_finally_statement (c_parser *parser) parameter_declaration = grokparm (parm, NULL); } if (seen_open_paren) - c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.require_close (parser); else { /* If there was no open parenthesis, we are recovering from @@ -9694,13 +9876,14 @@ c_parser_objc_synchronized_statement (c_parser *parser) c_parser_consume_token (parser); loc = c_parser_peek_token (parser)->location; objc_maybe_warn_exceptions (loc); - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { struct c_expr ce = c_parser_expression (parser); ce = convert_lvalue_to_rvalue (loc, ce, false, false); expr = ce.value; expr = c_fully_fold (expr, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } else expr = error_mark_node; @@ -9994,9 +10177,11 @@ c_parser_objc_at_property_declaration (c_parser *parser) /* Parse the optional attribute list... */ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { + matching_parens parens; + /* Eat the '(' */ - c_parser_consume_token (parser); - + parens.consume_open (parser); + /* Property attribute keywords are valid now. */ parser->objc_property_attr_context = true; @@ -10084,7 +10269,7 @@ c_parser_objc_at_property_declaration (c_parser *parser) break; } parser->objc_property_attr_context = false; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } /* ... and the property declaration(s). */ properties = c_parser_struct_declaration (parser); @@ -10744,7 +10929,8 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) vec *args; tree t, args_tree; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; args = c_parser_expr_list (parser, false, true, NULL, NULL, NULL, NULL); @@ -10781,7 +10967,7 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) } release_tree_vector (args); - c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.require_close (parser); return list; } @@ -10939,10 +11125,11 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, /* The clauses location. */ location_t loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { list = c_parser_omp_variable_list (parser, loc, kind, list); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } return list; } @@ -11079,10 +11266,11 @@ c_parser_omp_clause_collapse (c_parser *parser, tree list) check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile"); loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { num = c_parser_expr_no_commas (parser, NULL).value; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } if (num == error_mark_node) return list; @@ -11134,7 +11322,8 @@ c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) location_t loc = c_parser_peek_token (parser)->location; tree c; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -11174,7 +11363,7 @@ c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) else c_parser_error (parser, "expected % or %"); } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) return list; @@ -11237,7 +11426,8 @@ c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) location_t location = c_parser_peek_token (parser)->location; enum tree_code if_modifier = ERROR_MARK; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (is_omp && c_parser_next_token_is (parser, CPP_NAME)) @@ -11318,7 +11508,7 @@ c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) } tree t = c_parser_condition (parser), c; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) @@ -11417,7 +11607,8 @@ static tree c_parser_omp_clause_num_threads (c_parser *parser, tree list) { location_t num_threads_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -11425,7 +11616,7 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -11462,7 +11653,8 @@ static tree c_parser_omp_clause_num_tasks (c_parser *parser, tree list) { location_t num_tasks_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -11470,7 +11662,7 @@ c_parser_omp_clause_num_tasks (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -11507,7 +11699,8 @@ static tree c_parser_omp_clause_grainsize (c_parser *parser, tree list) { location_t grainsize_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -11515,7 +11708,7 @@ c_parser_omp_clause_grainsize (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -11552,7 +11745,8 @@ static tree c_parser_omp_clause_priority (c_parser *parser, tree list) { location_t priority_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -11560,7 +11754,7 @@ c_parser_omp_clause_priority (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -11598,7 +11792,8 @@ static tree c_parser_omp_clause_hint (c_parser *parser, tree list) { location_t hint_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -11606,7 +11801,7 @@ c_parser_omp_clause_hint (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -11635,7 +11830,8 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) tree c; const char *p; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (!c_parser_next_token_is (parser, CPP_NAME)) { @@ -11663,14 +11859,14 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) goto out_err; } c_parser_consume_token (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap"); c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); OMP_CLAUSE_CHAIN (c) = list; return c; out_err: - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return list; } @@ -11707,7 +11903,8 @@ c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code, { location_t loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; location_t expr_loc = c_parser_peek_token (parser)->location; @@ -11716,7 +11913,7 @@ c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code, tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (t == error_mark_node) return list; @@ -12046,9 +12243,10 @@ c_parser_omp_clause_ordered (c_parser *parser, tree list) location_t loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { - c_parser_consume_token (parser); + matching_parens parens; + parens.consume_open (parser); num = c_parser_expr_no_commas (parser, NULL).value; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } if (num == error_mark_node) return list; @@ -12102,7 +12300,8 @@ static tree c_parser_omp_clause_reduction (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { enum tree_code code = ERROR_MARK; tree reduc_id = NULL_TREE; @@ -12200,7 +12399,7 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) list = nl; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } return list; } @@ -12228,7 +12427,8 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list) location_t loc = c_parser_peek_token (parser)->location; int modifiers = 0, nmodifiers = 0; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); @@ -12339,7 +12539,7 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list) else c_parser_error (parser, "expected integer expression"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } else c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, @@ -12452,7 +12652,8 @@ static tree c_parser_omp_clause_num_teams (c_parser *parser, tree list) { location_t num_teams_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -12460,7 +12661,7 @@ c_parser_omp_clause_num_teams (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -12496,7 +12697,8 @@ static tree c_parser_omp_clause_thread_limit (c_parser *parser, tree list) { location_t num_thread_limit_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expression (parser); @@ -12504,7 +12706,7 @@ c_parser_omp_clause_thread_limit (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -12544,7 +12746,8 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) location_t clause_loc = c_parser_peek_token (parser)->location; tree nl, c; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; nl = c_parser_omp_variable_list (parser, clause_loc, @@ -12571,7 +12774,7 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return nl; } @@ -12590,7 +12793,8 @@ c_parser_omp_clause_linear (c_parser *parser, tree list, bool is_cilk_simd_fn) tree nl, c, step; enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (!is_cilk_simd_fn @@ -12613,7 +12817,7 @@ c_parser_omp_clause_linear (c_parser *parser, tree list, bool is_cilk_simd_fn) OMP_CLAUSE_LINEAR, list); if (kind != OMP_CLAUSE_LINEAR_DEFAULT) - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (c_parser_next_token_is (parser, CPP_COLON)) { @@ -12645,7 +12849,7 @@ c_parser_omp_clause_linear (c_parser *parser, tree list, bool is_cilk_simd_fn) OMP_CLAUSE_LINEAR_KIND (c) = kind; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return nl; } @@ -12658,7 +12862,8 @@ c_parser_omp_clause_safelen (c_parser *parser, tree list) location_t clause_loc = c_parser_peek_token (parser)->location; tree c, t; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; location_t expr_loc = c_parser_peek_token (parser)->location; @@ -12675,7 +12880,7 @@ c_parser_omp_clause_safelen (c_parser *parser, tree list) t = NULL_TREE; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (t == NULL_TREE || t == error_mark_node) return list; @@ -12696,7 +12901,8 @@ c_parser_omp_clause_simdlen (c_parser *parser, tree list) location_t clause_loc = c_parser_peek_token (parser)->location; tree c, t; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; location_t expr_loc = c_parser_peek_token (parser)->location; @@ -12713,7 +12919,7 @@ c_parser_omp_clause_simdlen (c_parser *parser, tree list) t = NULL_TREE; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (t == NULL_TREE || t == error_mark_node) return list; @@ -12825,7 +13031,8 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; tree nl, c; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (c_parser_next_token_is (parser, CPP_NAME)) @@ -12855,7 +13062,7 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) OMP_CLAUSE_DEPEND_KIND (c) = kind; OMP_CLAUSE_DECL (c) = NULL_TREE; OMP_CLAUSE_CHAIN (c) = list; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return c; } @@ -12873,13 +13080,13 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) OMP_CLAUSE_DEPEND_KIND (c) = kind; } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return nl; invalid_kind: c_parser_error (parser, "invalid depend kind"); resync_fail: - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return list; } @@ -12907,7 +13114,8 @@ c_parser_omp_clause_map (c_parser *parser, tree list) tree always_id = NULL_TREE; tree nl, c; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (c_parser_next_token_is (parser, CPP_NAME)) @@ -12974,7 +13182,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) if (always_id_kind != C_ID_ID) { c_parser_error (parser, "expected identifier"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return list; } @@ -12994,7 +13202,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) } if (always == 1) { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return list; } } @@ -13004,7 +13212,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return nl; } @@ -13015,7 +13223,8 @@ static tree c_parser_omp_clause_device (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { location_t expr_loc = c_parser_peek_token (parser)->location; c_expr expr = c_parser_expr_no_commas (parser, NULL); @@ -13023,7 +13232,7 @@ c_parser_omp_clause_device (c_parser *parser, tree list) tree c, t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { @@ -13052,7 +13261,8 @@ c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) tree c, t = NULL_TREE; location_t loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (!c_parser_next_token_is_keyword (parser, RID_STATIC)) @@ -13073,7 +13283,7 @@ c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); t = expr.value; t = c_fully_fold (t, false, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } else c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, @@ -13102,7 +13312,8 @@ c_parser_omp_clause_proc_bind (c_parser *parser, tree list) enum omp_clause_proc_bind_kind kind; tree c; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (c_parser_next_token_is (parser, CPP_NAME)) @@ -13121,7 +13332,7 @@ c_parser_omp_clause_proc_bind (c_parser *parser, tree list) goto invalid_kind; c_parser_consume_token (parser); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); OMP_CLAUSE_PROC_BIND_KIND (c) = kind; OMP_CLAUSE_CHAIN (c) = list; @@ -13129,7 +13340,7 @@ c_parser_omp_clause_proc_bind (c_parser *parser, tree list) invalid_kind: c_parser_error (parser, "invalid proc_bind kind"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return list; } @@ -13160,11 +13371,12 @@ c_parser_omp_clause_uniform (c_parser *parser, tree list) /* The clauses location. */ location_t loc = c_parser_peek_token (parser)->location; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM, list); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); } return list; } @@ -14957,7 +15169,8 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, { int bracecount = 0; - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) goto pop_scopes; /* Parse the initialization declaration or expression. */ @@ -15064,7 +15277,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, incr = c_process_expr_stmt (incr_loc, c_parser_expression (parser).value); } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); if (decl == NULL || decl == error_mark_node || init == error_mark_node) fail = true; @@ -17571,7 +17784,8 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses, clause. Represent it in OpenMP terms. */ check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength"); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return clauses; location_t loc = c_parser_peek_token (parser)->location; @@ -17607,7 +17821,7 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses, } } - c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.require_close (parser); return clauses; } @@ -17629,7 +17843,8 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses, static tree c_parser_cilk_clause_linear (c_parser *parser, tree clauses) { - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (!parens.require_open (parser)) return clauses; location_t loc = c_parser_peek_token (parser)->location; @@ -17691,7 +17906,7 @@ c_parser_cilk_clause_linear (c_parser *parser, tree clauses) c_parser_consume_token (parser); } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + parens.skip_until_found_close (parser); return clauses; } @@ -18055,7 +18270,8 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) } parser->in_transaction = this_in; - if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + matching_parens parens; + if (parens.require_open (parser)) { tree expr = c_parser_expression (parser).value; ret.original_type = TREE_TYPE (expr); @@ -18064,7 +18280,7 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) TRANSACTION_EXPR_RELAXED (ret.value) = 1; SET_EXPR_LOCATION (ret.value, loc); ret.original_code = TRANSACTION_EXPR; - if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + if (!parens.require_close (parser)) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); goto error; diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h index 1e344c40e27..01a7b724081 100644 --- a/gcc/c/c-parser.h +++ b/gcc/c/c-parser.h @@ -136,11 +136,13 @@ 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); -extern void c_parser_error (c_parser *parser, const char *gmsgid); + const char *msgid, + location_t matching_location = UNKNOWN_LOCATION); +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, - const char *msgid); + const char *msgid, + location_t = UNKNOWN_LOCATION); extern bool c_parser_next_token_starts_declspecs (c_parser *parser); bool c_parser_next_tokens_start_declaration (c_parser *parser); bool c_token_starts_typename (c_token *token); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d3510cf1965..bc0959cfef0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,114 @@ +2017-08-10 David Malcolm + + * parser.c (cp_parser_error): Update for new param to + c_parse_error. + (class token_pair): New class. + (struct matching_paren_traits): New struct. + (matching_parens): New typedef. + (struct matching_brace_traits): New struct. + (matching_braces): New typedef. + (cp_parser_statement_expr): Convert explicit parsing of + CPP_OPEN_PAREN and CPP_CLOSE_PAREN to use of + class matching_parens, so that the pertinent open parenthesis is + highlighted when there are problems locating the close + parenthesis. + (cp_parser_primary_expression): Likewise. + (cp_parser_compound_literal_p): Remove consumption of opening + paren. + (cp_parser_postfix_expression): Convert explicit parsing of + CPP_OPEN_PAREN and CPP_CLOSE_PAREN to use matching parens, as + above. Use it to consume the opening paren previously consumed by + cp_parser_compound_literal_p. + (cp_parser_parenthesized_expression_list): Likewise. + (cp_parser_unary_expression): Likewise. + (cp_parser_new_expression): Likewise. + (cp_parser_cast_expression): Likewise. + (cp_parser_builtin_offsetof): Likewise. + (cp_parser_trait_expr): Likewise. + (cp_parser_lambda_declarator_opt): Likewise. + (cp_parser_lambda_body): Likewise, for matching_braces. + (cp_parser_compound_statement): Likewise. + (cp_parser_selection_statement): Likewise, for matching_parens. + (cp_parser_iteration_statement): Likewise. + (cp_parser_already_scoped_statement): Likewise, for + matching_braces. + (cp_parser_linkage_specification): Likewise. + (cp_parser_static_assert): Likewise, for matching_parens. + (cp_parser_decltype): Likewise. + (cp_parser_operator): Likewise. + (cp_parser_enum_specifier): Likewise. + (cp_parser_namespace_definition): Likewise. + (cp_parser_direct_declarator): Likewise. + (cp_parser_braced_list): Likewise. + (cp_parser_class_specifier_1): Likewise, for matching_braces. + (cp_parser_constant_initializer): Likewise. + (cp_parser_noexcept_specification_opt): Likewise, for + matching_parens. + (cp_parser_exception_specification_opt): Likewise. + (cp_parser_handler): Likewise. + (cp_parser_asm_specification_opt): Likewise. + (cp_parser_asm_operand_list): Likewise. + (cp_parser_gnu_attributes_opt): Likewise. + (cp_parser_std_attribute_spec): Likewise. + (cp_parser_requirement_parameter_list): Likewise. + (cp_parser_requirement_body): Likewise, for matching_braces. + (cp_parser_compound_requirement): Likewise. + (cp_parser_template_introduction): Likewise. + (cp_parser_sizeof_pack): Likewise, for matching_parens. + (cp_parser_sizeof_operand): Likewise; use it to consume the + opening paren previously consumed by cp_parser_compound_literal_p. + (get_matching_symbol): New function. + (cp_parser_required_error): Add param "matching_location". Remove + calls to cp_parser_error, instead setting a non-NULL gmsgid, and + handling it if set by calling c_parse_error, potentially with a + secondary location if matching_location was set. + (cp_parser_require): Add param "matching_location", with a default + value of UNKNOWN_LOCATION. + (cp_parser_require_keyword): Update for new param of + cp_parser_required_error. + (cp_parser_objc_encode_expression): Update to class matching_parens + as above. + (cp_parser_objc_defs_expression): Likewise. + (cp_parser_objc_protocol_expression): Likewise. + (cp_parser_objc_selector_expression): Likewise. + (cp_parser_objc_typename): Likewise. + (cp_parser_objc_superclass_or_category): Likewise. + (cp_parser_objc_try_catch_finally_statement): Likewise. + (cp_parser_objc_synchronized_statement): Likewise. + (cp_parser_objc_at_property_declaration): Likewise. + (cp_parser_oacc_single_int_clause): Likewise. + (cp_parser_oacc_shape_clause): Likewise. + (cp_parser_omp_clause_collapse): Likewise. + (cp_parser_omp_clause_default): Likewise. + (cp_parser_omp_clause_final): Likewise. + (cp_parser_omp_clause_if): Likewise. + (cp_parser_omp_clause_num_threads): Likewise. + (cp_parser_omp_clause_num_tasks): Likewise. + (cp_parser_omp_clause_grainsize): Likewise. + (cp_parser_omp_clause_priority): Likewise. + (cp_parser_omp_clause_hint): Likewise. + (cp_parser_omp_clause_defaultmap): Likewise. + (cp_parser_omp_clause_ordered): Likewise. + (cp_parser_omp_clause_schedule): Likewise. + (cp_parser_omp_clause_num_teams): Likewise. + (cp_parser_omp_clause_thread_limit): Likewise. + (cp_parser_omp_clause_aligned): Likewise. + (cp_parser_omp_clause_linear): Likewise. + (cp_parser_omp_clause_safelen): Likewise. + (cp_parser_omp_clause_simdlen): Likewise. + (cp_parser_omp_clause_depend): Likewise. + (cp_parser_omp_clause_device): Likewise. + (cp_parser_omp_clause_dist_schedule): Likewise. + (cp_parser_oacc_clause_async): Likewise. + (cp_parser_omp_critical): Likewise. + (cp_parser_omp_for_loop): Likewise. + (cp_parser_omp_sections_scope): Likewise. + (cp_parser_omp_declare_reduction_exprs): Likewise. + Update for new param to cp_parser_required_error. + (cp_parser_oacc_routine): Likewise. + (cp_parser_transaction_expression): Likewise. + (cp_parser_cilk_simd_vectorlength): Likewise. + 2017-08-09 Jason Merrill PR c++/81525 - wrong constant value with generic lambda diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9d989a7f84f..b849824fcd0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2551,9 +2551,9 @@ static void set_and_check_decl_spec_loc static bool cp_parser_friend_p (const cp_decl_specifier_seq *); static void cp_parser_required_error - (cp_parser *, required_token, bool); + (cp_parser *, required_token, bool, location_t); static cp_token *cp_parser_require - (cp_parser *, enum cpp_ttype, required_token); + (cp_parser *, enum cpp_ttype, required_token, location_t = UNKNOWN_LOCATION); static cp_token *cp_parser_require_keyword (cp_parser *, enum rid, required_token); static bool cp_parser_token_starts_function_definition_p @@ -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); } } @@ -4503,6 +4504,90 @@ struct tentative_firewall } }; +/* Some tokens naturally come in pairs e.g.'(' and ')'. + This class is for tracking such a matching pair of symbols. + In particular, it tracks the location of the first token, + so that if the second token is missing, we can highlight the + location of the first token when notifying the user about the + problem. */ + +template +class token_pair +{ + public: + /* token_pair's ctor. */ + token_pair () : m_open_loc (UNKNOWN_LOCATION) {} + + /* If the next token is the opening symbol for this pair, consume it and + return true. + Otherwise, issue an error and return false. + In either case, record the location of the opening token. */ + + bool require_open (cp_parser *parser) + { + m_open_loc = cp_lexer_peek_token (parser->lexer)->location; + return cp_parser_require (parser, traits_t::open_token_type, + traits_t::required_token_open); + } + + /* Consume the next token from PARSER, recording its location as + that of the opening token within the pair. */ + + cp_token * consume_open (cp_parser *parser) + { + cp_token *tok = cp_lexer_consume_token (parser->lexer); + gcc_assert (tok->type == traits_t::open_token_type); + m_open_loc = tok->location; + return tok; + } + + /* If the next token is the closing symbol for this pair, consume it + and return it. + Otherwise, issue an error, highlighting the location of the + corresponding opening token, and return NULL. */ + + cp_token *require_close (cp_parser *parser) const + { + return cp_parser_require (parser, traits_t::close_token_type, + traits_t::required_token_close, + m_open_loc); + } + + private: + location_t m_open_loc; +}; + +/* Traits for token_pair for tracking matching pairs of parentheses. */ + +struct matching_paren_traits +{ + static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN; + static const enum required_token required_token_open = RT_OPEN_PAREN; + static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN; + static const enum required_token required_token_close = RT_CLOSE_PAREN; +}; + +/* "matching_parens" is a token_pair class for tracking matching + pairs of parentheses. */ + +typedef token_pair matching_parens; + +/* Traits for token_pair for tracking matching pairs of braces. */ + +struct matching_brace_traits +{ + static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE; + static const enum required_token required_token_open = RT_OPEN_BRACE; + static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE; + static const enum required_token required_token_close = RT_CLOSE_BRACE; +}; + +/* "matching_braces" is a token_pair class for tracking matching + pairs of braces. */ + +typedef token_pair matching_braces; + + /* Parse a GNU statement-expression, i.e. ({ stmts }), except for the enclosing parentheses. */ @@ -4513,7 +4598,8 @@ cp_parser_statement_expr (cp_parser *parser) /* Consume the '('. */ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); /* Start the statement-expression. */ tree expr = begin_stmt_expr (); /* Parse the compound-statement. */ @@ -4522,7 +4608,7 @@ cp_parser_statement_expr (cp_parser *parser) expr = finish_stmt_expr (expr, false); /* Consume the ')'. */ location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_end_of_statement (parser); cp_parser_end_tentative_firewall (parser, start, expr); @@ -4928,7 +5014,8 @@ cp_parser_primary_expression (cp_parser *parser, location_t open_paren_loc = token->location; /* Consume the `('. */ - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); /* Within a parenthesized expression, a `>' token is always the greater-than operator. */ saved_greater_than_is_operator_p @@ -4976,7 +5063,7 @@ cp_parser_primary_expression (cp_parser *parser, token = cp_lexer_peek_token (parser->lexer); location_t close_paren_loc = token->location; expr.set_range (open_paren_loc, close_paren_loc); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) + if (!parens.require_close (parser) && !cp_parser_uncommitted_to_tentative_parse_p (parser)) cp_parser_skip_to_end_of_statement (parser); @@ -5098,7 +5185,8 @@ cp_parser_primary_expression (cp_parser *parser, `va_arg'. Consume the `__builtin_va_arg' token. */ cp_lexer_consume_token (parser->lexer); /* Look for the opening `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Now, parse the assignment-expression. */ expression = cp_parser_assignment_expression (parser); /* Look for the `,'. */ @@ -5112,7 +5200,7 @@ cp_parser_primary_expression (cp_parser *parser, /* Look for the closing `)'. */ location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Using `va_arg' in a constant-expression is not allowed. */ if (cp_parser_non_integral_constant_expression (parser, @@ -6345,9 +6433,6 @@ cp_parser_qualifying_entity (cp_parser *parser, static bool cp_parser_compound_literal_p (cp_parser *parser) { - /* Consume the `('. */ - cp_lexer_consume_token (parser->lexer); - cp_lexer_save_tokens (parser->lexer); /* Skip tokens until the next token is a closing parenthesis. @@ -6465,7 +6550,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, parser->greater_than_is_operator_p = true; /* And the expression which is being cast. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); expression = cp_parser_expression (parser, & idk, /*cast_p=*/true); cp_token *close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); @@ -6526,7 +6612,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, /* Consume the `typeid' token. */ cp_lexer_consume_token (parser->lexer); /* Look for the `(' token. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Types cannot be defined in a `typeid' expression. */ saved_message = parser->type_definition_forbidden_message; parser->type_definition_forbidden_message @@ -6542,8 +6629,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, /* Look for the `)' token. Otherwise, we can't be sure that we're not looking at an expression: consider `typeid (int (3))', for example. */ - cp_token *close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN, - RT_CLOSE_PAREN); + cp_token *close_paren = parens.require_close (parser); /* If all went well, simply lookup the type-id. */ if (cp_parser_parse_definitely (parser)) postfix_expression = get_typeid (type, tf_warning_or_error); @@ -6557,8 +6643,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, /* Compute its typeid. */ postfix_expression = build_typeid (expression, tf_warning_or_error); /* Look for the `)' token. */ - close_paren - = cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + close_paren = parens.require_close (parser); } /* Restore the saved message. */ parser->type_definition_forbidden_message = saved_message; @@ -6759,6 +6844,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, cp_parser_parse_tentatively (parser); + matching_parens parens; + parens.consume_open (parser); + /* Avoid calling cp_parser_type_id pointlessly, see comment in cp_parser_cast_expression about c++/29234. */ if (!cp_parser_compound_literal_p (parser)) @@ -6770,8 +6858,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, parser->in_type_id_in_expr_p = true; type = cp_parser_type_id (parser); parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; - /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); } /* If things aren't going well, there's no need to @@ -7561,7 +7648,8 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, if (non_constant_p) *non_constant_p = false; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return NULL; expression_list = make_tree_vector (); @@ -7657,7 +7745,7 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, if (close_paren_loc) *close_paren_loc = cp_lexer_peek_token (parser->lexer)->location; - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) { int ending; @@ -7957,7 +8045,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, bool saved_greater_than_is_operator_p; cp_lexer_consume_token (parser->lexer); - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); saved_message = parser->type_definition_forbidden_message; parser->type_definition_forbidden_message @@ -7991,7 +8080,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, parser->type_definition_forbidden_message = saved_message; - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); return finish_noexcept_expr (expr, tf_warning_or_error); } @@ -8235,7 +8324,8 @@ cp_parser_new_expression (cp_parser* parser) const char *saved_message = parser->type_definition_forbidden_message; /* Consume the `('. */ - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); /* Parse the type-id. */ parser->type_definition_forbidden_message @@ -8247,7 +8337,7 @@ cp_parser_new_expression (cp_parser* parser) parser->type_definition_forbidden_message = saved_message; /* Look for the closing `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); token = cp_lexer_peek_token (parser->lexer); /* There should not be a direct-new-declarator in this production, but GCC used to allowed this, so we check and emit a sensible error @@ -8787,7 +8877,8 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, parser->type_definition_forbidden_message = G_("types may not be defined in casts"); /* Consume the `('. */ - cp_token *open_paren = cp_lexer_consume_token (parser->lexer); + matching_parens parens; + cp_token *open_paren = parens.consume_open (parser); location_t open_paren_loc = open_paren->location; location_t close_paren_loc = UNKNOWN_LOCATION; @@ -8852,8 +8943,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, /* Look for the type-id. */ type = cp_parser_type_id (parser); /* Look for the closing `)'. */ - cp_token *close_paren - = cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + cp_token *close_paren = parens.require_close (parser); if (close_paren) close_paren_loc = close_paren->location; parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; @@ -9638,7 +9728,8 @@ cp_parser_builtin_offsetof (cp_parser *parser) /* Consume the "__builtin_offsetof" token. */ cp_lexer_consume_token (parser->lexer); /* Consume the opening `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Parse the type-id. */ location_t loc = cp_lexer_peek_token (parser->lexer)->location; type = cp_parser_type_id (parser); @@ -9688,7 +9779,7 @@ cp_parser_builtin_offsetof (cp_parser *parser) default: /* Error. We know the following require will fail, but that gives the proper error message. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); cp_parser_skip_to_closing_parenthesis (parser, true, false, true); expr = error_mark_node; goto failure; @@ -9834,7 +9925,8 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) /* Consume the token. */ cp_lexer_consume_token (parser->lexer); - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); { type_id_in_expr_sentinel s (parser); @@ -9873,7 +9965,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) } } - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Complete the trait expression, which may mean either processing the trait expr now or saving it for template instantiation. */ @@ -10354,7 +10446,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) opening parenthesis if present. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); begin_scope (sk_function_parms, /*entity=*/NULL_TREE); @@ -10369,7 +10462,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_Wpedantic, "default argument specified for lambda parameter"); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); attributes = cp_parser_attributes_opt (parser); @@ -10526,7 +10619,8 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) start_lambda_scope (fco); body = begin_function_body (); - if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + matching_braces braces; + if (!braces.require_open (parser)) goto out; /* Push the proxies for any explicit captures. */ @@ -10567,7 +10661,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) expr = cp_parser_expression (parser, &idk); cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); if (cp_parser_parse_definitely (parser)) { @@ -10591,7 +10685,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL)) cp_parser_label_declaration (parser); cp_parser_statement_seq_opt (parser, NULL_TREE); - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); } finish_compound_stmt (compound_stmt); @@ -11127,9 +11221,10 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, int bcs_flags, bool function_body) { tree compound_stmt; + matching_braces braces; /* Consume the `{'. */ - if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + if (!braces.require_open (parser)) return error_mark_node; if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) && !function_body && cxx_dialect < cxx14) @@ -11145,7 +11240,7 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, /* Finish the compound-statement. */ finish_compound_stmt (compound_stmt); /* Consume the `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); return compound_stmt; } @@ -11266,7 +11361,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, } /* Look for the `('. */ - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) { cp_parser_skip_to_end_of_statement (parser); return error_mark_node; @@ -11295,7 +11391,7 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, /* Parse the condition. */ condition = cp_parser_condition (parser); /* Look for the `)'. */ - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, true, false, /*consume_paren=*/true); @@ -12082,12 +12178,13 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) /* Begin the while-statement. */ statement = begin_while_stmt (); /* Look for the `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Parse the condition. */ condition = cp_parser_condition (parser); finish_while_stmt_cond (condition, statement, ivdep); /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Parse the dependent statement. */ parser->in_statement = IN_ITERATION_STMT; cp_parser_already_scoped_statement (parser, if_p, guard_tinfo); @@ -12111,13 +12208,14 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) /* Look for the `while' keyword. */ cp_parser_require_keyword (parser, RID_WHILE, RT_WHILE); /* Look for the `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Parse the expression. */ expression = cp_parser_expression (parser); /* We're done with the do-statement. */ finish_do_stmt (expression, statement, ivdep); /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Look for the `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); } @@ -12126,12 +12224,13 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) case RID_FOR: { /* Look for the `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); statement = cp_parser_for (parser, ivdep); /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Parse the body of the for-statement. */ parser->in_statement = IN_ITERATION_STMT; @@ -12481,13 +12580,14 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p, { /* Avoid calling cp_parser_compound_statement, so that we don't create a new scope. Do everything else by hand. */ - cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); + matching_braces braces; + braces.require_open (parser); /* If the next keyword is `__label__' we have a label declaration. */ while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL)) cp_parser_label_declaration (parser); /* Parse an (optional) statement-seq. */ cp_parser_statement_seq_opt (parser, NULL_TREE); - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); } } @@ -13714,11 +13814,12 @@ cp_parser_linkage_specification (cp_parser* parser) cp_ensure_no_oacc_routine (parser); /* Consume the `{' token. */ - cp_lexer_consume_token (parser->lexer); + matching_braces braces; + braces.consume_open (parser)->location; /* Parse the declarations. */ cp_parser_declaration_seq_opt (parser); /* Look for the closing `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); } /* Otherwise, there's just one declaration. */ else @@ -13770,7 +13871,8 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) cp_parser_commit_to_tentative_parse (parser); /* Parse the `(' starting the static assertion condition. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Parse the constant-expression. Allow a non-constant expression here in order to give better diagnostics in finish_static_assert. */ @@ -13802,7 +13904,7 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) /*wide_ok=*/true); /* A `)' completes the static assertion. */ - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, @@ -13956,7 +14058,8 @@ cp_parser_decltype (cp_parser *parser) return error_mark_node; /* Parse the opening `('. */ - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return error_mark_node; /* decltype (auto) */ @@ -13964,7 +14067,7 @@ cp_parser_decltype (cp_parser *parser) && cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO)) { cp_lexer_consume_token (parser->lexer); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) return error_mark_node; expr = make_decltype_auto (); AUTO_IS_DECLTYPE (expr) = true; @@ -14019,7 +14122,7 @@ cp_parser_decltype (cp_parser *parser) = saved_non_integral_constant_expression_p; /* Parse to the closing `)'. */ - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) { cp_parser_skip_to_closing_parenthesis (parser, true, false, /*consume_paren=*/true); @@ -14718,11 +14821,14 @@ cp_parser_operator (cp_parser* parser) break; case CPP_OPEN_PAREN: - /* Consume the `('. */ - cp_lexer_consume_token (parser->lexer); - /* Look for the matching `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); - return cp_operator_id (CALL_EXPR); + { + /* Consume the `('. */ + matching_parens parens; + parens.consume_open (parser); + /* Look for the matching `)'. */ + parens.require_close (parser); + return cp_operator_id (CALL_EXPR); + } case CPP_OPEN_SQUARE: /* Consume the `['. */ @@ -18095,7 +18201,8 @@ cp_parser_enum_specifier (cp_parser* parser) begin_scope (sk_scoped_enum, type); /* Consume the opening brace. */ - cp_lexer_consume_token (parser->lexer); + matching_braces braces; + braces.consume_open (parser); if (type == error_mark_node) ; /* Nothing to add */ @@ -18128,7 +18235,7 @@ cp_parser_enum_specifier (cp_parser* parser) cp_parser_enumerator_list (parser, type); /* Consume the final '}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); if (scoped_enum_p) finish_scope (); @@ -18421,13 +18528,14 @@ cp_parser_namespace_definition (cp_parser* parser) warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace); /* Look for the `{' to validate starting the namespace. */ - if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + matching_braces braces; + if (braces.require_open (parser)) { /* Parse the body of the namespace. */ cp_parser_namespace_body (parser); /* Look for the final `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); } if (has_visibility) @@ -19808,7 +19916,8 @@ cp_parser_direct_declarator (cp_parser* parser, cp_parser_parse_tentatively (parser); /* Consume the `('. */ - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); if (first) { /* If this is going to be an abstract declarator, we're @@ -19823,7 +19932,7 @@ cp_parser_direct_declarator (cp_parser* parser, params = cp_parser_parameter_declaration_clause (parser); /* Consume the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* If all went well, parse the cv-qualifier-seq, ref-qualifier and the exception-specification. */ @@ -19919,7 +20028,8 @@ cp_parser_direct_declarator (cp_parser* parser, parser->in_declarator_p = saved_in_declarator_p; /* Consume the `('. */ - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); /* Parse the nested declarator. */ saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; parser->in_type_id_in_expr_p = true; @@ -19930,7 +20040,7 @@ cp_parser_direct_declarator (cp_parser* parser, parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; first = false; /* Expect a `)'. */ - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) declarator = cp_error_declarator; if (declarator == cp_error_declarator) break; @@ -21778,7 +21888,8 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; /* Consume the `{' token. */ - cp_lexer_consume_token (parser->lexer); + matching_braces braces; + braces.consume_open (parser); /* Create a CONSTRUCTOR to represent the braced-initializer. */ initializer = make_node (CONSTRUCTOR); /* If it's not a `}', then there is a non-trivial initializer. */ @@ -21795,7 +21906,7 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) *non_constant_p = false; /* Now, there should be a trailing `}'. */ location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); TREE_TYPE (initializer) = init_list_type_node; cp_expr result (initializer); @@ -22222,7 +22333,8 @@ cp_parser_class_specifier_1 (cp_parser* parser) } /* Look for the `{'. */ - if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + matching_braces braces; + if (!braces.require_open (parser)) { pop_deferring_access_checks (); return error_mark_node; @@ -22274,7 +22386,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) cp_parser_member_specification_opt (parser); /* Look for the trailing `}'. */ - closing_brace = cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + closing_brace = braces.require_close (parser); /* Look for trailing attributes to apply to this class. */ if (cp_parser_allow_gnu_extensions_p (parser)) attributes = cp_parser_gnu_attributes_opt (parser); @@ -23753,11 +23865,12 @@ cp_parser_constant_initializer (cp_parser* parser) cp_parser_error (parser, "a brace-enclosed initializer is not allowed here"); /* Consume the opening brace. */ - cp_lexer_consume_token (parser->lexer); + matching_braces braces; + braces.consume_open (parser); /* Skip the initializer. */ cp_parser_skip_to_closing_brace (parser); /* Look for the trailing `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); return error_mark_node; } @@ -24013,7 +24126,8 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) { - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); if (require_constexpr) { @@ -24033,7 +24147,7 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, *consumed_expr = true; } - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); } else { @@ -24087,7 +24201,8 @@ cp_parser_exception_specification_opt (cp_parser* parser) cp_lexer_consume_token (parser->lexer); /* Look for the `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -24123,7 +24238,7 @@ cp_parser_exception_specification_opt (cp_parser* parser) type_id_list = empty_except_spec; /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); return type_id_list; } @@ -24270,10 +24385,11 @@ cp_parser_handler (cp_parser* parser) cp_parser_require_keyword (parser, RID_CATCH, RT_CATCH); handler = begin_handler (); - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); declaration = cp_parser_exception_declaration (parser); finish_handler_parms (declaration, handler); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false); finish_handler (handler); } @@ -24389,13 +24505,14 @@ cp_parser_asm_specification_opt (cp_parser* parser) /* Consume the `asm' token. */ cp_lexer_consume_token (parser->lexer); /* Look for the `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Look for the string-literal. */ asm_specification = cp_parser_string_literal (parser, false, false); /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); return asm_specification; } @@ -24447,11 +24564,12 @@ cp_parser_asm_operand_list (cp_parser* parser) string_literal = cp_parser_string_literal (parser, false, false); /* Look for the `('. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); /* Parse the expression. */ expression = cp_parser_expression (parser); /* Look for the `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); if (name == error_mark_node || string_literal == error_mark_node @@ -24705,8 +24823,10 @@ cp_parser_gnu_attributes_opt (cp_parser* parser) /* Consume the `__attribute__' keyword. */ cp_lexer_consume_token (parser->lexer); /* Look for the two `(' tokens. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens outer_parens; + outer_parens.require_open (parser); + matching_parens inner_parens; + inner_parens.require_open (parser); /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -24719,9 +24839,9 @@ cp_parser_gnu_attributes_opt (cp_parser* parser) attribute_list = NULL; /* Look for the two `)' tokens. */ - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!inner_parens.require_close (parser)) ok = false; - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!outer_parens.require_close (parser)) ok = false; if (!ok) cp_parser_skip_to_end_of_statement (parser); @@ -25148,7 +25268,8 @@ cp_parser_std_attribute_spec (cp_parser *parser) cp_lexer_consume_token (parser->lexer); maybe_warn_cpp0x (CPP0X_ATTRIBUTES); - if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN) == NULL) + matching_parens parens; + if (!parens.require_open (parser)) { cp_parser_error (parser, "expected %<(%>"); return error_mark_node; @@ -25181,7 +25302,7 @@ cp_parser_std_attribute_spec (cp_parser *parser) if (alignas_expr == error_mark_node) return error_mark_node; - if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) == NULL) + if (!parens.require_close (parser)) { cp_parser_error (parser, "expected %<)%>"); return error_mark_node; @@ -25413,12 +25534,13 @@ cp_parser_requires_expression (cp_parser *parser) static tree cp_parser_requirement_parameter_list (cp_parser *parser) { - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return error_mark_node; tree parms = cp_parser_parameter_declaration_clause (parser); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) return error_mark_node; return parms; @@ -25431,12 +25553,13 @@ cp_parser_requirement_parameter_list (cp_parser *parser) static tree cp_parser_requirement_body (cp_parser *parser) { - if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + matching_braces braces; + if (!braces.require_open (parser)) return error_mark_node; tree reqs = cp_parser_requirement_list (parser); - if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE)) + if (!braces.require_close (parser)) return error_mark_node; return reqs; @@ -25575,14 +25698,15 @@ static tree cp_parser_compound_requirement (cp_parser *parser) { /* Parse an expression enclosed in '{ }'s. */ - if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + matching_braces braces; + if (!braces.require_open (parser)) return error_mark_node; tree expr = cp_parser_expression (parser, NULL, false, false); if (!expr || expr == error_mark_node) return error_mark_node; - if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE)) + if (!braces.require_close (parser)) return error_mark_node; /* Parse the optional noexcept. */ @@ -26653,7 +26777,8 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p) cp_parser_simulate_error (parser); /* Look for opening brace for introduction. */ - cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); + matching_braces braces; + braces.require_open (parser); if (!cp_parser_parse_definitely (parser)) return false; @@ -26673,7 +26798,7 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p) } /* Look for closing brace for introduction. */ - if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE)) + if (!braces.require_close (parser)) return true; if (tmpl_decl == error_mark_node) @@ -27558,9 +27683,10 @@ cp_parser_sizeof_pack (cp_parser *parser) cp_lexer_consume_token (parser->lexer); maybe_warn_variadic_templates (); + matching_parens parens; bool paren = cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN); if (paren) - cp_lexer_consume_token (parser->lexer); + parens.consume_open (parser); else permerror (cp_lexer_peek_token (parser->lexer)->location, "% argument must be surrounded by parentheses"); @@ -27585,7 +27711,7 @@ cp_parser_sizeof_pack (cp_parser *parser) PACK_EXPANSION_SIZEOF_P (expr) = true; if (paren) - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); return expr; } @@ -27639,6 +27765,10 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) /* We can't be sure yet whether we're looking at a type-id or an expression. */ cp_parser_parse_tentatively (parser); + + matching_parens parens; + parens.consume_open (parser); + /* Note: as a GNU Extension, compound literals are considered postfix-expressions as they are in C99, so they are valid arguments to sizeof. See comment in cp_parser_cast_expression @@ -27652,7 +27782,7 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) /* Look for the type-id. */ type = cp_parser_type_id (parser); /* Look for the closing `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; } @@ -27934,187 +28064,245 @@ cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers) return decl_spec_seq_has_spec_p (decl_specifiers, ds_friend); } +/* Get a description of the matching symbol to TOKEN_DESC e.g. "(" for + RT_CLOSE_PAREN. */ + +static const char * +get_matching_symbol (required_token token_desc) +{ + switch (token_desc) + { + default: + gcc_unreachable (); + return ""; + case RT_CLOSE_BRACE: + return "{"; + case RT_CLOSE_PAREN: + return "("; + } +} + /* 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 - a indicated keyword. */ + a indicated keyword. + + 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 TOKEN_DESC is + RT_CLOSE_PAREN). */ static void cp_parser_required_error (cp_parser *parser, required_token token_desc, - bool keyword) + bool keyword, + location_t matching_location) { + if (cp_parser_simulate_error (parser)) + return; + + const char *gmsgid = NULL; switch (token_desc) { case RT_NEW: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_DELETE: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_RETURN: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_WHILE: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_EXTERN: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_STATIC_ASSERT: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_DECLTYPE: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_OPERATOR: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_CLASS: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_TEMPLATE: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_NAMESPACE: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_USING: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_ASM: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_TRY: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_CATCH: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + break; case RT_THROW: - cp_parser_error (parser, "expected %"); - return; + gmsgid = G_("expected %"); + 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 %, %, or %"); - return; + gmsgid = G_("expected %, %, or %"); + 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); + + gcc_rich_location richloc (input_location); + + /* If matching_location != UNKNOWN_LOCATION, highlight it. + Attempt to consolidate diagnostics by printing it as a + secondary range within the main diagnostic. */ + bool added_matching_location = false; + if (matching_location != UNKNOWN_LOCATION) + added_matching_location + = richloc.add_location_if_nearby (matching_location); + + c_parse_error (gmsgid, + (token->type == CPP_KEYWORD ? CPP_NAME : token->type), + token->u.value, token->flags, &richloc); + + /* If we weren't able to consolidate matching_location, then + print it as a secondary diagnostic. */ + if (matching_location != UNKNOWN_LOCATION && !added_matching_location) + inform (matching_location, "to match this %qs", + get_matching_symbol (token_desc)); + } +} /* If the next token is of the indicated TYPE, consume it. Otherwise, issue an error message indicating that TOKEN_DESC was expected. Returns the token consumed, if the token had the appropriate type. - Otherwise, returns NULL. */ + Otherwise, returns NULL. + + 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 TOKEN_DESC is + RT_CLOSE_PAREN). */ static cp_token * cp_parser_require (cp_parser* parser, enum cpp_ttype type, - required_token token_desc) + required_token token_desc, + location_t matching_location) { if (cp_lexer_next_token_is (parser->lexer, type)) return cp_lexer_consume_token (parser->lexer); @@ -28122,7 +28310,8 @@ cp_parser_require (cp_parser* parser, { /* Output the MESSAGE -- unless we're parsing tentatively. */ if (!cp_parser_simulate_error (parser)) - cp_parser_required_error (parser, token_desc, /*keyword=*/false); + cp_parser_required_error (parser, token_desc, /*keyword=*/false, + matching_location); return NULL; } } @@ -28224,7 +28413,8 @@ cp_parser_require_keyword (cp_parser* parser, if (token && token->keyword != keyword) { - cp_parser_required_error (parser, token_desc, /*keyword=*/true); + cp_parser_required_error (parser, token_desc, /*keyword=*/true, + UNKNOWN_LOCATION); return NULL; } @@ -29046,10 +29236,11 @@ cp_parser_objc_encode_expression (cp_parser* parser) location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@encode'. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); token = cp_lexer_peek_token (parser->lexer); type = complete_type (cp_parser_type_id (parser)); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); if (!type) { @@ -29091,9 +29282,10 @@ cp_parser_objc_defs_expression (cp_parser *parser) tree name; cp_lexer_consume_token (parser->lexer); /* Eat '@defs'. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); name = cp_parser_identifier (parser); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); return objc_get_class_ivars (name); } @@ -29112,9 +29304,10 @@ cp_parser_objc_protocol_expression (cp_parser* parser) location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@protocol'. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); proto = cp_parser_identifier (parser); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Build a location of the form: @protocol(prot) @@ -29152,7 +29345,8 @@ cp_parser_objc_selector_expression (cp_parser* parser) location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@selector'. */ - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); token = cp_lexer_peek_token (parser->lexer); while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON @@ -29199,7 +29393,7 @@ cp_parser_objc_selector_expression (cp_parser* parser) } finish_selector: - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* Build a location of the form: @@ -29406,7 +29600,8 @@ cp_parser_objc_typename (cp_parser* parser) { tree proto_quals, cp_type = NULL_TREE; - cp_lexer_consume_token (parser->lexer); /* Eat '('. */ + matching_parens parens; + parens.consume_open (parser); /* Eat '('. */ proto_quals = cp_parser_objc_protocol_qualifiers (parser); /* An ObjC type name may consist of just protocol qualifiers, in which @@ -29432,7 +29627,7 @@ cp_parser_objc_typename (cp_parser* parser) } } - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); type_name = build_tree_list (proto_quals, cp_type); } @@ -30046,7 +30241,8 @@ cp_parser_objc_superclass_or_category (cp_parser *parser, } else if (next->type == CPP_OPEN_PAREN) { - cp_lexer_consume_token (parser->lexer); /* Eat '('. */ + matching_parens parens; + parens.consume_open (parser); /* Eat '('. */ /* If there is no category name, and this is an @interface, we have a class extension. */ @@ -30058,7 +30254,7 @@ cp_parser_objc_superclass_or_category (cp_parser *parser, else *categ = cp_parser_identifier (parser); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); } } @@ -30246,9 +30442,10 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) cp_parameter_declarator *parm; tree parameter_declaration = error_mark_node; bool seen_open_paren = false; + matching_parens parens; cp_lexer_consume_token (parser->lexer); - if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + if (parens.require_open (parser)) seen_open_paren = true; if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) { @@ -30274,7 +30471,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) /*attrlist=*/NULL); } if (seen_open_paren) - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); else { /* If there was no open parenthesis, we are recovering from @@ -30328,9 +30525,10 @@ cp_parser_objc_synchronized_statement (cp_parser *parser) location = cp_lexer_peek_token (parser->lexer)->location; objc_maybe_warn_exceptions (location); - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); lock = cp_parser_expression (parser); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); /* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST node, lest it get absorbed into the surrounding block. */ @@ -30571,7 +30769,8 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { /* Eat the '('. */ - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); while (true) { @@ -30659,7 +30858,7 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) "error: expected ‘)’ before ‘,’ token". This is because cp_parser_require, unlike the C counterpart, will produce an error even if we are in error recovery. */ - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) { cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, @@ -31350,13 +31549,14 @@ cp_parser_oacc_single_int_clause (cp_parser *parser, omp_clause_code code, { location_t loc = cp_lexer_peek_token (parser->lexer)->location; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; tree t = cp_parser_assignment_expression (parser, NULL, false, false); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) { cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, @@ -31403,7 +31603,8 @@ cp_parser_oacc_shape_clause (cp_parser *parser, omp_clause_code kind, if (cp_lexer_next_token_is (lexer, CPP_OPEN_PAREN)) { - cp_lexer_consume_token (lexer); + matching_parens parens; + parens.consume_open (parser); do { @@ -31477,7 +31678,7 @@ cp_parser_oacc_shape_clause (cp_parser *parser, omp_clause_code kind, } while (1); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) goto cleanup_error; } @@ -31623,12 +31824,13 @@ cp_parser_omp_clause_collapse (cp_parser *parser, tree list, location_t location HOST_WIDE_INT n; loc = cp_lexer_peek_token (parser->lexer)->location; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; num = cp_parser_constant_expression (parser); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -31667,7 +31869,8 @@ cp_parser_omp_clause_default (cp_parser *parser, tree list, enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; tree c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -31710,7 +31913,7 @@ cp_parser_omp_clause_default (cp_parser *parser, tree list, } if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -31734,13 +31937,14 @@ cp_parser_omp_clause_final (cp_parser *parser, tree list, location_t location) { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_condition (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -31771,7 +31975,8 @@ cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location, tree t, c; enum tree_code if_modifier = ERROR_MARK; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (is_omp && cp_lexer_next_token_is (parser->lexer, CPP_NAME)) @@ -31854,7 +32059,7 @@ cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location, t = cp_parser_condition (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -31949,13 +32154,14 @@ cp_parser_omp_clause_num_threads (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -31979,13 +32185,14 @@ cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32009,13 +32216,14 @@ cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32039,13 +32247,14 @@ cp_parser_omp_clause_priority (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32069,13 +32278,14 @@ cp_parser_omp_clause_hint (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32099,7 +32309,8 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, tree c, id; const char *p; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) @@ -32131,7 +32342,7 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, goto out_err; } cp_lexer_consume_token (parser->lexer); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) goto out_err; check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap", @@ -32166,11 +32377,12 @@ cp_parser_omp_clause_ordered (cp_parser *parser, if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); num = cp_parser_constant_expression (parser); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32327,7 +32539,8 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list, location_t location tree c, t; int modifiers = 0, nmodifiers = 0; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; c = build_omp_clause (location, OMP_CLAUSE_SCHEDULE); @@ -32421,7 +32634,7 @@ cp_parser_omp_clause_schedule (cp_parser *parser, tree list, location_t location else OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) goto resync_fail; } else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) @@ -32527,13 +32740,14 @@ cp_parser_omp_clause_num_teams (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32557,13 +32771,14 @@ cp_parser_omp_clause_thread_limit (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32588,7 +32803,8 @@ cp_parser_omp_clause_aligned (cp_parser *parser, tree list) tree nlist, c, alignment = NULL_TREE; bool colon; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALIGNED, list, @@ -32598,7 +32814,7 @@ cp_parser_omp_clause_aligned (cp_parser *parser, tree list) { alignment = cp_parser_constant_expression (parser); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32629,7 +32845,8 @@ cp_parser_omp_clause_linear (cp_parser *parser, tree list, bool colon; enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (!is_cilk_simd_fn @@ -32659,7 +32876,7 @@ cp_parser_omp_clause_linear (cp_parser *parser, tree list, colon = cp_lexer_next_token_is (parser->lexer, CPP_COLON); if (colon) cp_parser_require (parser, CPP_COLON, RT_COLON); - else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + else if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32697,7 +32914,7 @@ cp_parser_omp_clause_linear (cp_parser *parser, tree list, sorry ("using parameters for % step is not supported yet"); step = integer_one_node; } - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32724,13 +32941,14 @@ cp_parser_omp_clause_safelen (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_constant_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32753,13 +32971,14 @@ cp_parser_omp_clause_simdlen (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_constant_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -32875,7 +33094,8 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) tree nlist, c; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) @@ -32907,7 +33127,7 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) OMP_CLAUSE_DEPEND_KIND (c) = kind; OMP_CLAUSE_DECL (c) = NULL_TREE; OMP_CLAUSE_CHAIN (c) = list; - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -33038,13 +33258,14 @@ cp_parser_omp_clause_device (cp_parser *parser, tree list, { tree t, c; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -33069,7 +33290,8 @@ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, { tree c, t; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return list; c = build_omp_clause (location, OMP_CLAUSE_DIST_SCHEDULE); @@ -33088,7 +33310,7 @@ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, goto resync_fail; OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) goto resync_fail; } else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) @@ -33174,11 +33396,12 @@ cp_parser_oacc_clause_async (cp_parser *parser, tree list) if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) { - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); t = cp_parser_expression (parser); if (t == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -34228,12 +34451,13 @@ cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok, bool *if_p) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - cp_lexer_consume_token (parser->lexer); + matching_parens parens; + parens.consume_open (parser); name = cp_parser_identifier (parser); if (name == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -34731,7 +34955,8 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, } loc = cp_lexer_consume_token (parser->lexer)->location; - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return NULL; init = orig_init = decl = real_decl = NULL; @@ -34863,7 +35088,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, protected_set_expr_location (incr, input_location); } - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); @@ -35222,7 +35447,8 @@ cp_parser_omp_sections_scope (cp_parser *parser) bool error_suppress = false; cp_token *tok; - if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + matching_braces braces; + if (!braces.require_open (parser)) return NULL_TREE; stmt = push_stmt_list (); @@ -35259,7 +35485,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + braces.require_close (parser); substmt = pop_stmt_list (stmt); @@ -37121,7 +37347,8 @@ cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) if (strcmp (p, "initializer") == 0) { cp_lexer_consume_token (parser->lexer); - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return false; p = ""; @@ -37212,12 +37439,13 @@ cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) if (ctor) add_decl_expr (omp_orig); - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) return false; } if (!cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)) - cp_parser_required_error (parser, RT_PRAGMA_EOL, /*keyword=*/false); + cp_parser_required_error (parser, RT_PRAGMA_EOL, /*keyword=*/false, + UNKNOWN_LOCATION); return true; } @@ -37645,7 +37873,8 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, /* Look for optional '( name )'. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - cp_lexer_consume_token (parser->lexer); /* '(' */ + matching_parens parens; + parens.consume_open (parser); /* '(' */ /* We parse the name as an id-expression. If it resolves to anything other than a non-overloaded function at namespace @@ -37662,7 +37891,7 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, name_loc); if (decl == error_mark_node - || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + || !parens.require_close (parser)) { cp_parser_skip_to_pragma_eol (parser, pragma_tok); parser->oacc_routine = NULL; @@ -38094,12 +38323,13 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) if (!noex || !noex_expr || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) { - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + matching_parens parens; + parens.require_open (parser); expr = cp_parser_expression (parser); expr = finish_parenthesized_expr (expr); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + parens.require_close (parser); } else { @@ -38687,7 +38917,8 @@ cp_parser_cilk_simd_vectorlength (cp_parser *parser, tree clauses, check_no_duplicate_clause (clauses, OMP_CLAUSE_SIMDLEN, "vectorlength", loc); - if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + matching_parens parens; + if (!parens.require_open (parser)) return error_mark_node; expr = cp_parser_constant_expression (parser); @@ -38724,7 +38955,7 @@ cp_parser_cilk_simd_vectorlength (cp_parser *parser, tree clauses, } } - if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + if (!parens.require_close (parser)) return error_mark_node; return clauses; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a1e72369cd3..869e7b02098 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2017-08-10 David Malcolm + + * c-c++-common/missing-close-symbol.c: New test case. + * c-c++-common/missing-symbol.c: New test case. + * gcc.dg/unclosed-init.c: New test case. + * g++.dg/diagnostic/unclosed-extern-c.C: New test case. + * g++.dg/diagnostic/unclosed-function.C: New test case. + * g++.dg/diagnostic/unclosed-namespace.C: New test case. + * g++.dg/diagnostic/unclosed-struct.C: New test case. + * g++.dg/parse/pragma2.C: Update to reflect movement of the + "expected identifier" error. + 2017-08-10 Fritz Reese * gfortran.dg/dec_d_lines_1.f: New test. diff --git a/gcc/testsuite/c-c++-common/missing-close-symbol.c b/gcc/testsuite/c-c++-common/missing-close-symbol.c new file mode 100644 index 00000000000..85b96f28ef8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/missing-close-symbol.c @@ -0,0 +1,33 @@ +/* { dg-options "-fdiagnostics-show-caret" } */ + +/* Verify that the C/C++ frontends show the pertinent opening symbol when + a closing symbol is missing. */ + +/* Verify that, when they are on the same line, that the opening symbol is + shown as a secondary range within the main diagnostic. */ + +void test_static_assert_same_line (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 "" } */ +} + +/* Verify that, when they are on different lines, that the opening symbol is + shown via a secondary diagnostic. */ + +void test_static_assert_different_line (void) +{ + _Static_assert(sizeof(int) >= sizeof(char), /* { dg-message "to match this '\\('" } */ + "msg"; /* { dg-error "expected '\\)' before ';' token" } */ + /* { dg-begin-multiline-output "" } + "msg"; + ^ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + _Static_assert(sizeof(int) >= sizeof(char), + ^ + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/c-c++-common/missing-symbol.c b/gcc/testsuite/c-c++-common/missing-symbol.c new file mode 100644 index 00000000000..33a501b9988 --- /dev/null +++ b/gcc/testsuite/c-c++-common/missing-symbol.c @@ -0,0 +1,50 @@ +/* { dg-options "-fdiagnostics-show-caret" } */ + +extern int foo (void); +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 "" } */ + /* { dg-begin-multiline-output "" } + switch (i + ^ + { dg-end-multiline-output "" } */ + + case 0: + return 5; + default: + return i; + } +} /* { dg-error "1: expected" } */ + /* { dg-begin-multiline-output "" } + } + ^ + { dg-end-multiline-output "" } */ + +void missing_close_paren_in_if (void) +{ + if (foo () /* { dg-line start_of_if } */ + && bar () + { /* { dg-error "5: expected '\\)' before '.' token" } */ + /* { dg-begin-multiline-output "" } + { + ^ + { 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-error "1: expected" } */ + /* { dg-begin-multiline-output "" } + } + ^ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C new file mode 100644 index 00000000000..fda3532266d --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C @@ -0,0 +1,3 @@ +extern "C" { /* { dg-message "12: to match this '.'" } */ + +void test (void); /* { dg-error "17: expected '.' at end of input" } */ diff --git a/gcc/testsuite/g++.dg/diagnostic/unclosed-function.C b/gcc/testsuite/g++.dg/diagnostic/unclosed-function.C new file mode 100644 index 00000000000..e1e15504172 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-function.C @@ -0,0 +1,3 @@ +void test (void) +{ /* { dg-message "1: to match this '.'" } */ + int filler; /* { dg-error "13: expected '.' at end of input" } */ diff --git a/gcc/testsuite/g++.dg/diagnostic/unclosed-namespace.C b/gcc/testsuite/g++.dg/diagnostic/unclosed-namespace.C new file mode 100644 index 00000000000..ff113226cc7 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-namespace.C @@ -0,0 +1,2 @@ +namespace unclosed { /* { dg-message "20: to match this '.'" } */ +int filler; /* { dg-error "11: expected '.' at end of input" } */ diff --git a/gcc/testsuite/g++.dg/diagnostic/unclosed-struct.C b/gcc/testsuite/g++.dg/diagnostic/unclosed-struct.C new file mode 100644 index 00000000000..8c206bbecc4 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-struct.C @@ -0,0 +1,3 @@ +struct unclosed { /* { dg-message "17: to match this '.'" } */ + int dummy; /* { dg-error "12: expected '.' at end of input" } */ + // { dg-error "expected unqualified-id at end of input" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/parse/pragma2.C b/gcc/testsuite/g++.dg/parse/pragma2.C index c5616ff74f5..3dc5fc17788 100644 --- a/gcc/testsuite/g++.dg/parse/pragma2.C +++ b/gcc/testsuite/g++.dg/parse/pragma2.C @@ -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); diff --git a/gcc/testsuite/gcc.dg/unclosed-init.c b/gcc/testsuite/gcc.dg/unclosed-init.c new file mode 100644 index 00000000000..c0e4dd8da9b --- /dev/null +++ b/gcc/testsuite/gcc.dg/unclosed-init.c @@ -0,0 +1,3 @@ +int unclosed[] = { /* { dg-message "18: to match this '.'" } */ + 42 + /* { dg-error "0: expected '.' at end of input" } */ -- 2.30.2