]> gcc.gnu.org Git - gcc.git/commitdiff
re PR c/23722 (bad error recovery with if blocks and else)
authorManuel López-Ibáñez <manu@gcc.gnu.org>
Mon, 26 Nov 2007 19:01:54 +0000 (19:01 +0000)
committerManuel López-Ibáñez <manu@gcc.gnu.org>
Mon, 26 Nov 2007 19:01:54 +0000 (19:01 +0000)
2007-11-26  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>

PR c/23722
* c-parser.c (struct c_parser): New bit in_if_block.
(c_parser_compound_statement_nostart): Handle unexpected 'else'
keyword.
(c_parser_statement_after_labels): Set in_if_block to false while
parsing.
(c_parser_if_body): Don't call c_parser_statement_after_labels if
a semicolon is found, just consume it. Don't call
c_parser_statement_after_labels if an open brace is found, call
c_parser_compound_statement instead.
(c_parser_else_body): New.
(c_parser_if_statement): Set in_if_block to true when parsing the
body of the 'if' statement. Use c_parser_else_body.

testsuite/
* gcc.dg/cpp/19990413-1.c: Update.
* gcc.dg/parse-else-error.c: New.
* gcc.dg/parse-else-error-2.c: New.
* gcc.dg/parse-else-error-3.c: New.
* gcc.dg/parse-else-error-4.c: New.

From-SVN: r130446

gcc/ChangeLog
gcc/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/19990413-1.c
gcc/testsuite/gcc.dg/parse-else-error-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/parse-else-error-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/parse-else-error-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/parse-else-error.c [new file with mode: 0644]

index 41aaf4b3ba84a3e8c6fea661395f4b00463941dc..d475e408985957505b3cfa2abdce64760b62ee1c 100644 (file)
@@ -1,3 +1,19 @@
+2007-11-26  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>
+
+       PR c/23722
+       * c-parser.c (struct c_parser): New bit in_if_block.
+       (c_parser_compound_statement_nostart): Handle unexpected 'else'
+       keyword.
+       (c_parser_statement_after_labels): Set in_if_block to false while
+       parsing.
+       (c_parser_if_body): Don't call c_parser_statement_after_labels if
+       a semicolon is found, just consume it. Don't call
+       c_parser_statement_after_labels if an open brace is found, call
+       c_parser_compound_statement instead.
+       (c_parser_else_body): New.
+       (c_parser_if_statement): Set in_if_block to true when parsing the
+       body of the 'if' statement. Use c_parser_else_body.
+
 2007-11-26  Andreas Krebbel  <krebbel1@de.ibm.com>
 
        PR 34081/C++
index 529354701a4f2ffc218fb8708747fc8cc890000c..1e32b5b9d98c6381e8772d9eaa8bcd80c193e15c 100644 (file)
@@ -280,6 +280,8 @@ typedef struct c_parser GTY(())
   /* True if we're processing a pragma, and shouldn't automatically
      consume CPP_PRAGMA_EOL.  */
   BOOL_BITFIELD in_pragma : 1;
+  /* True if we're parsing the outermost block of an if statement.  */
+  BOOL_BITFIELD in_if_block : 1;
   /* True if we want to lex an untranslated string.  */
   BOOL_BITFIELD lex_untranslated_string : 1;
   /* Objective-C specific parser/lexer information.  */
@@ -3541,6 +3543,20 @@ c_parser_compound_statement_nostart (c_parser *parser)
          c_parser_error (parser, "expected declaration or statement");
          return;
        }
+      else if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+        {
+          if (parser->in_if_block) 
+            {
+              error ("%H""expected %<}%> before %<else%>", &loc);
+              return;
+            }
+          else 
+            {
+              error ("%H%<else%> without a previous %<if%>", &loc);
+              c_parser_consume_token (parser);
+              continue;
+            }
+        }
       else
        {
        statement:
@@ -3740,6 +3756,8 @@ c_parser_statement_after_labels (c_parser *parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
   tree stmt = NULL_TREE;
+  bool in_if_block = parser->in_if_block;
+  parser->in_if_block = false;
   switch (c_parser_peek_token (parser)->type)
     {
     case CPP_OPEN_BRACE:
@@ -3873,6 +3891,8 @@ c_parser_statement_after_labels (c_parser *parser)
      earlier?  */
   if (stmt && CAN_HAVE_LOCATION_P (stmt))
     SET_EXPR_LOCATION (stmt, loc);
+
+  parser->in_if_block = in_if_block;
 }
 
 /* Parse a parenthesized condition from an if, do or while statement.
@@ -3906,11 +3926,13 @@ c_parser_c99_block_statement (c_parser *parser)
   return c_end_compound_stmt (block, flag_isoc99);
 }
 
-/* Parse the body of an if statement or the else half thereof.  This
-   is just parsing a statement but (a) it is a block in C99, (b) we
-   track whether the body is an if statement for the sake of
-   -Wparentheses warnings, (c) we handle an empty body specially for
-   the sake of -Wempty-body warnings.  */
+/* Parse the body of an if statement.  This is just parsing a
+   statement but (a) it is a block in C99, (b) we track whether the
+   body is an if statement for the sake of -Wparentheses warnings, (c)
+   we handle an empty body specially for the sake of -Wempty-body
+   warnings, and (d) we call parser_compound_statement directly
+   because c_parser_statement_after_labels resets
+   parser->in_if_block.  */
 
 static tree
 c_parser_if_body (c_parser *parser, bool *if_p)
@@ -3923,8 +3945,37 @@ c_parser_if_body (c_parser *parser, bool *if_p)
     c_parser_label (parser);
   *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
-    add_stmt (build_empty_stmt ());
-  c_parser_statement_after_labels (parser);
+    {
+      add_stmt (build_empty_stmt ());
+      c_parser_consume_token (parser);
+    }
+  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    add_stmt (c_parser_compound_statement (parser));
+  else
+    c_parser_statement_after_labels (parser);
+  return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse the else body of an if statement.  This is just parsing a
+   statement but (a) it is a block in C99, (b) we handle an empty body
+   specially for the sake of -Wempty-body warnings.  */
+
+static tree
+c_parser_else_body (c_parser *parser)
+{
+  tree block = c_begin_compound_stmt (flag_isoc99);
+  while (c_parser_next_token_is_keyword (parser, RID_CASE)
+        || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+        || (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+    c_parser_label (parser);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      add_stmt (build_empty_stmt ());
+      c_parser_consume_token (parser);
+    }
+  else 
+    c_parser_statement_after_labels (parser);
   return c_end_compound_stmt (block, flag_isoc99);
 }
 
@@ -3941,18 +3992,23 @@ c_parser_if_statement (c_parser *parser)
   tree block;
   location_t loc;
   tree cond;
-  bool first_if = false, second_if = false;
+  bool first_if = false;
   tree first_body, second_body;
+  bool in_if_block;
+
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
   c_parser_consume_token (parser);
   block = c_begin_compound_stmt (flag_isoc99);
   loc = c_parser_peek_token (parser)->location;
   cond = c_parser_paren_condition (parser);
+  in_if_block = parser->in_if_block;
+  parser->in_if_block = true;
   first_body = c_parser_if_body (parser, &first_if);
+  parser->in_if_block = in_if_block;
   if (c_parser_next_token_is_keyword (parser, RID_ELSE))
     {
       c_parser_consume_token (parser);
-      second_body = c_parser_if_body (parser, &second_if);
+      second_body = c_parser_else_body (parser);
     }
   else
     second_body = NULL_TREE;
index 05e3960c5d6e0de6f11975ef62efc9498257bf77..5ca77e8a70e45dc7ba5e81bfb507eac6d4a455b3 100644 (file)
@@ -1,3 +1,12 @@
+2007-11-26  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>
+
+       PR c/23722
+       * gcc.dg/cpp/19990413-1.c: Update.
+       * gcc.dg/parse-else-error.c: New.
+       * gcc.dg/parse-else-error-2.c: New.
+       * gcc.dg/parse-else-error-3.c: New.
+       * gcc.dg/parse-else-error-4.c: New.
+
 2007-11-26  Andreas Krebbel  <krebbel1@de.ibm.com>
 
        PR 34081/C++
index 61d8ad6550d5482c5346eba1b592a1cc6c556419..17d8441e8e6eb184435f88dc01c0fed4a4246b19 100644 (file)
@@ -9,5 +9,5 @@ func(void)
 {
   FOO(i
       = 4)
-  else;  /* { dg-error "parse error|syntax error|expected" "error on this line" { target *-*-* } { 12 } } */ 
+  else;  /* { dg-error "'else' without a previous 'if'" "error on this line" { target *-*-* } { 12 } } */ 
 }
diff --git a/gcc/testsuite/gcc.dg/parse-else-error-2.c b/gcc/testsuite/gcc.dg/parse-else-error-2.c
new file mode 100644 (file)
index 0000000..ce59af3
--- /dev/null
@@ -0,0 +1,13 @@
+/* PR 23722 */
+/* { dg-do compile } */
+/* { dg-options "-fsyntax-only" } */
+int f()
+{
+  if (1)
+    {
+      return 1;
+  else /* { dg-error "expected .\}. before 'else'" } */
+  {
+      }
+  }
+} /* { dg-error "expected identifier or '\\(' before .\}. token" } */
diff --git a/gcc/testsuite/gcc.dg/parse-else-error-3.c b/gcc/testsuite/gcc.dg/parse-else-error-3.c
new file mode 100644 (file)
index 0000000..13666f5
--- /dev/null
@@ -0,0 +1,11 @@
+/* PR 23722 */
+/* { dg-do compile } */
+/* { dg-options "-fsyntax-only" } */
+int f()
+{
+
+  else  /* { dg-error "'else' without a previous 'if'" } */
+    {
+      return 0;
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/parse-else-error-4.c b/gcc/testsuite/gcc.dg/parse-else-error-4.c
new file mode 100644 (file)
index 0000000..617c3f3
--- /dev/null
@@ -0,0 +1,14 @@
+/* PR 23722 */
+/* { dg-do compile } */
+/* { dg-options "-fsyntax-only" } */
+int f()
+{
+  if (1)
+    {
+      return 1;
+    }
+  else 
+    {
+      else; /* { dg-error "'else' without a previous 'if'" } */
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/parse-else-error.c b/gcc/testsuite/gcc.dg/parse-else-error.c
new file mode 100644 (file)
index 0000000..ca20bdf
--- /dev/null
@@ -0,0 +1,12 @@
+/* PR 23722 */
+/* { dg-do compile } */
+/* { dg-options "-fsyntax-only" } */
+int f()
+{
+  if (1)
+  {
+   return 1;
+  else /* { dg-error "expected .\}. before 'else'" } */
+  {
+  }
+}
This page took 0.128234 seconds and 5 git commands to generate.