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] Fix PR c/28649: Poor error recovery of C parser


The following testcase contains three bugs:

  void foo()
  {
     +;
     +;
  }

  int +;

But the C frontend only reports the first one:

  bug.c: In function 'foo':
  bug.c:3: error: expected expression before ';' token

The old yacc-based parser reported two bugs:

  bug.c: In function 'foo':
  bug.c:3: error: parse error before ';' token
  bug.c: At top level:
  bug.c:7: error: parse error before '+' token

The C++ frontend reports all, btw.:

  bug.cc: In function 'void foo()':
  bug.cc:3: error: expected primary-expression before ';' token
  bug.cc:4: error: expected primary-expression before ';' token
  bug.cc: At global scope:
  bug.cc:7: error: expected unqualified-id before '+' token

The problem is that parser->error is set on the first bug, but not
cleared after the parser reached the end of the first statement.
Therefore subsequent errors are not reported, and
c_parser_skip_to_end_of_block_or_statement is called in inappropriate
places, thus skipping even more statements or declarations.
This sometimes leads to bogus error messages, e.g.:

  void foo() { +; }
  int i;
  void bar() { i++; }

  bug.c: In function 'foo':
  bug.c:1: error: expected expression before ';' token
  bug.c: In function 'bar':
  bug.c:3: error: 'i' undeclared (first use in this function)
  bug.c:3: error: (Each undeclared identifier is reported only once
  bug.c:3: error: for each function it appears in.)

Functions like c_parser_skip_to_end_of_block_or_statement reset
parser->error. But if a less severe error occurs that doesn't
require c_parser_skip_to_end_of_block_or_statement to be run
immediately, the flag isn't cleared.

The patch fixes the problem by resetting the flag after each statement.
Now all bugs are diagnosed for the first example:

  bug.c: In function 'foo':
  bug.c:3: error: expected expression before ';' token
  bug.c:4: error: expected expression before ';' token
  bug.c: At top level:
  bug.c:7: error: expected identifier or '(' before '+' token

And the bogus bug in line 3 of the second example is gone, too.

The parser now catches two more bugs in the testsuite, so a few
error-markers had to be added.

Bootstrapped and regtested on x86_64-unknown-linux-gnu.
Ok for mainline and 4.1 branch?

Regards,
Volker

:ADDPATCH C:


2006-08-08  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>

	PR c/28649
	* c-parser.c (c_parser_compound_statement_nostart): Reset
	parser->error after each statement.

===================================================================
--- gcc/gcc/c-parser.c	(revision 115987)
+++ gcc/gcc/c-parser.c	(working copy)
@@ -3486,6 +3486,8 @@ c_parser_compound_statement_nostart (c_parser
 	  last_stmt = true;
 	  c_parser_statement_after_labels (parser);
 	}
+
+      parser->error = false;
     }
   if (last_label)
     error ("label at end of compound statement");
===================================================================

2006-08-08  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>

	PR c/28649
	* gcc.dg/parse-error-1.c: New test.
	* gcc.dg/parse-error-2.c: New test.
	* gcc.dg/cpp/digraph2.c: Add error-marker.
	* gcc.dg/noncompile/920923-1.c: Likewise.

===================================================================
--- gcc/gcc/testsuite/gcc.dg/parse-error-1.c	2005-08-29 00:25:44 +0200
+++ gcc/gcc/testsuite/gcc.dg/parse-error-1.c	2006-08-08 01:19:39 +0200
@@ -0,0 +1,10 @@
+/* PR c/28649 */
+/* { dg-do compile } */
+
+void foo()
+{
+   +;  /* { dg-error "expected expression" } */
+   +;  /* { dg-error "expected expression" } */
+}
+
+int +;  /* { dg-error "expected identifier" } */
===================================================================
--- gcc/gcc/testsuite/gcc.dg/parse-error-2.c	2005-08-29 00:25:44 +0200
+++ gcc/gcc/testsuite/gcc.dg/parse-error-2.c	2006-08-08 11:34:47 +0200
@@ -0,0 +1,14 @@
+/* PR c/28649 */
+/* { dg-do compile } */
+
+void foo()
+{
+  +;  /* { dg-error "expected expression" } */
+}
+
+int i;
+
+void bar()
+{
+  i++;  /* { dg-bogus "undeclared" } */
+}
===================================================================
--- gcc/gcc/testsuite/gcc.dg/cpp/digraph2.c	(revision 115987)
+++ gcc/gcc/testsuite/gcc.dg/cpp/digraph2.c	(working copy)
@@ -13,7 +13,7 @@
 
 /* Place this after main () so we get to test both the compiler above
    and the preprocessor below.  */
-%:define glue
+%:define glue                   /* { dg-error "expected declaration" } */
 #ifdef glue
 #error glue is defined!
 #endif
===================================================================
--- gcc/gcc/testsuite/gcc.dg/noncompile/920923-1.c	(revision 115987)
+++ gcc/gcc/testsuite/gcc.dg/noncompile/920923-1.c	(working copy)
@@ -56,7 +56,7 @@
 {
      register prec_t bucket;
      register caddr_t p_addr;	/* { dg-error "expected|undeclared" } */
-     bucket = mem_hash+((((v_addr)>>ITEMBITS))&hash_mask);
+     bucket = mem_hash+((((v_addr)>>ITEMBITS))&hash_mask);  /* { dg-error "undeclared" } */
      do {
 	  if (bucket->v_addr == ((v_addr)>>ITEMBITS) {	/* { dg-error "expected|undeclared|no member" } */
 	       if(!(bucket->perm_set&va_op))
===================================================================



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