From patchwork Thu Aug 10 14:10:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 800204 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-460177-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="F5nyxsZd"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xSq0r33tSz9t2W for ; Thu, 10 Aug 2017 23:36:26 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; q=dns; s= default; b=UnRfXH3pxHVjDSFAbK7rUA51MRJ08c2BNVMH+r+5fi0rhAa3hG4qs FNcQSn8KxaE81RDxG5XhYMBPfNQiOm93H5hckf/oMo7Iq7YAyXfMvl9uBJ6mZ96l VQ2jMwQaeBh8x8acpHei4ag/u7vJYgSzCVSytmW77hJGZ5QX/SOncY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=default; bh=cz4rHR0Px5MSn8Jb1r5uioSVB+w=; b=F5nyxsZdnk8QM4j0qvDi8LYCyv9q CDBLOtAxwlfqCAfurXYaNfaVGNSD4MvD9y9cQNrv0rjbIjJvQ8uuWuAtCJHZe+pF t0eZ0QOcB+K2peuD0QIzj3pdN76k8gwng4kEMNviH786QgKUiObvE7Znnu4Z1xAu 7dQB7sv+fVKWlHM= Received: (qmail 49832 invoked by alias); 10 Aug 2017 13:35:57 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 49692 invoked by uid 89); 10 Aug 2017 13:35:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS, T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.2 spammy=74117 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 10 Aug 2017 13:35:33 +0000 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C366D40244 for ; Thu, 10 Aug 2017 13:35:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com C366D40244 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dmalcolm@redhat.com Received: from c64.redhat.com (ovpn-112-12.phx2.redhat.com [10.3.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id BD107956AD; Thu, 10 Aug 2017 13:35:29 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [committed, v3] C/C++: show pertinent open token when missing a close token Date: Thu, 10 Aug 2017 10:10:34 -0400 Message-Id: <1502374234-62016-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1501618904-5593-1-git-send-email-dmalcolm@redhat.com> References: <1501618904-5593-1-git-send-email-dmalcolm@redhat.com> MIME-Version: 1.0 X-IsSubscribed: yes For reference, here's the combined patch I committed just now (as r251026), after double-checking bootstrap®rtest on x86_64-pc-linux-gnu. Thanks Marek, Trevor, Jason, Jeff, and Martin for review. Dave 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. --- gcc/c-family/c-common.c | 17 +- gcc/c-family/c-common.h | 3 +- gcc/c/c-parser.c | 644 ++++++++++------ gcc/c/c-parser.h | 8 +- gcc/cp/parser.c | 811 +++++++++++++-------- gcc/testsuite/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 + gcc/testsuite/g++.dg/diagnostic/unclosed-struct.C | 3 + gcc/testsuite/g++.dg/parse/pragma2.C | 4 +- gcc/testsuite/gcc.dg/unclosed-init.c | 3 + 13 files changed, 1066 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/c-common.c b/gcc/c-family/c-common.c index feb0904..30b0603 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5949,12 +5949,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)) @@ -5995,7 +5996,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; } @@ -6023,7 +6024,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; } @@ -6036,16 +6037,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 a29f1ad..63fe845 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/c-parser.c b/gcc/c/c-parser.c index 606c07c..e13bbdc 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; @@ -6937,9 +7111,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; @@ -7166,10 +7341,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) { @@ -7248,11 +7424,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; @@ -7411,7 +7588,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++; @@ -7553,7 +7731,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; @@ -7799,7 +7977,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: @@ -7836,7 +8014,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; @@ -7876,25 +8055,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) @@ -8011,34 +8190,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); @@ -8204,67 +8383,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); @@ -8857,7 +9036,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)) @@ -8877,7 +9057,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); @@ -9411,9 +9591,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 @@ -9619,7 +9800,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)) { @@ -9642,7 +9824,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 @@ -9691,13 +9873,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; @@ -9991,9 +10174,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; @@ -10081,7 +10266,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); @@ -10741,7 +10926,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); @@ -10778,7 +10964,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; } @@ -10936,10 +11122,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; } @@ -11076,10 +11263,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; @@ -11131,7 +11319,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)) { @@ -11171,7 +11360,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; @@ -11234,7 +11423,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)) @@ -11315,7 +11505,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) @@ -11414,7 +11604,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); @@ -11422,7 +11613,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))) { @@ -11459,7 +11650,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); @@ -11467,7 +11659,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))) { @@ -11504,7 +11696,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); @@ -11512,7 +11705,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))) { @@ -11549,7 +11742,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); @@ -11557,7 +11751,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))) { @@ -11595,7 +11789,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); @@ -11603,7 +11798,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))) { @@ -11632,7 +11827,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)) { @@ -11660,14 +11856,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; } @@ -11704,7 +11900,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; @@ -11713,7 +11910,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; @@ -12043,9 +12240,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; @@ -12099,7 +12297,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; @@ -12197,7 +12396,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; } @@ -12225,7 +12424,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); @@ -12336,7 +12536,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, @@ -12449,7 +12649,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); @@ -12457,7 +12658,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))) { @@ -12493,7 +12694,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); @@ -12501,7 +12703,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))) { @@ -12541,7 +12743,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, @@ -12568,7 +12771,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; } @@ -12587,7 +12790,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 @@ -12610,7 +12814,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)) { @@ -12642,7 +12846,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; } @@ -12655,7 +12859,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; @@ -12672,7 +12877,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; @@ -12693,7 +12898,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; @@ -12710,7 +12916,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; @@ -12822,7 +13028,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)) @@ -12852,7 +13059,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; } @@ -12870,13 +13077,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; } @@ -12904,7 +13111,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)) @@ -12971,7 +13179,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; } @@ -12991,7 +13199,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; } } @@ -13001,7 +13209,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; } @@ -13012,7 +13220,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); @@ -13020,7 +13229,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))) { @@ -13049,7 +13258,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)) @@ -13070,7 +13280,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, @@ -13099,7 +13309,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)) @@ -13118,7 +13329,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; @@ -13126,7 +13337,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; } @@ -13157,11 +13368,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; } @@ -14954,7 +15166,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. */ @@ -15061,7 +15274,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; @@ -17568,7 +17781,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; @@ -17604,7 +17818,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; } @@ -17626,7 +17840,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; @@ -17688,7 +17903,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; } @@ -18052,7 +18267,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); @@ -18061,7 +18277,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 1e344c4..01a7b72 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/parser.c b/gcc/cp/parser.c index 23bd278..0da92ab 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; } @@ -29035,10 +29225,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) { @@ -29080,9 +29271,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); } @@ -29101,9 +29293,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) @@ -29141,7 +29334,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 @@ -29188,7 +29382,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: @@ -29395,7 +29589,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 @@ -29421,7 +29616,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); } @@ -30035,7 +30230,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. */ @@ -30047,7 +30243,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); } } @@ -30235,9 +30431,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)) { @@ -30263,7 +30460,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 @@ -30317,9 +30514,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. */ @@ -30560,7 +30758,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) { @@ -30648,7 +30847,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, @@ -31339,13 +31538,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, @@ -31392,7 +31592,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 { @@ -31466,7 +31667,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; } @@ -31612,12 +31813,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); @@ -31656,7 +31858,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)) { @@ -31699,7 +31902,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); @@ -31723,13 +31926,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); @@ -31760,7 +31964,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)) @@ -31843,7 +32048,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); @@ -31938,13 +32143,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); @@ -31968,13 +32174,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); @@ -31998,13 +32205,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); @@ -32028,13 +32236,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); @@ -32058,13 +32267,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); @@ -32088,7 +32298,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)) @@ -32120,7 +32331,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", @@ -32155,11 +32366,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); @@ -32316,7 +32528,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); @@ -32410,7 +32623,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)) @@ -32516,13 +32729,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); @@ -32546,13 +32760,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); @@ -32577,7 +32792,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, @@ -32587,7 +32803,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); @@ -32618,7 +32834,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 @@ -32648,7 +32865,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); @@ -32686,7 +32903,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); @@ -32713,13 +32930,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); @@ -32742,13 +32960,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); @@ -32864,7 +33083,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)) @@ -32896,7 +33116,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); @@ -33027,13 +33247,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); @@ -33058,7 +33279,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); @@ -33077,7 +33299,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)) @@ -33163,11 +33385,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); @@ -34217,12 +34440,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); @@ -34720,7 +34944,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; @@ -34852,7 +35077,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); @@ -35211,7 +35436,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 (); @@ -35248,7 +35474,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); @@ -37110,7 +37336,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 = ""; @@ -37201,12 +37428,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; } @@ -37634,7 +37862,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 @@ -37651,7 +37880,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; @@ -38083,12 +38312,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 { @@ -38676,7 +38906,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); @@ -38713,7 +38944,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/c-c++-common/missing-close-symbol.c b/gcc/testsuite/c-c++-common/missing-close-symbol.c new file mode 100644 index 0000000..85b96f28 --- /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 0000000..33a501b --- /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 0000000..fda3532 --- /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 0000000..e1e1550 --- /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 0000000..ff11322 --- /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 0000000..8c206bb --- /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 c5616ff..3dc5fc1 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 0000000..c0e4dd8 --- /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" } */