From 2ec7d0b2281e57a456d6122dadd5646804a9d36e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 1 Mar 2019 16:28:04 -0800
Subject: [PATCH 01/11] Do not panic on missing close paren

Fix #58856.
---
 src/libsyntax/parse/parser.rs           |  4 +-
 src/test/ui/issues/issue-58856-1.rs     |  9 ++++
 src/test/ui/issues/issue-58856-1.stderr | 30 ++++++++++++++
 src/test/ui/issues/issue-58856-2.rs     | 13 ++++++
 src/test/ui/issues/issue-58856-2.stderr | 55 +++++++++++++++++++++++++
 5 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/issues/issue-58856-1.rs
 create mode 100644 src/test/ui/issues/issue-58856-1.stderr
 create mode 100644 src/test/ui/issues/issue-58856-2.rs
 create mode 100644 src/test/ui/issues/issue-58856-2.stderr

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fd5038a8614f2..dd4c2393fa58a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -6332,8 +6332,10 @@ impl<'a> Parser<'a> {
                     &token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
                 fn_inputs.append(&mut input);
                 (fn_inputs, recovered)
+            } else if let Err(err) = self.expect_one_of(&[], &[]) {
+                return Err(err);
             } else {
-                return self.unexpected();
+                (vec![self_arg], true)
             }
         } else {
             self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs
new file mode 100644
index 0000000000000..9311bb0802f2a
--- /dev/null
+++ b/src/test/ui/issues/issue-58856-1.rs
@@ -0,0 +1,9 @@
+impl A {
+//~^ ERROR cannot find type `A` in this scope
+    fn b(self>
+    //~^ ERROR expected one of `)`, `,`, or `:`, found `>`
+    //~| ERROR expected one of `->`, `where`, or `{`, found `>`
+    //~| ERROR expected one of `->`, `async`, `const`, `crate`, `default`, `existential`,
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr
new file mode 100644
index 0000000000000..3cbfd375e785e
--- /dev/null
+++ b/src/test/ui/issues/issue-58856-1.stderr
@@ -0,0 +1,30 @@
+error: expected one of `)`, `,`, or `:`, found `>`
+  --> $DIR/issue-58856-1.rs:3:14
+   |
+LL |     fn b(self>
+   |         -    ^
+   |         |    |
+   |         |    help: `)` may belong here
+   |         unclosed delimiter
+
+error: expected one of `->`, `where`, or `{`, found `>`
+  --> $DIR/issue-58856-1.rs:3:14
+   |
+LL |     fn b(self>
+   |              ^ expected one of `->`, `where`, or `{` here
+
+error: expected one of `->`, `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, `where`, or `}`, found `>`
+  --> $DIR/issue-58856-1.rs:3:14
+   |
+LL |     fn b(self>
+   |              ^ expected one of 13 possible tokens here
+
+error[E0412]: cannot find type `A` in this scope
+  --> $DIR/issue-58856-1.rs:1:6
+   |
+LL | impl A {
+   |      ^ not found in this scope
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/issues/issue-58856-2.rs
new file mode 100644
index 0000000000000..4c764761e8ec5
--- /dev/null
+++ b/src/test/ui/issues/issue-58856-2.rs
@@ -0,0 +1,13 @@
+trait Howness {}
+impl Howness for () {
+    fn how_are_you(&self -> Empty {
+    //~^ ERROR expected one of `)` or `,`, found `->`
+    //~| ERROR method `how_are_you` is not a member of trait `Howness`
+    //~| ERROR cannot find type `Empty` in this scope
+        Empty
+        //~^ ERROR cannot find value `Empty` in this scope
+    }
+}
+//~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`,
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr
new file mode 100644
index 0000000000000..30027278e23ca
--- /dev/null
+++ b/src/test/ui/issues/issue-58856-2.stderr
@@ -0,0 +1,55 @@
+error: expected one of `)` or `,`, found `->`
+  --> $DIR/issue-58856-2.rs:3:26
+   |
+LL |     fn how_are_you(&self -> Empty {
+   |                   -     -^^
+   |                   |     |
+   |                   |     help: `)` may belong here
+   |                   unclosed delimiter
+
+error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)`
+  --> $DIR/issue-58856-2.rs:10:1
+   |
+LL |     }
+   |      - expected one of 11 possible tokens here
+LL | }
+   | ^ unexpected token
+
+error[E0407]: method `how_are_you` is not a member of trait `Howness`
+  --> $DIR/issue-58856-2.rs:3:5
+   |
+LL | /     fn how_are_you(&self -> Empty {
+LL | |     //~^ ERROR expected one of `)` or `,`, found `->`
+LL | |     //~| ERROR method `how_are_you` is not a member of trait `Howness`
+LL | |     //~| ERROR cannot find type `Empty` in this scope
+LL | |         Empty
+LL | |         //~^ ERROR cannot find value `Empty` in this scope
+LL | |     }
+   | |_____^ not a member of trait `Howness`
+
+error[E0412]: cannot find type `Empty` in this scope
+  --> $DIR/issue-58856-2.rs:3:29
+   |
+LL |     fn how_are_you(&self -> Empty {
+   |                             ^^^^^ not found in this scope
+help: possible candidates are found in other modules, you can import them into scope
+   |
+LL | use std::io::Empty;
+   |
+LL | use std::iter::Empty;
+   |
+
+error[E0425]: cannot find value `Empty` in this scope
+  --> $DIR/issue-58856-2.rs:7:9
+   |
+LL |         Empty
+   |         ^^^^^ not found in this scope
+help: possible candidate is found in another module, you can import it into scope
+   |
+LL | use std::sync::mpsc::TryRecvError::Empty;
+   |
+
+error: aborting due to 5 previous errors
+
+Some errors occurred: E0407, E0412, E0425.
+For more information about an error, try `rustc --explain E0407`.

From cc535a2a19444d7b96e80dc8f445d50452e5495d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 1 Mar 2019 21:47:06 -0800
Subject: [PATCH 02/11] Bail when encountering a second unexpected token in the
 same span

---
 src/libsyntax/parse/parser.rs           | 14 +++++++---
 src/test/ui/issues/issue-58856-1.rs     |  7 +++--
 src/test/ui/issues/issue-58856-1.stderr | 25 +++---------------
 src/test/ui/issues/issue-58856-2.rs     |  5 ++--
 src/test/ui/issues/issue-58856-2.stderr | 35 ++++---------------------
 src/test/ui/parser/recover-enum2.rs     |  3 ---
 src/test/ui/parser/recover-enum2.stderr | 14 +---------
 7 files changed, 25 insertions(+), 78 deletions(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index dd4c2393fa58a..c27a1f79d8ccb 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -46,7 +46,7 @@ use crate::ThinVec;
 use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
 use crate::symbol::{Symbol, keywords};
 
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
 use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{Span, MultiSpan, BytePos, FileName};
 use log::{debug, trace};
@@ -256,6 +256,7 @@ pub struct Parser<'a> {
     /// it gets removed from here. Every entry left at the end gets emitted as an independent
     /// error.
     crate unclosed_delims: Vec<UnmatchedBrace>,
+    last_unexpected_token_span: Option<Span>,
 }
 
 
@@ -582,6 +583,7 @@ impl<'a> Parser<'a> {
             unmatched_angle_bracket_count: 0,
             max_angle_bracket_count: 0,
             unclosed_delims: Vec::new(),
+            last_unexpected_token_span: None,
         };
 
         let tok = parser.next_tok();
@@ -775,6 +777,8 @@ impl<'a> Parser<'a> {
         } else if inedible.contains(&self.token) {
             // leave it in the input
             Ok(false)
+        } else if self.last_unexpected_token_span == Some(self.span) {
+            FatalError.raise();
         } else {
             let mut expected = edible.iter()
                 .map(|x| TokenType::Token(x.clone()))
@@ -802,6 +806,7 @@ impl<'a> Parser<'a> {
                  (self.sess.source_map().next_point(self.prev_span),
                   format!("expected {} here", expect)))
             };
+            self.last_unexpected_token_span = Some(self.span);
             let mut err = self.fatal(&msg_exp);
             if self.token.is_ident_named("and") {
                 err.span_suggestion_short(
@@ -6332,10 +6337,11 @@ impl<'a> Parser<'a> {
                     &token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
                 fn_inputs.append(&mut input);
                 (fn_inputs, recovered)
-            } else if let Err(err) = self.expect_one_of(&[], &[]) {
-                return Err(err);
             } else {
-                (vec![self_arg], true)
+                match self.expect_one_of(&[], &[]) {
+                    Err(err) => return Err(err),
+                    Ok(recovered) => (vec![self_arg], recovered),
+                }
             }
         } else {
             self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs
index 9311bb0802f2a..f5edac0d2e316 100644
--- a/src/test/ui/issues/issue-58856-1.rs
+++ b/src/test/ui/issues/issue-58856-1.rs
@@ -1,9 +1,8 @@
+struct A;
+
 impl A {
-//~^ ERROR cannot find type `A` in this scope
-    fn b(self>
+    fn b(self> {}
     //~^ ERROR expected one of `)`, `,`, or `:`, found `>`
-    //~| ERROR expected one of `->`, `where`, or `{`, found `>`
-    //~| ERROR expected one of `->`, `async`, `const`, `crate`, `default`, `existential`,
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr
index 3cbfd375e785e..85101e467b137 100644
--- a/src/test/ui/issues/issue-58856-1.stderr
+++ b/src/test/ui/issues/issue-58856-1.stderr
@@ -1,30 +1,11 @@
 error: expected one of `)`, `,`, or `:`, found `>`
-  --> $DIR/issue-58856-1.rs:3:14
+  --> $DIR/issue-58856-1.rs:4:14
    |
-LL |     fn b(self>
+LL |     fn b(self> {}
    |         -    ^
    |         |    |
    |         |    help: `)` may belong here
    |         unclosed delimiter
 
-error: expected one of `->`, `where`, or `{`, found `>`
-  --> $DIR/issue-58856-1.rs:3:14
-   |
-LL |     fn b(self>
-   |              ^ expected one of `->`, `where`, or `{` here
-
-error: expected one of `->`, `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, `where`, or `}`, found `>`
-  --> $DIR/issue-58856-1.rs:3:14
-   |
-LL |     fn b(self>
-   |              ^ expected one of 13 possible tokens here
-
-error[E0412]: cannot find type `A` in this scope
-  --> $DIR/issue-58856-1.rs:1:6
-   |
-LL | impl A {
-   |      ^ not found in this scope
-
-error: aborting due to 4 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/issues/issue-58856-2.rs
index 4c764761e8ec5..acc38e4c20163 100644
--- a/src/test/ui/issues/issue-58856-2.rs
+++ b/src/test/ui/issues/issue-58856-2.rs
@@ -1,11 +1,12 @@
+struct Empty;
+
 trait Howness {}
+
 impl Howness for () {
     fn how_are_you(&self -> Empty {
     //~^ ERROR expected one of `)` or `,`, found `->`
     //~| ERROR method `how_are_you` is not a member of trait `Howness`
-    //~| ERROR cannot find type `Empty` in this scope
         Empty
-        //~^ ERROR cannot find value `Empty` in this scope
     }
 }
 //~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`,
diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr
index 30027278e23ca..55a9e9d5cb863 100644
--- a/src/test/ui/issues/issue-58856-2.stderr
+++ b/src/test/ui/issues/issue-58856-2.stderr
@@ -1,5 +1,5 @@
 error: expected one of `)` or `,`, found `->`
-  --> $DIR/issue-58856-2.rs:3:26
+  --> $DIR/issue-58856-2.rs:6:26
    |
 LL |     fn how_are_you(&self -> Empty {
    |                   -     -^^
@@ -8,7 +8,7 @@ LL |     fn how_are_you(&self -> Empty {
    |                   unclosed delimiter
 
 error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)`
-  --> $DIR/issue-58856-2.rs:10:1
+  --> $DIR/issue-58856-2.rs:11:1
    |
 LL |     }
    |      - expected one of 11 possible tokens here
@@ -16,40 +16,15 @@ LL | }
    | ^ unexpected token
 
 error[E0407]: method `how_are_you` is not a member of trait `Howness`
-  --> $DIR/issue-58856-2.rs:3:5
+  --> $DIR/issue-58856-2.rs:6:5
    |
 LL | /     fn how_are_you(&self -> Empty {
 LL | |     //~^ ERROR expected one of `)` or `,`, found `->`
 LL | |     //~| ERROR method `how_are_you` is not a member of trait `Howness`
-LL | |     //~| ERROR cannot find type `Empty` in this scope
 LL | |         Empty
-LL | |         //~^ ERROR cannot find value `Empty` in this scope
 LL | |     }
    | |_____^ not a member of trait `Howness`
 
-error[E0412]: cannot find type `Empty` in this scope
-  --> $DIR/issue-58856-2.rs:3:29
-   |
-LL |     fn how_are_you(&self -> Empty {
-   |                             ^^^^^ not found in this scope
-help: possible candidates are found in other modules, you can import them into scope
-   |
-LL | use std::io::Empty;
-   |
-LL | use std::iter::Empty;
-   |
-
-error[E0425]: cannot find value `Empty` in this scope
-  --> $DIR/issue-58856-2.rs:7:9
-   |
-LL |         Empty
-   |         ^^^^^ not found in this scope
-help: possible candidate is found in another module, you can import it into scope
-   |
-LL | use std::sync::mpsc::TryRecvError::Empty;
-   |
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
-Some errors occurred: E0407, E0412, E0425.
-For more information about an error, try `rustc --explain E0407`.
+For more information about this error, try `rustc --explain E0407`.
diff --git a/src/test/ui/parser/recover-enum2.rs b/src/test/ui/parser/recover-enum2.rs
index 65a187737879d..7f2f2cc7ab039 100644
--- a/src/test/ui/parser/recover-enum2.rs
+++ b/src/test/ui/parser/recover-enum2.rs
@@ -25,9 +25,6 @@ fn main() {
         // fail again
         enum Test4 {
             Nope(i32 {}) //~ ERROR: found `{`
-                         //~^ ERROR: found `{`
         }
     }
-    // still recover later
-    let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
 }
diff --git a/src/test/ui/parser/recover-enum2.stderr b/src/test/ui/parser/recover-enum2.stderr
index b308e644ad9f8..315bfde77c73c 100644
--- a/src/test/ui/parser/recover-enum2.stderr
+++ b/src/test/ui/parser/recover-enum2.stderr
@@ -10,17 +10,5 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
 LL |             Nope(i32 {}) //~ ERROR: found `{`
    |                      ^ expected one of 7 possible tokens here
 
-error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `...`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{`
-  --> $DIR/recover-enum2.rs:27:22
-   |
-LL |             Nope(i32 {}) //~ ERROR: found `{`
-   |                      ^ expected one of 24 possible tokens here
-
-error: expected expression, found reserved identifier `_`
-  --> $DIR/recover-enum2.rs:32:22
-   |
-LL |     let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
-   |                      ^ expected expression
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 

From ed2de5a8421822ecf9aa3df30bc6c2e55d4ea97d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 1 Mar 2019 22:14:22 -0800
Subject: [PATCH 03/11] Emit unclosed delimiters during recovery

---
 src/libsyntax/parse/parser.rs           |  1 +
 src/test/ui/issues/issue-58856-1.rs     |  4 ++++
 src/test/ui/issues/issue-58856-1.stderr | 10 +++++++++-
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c27a1f79d8ccb..0187ad743aa71 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -778,6 +778,7 @@ impl<'a> Parser<'a> {
             // leave it in the input
             Ok(false)
         } else if self.last_unexpected_token_span == Some(self.span) {
+            emit_unclosed_delims(&self.unclosed_delims, self.diagnostic());
             FatalError.raise();
         } else {
             let mut expected = edible.iter()
diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs
index f5edac0d2e316..7dc3658776e60 100644
--- a/src/test/ui/issues/issue-58856-1.rs
+++ b/src/test/ui/issues/issue-58856-1.rs
@@ -5,4 +5,8 @@ impl A {
     //~^ ERROR expected one of `)`, `,`, or `:`, found `>`
 }
 
+// verify that mismatched delimiters get emitted
+fn foo(] {}
+//~^ ERROR incorrect close delimiter
+
 fn main() {}
diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr
index 85101e467b137..f26ebbe15c5b9 100644
--- a/src/test/ui/issues/issue-58856-1.stderr
+++ b/src/test/ui/issues/issue-58856-1.stderr
@@ -7,5 +7,13 @@ LL |     fn b(self> {}
    |         |    help: `)` may belong here
    |         unclosed delimiter
 
-error: aborting due to previous error
+error: incorrect close delimiter: `]`
+  --> $DIR/issue-58856-1.rs:9:8
+   |
+LL | fn foo(] {}
+   |       -^ incorrect close delimiter
+   |       |
+   |       un-closed delimiter
+
+error: aborting due to 2 previous errors
 

From e38e915cdfaecb5a89d9bf2b041f19c6598ade09 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 1 Mar 2019 22:35:21 -0800
Subject: [PATCH 04/11] Reduce test case

---
 src/test/ui/issues/issue-58856-1.rs     |  8 +-------
 src/test/ui/issues/issue-58856-1.stderr | 14 +++-----------
 2 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs
index 7dc3658776e60..db3984cd18987 100644
--- a/src/test/ui/issues/issue-58856-1.rs
+++ b/src/test/ui/issues/issue-58856-1.rs
@@ -1,12 +1,6 @@
-struct A;
-
 impl A {
-    fn b(self> {}
+    fn b(self>
     //~^ ERROR expected one of `)`, `,`, or `:`, found `>`
 }
 
-// verify that mismatched delimiters get emitted
-fn foo(] {}
-//~^ ERROR incorrect close delimiter
-
 fn main() {}
diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr
index f26ebbe15c5b9..20cdf55365fc7 100644
--- a/src/test/ui/issues/issue-58856-1.stderr
+++ b/src/test/ui/issues/issue-58856-1.stderr
@@ -1,19 +1,11 @@
 error: expected one of `)`, `,`, or `:`, found `>`
-  --> $DIR/issue-58856-1.rs:4:14
+  --> $DIR/issue-58856-1.rs:2:14
    |
-LL |     fn b(self> {}
+LL |     fn b(self>
    |         -    ^
    |         |    |
    |         |    help: `)` may belong here
    |         unclosed delimiter
 
-error: incorrect close delimiter: `]`
-  --> $DIR/issue-58856-1.rs:9:8
-   |
-LL | fn foo(] {}
-   |       -^ incorrect close delimiter
-   |       |
-   |       un-closed delimiter
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 

From c70a516c23ae19ce568166a81e64c92a4ecf540a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 3 Mar 2019 11:13:19 -0800
Subject: [PATCH 05/11] Panic when unmatched delimiters aren't emitted

---
 src/libsyntax/ext/tt/macro_parser.rs | 2 +-
 src/libsyntax/parse/parser.rs        | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index fe1cffb092b1c..1a419e7fadaa0 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -761,7 +761,7 @@ pub fn parse(
         else if bb_items.is_empty() && next_items.is_empty() {
             return Failure(
                 parser.span,
-                parser.token,
+                parser.token.clone(),
                 "no rules expected this token in macro call",
             );
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0187ad743aa71..33fe81ea8c414 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -259,6 +259,13 @@ pub struct Parser<'a> {
     last_unexpected_token_span: Option<Span>,
 }
 
+impl<'a> Drop for Parser<'a> {
+    fn drop(&mut self) {
+        if !self.unclosed_delims.is_empty() {
+            panic!("unclosed delimiter errors not emitted");
+        }
+    }
+}
 
 #[derive(Clone)]
 struct TokenCursor {

From 51d0e86c221dbd937ca248f25a95dad787035b9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 3 Mar 2019 12:14:25 -0800
Subject: [PATCH 06/11] Emit missing unclosed delimiter errors

---
 src/librustc_metadata/cstore_impl.rs          |  4 +-
 src/libsyntax/parse/parser.rs                 | 14 ++++--
 src/libsyntax/parse/token.rs                  | 12 ++---
 src/libsyntax_ext/proc_macro_server.rs        |  4 +-
 src/test/ui/parser-recovery-2.stderr          | 12 ++---
 src/test/ui/resolve/token-error-correct-3.rs  | 16 +++---
 .../ui/resolve/token-error-correct-3.stderr   | 49 +++++++++----------
 7 files changed, 56 insertions(+), 55 deletions(-)

diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index f49b88f14e60e..67a249e605ecc 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -439,8 +439,8 @@ impl cstore::CStore {
 
         let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);
         let local_span = Span::new(source_file.start_pos, source_file.end_pos, NO_EXPANSION);
-        let (body, errors) = source_file_to_stream(&sess.parse_sess, source_file, None);
-        emit_unclosed_delims(&errors, &sess.diagnostic());
+        let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None);
+        emit_unclosed_delims(&mut errors, &sess.diagnostic());
 
         // Mark the attrs as used
         let attrs = data.get_item_attrs(id.index, sess);
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 33fe81ea8c414..bde14e192e96b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -7798,7 +7798,10 @@ impl<'a> Parser<'a> {
         attributes_allowed: bool,
     ) -> PResult<'a, Option<P<Item>>> {
         let (ret, tokens) = self.collect_tokens(|this| {
-            this.parse_item_implementation(attrs, macros_allowed, attributes_allowed)
+            let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed);
+            let diag = this.diagnostic();
+            emit_unclosed_delims(&mut this.unclosed_delims, diag);
+            item
         })?;
 
         // Once we've parsed an item and recorded the tokens we got while
@@ -8555,8 +8558,8 @@ impl<'a> Parser<'a> {
             module: self.parse_mod_items(&token::Eof, lo)?,
             span: lo.to(self.span),
         });
-        emit_unclosed_delims(&self.unclosed_delims, self.diagnostic());
-        self.unclosed_delims.clear();
+        let diag = self.diagnostic();
+        emit_unclosed_delims(&mut self.unclosed_delims, diag);
         krate
     }
 
@@ -8587,8 +8590,8 @@ impl<'a> Parser<'a> {
     }
 }
 
-pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors::Handler) {
-    for unmatched in unclosed_delims {
+pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {
+    for unmatched in unclosed_delims.iter() {
         let mut err = handler.struct_span_err(unmatched.found_span, &format!(
             "incorrect close delimiter: `{}`",
             pprust::token_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
@@ -8602,4 +8605,5 @@ pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors
         }
         err.emit();
     }
+    unclosed_delims.clear();
 }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index eec422d6266c3..bb4da12bae893 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -675,9 +675,9 @@ impl Nonterminal {
         // FIXME(#43081): Avoid this pretty-print + reparse hack
         let source = pprust::nonterminal_to_string(self);
         let filename = FileName::macro_expansion_source_code(&source);
-        let (tokens_for_real, errors) =
+        let (tokens_for_real, mut errors) =
             parse_stream_from_source_str(filename, source, sess, Some(span));
-        emit_unclosed_delims(&errors, &sess.span_diagnostic);
+        emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
 
         // During early phases of the compiler the AST could get modified
         // directly (e.g., attributes added or removed) and the internal cache
@@ -740,13 +740,13 @@ fn prepend_attrs(sess: &ParseSess,
         let source = pprust::attr_to_string(attr);
         let macro_filename = FileName::macro_expansion_source_code(&source);
         if attr.is_sugared_doc {
-            let (stream, errors) = parse_stream_from_source_str(
+            let (stream, mut errors) = parse_stream_from_source_str(
                 macro_filename,
                 source,
                 sess,
                 Some(span),
             );
-            emit_unclosed_delims(&errors, &sess.span_diagnostic);
+            emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
             builder.push(stream);
             continue
         }
@@ -763,13 +763,13 @@ fn prepend_attrs(sess: &ParseSess,
         // ... and for more complicated paths, fall back to a reparse hack that
         // should eventually be removed.
         } else {
-            let (stream, errors) = parse_stream_from_source_str(
+            let (stream, mut errors) = parse_stream_from_source_str(
                 macro_filename,
                 source,
                 sess,
                 Some(span),
             );
-            emit_unclosed_delims(&errors, &sess.span_diagnostic);
+            emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
             brackets.push(stream);
         }
 
diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs
index 4c4b33c04422b..5822b5607f7df 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax_ext/proc_macro_server.rs
@@ -410,13 +410,13 @@ impl server::TokenStream for Rustc<'_> {
         stream.is_empty()
     }
     fn from_str(&mut self, src: &str) -> Self::TokenStream {
-        let (tokens, errors) = parse::parse_stream_from_source_str(
+        let (tokens, mut errors) = parse::parse_stream_from_source_str(
             FileName::proc_macro_source_code(src.clone()),
             src.to_string(),
             self.sess,
             Some(self.call_site),
         );
-        emit_unclosed_delims(&errors, &self.sess.span_diagnostic);
+        emit_unclosed_delims(&mut errors, &self.sess.span_diagnostic);
         tokens
     }
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
diff --git a/src/test/ui/parser-recovery-2.stderr b/src/test/ui/parser-recovery-2.stderr
index 76f7af38e776d..92d8cbc100a03 100644
--- a/src/test/ui/parser-recovery-2.stderr
+++ b/src/test/ui/parser-recovery-2.stderr
@@ -1,9 +1,3 @@
-error: unexpected token: `;`
-  --> $DIR/parser-recovery-2.rs:12:15
-   |
-LL |     let x = y.;  //~ ERROR unexpected token
-   |               ^
-
 error: incorrect close delimiter: `)`
   --> $DIR/parser-recovery-2.rs:8:5
    |
@@ -13,6 +7,12 @@ LL |         let x = foo(); //~ ERROR cannot find function `foo` in this scope
 LL |     ) //~ ERROR incorrect close delimiter: `)`
    |     ^ incorrect close delimiter
 
+error: unexpected token: `;`
+  --> $DIR/parser-recovery-2.rs:12:15
+   |
+LL |     let x = y.;  //~ ERROR unexpected token
+   |               ^
+
 error[E0425]: cannot find function `foo` in this scope
   --> $DIR/parser-recovery-2.rs:7:17
    |
diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs
index b1ca0bbfc57c1..05bdbeacf72fe 100644
--- a/src/test/ui/resolve/token-error-correct-3.rs
+++ b/src/test/ui/resolve/token-error-correct-3.rs
@@ -10,16 +10,14 @@ pub mod raw {
     pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                                callback: F)
                                                                -> io::Result<bool> {
-        if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory`
-            callback(path.as_ref(); //~ ERROR expected one of
-            fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
-            //~^ expected (), found enum `std::result::Result`
-            //~| expected type `()`
-            //~| found type `std::result::Result<bool, std::io::Error>`
-            //~| expected one of
+        if !is_directory(path.as_ref()) {
+            //~^ ERROR cannot find function `is_directory`
+            callback(path.as_ref();
+            //~^ ERROR expected one of
+            //~| ERROR this function takes 1 parameter but 2 parameters were supplied
+            fs::create_dir_all(path.as_ref()).map(|()| true)
         } else {
-            //~^ ERROR: expected one of
-            //~| unexpected token
+            //~^ ERROR incorrect close delimiter: `}`
             Ok(false);
         }
 
diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr
index a6bb83c71f313..0f1cbd6c2f772 100644
--- a/src/test/ui/resolve/token-error-correct-3.stderr
+++ b/src/test/ui/resolve/token-error-correct-3.stderr
@@ -1,39 +1,38 @@
-error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
-  --> $DIR/token-error-correct-3.rs:14:35
-   |
-LL |             callback(path.as_ref(); //~ ERROR expected one of
-   |                     -             ^
-   |                     |             |
-   |                     |             help: `)` may belong here
-   |                     unclosed delimiter
-
-error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
-  --> $DIR/token-error-correct-3.rs:20:9
+error: incorrect close delimiter: `}`
+  --> $DIR/token-error-correct-3.rs:19:9
    |
-LL |             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
-   |                                                             - expected one of `.`, `;`, `?`, `}`, or an operator here
+LL |         if !is_directory(path.as_ref()) {
+   |                                         - close delimiter possibly meant for this
+LL |             //~^ ERROR cannot find function `is_directory`
+LL |             callback(path.as_ref();
+   |                     - un-closed delimiter
 ...
 LL |         } else {
-   |         ^ unexpected token
+   |         ^ incorrect close delimiter
+
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
+  --> $DIR/token-error-correct-3.rs:15:35
+   |
+LL |             callback(path.as_ref();
+   |                                   ^ expected one of `)`, `,`, `.`, `?`, or an operator here
 
 error[E0425]: cannot find function `is_directory` in this scope
   --> $DIR/token-error-correct-3.rs:13:13
    |
-LL |         if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory`
+LL |         if !is_directory(path.as_ref()) {
    |             ^^^^^^^^^^^^ not found in this scope
 
-error[E0308]: mismatched types
+error[E0057]: this function takes 1 parameter but 2 parameters were supplied
   --> $DIR/token-error-correct-3.rs:15:13
    |
-LL |             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
-   |             |
-   |             expected (), found enum `std::result::Result`
-   |
-   = note: expected type `()`
-              found type `std::result::Result<bool, std::io::Error>`
+LL | /             callback(path.as_ref();
+LL | |             //~^ ERROR expected one of
+LL | |             //~| ERROR this function takes 1 parameter but 2 parameters were supplied
+LL | |             fs::create_dir_all(path.as_ref()).map(|()| true)
+LL | |         } else {
+   | |_________^ expected 1 parameter
 
 error: aborting due to 4 previous errors
 
-Some errors occurred: E0308, E0425.
-For more information about an error, try `rustc --explain E0308`.
+Some errors occurred: E0057, E0425.
+For more information about an error, try `rustc --explain E0057`.

From ac6cc2d6b0aad0b1cc97f1db6d8e9d4f117eca95 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 3 Mar 2019 12:45:49 -0800
Subject: [PATCH 07/11] Collect unclosed delimiters in parent parser

---
 src/libsyntax/parse/parser.rs                 | 17 +++++--
 src/test/ui/parser-recovery-2.stderr          | 12 ++---
 src/test/ui/resolve/token-error-correct-3.rs  |  4 +-
 .../ui/resolve/token-error-correct-3.stderr   | 47 ++++++++++---------
 4 files changed, 45 insertions(+), 35 deletions(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index bde14e192e96b..348c26d2044b9 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1510,9 +1510,13 @@ impl<'a> Parser<'a> {
     pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> {
         maybe_whole!(self, NtTraitItem, |x| x);
         let attrs = self.parse_outer_attributes()?;
+        let mut unclosed_delims = vec![];
         let (mut item, tokens) = self.collect_tokens(|this| {
-            this.parse_trait_item_(at_end, attrs)
+            let item = this.parse_trait_item_(at_end, attrs);
+            unclosed_delims.append(&mut this.unclosed_delims);
+            item
         })?;
+        self.unclosed_delims.append(&mut unclosed_delims);
         // See `parse_item` for why this clause is here.
         if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
             item.tokens = Some(tokens);
@@ -6475,9 +6479,13 @@ impl<'a> Parser<'a> {
     pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
         maybe_whole!(self, NtImplItem, |x| x);
         let attrs = self.parse_outer_attributes()?;
+        let mut unclosed_delims = vec![];
         let (mut item, tokens) = self.collect_tokens(|this| {
-            this.parse_impl_item_(at_end, attrs)
+            let item = this.parse_impl_item_(at_end, attrs);
+            unclosed_delims.append(&mut this.unclosed_delims);
+            item
         })?;
+        self.unclosed_delims.append(&mut unclosed_delims);
 
         // See `parse_item` for why this clause is here.
         if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
@@ -7797,12 +7805,13 @@ impl<'a> Parser<'a> {
         macros_allowed: bool,
         attributes_allowed: bool,
     ) -> PResult<'a, Option<P<Item>>> {
+        let mut unclosed_delims = vec![];
         let (ret, tokens) = self.collect_tokens(|this| {
             let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed);
-            let diag = this.diagnostic();
-            emit_unclosed_delims(&mut this.unclosed_delims, diag);
+            unclosed_delims.append(&mut this.unclosed_delims);
             item
         })?;
+        self.unclosed_delims.append(&mut unclosed_delims);
 
         // Once we've parsed an item and recorded the tokens we got while
         // parsing we may want to store `tokens` into the item we're about to
diff --git a/src/test/ui/parser-recovery-2.stderr b/src/test/ui/parser-recovery-2.stderr
index 92d8cbc100a03..76f7af38e776d 100644
--- a/src/test/ui/parser-recovery-2.stderr
+++ b/src/test/ui/parser-recovery-2.stderr
@@ -1,3 +1,9 @@
+error: unexpected token: `;`
+  --> $DIR/parser-recovery-2.rs:12:15
+   |
+LL |     let x = y.;  //~ ERROR unexpected token
+   |               ^
+
 error: incorrect close delimiter: `)`
   --> $DIR/parser-recovery-2.rs:8:5
    |
@@ -7,12 +13,6 @@ LL |         let x = foo(); //~ ERROR cannot find function `foo` in this scope
 LL |     ) //~ ERROR incorrect close delimiter: `)`
    |     ^ incorrect close delimiter
 
-error: unexpected token: `;`
-  --> $DIR/parser-recovery-2.rs:12:15
-   |
-LL |     let x = y.;  //~ ERROR unexpected token
-   |               ^
-
 error[E0425]: cannot find function `foo` in this scope
   --> $DIR/parser-recovery-2.rs:7:17
    |
diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs
index 05bdbeacf72fe..212b88ac8b05f 100644
--- a/src/test/ui/resolve/token-error-correct-3.rs
+++ b/src/test/ui/resolve/token-error-correct-3.rs
@@ -14,10 +14,10 @@ pub mod raw {
             //~^ ERROR cannot find function `is_directory`
             callback(path.as_ref();
             //~^ ERROR expected one of
-            //~| ERROR this function takes 1 parameter but 2 parameters were supplied
             fs::create_dir_all(path.as_ref()).map(|()| true)
+            //~^ ERROR mismatched types
         } else {
-            //~^ ERROR incorrect close delimiter: `}`
+            //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
             Ok(false);
         }
 
diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr
index 0f1cbd6c2f772..035a5ede45384 100644
--- a/src/test/ui/resolve/token-error-correct-3.stderr
+++ b/src/test/ui/resolve/token-error-correct-3.stderr
@@ -1,20 +1,20 @@
-error: incorrect close delimiter: `}`
-  --> $DIR/token-error-correct-3.rs:19:9
-   |
-LL |         if !is_directory(path.as_ref()) {
-   |                                         - close delimiter possibly meant for this
-LL |             //~^ ERROR cannot find function `is_directory`
-LL |             callback(path.as_ref();
-   |                     - un-closed delimiter
-...
-LL |         } else {
-   |         ^ incorrect close delimiter
-
 error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
   --> $DIR/token-error-correct-3.rs:15:35
    |
 LL |             callback(path.as_ref();
-   |                                   ^ expected one of `)`, `,`, `.`, `?`, or an operator here
+   |                     -             ^
+   |                     |             |
+   |                     |             help: `)` may belong here
+   |                     unclosed delimiter
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
+  --> $DIR/token-error-correct-3.rs:19:9
+   |
+LL |             fs::create_dir_all(path.as_ref()).map(|()| true)
+   |                                                             - expected one of `.`, `;`, `?`, `}`, or an operator here
+LL |             //~^ ERROR mismatched types
+LL |         } else {
+   |         ^ unexpected token
 
 error[E0425]: cannot find function `is_directory` in this scope
   --> $DIR/token-error-correct-3.rs:13:13
@@ -22,17 +22,18 @@ error[E0425]: cannot find function `is_directory` in this scope
 LL |         if !is_directory(path.as_ref()) {
    |             ^^^^^^^^^^^^ not found in this scope
 
-error[E0057]: this function takes 1 parameter but 2 parameters were supplied
-  --> $DIR/token-error-correct-3.rs:15:13
+error[E0308]: mismatched types
+  --> $DIR/token-error-correct-3.rs:17:13
+   |
+LL |             fs::create_dir_all(path.as_ref()).map(|()| true)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
+   |             |
+   |             expected (), found enum `std::result::Result`
    |
-LL | /             callback(path.as_ref();
-LL | |             //~^ ERROR expected one of
-LL | |             //~| ERROR this function takes 1 parameter but 2 parameters were supplied
-LL | |             fs::create_dir_all(path.as_ref()).map(|()| true)
-LL | |         } else {
-   | |_________^ expected 1 parameter
+   = note: expected type `()`
+              found type `std::result::Result<bool, std::io::Error>`
 
 error: aborting due to 4 previous errors
 
-Some errors occurred: E0057, E0425.
-For more information about an error, try `rustc --explain E0057`.
+Some errors occurred: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.

From f156d9220703d99709be32ea1be0be0d44535114 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 3 Mar 2019 14:11:41 -0800
Subject: [PATCH 08/11] Always emit mismatched delim errors, never panic

---
 src/libsyntax/parse/parser.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 348c26d2044b9..860964a736f5e 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -262,7 +262,8 @@ pub struct Parser<'a> {
 impl<'a> Drop for Parser<'a> {
     fn drop(&mut self) {
         if !self.unclosed_delims.is_empty() {
-            panic!("unclosed delimiter errors not emitted");
+            let diag = self.diagnostic();
+            emit_unclosed_delims(&mut self.unclosed_delims, diag);
         }
     }
 }
@@ -8567,8 +8568,6 @@ impl<'a> Parser<'a> {
             module: self.parse_mod_items(&token::Eof, lo)?,
             span: lo.to(self.span),
         });
-        let diag = self.diagnostic();
-        emit_unclosed_delims(&mut self.unclosed_delims, diag);
         krate
     }
 

From 3818f8ba340de08f863b1c431fdf27f767dfca8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 3 Mar 2019 16:59:24 -0800
Subject: [PATCH 09/11] Add regression test for #58886

---
 .../ui/parser/unclosed-delimiter-in-dep.rs    |  6 +++++
 .../parser/unclosed-delimiter-in-dep.stderr   | 23 +++++++++++++++++++
 src/test/ui/parser/unclosed_delim_mod.rs      |  6 +++++
 src/test/ui/parser/unclosed_delim_mod.stderr  | 18 +++++++++++++++
 4 files changed, 53 insertions(+)
 create mode 100644 src/test/ui/parser/unclosed-delimiter-in-dep.rs
 create mode 100644 src/test/ui/parser/unclosed-delimiter-in-dep.stderr
 create mode 100644 src/test/ui/parser/unclosed_delim_mod.rs
 create mode 100644 src/test/ui/parser/unclosed_delim_mod.stderr

diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.rs b/src/test/ui/parser/unclosed-delimiter-in-dep.rs
new file mode 100644
index 0000000000000..6db1b66e9f785
--- /dev/null
+++ b/src/test/ui/parser/unclosed-delimiter-in-dep.rs
@@ -0,0 +1,6 @@
+mod unclosed_delim_mod;
+
+fn main() {
+    let _: usize = unclosed_delim_mod::new();
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
new file mode 100644
index 0000000000000..633c63bea9105
--- /dev/null
+++ b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr
@@ -0,0 +1,23 @@
+error: incorrect close delimiter: `}`
+  --> $DIR/unclosed_delim_mod.rs:5:1
+   |
+LL | pub fn new() -> Result<Value, ()> {
+   |                                   - close delimiter possibly meant for this
+LL |     Ok(Value {
+   |       - un-closed delimiter
+LL |     }
+LL | }
+   | ^ incorrect close delimiter
+
+error[E0308]: mismatched types
+  --> $DIR/unclosed-delimiter-in-dep.rs:4:20
+   |
+LL |     let _: usize = unclosed_delim_mod::new();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ expected usize, found enum `std::result::Result`
+   |
+   = note: expected type `usize`
+              found type `std::result::Result<unclosed_delim_mod::Value, ()>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/unclosed_delim_mod.rs b/src/test/ui/parser/unclosed_delim_mod.rs
new file mode 100644
index 0000000000000..b1664f49dc591
--- /dev/null
+++ b/src/test/ui/parser/unclosed_delim_mod.rs
@@ -0,0 +1,6 @@
+pub struct Value {}
+pub fn new() -> Result<Value, ()> {
+    Ok(Value {
+    }
+}
+//~^ ERROR incorrect close delimiter
diff --git a/src/test/ui/parser/unclosed_delim_mod.stderr b/src/test/ui/parser/unclosed_delim_mod.stderr
new file mode 100644
index 0000000000000..cc04eb531cbea
--- /dev/null
+++ b/src/test/ui/parser/unclosed_delim_mod.stderr
@@ -0,0 +1,18 @@
+error: incorrect close delimiter: `}`
+  --> $DIR/unclosed_delim_mod.rs:5:1
+   |
+LL | pub fn new() -> Result<Value, ()> {
+   |                                   - close delimiter possibly meant for this
+LL |     Ok(Value {
+   |       - un-closed delimiter
+LL |     }
+LL | }
+   | ^ incorrect close delimiter
+
+error[E0601]: `main` function not found in crate `unclosed_delim_mod`
+   |
+   = note: consider adding a `main` function to `$DIR/unclosed_delim_mod.rs`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.

From 6f0f2fc6d6ca0800c8b8b95932010d51af4e4663 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 4 Mar 2019 12:59:43 -0800
Subject: [PATCH 10/11] Simplify code

---
 src/libsyntax/parse/mod.rs             | 11 +++++++++--
 src/libsyntax/parse/parser.rs          |  6 ++----
 src/libsyntax/parse/token.rs           | 21 +++------------------
 src/libsyntax_ext/proc_macro_server.rs |  7 ++-----
 4 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index b2d4d97d57d89..6583458b44694 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -6,6 +6,7 @@ use crate::source_map::{SourceMap, FilePathMapping};
 use crate::feature_gate::UnstableFeatures;
 use crate::parse::parser::Parser;
 use crate::symbol::Symbol;
+use crate::syntax::parse::parser::emit_unclosed_delims;
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::diagnostics::plugin::ErrorMap;
 use crate::print::pprust::token_to_string;
@@ -141,8 +142,14 @@ pub fn parse_stream_from_source_str(
     source: String,
     sess: &ParseSess,
     override_span: Option<Span>,
-) -> (TokenStream, Vec<lexer::UnmatchedBrace>) {
-    source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span)
+) -> TokenStream {
+    let (stream, mut errors) = source_file_to_stream(
+        sess,
+        sess.source_map().new_source_file(name, source),
+        override_span,
+    );
+    emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
+    stream
 }
 
 /// Creates a new parser from a source string.
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 860964a736f5e..58c1c5006bbf4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -261,10 +261,8 @@ pub struct Parser<'a> {
 
 impl<'a> Drop for Parser<'a> {
     fn drop(&mut self) {
-        if !self.unclosed_delims.is_empty() {
-            let diag = self.diagnostic();
-            emit_unclosed_delims(&mut self.unclosed_delims, diag);
-        }
+        let diag = self.diagnostic();
+        emit_unclosed_delims(&mut self.unclosed_delims, diag);
     }
 }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index bb4da12bae893..2fa4f5263fbc5 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -10,7 +10,6 @@ use crate::print::pprust;
 use crate::ptr::P;
 use crate::symbol::keywords;
 use crate::syntax::parse::parse_stream_from_source_str;
-use crate::syntax::parse::parser::emit_unclosed_delims;
 use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree};
 
 use syntax_pos::symbol::{self, Symbol};
@@ -675,9 +674,7 @@ impl Nonterminal {
         // FIXME(#43081): Avoid this pretty-print + reparse hack
         let source = pprust::nonterminal_to_string(self);
         let filename = FileName::macro_expansion_source_code(&source);
-        let (tokens_for_real, mut errors) =
-            parse_stream_from_source_str(filename, source, sess, Some(span));
-        emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
+        let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span));
 
         // During early phases of the compiler the AST could get modified
         // directly (e.g., attributes added or removed) and the internal cache
@@ -740,13 +737,7 @@ fn prepend_attrs(sess: &ParseSess,
         let source = pprust::attr_to_string(attr);
         let macro_filename = FileName::macro_expansion_source_code(&source);
         if attr.is_sugared_doc {
-            let (stream, mut errors) = parse_stream_from_source_str(
-                macro_filename,
-                source,
-                sess,
-                Some(span),
-            );
-            emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
+            let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
             builder.push(stream);
             continue
         }
@@ -763,13 +754,7 @@ fn prepend_attrs(sess: &ParseSess,
         // ... and for more complicated paths, fall back to a reparse hack that
         // should eventually be removed.
         } else {
-            let (stream, mut errors) = parse_stream_from_source_str(
-                macro_filename,
-                source,
-                sess,
-                Some(span),
-            );
-            emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
+            let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
             brackets.push(stream);
         }
 
diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs
index 5822b5607f7df..a7ac95ba9ef50 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax_ext/proc_macro_server.rs
@@ -12,7 +12,6 @@ use syntax::ast;
 use syntax::ext::base::ExtCtxt;
 use syntax::parse::lexer::comments;
 use syntax::parse::{self, token, ParseSess};
-use syntax::parse::parser::emit_unclosed_delims;
 use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
 use syntax_pos::hygiene::{SyntaxContext, Transparency};
 use syntax_pos::symbol::{keywords, Symbol};
@@ -410,14 +409,12 @@ impl server::TokenStream for Rustc<'_> {
         stream.is_empty()
     }
     fn from_str(&mut self, src: &str) -> Self::TokenStream {
-        let (tokens, mut errors) = parse::parse_stream_from_source_str(
+        parse::parse_stream_from_source_str(
             FileName::proc_macro_source_code(src.clone()),
             src.to_string(),
             self.sess,
             Some(self.call_site),
-        );
-        emit_unclosed_delims(&mut errors, &self.sess.span_diagnostic);
-        tokens
+        )
     }
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
         stream.to_string()

From 551ea65c87ef567cb22856a769df2a75f2cbb235 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 6 Mar 2019 19:09:24 -0800
Subject: [PATCH 11/11] Rely on drop to emit unclosed delims

---
 src/libsyntax/parse/parser.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 58c1c5006bbf4..7e63da2704996 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -784,7 +784,6 @@ impl<'a> Parser<'a> {
             // leave it in the input
             Ok(false)
         } else if self.last_unexpected_token_span == Some(self.span) {
-            emit_unclosed_delims(&self.unclosed_delims, self.diagnostic());
             FatalError.raise();
         } else {
             let mut expected = edible.iter()