From 09997e72272157a88c40cd2b1b1b7a14f808c0e0 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Sat, 7 Mar 2020 11:00:40 +0100
Subject: [PATCH] error_block_no_opening_brace: handle closures better

---
 src/librustc_parse/parser/stmt.rs                | 16 +++++++---------
 src/librustc_span/source_map.rs                  |  7 +++++++
 .../ui/parser/attr-stmt-expr-attr-bad.stderr     | 16 ++++++++--------
 src/test/ui/parser/closure-return-syntax.stderr  |  4 ++--
 4 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 8afc86c704d..fb85f54b136 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -259,16 +259,14 @@ impl<'a> Parser<'a> {
         //
         // which is valid in other languages, but not Rust.
         match self.parse_stmt_without_recovery() {
-            Ok(Some(stmt)) => {
+            // If the next token is an open brace (e.g., `if a b {`), the place-
+            // inside-a-block suggestion would be more likely wrong than right.
+            Ok(Some(_))
                 if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
-                    || do_not_suggest_help
-                {
-                    // If the next token is an open brace (e.g., `if a b {`), the place-
-                    // inside-a-block suggestion would be more likely wrong than right.
-                    e.span_label(sp, "expected `{`");
-                    return Err(e);
-                }
-                let stmt_span = if self.eat(&token::Semi) {
+                    || do_not_suggest_help => {}
+            Ok(Some(stmt)) => {
+                let stmt_own_line = self.sess.source_map().is_line_before_span_empty(sp);
+                let stmt_span = if stmt_own_line && self.eat(&token::Semi) {
                     // Expand the span to include the semicolon.
                     stmt.span.with_hi(self.prev_token.span.hi())
                 } else {
diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs
index cd2d2c4c3d7..5170f69e059 100644
--- a/src/librustc_span/source_map.rs
+++ b/src/librustc_span/source_map.rs
@@ -517,6 +517,13 @@ impl SourceMap {
         Ok((lo, hi))
     }
 
+    pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
+        match self.span_to_prev_source(sp) {
+            Ok(s) => s.split('\n').last().map(|l| l.trim_start().is_empty()).unwrap_or(false),
+            Err(_) => false,
+        }
+    }
+
     pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
         debug!("span_to_lines(sp={:?})", sp);
         let (lo, hi) = self.is_valid_span(sp)?;
diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
index 4dcba27cb68..af490150913 100644
--- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
+++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
@@ -140,7 +140,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:41:37
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
-   |                                --   ^       --- help: try placing this code inside a block: `{ {}; }`
+   |                                --   ^       -- help: try placing this code inside a block: `{ {} }`
    |                                |    |
    |                                |    expected `{`
    |                                this `if` expression has a condition, but no block
@@ -163,7 +163,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:47:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
-   |                                             ^       --- help: try placing this code inside a block: `{ {}; }`
+   |                                             ^       -- help: try placing this code inside a block: `{ {} }`
    |                                             |
    |                                             expected `{`
 
@@ -179,7 +179,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:51:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
-   |                                             ^       -------- help: try placing this code inside a block: `{ if 0 {}; }`
+   |                                             ^       ------- help: try placing this code inside a block: `{ if 0 {} }`
    |                                             |
    |                                             expected `{`
 
@@ -187,7 +187,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:53:50
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
-   |                                             --   ^       --- help: try placing this code inside a block: `{ {}; }`
+   |                                             --   ^       -- help: try placing this code inside a block: `{ {} }`
    |                                             |    |
    |                                             |    expected `{`
    |                                             this `if` expression has a condition, but no block
@@ -204,7 +204,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:57:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
-   |                                --           ^       --- help: try placing this code inside a block: `{ {}; }`
+   |                                --           ^       -- help: try placing this code inside a block: `{ {} }`
    |                                |            |
    |                                |            expected `{`
    |                                this `if` expression has a condition, but no block
@@ -227,7 +227,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:63:53
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
-   |                                                     ^       --- help: try placing this code inside a block: `{ {}; }`
+   |                                                     ^       -- help: try placing this code inside a block: `{ {} }`
    |                                                     |
    |                                                     expected `{`
 
@@ -243,7 +243,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:67:53
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
-   |                                                     ^       ---------------- help: try placing this code inside a block: `{ if let _ = 0 {}; }`
+   |                                                     ^       --------------- help: try placing this code inside a block: `{ if let _ = 0 {} }`
    |                                                     |
    |                                                     expected `{`
 
@@ -251,7 +251,7 @@ error: expected `{`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:69:66
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
-   |                                                     --           ^       --- help: try placing this code inside a block: `{ {}; }`
+   |                                                     --           ^       -- help: try placing this code inside a block: `{ {} }`
    |                                                     |            |
    |                                                     |            expected `{`
    |                                                     this `if` expression has a condition, but no block
diff --git a/src/test/ui/parser/closure-return-syntax.stderr b/src/test/ui/parser/closure-return-syntax.stderr
index 7bf6202a72a..1ccdd977305 100644
--- a/src/test/ui/parser/closure-return-syntax.stderr
+++ b/src/test/ui/parser/closure-return-syntax.stderr
@@ -2,10 +2,10 @@ error: expected `{`, found `22`
   --> $DIR/closure-return-syntax.rs:5:23
    |
 LL |     let x = || -> i32 22;
-   |                       ^^-
+   |                       ^^
    |                       |
    |                       expected `{`
-   |                       help: try placing this code inside a block: `{ 22; }`
+   |                       help: try placing this code inside a block: `{ 22 }`
 
 error: aborting due to previous error