rust-lang/rust

ICE on "Error constructed but not emitted"

dwrensha opened this issue · 5 comments

I'm seeing an internal compiler error on the following input (found by fuzz-rustc):

fn i(n{...,f #
error: this file contains an un-closed delimiter
 --> main.rs:2:2
  |
1 | fn i(n{...,f #
  |     - - un-closed delimiter
  |     |
  |     un-closed delimiter
2 | 
  |  ^

error: expected field pattern, found `...`
 --> main.rs:1:8
  |
1 | fn i(n{...,f #
  |        ^^^ help: to omit remaining fields, use one fewer `.`: `..`

error: internal compiler error: the following error was constructed but not emitted

error: expected `}`, found `,`
 --> main.rs:1:11
  |
1 | fn i(n{...,f #
  |        ---^
  |        |  |
  |        |  expected `}`
  |        `..` must be at the end and cannot have a trailing comma

thread 'rustc' panicked at 'explicit panic', src/librustc_errors/diagnostic_builder.rs:390:13
stack backtrace:
   0: std::panicking::default_hook::{{closure}}
   1: std::panicking::default_hook
   2: rustc::util::common::panic_hook
   3: std::panicking::rust_panic_with_hook
   4: std::panicking::begin_panic
   5: <rustc_errors::diagnostic_builder::DiagnosticBuilder as core::ops::drop::Drop>::drop
   6: syntax::parse::parser::Parser::parse_pat_fields
   7: syntax::parse::parser::Parser::parse_pat_with_range_pat
   8: syntax::parse::parser::Parser::parse_fn_args::{{closure}}
   9: syntax::parse::parser::Parser::parse_seq_to_before_tokens
  10: syntax::parse::parser::Parser::parse_fn_args
  11: syntax::parse::parser::Parser::parse_fn_decl
  12: syntax::parse::parser::Parser::parse_item_fn
  13: syntax::parse::parser::Parser::parse_item_implementation
  14: syntax::parse::parser::Parser::parse_item_
  15: syntax::parse::parser::Parser::parse_item
  16: syntax::parse::parser::Parser::parse_mod_items
  17: syntax::parse::parser::Parser::parse_crate_mod
  18: syntax::parse::parse_crate_from_file
  19: rustc_interface::passes::parse::{{closure}}
  20: rustc::util::common::time
  21: rustc_interface::passes::parse
  22: rustc_interface::queries::Query<T>::compute
  23: rustc_interface::queries::<impl rustc_interface::interface::Compiler>::parse
  24: rustc_interface::interface::run_compiler_in_existing_thread_pool
  25: std::thread::local::LocalKey<T>::with
  26: syntax::with_globals
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
query stack during panic:
end of query stack
error: aborting due to 4 previous errors


error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.38.0-nightly (04b88a9eb 2019-07-29) running on x86_64-apple-darwin

The error happens on stable, beta, and nightly.

ExpHP commented

The only early return I see that doesn't emit delayed_error is here:

https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs#L3623

ExpHP commented

Applying the most obvious patch, I get the following non-ICE output:

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fb5ff7e8f9..665308eda2 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3620,7 +3620,15 @@ impl<'a> Parser<'a> {
         let mut etc_span = None;
 
         while self.token != token::CloseDelim(token::Brace) {
-            let attrs = self.parse_outer_attributes()?;
+            let attrs = match self.parse_outer_attributes() {
+                Ok(attrs) => attrs,
+                Err(err) => {
+                    if let Some(mut delayed) = delayed_err {
+                        delayed.emit();
+                    }
+                    return Err(err);
+                },
+            };
             let lo = self.token.span;
 
             // check that a comma comes after every field
   Compiling lolr v0.1.0 (/home/lampam/cpp/throwaway/lolr)
error: this file contains an un-closed delimiter
 --> src/main.rs:1:16
  |
1 | fn i(n{...,f #
  |     - -        ^
  |     | |
  |     | un-closed delimiter
  |     un-closed delimiter

error: expected field pattern, found `...`
 --> src/main.rs:1:8
  |
1 | fn i(n{...,f #
  |        ^^^ help: to omit remaining fields, use one fewer `.`: `..`

error: expected `}`, found `,`
 --> src/main.rs:1:11
  |
1 | fn i(n{...,f #
  |        ---^
  |        |  |
  |        |  expected `}`
  |        `..` must be at the end and cannot have a trailing comma

error: expected `[`, found `}`
 --> src/main.rs:1:15
  |
1 | fn i(n{...,f #
  |               ^ expected `[`

error: expected `:`, found `)`
 --> src/main.rs:1:15
  |
1 | fn i(n{...,f #
  |               ^ expected `:`

error: expected one of `->`, `where`, or `{`, found `<eof>`
 --> src/main.rs:1:15
  |
1 | fn i(n{...,f #
  |               ^ expected one of `->`, `where`, or `{` here

error: aborting due to 6 previous errors

error: Could not compile `lolr`.

To learn more, run the command again with --verbose.

The "expected :, found )" bit doesn't seem quite right. 🙂

@ExpHP expected <something>, found <closing delimiter> is an unfortunate side effect of the unmatched delimiter recovery logic not accounting for TokenTrees. Submit a PR with this patch to fix this ICE as fixing the slightly misleading message will require a much larger (unrelated) change.

ExpHP commented

I'll toss one up after I finish running the test suite.

One thing: I'm not sure how to annotate the test. It looks like there's four errors that all point to EOF, but whatever I try to write, only one of them gets recognized as referring to that line.

fn i(n{...,f #
//~^ ERROR expected field pattern
//~| ERROR expected `}`, found `,`
//~ ERROR expected `[`, found `}`
//~ ERROR expected `:`, found `)`
//~ ERROR expected one of `->`, `where`, or `{`, found `<eof>`"
//~ ERROR this file contains an un-closed delimiter
unexpected errors (from JSON output): [
    Error {
        line_num: 7,
        kind: Some(
            Error,
        ),
        msg: "7:52: 7:53: expected `[`, found `}`",
    },
    Error {
        line_num: 7,
        kind: Some(
            Error,
        ),
        msg: "7:52: 7:53: expected `:`, found `)`",
    },
    Error {
        line_num: 7,
        kind: Some(
            Error,
        ),
        msg: "7:52: 7:53: expected one of `->`, `where`, or `{`, found `<eof>`",
    },
]

not found errors (from test file): [
    Error {
        line_num: 4,
        kind: Some(
            Error,
        ),
        msg: "expected `[`, found `}`",
    },
    Error {
        line_num: 5,
        kind: Some(
            Error,
        ),
        msg: "expected `:`, found `)`",
    },
    Error {
        line_num: 6,
        kind: Some(
            Error,
        ),
        msg: "expected one of `->`, `where`, or `{`, found `<eof>`",
    },
]