]> granicus.if.org Git - clang/commitdiff
merge recovery-2.c into recovery-3.c.
authorChris Lattner <sabre@nondot.org>
Fri, 12 Dec 2008 06:19:11 +0000 (06:19 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 12 Dec 2008 06:19:11 +0000 (06:19 +0000)
Substantially improve error recovery after broken if conditions by
parsing the full if when we have a semantic error instead of using
parser recovery techniques to recover from a semantic error.

This fixes rdar://6094870 - spurious error after invalid 'if' condition

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60929 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseStmt.cpp
test/Parser/recovery-2.c [deleted file]
test/Parser/recovery-3.c

index bde4a502178dea7caac89c7ff0ce9ccac4d590a1..263079f1380a74d2abe0b71cc333a674214d3133 100644 (file)
@@ -448,20 +448,28 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
   ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
 
   // Parse the condition.
+  SourceLocation LParenLoc = ConsumeParen();
+  
   OwningExprResult CondExp(Actions);
-  if (getLang().CPlusPlus) {
-    SourceLocation LParenLoc = ConsumeParen();
+  if (getLang().CPlusPlus)
     CondExp = ParseCXXCondition();
-    MatchRHSPunctuation(tok::r_paren, LParenLoc);
-  } else {
-    CondExp = ParseSimpleParenExpression();
-  }
-
-  if (CondExp.isInvalid()) {
+  else
+    CondExp = ParseExpression();
+  
+  // If the parser was confused by the condition and we don't have a ')', try to
+  // recover by skipping ahead to a semi and bailing out.  If condexp is
+  // semantically invalid but we have well formed code, keep going.
+  if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) {
     SkipUntil(tok::semi);
-    return StmtError();
+    // Skipping may have stopped if it found the containing ')'.  If so, we can
+    // continue parsing the if statement.
+    if (Tok.isNot(tok::r_paren))
+      return StmtError();
   }
   
+  // Otherwise the condition is valid or the rparen is present.
+  MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
   // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do this
   // if the body isn't a compound statement to avoid push/pop in common cases.
@@ -521,6 +529,11 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
   }
 
   IfScope.Exit();
+  
+  // If the condition was invalid, discard the if statement.  We could recover
+  // better by replacing it with a valid expr, but don't do that yet.
+  if (CondExp.isInvalid())
+    return StmtError();
 
   // If the then or else stmt is invalid and the other is valid (and present),
   // make turn the invalid one into a null stmt to avoid dropping the other 
diff --git a/test/Parser/recovery-2.c b/test/Parser/recovery-2.c
deleted file mode 100644 (file)
index 4451232..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: clang -fsyntax-only -verify -pedantic %s
-
-
-// PR2241
-float f[] = { 
-  1e,            // expected-error {{exponent}}
-  1ee0           // expected-error {{exponent}}
-};
index 955d7288277e87aefd4856930dca630d4c3cee94..0c8206fe280e8de6d6da63a17e3b11f0e715a2d6 100644 (file)
@@ -1,5 +1,12 @@
 // RUN: clang -fsyntax-only -verify -pedantic %s
 
+// PR2241
+float test2241[] = { 
+  1e,            // expected-error {{exponent}}
+  1ee0           // expected-error {{exponent}}
+};
+
+
 // Testcase derived from PR2692
 static char *f (char * (*g) (char **, int), char **p, ...) {
     char *s;
@@ -12,3 +19,28 @@ static char *f (char * (*g) (char **, int), char **p, ...) {
 } // expected-error {{expected external declaration}}
 
 
+// rdar://6094870
+int test(int) {
+  struct { int i; } x;
+  
+  if (x.hello)   // expected-error {{no member named 'hello'}}
+    test(0);
+  else
+    ;
+  
+  if (x.hello == 0)   // expected-error {{no member named 'hello'}}
+    test(0);
+  else
+    ;
+  
+  if ((x.hello == 0))   // expected-error {{no member named 'hello'}}
+    test(0);
+  else
+    ;
+  
+  if (x.i == 0))   // expected-error {{expected expression}}
+    test(0);
+  else
+    ;
+}
+