From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 40259 invoked by alias); 1 Aug 2017 19:47:27 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 39310 invoked by uid 89); 1 Aug 2017 19:47:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS,T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.2 spammy=idk, surrounded, (unknown) 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; Tue, 01 Aug 2017 19:47:06 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5E3C4FF325; Tue, 1 Aug 2017 19:47:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 5E3C4FF325 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dmalcolm@redhat.com Received: from c64.redhat.com (ovpn-112-25.phx2.redhat.com [10.3.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4736E61B8B; Tue, 1 Aug 2017 19:47:04 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: Trevor Saunders , David Malcolm Subject: [PATCH 3/3] matching tokens: C++ parts (v2) Date: Tue, 01 Aug 2017 19:47:00 -0000 Message-Id: <1501618904-5593-4-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1501618904-5593-1-git-send-email-dmalcolm@redhat.com> References: <20170712131300.u3ofifbzkp52lcxa@ball> <1501618904-5593-1-git-send-email-dmalcolm@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-IsSubscribed: yes X-SW-Source: 2017-08/txt/msg00117.txt.bz2 Changed in v2: * Renamed template argument to traits_t; eliminated subclasses, just using traits struct. * Moved constants into struct bodies. * Fixed typo. OK for trunk? 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_postfix_expression): Likewise. (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. (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: * 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/cp/parser.c | 811 +++++++++++++-------- .../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 +- 6 files changed, 539 insertions(+), 287 deletions(-) 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 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 88d0b2b..efbc376 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,100 @@ 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; + } + + /* Peek the next token from PARSER, recording its location as + that of the opening token within the pair. */ + + void peek_open (cp_parser *parser) + { + cp_token *tok = cp_lexer_peek_token (parser->lexer); + gcc_assert (tok->type == traits_t::open_token_type); + m_open_loc = tok->location; + } + + /* 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 +4608,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 +4618,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 +5024,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 +5073,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 +5195,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 +5210,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, @@ -6465,7 +6563,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 +6625,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 +6642,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 +6656,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; @@ -7561,7 +7659,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 +7756,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 +8056,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 +8091,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 +8335,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 +8348,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 +8888,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 +8954,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 +9739,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 +9790,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 +9936,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 +9976,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 +10457,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 +10473,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 +10630,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 +10672,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 +10696,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 +11232,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 +11251,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 +11372,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 +11402,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 +12189,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 +12219,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 +12235,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 +12591,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 +13825,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 +13882,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 +13915,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 +14069,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 +14078,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 +14133,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 +14832,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 +18212,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 +18246,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 +18539,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 +19927,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 +19943,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 +20039,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 +20051,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 +21899,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 +21917,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 +22344,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 +22397,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 +23876,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 +24137,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 +24158,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 +24212,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 +24249,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 +24396,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 +24516,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 +24575,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 +24834,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 +24850,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); @@ -25144,7 +25275,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; @@ -25177,7 +25309,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; @@ -25409,12 +25541,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; @@ -25427,12 +25560,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; @@ -25571,14 +25705,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. */ @@ -26649,7 +26784,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; @@ -26669,7 +26805,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) @@ -27554,9 +27690,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"); @@ -27581,7 +27718,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; } @@ -27632,6 +27769,9 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) { tree type = NULL_TREE; + matching_parens parens; + parens.peek_open (parser); + /* We can't be sure yet whether we're looking at a type-id or an expression. */ cp_parser_parse_tentatively (parser); @@ -27648,7 +27788,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; } @@ -27930,187 +28070,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); @@ -28118,7 +28316,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; } } @@ -28220,7 +28419,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; } @@ -29031,10 +29231,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) { @@ -29076,9 +29277,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); } @@ -29097,9 +29299,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) @@ -29137,7 +29340,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 @@ -29184,7 +29388,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: @@ -29391,7 +29595,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 @@ -29417,7 +29622,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); } @@ -30031,7 +30236,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. */ @@ -30043,7 +30249,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); } } @@ -30231,9 +30437,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)) { @@ -30259,7 +30466,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 @@ -30313,9 +30520,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. */ @@ -30556,7 +30764,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) { @@ -30644,7 +30853,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, @@ -31335,13 +31544,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, @@ -31388,7 +31598,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 { @@ -31462,7 +31673,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; } @@ -31608,12 +31819,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); @@ -31652,7 +31864,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)) { @@ -31695,7 +31908,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); @@ -31719,13 +31932,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); @@ -31756,7 +31970,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)) @@ -31839,7 +32054,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); @@ -31934,13 +32149,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); @@ -31964,13 +32180,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); @@ -31994,13 +32211,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); @@ -32024,13 +32242,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); @@ -32054,13 +32273,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); @@ -32084,7 +32304,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)) @@ -32116,7 +32337,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", @@ -32151,11 +32372,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); @@ -32312,7 +32534,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); @@ -32406,7 +32629,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)) @@ -32512,13 +32735,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); @@ -32542,13 +32766,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); @@ -32573,7 +32798,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, @@ -32583,7 +32809,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); @@ -32614,7 +32840,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 @@ -32644,7 +32871,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); @@ -32682,7 +32909,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); @@ -32709,13 +32936,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); @@ -32738,13 +32966,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); @@ -32860,7 +33089,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)) @@ -32892,7 +33122,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); @@ -33023,13 +33253,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); @@ -33054,7 +33285,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); @@ -33073,7 +33305,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)) @@ -33159,11 +33391,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); @@ -34213,12 +34446,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); @@ -34716,7 +34950,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; @@ -34848,7 +35083,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); @@ -35207,7 +35442,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 (); @@ -35244,7 +35480,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); @@ -37106,7 +37342,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 = ""; @@ -37197,12 +37434,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; } @@ -37630,7 +37868,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 @@ -37647,7 +37886,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; @@ -38079,12 +38318,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 { @@ -38672,7 +38912,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); @@ -38709,7 +38950,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/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); -- 1.8.5.3