]> granicus.if.org Git - clang/commitdiff
Improve recovery when there is a stray ']' or ')' before the ';' at
authorDouglas Gregor <dgregor@apple.com>
Tue, 7 Sep 2010 15:23:11 +0000 (15:23 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 7 Sep 2010 15:23:11 +0000 (15:23 +0000)
the end of a statement. Fixes <rdar://problem/6896493>.

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

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseObjc.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
test/FixIt/fixit-objc.m

index 28cd2d98f07f6e3ba02d4ef731ca614d5bb5a833..427bae2095014a3e1cbecc0a55dee120981fcee1 100644 (file)
@@ -124,6 +124,8 @@ def err_expected_while : Error<"expected 'while' in do/while loop">;
 def err_expected_semi_after : Error<"expected ';' after %0">;
 def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">;
 def err_expected_semi_after_expr : Error<"expected ';' after expression">;
+def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
+
 def err_expected_semi_after_method_proto : Error<
   "expected ';' after method prototype">;
 def err_expected_semi_after_namespace_name : Error<
index 41a2fb615791926c44bed35aae79e732854fce75..9c1630e899fdad8f0a307a22a210164b94689143 100644 (file)
@@ -464,6 +464,13 @@ private:
                         const char *DiagMsg = "",
                         tok::TokenKind SkipToTok = tok::unknown);
 
+  /// \brief The parser expects a semicolon and, if present, will consume it.
+  ///
+  /// If the next token is not a semicolon, this emits the specified diagnostic,
+  /// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior
+  /// to the semicolon, consumes that extra token.
+  bool ExpectAndConsumeSemi(unsigned DiagID);
+  
   //===--------------------------------------------------------------------===//
   // Scope manipulation
 
index 67d498523957d50aabffb4720f7a539049029003..8bb898591ed6337d0d717340aa34c42f8d1b50a3 100644 (file)
@@ -313,8 +313,9 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
   // Eat ';'.
   DeclEnd = Tok.getLocation();
   ExpectAndConsume(tok::semi,
-                   GNUAttr ? diag::err_expected_semi_after_attribute_list :
-                   diag::err_expected_semi_after_namespace_name, "", tok::semi);
+                   GNUAttr ? diag::err_expected_semi_after_attribute_list
+                           : diag::err_expected_semi_after_namespace_name, 
+                   "", tok::semi);
 
   return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS,
                                       IdentLoc, NamespcName, Attr);
@@ -422,7 +423,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
   MatchRHSPunctuation(tok::r_paren, LParenLoc);
 
   DeclEnd = Tok.getLocation();
-  ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert);
+  ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
 
   return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
                                               AssertExpr.take(),
index 6861ce940f7657b88134bd92418faccfcd8792d4..5f5b716a61cce8b932f7b7143cfb4123c9745385 100644 (file)
@@ -1731,7 +1731,7 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
   }
   
   // Otherwise, eat the semicolon.
-  ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+  ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
   return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.take()));
 }
 
index 6c240e608c2ecfe18c3916606a6561f607633024..3ff940faf9db71f1a2707b9336fb2e3a86429df1 100644 (file)
@@ -137,7 +137,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
       return StmtError();
     }
     // Otherwise, eat the semicolon.
-    ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+    ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
     return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
   }
 
@@ -507,7 +507,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
         // FIXME: Use attributes?
         // Eat the semicolon at the end of stmt and convert the expr into a
         // statement.
-        ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+        ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
         R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get()));
       }
     }
index 44bd0fbc0c0311210e85863b1bd8dde32dfcc90f..ca06ba72f64713948707365643292ad253c0f080 100644 (file)
@@ -162,6 +162,25 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
   return true;
 }
 
+bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
+  if (Tok.is(tok::semi) || Tok.is(tok::code_completion)) {
+    ConsumeAnyToken();
+    return false;
+  }
+  
+  if ((Tok.is(tok::r_paren) || Tok.is(tok::r_square)) && 
+      NextToken().is(tok::semi)) {
+    Diag(Tok, diag::err_extraneous_token_before_semi)
+      << PP.getSpelling(Tok)
+      << FixItHint::CreateRemoval(Tok.getLocation());
+    ConsumeAnyToken(); // The ')' or ']'.
+    ConsumeToken(); // The ';'.
+    return false;
+  }
+  
+  return ExpectAndConsume(tok::semi, DiagID);
+}
+
 //===----------------------------------------------------------------------===//
 // Error recovery.
 //===----------------------------------------------------------------------===//
index 03f28a1b586a01f96b98845023d959df2fb70756..bf704c66a0275679e834ee26fd0b2bc3df03612b 100644 (file)
@@ -1,6 +1,7 @@
+// RUN: %clang_cc1 -pedantic -verify %s
 // RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -fixit -x objective-c %t
-// RUN: %clang_cc1 -pedantic -verify -x objective-c %t
+// RUN: not %clang_cc1 -pedantic -fixit -x objective-c %t
+// RUN: %clang_cc1 -pedantic -Werror -x objective-c %t
 
 /* This is a test of the various code modification hints that are
    provided as part of warning or extension diagnostics. All of the
 @protocol X;
 
 void foo() {
-  <X> *P;    // should be fixed to 'id<X>'.
+  <X> *P;    // expected-warning{{protocol qualifiers without 'id' is archaic}}
 }
 
 @class A;
 @class NSString;
 
 @interface Test
-- (void)test:(NSString *)string;
+- (void)test:(NSString *)string; // expected-note{{passing argument to parameter 'string' here}}
 
 @property (copy) NSString *property;
 @end
 
-void g(NSString *a);
-void h(id a);
+void g(NSString *a); // expected-note{{passing argument to parameter 'a' here}}
+void h(id a); // expected-note 2{{passing argument to parameter 'a' here}}
 
 void f(Test *t) {
-  NSString *a = "Foo";
-  id b = "Foo";
-  A* c = "Foo"; // expected-warning {{incompatible pointer types initializing 'A *' with an expression of type 'char [4]'}}
-  g("Foo");
-  h("Foo");
-  h(("Foo"));
-  [t test:"Foo"];
-  t.property = "Foo";
+  NSString *a = "Foo"; // expected-warning {{incompatible pointer types initializing 'NSString *' with an expression of type 'char [4]'}}
+  id b = "Foo"; // expected-warning {{incompatible pointer types initializing 'id' with an expression of type 'char [4]'}}
+  g("Foo"); // expected-warning{{incompatible pointer types passing 'char [4]' to parameter of type 'NSString *'}}
+  h("Foo"); // expected-warning{{incompatible pointer types passing 'char [4]' to parameter of type 'id'}}
+  h(("Foo")); // expected-warning{{incompatible pointer types passing 'char [4]' to parameter of type 'id'}}
+  [t test:"Foo"]; // expected-warning{{incompatible pointer types sending 'char [4]' to parameter of type 'NSString *'}}
+  t.property = "Foo"; // expected-warning{{incompatible pointer types assigning to 'NSString *' from 'char [4]'}}
+
+  // <rdar://problem/6896493>
+  [t test:@"Foo"]]; // expected-error{{extraneous ']' before ';'}}
+  g(@"Foo")); // expected-error{{extraneous ')' before ';'}}
 }