This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/3] Matching tokens: C parts (v2)


Changed in v2:

* Renamed template argument to traits_t; eliminated subclasses, just
  using traits struct.
* Moved enum constants into struct bodies (string constants can't be
  without constexpr, which isn't available in C++98).
* Fixed typo.

OK for trunk?

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/testsuite/ChangeLog:
	* gcc.dg/unclosed-init.c: New test case.
---
 gcc/c/c-parser.c                     | 644 +++++++++++++++++++++++------------
 gcc/c/c-parser.h                     |   8 +-
 gcc/testsuite/gcc.dg/unclosed-init.c |   3 +
 3 files changed, 438 insertions(+), 217 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/unclosed-init.c

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 16cd357..3803154 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 <typename traits_t>
+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<T> 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<T> class for tracking matching
+   pairs of parentheses.  */
+
+typedef token_pair<matching_paren_traits> matching_parens;
+
+/* Traits for token_pair<T> 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<T> class for tracking matching
+   pairs of braces.  */
+
+typedef token_pair<matching_brace_traits> 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;
@@ -4395,7 +4563,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);
@@ -4433,7 +4602,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;
@@ -5456,10 +5625,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;
 }
 
@@ -5728,7 +5898,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)
@@ -5743,7 +5914,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
     {
@@ -5953,7 +6124,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;
@@ -6100,7 +6272,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;
@@ -6194,7 +6366,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);
@@ -6252,7 +6425,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;
@@ -6317,7 +6490,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;
@@ -6325,7 +6499,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;
@@ -6934,9 +7108,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;
@@ -7163,10 +7338,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)
 	{
@@ -7245,11 +7421,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;
@@ -7408,7 +7585,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++;
@@ -7550,7 +7728,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;
@@ -7796,7 +7974,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:
@@ -7833,7 +8011,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;
@@ -7873,25 +8052,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)
@@ -8008,34 +8187,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);
@@ -8201,67 +8380,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);
@@ -8854,7 +9033,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))
@@ -8874,7 +9054,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);
@@ -9408,9 +9588,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
@@ -9616,7 +9797,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))
 	{
@@ -9639,7 +9821,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
@@ -9688,13 +9870,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;
@@ -9988,9 +10171,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;
 
@@ -10078,7 +10263,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);
@@ -10738,7 +10923,8 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list)
   vec<tree, va_gc> *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);
@@ -10775,7 +10961,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;
 }
 
@@ -10933,10 +11119,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;
 }
@@ -11073,10 +11260,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;
@@ -11128,7 +11316,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))
     {
@@ -11168,7 +11357,7 @@ c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc)
       else
 	c_parser_error (parser, "expected %<none%> or %<shared%>");
     }
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  parens.skip_until_found_close (parser);
 
   if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
     return list;
@@ -11231,7 +11420,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))
@@ -11312,7 +11502,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)
@@ -11411,7 +11601,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);
@@ -11419,7 +11610,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)))
 	{
@@ -11456,7 +11647,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);
@@ -11464,7 +11656,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)))
 	{
@@ -11501,7 +11693,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);
@@ -11509,7 +11702,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)))
 	{
@@ -11546,7 +11739,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);
@@ -11554,7 +11748,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)))
 	{
@@ -11592,7 +11786,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);
@@ -11600,7 +11795,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)))
 	{
@@ -11629,7 +11824,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))
     {
@@ -11657,14 +11853,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;
 }
 
@@ -11701,7 +11897,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;
@@ -11710,7 +11907,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;
@@ -12040,9 +12237,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;
@@ -12096,7 +12294,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;
@@ -12194,7 +12393,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;
 }
@@ -12222,7 +12421,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);
@@ -12333,7 +12533,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,
@@ -12446,7 +12646,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);
@@ -12454,7 +12655,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)))
 	{
@@ -12490,7 +12691,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);
@@ -12498,7 +12700,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)))
 	{
@@ -12538,7 +12740,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,
@@ -12565,7 +12768,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;
 }
 
@@ -12584,7 +12787,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
@@ -12607,7 +12811,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))
     {
@@ -12639,7 +12843,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;
 }
 
@@ -12652,7 +12856,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;
@@ -12669,7 +12874,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;
 
@@ -12690,7 +12895,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;
@@ -12707,7 +12913,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;
 
@@ -12819,7 +13025,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))
@@ -12849,7 +13056,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;
     }
 
@@ -12867,13 +13074,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;
 }
 
@@ -12901,7 +13108,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))
@@ -12968,7 +13176,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;
 	}
 
@@ -12988,7 +13196,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;
 	}
     }
@@ -12998,7 +13206,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;
 }
 
@@ -13009,7 +13217,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);
@@ -13017,7 +13226,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)))
 	{
@@ -13046,7 +13255,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))
@@ -13067,7 +13277,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,
@@ -13096,7 +13306,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))
@@ -13115,7 +13326,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;
@@ -13123,7 +13334,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;
 }
 
@@ -13154,11 +13365,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;
 }
@@ -14951,7 +15163,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.  */
@@ -15058,7 +15271,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;
@@ -17565,7 +17778,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;
@@ -17601,7 +17815,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;
 }
@@ -17623,7 +17837,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;
@@ -17685,7 +17900,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;
 }
@@ -18049,7 +18264,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);
@@ -18058,7 +18274,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/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" } */
-- 
1.8.5.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]