Skip to content

Commit 3f6ea77

Browse files
authored
Merge pull request rust-lang#3240 from Xanewok/parser-panic
Catch possible tokenizer panics
2 parents d1c7afe + c7ee2a2 commit 3f6ea77

File tree

2 files changed

+41
-13
lines changed

2 files changed

+41
-13
lines changed

src/formatting.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::time::{Duration, Instant};
88

99
use syntax::ast;
1010
use syntax::errors::emitter::{ColorConfig, EmitterWriter};
11-
use syntax::errors::Handler;
11+
use syntax::errors::{DiagnosticBuilder, Handler};
1212
use syntax::parse::{self, ParseSess};
1313
use syntax::source_map::{FilePathMapping, SourceMap, Span};
1414

@@ -73,7 +73,12 @@ fn format_project<T: FormatHandler>(
7373
let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
7474
let mut parse_session = make_parse_sess(source_map.clone(), config);
7575
let mut report = FormatReport::new();
76-
let krate = parse_crate(input, &parse_session, config, &mut report)?;
76+
let krate = match parse_crate(input, &parse_session, config, &mut report) {
77+
Ok(krate) => krate,
78+
// Surface parse error via Session (errors are merged there from report)
79+
Err(ErrorKind::ParseError) => return Ok(report),
80+
Err(e) => return Err(e),
81+
};
7782
timer = timer.done_parsing();
7883

7984
// Suppress error output if we have to do any further parsing.
@@ -604,30 +609,41 @@ fn parse_crate(
604609
) -> Result<ast::Crate, ErrorKind> {
605610
let input_is_stdin = input.is_text();
606611

607-
let mut parser = match input {
608-
Input::File(file) => parse::new_parser_from_file(parse_session, &file),
609-
Input::Text(text) => parse::new_parser_from_source_str(
612+
let parser = match input {
613+
Input::File(file) => Ok(parse::new_parser_from_file(parse_session, &file)),
614+
Input::Text(text) => parse::maybe_new_parser_from_source_str(
610615
parse_session,
611616
syntax::source_map::FileName::Custom("stdin".to_owned()),
612617
text,
613-
),
618+
)
619+
.map_err(|diags| {
620+
diags
621+
.into_iter()
622+
.map(|d| DiagnosticBuilder::new_diagnostic(&parse_session.span_diagnostic, d))
623+
.collect::<Vec<_>>()
624+
}),
614625
};
615626

616-
parser.cfg_mods = false;
617-
if config.skip_children() {
618-
parser.recurse_into_file_modules = false;
619-
}
627+
let result = match parser {
628+
Ok(mut parser) => {
629+
parser.cfg_mods = false;
630+
if config.skip_children() {
631+
parser.recurse_into_file_modules = false;
632+
}
620633

621-
let mut parser = AssertUnwindSafe(parser);
622-
let result = catch_unwind(move || parser.0.parse_crate_mod());
634+
let mut parser = AssertUnwindSafe(parser);
635+
catch_unwind(move || parser.0.parse_crate_mod().map_err(|d| vec![d]))
636+
}
637+
Err(db) => Ok(Err(db)),
638+
};
623639

624640
match result {
625641
Ok(Ok(c)) => {
626642
if !parse_session.span_diagnostic.has_errors() {
627643
return Ok(c);
628644
}
629645
}
630-
Ok(Err(mut e)) => e.emit(),
646+
Ok(Err(mut diagnostics)) => diagnostics.iter_mut().for_each(|d| d.emit()),
631647
Err(_) => {
632648
// Note that if you see this message and want more information,
633649
// then run the `parse_crate_mod` function above without

src/test/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,18 @@ fn stdin_formatting_smoke_test() {
286286
assert_eq!(buf, "fn main() {}\r\n".as_bytes());
287287
}
288288

289+
#[test]
290+
fn stdin_parser_panic_caught() {
291+
// https://github.com/rust-lang/rustfmt/issues/3239
292+
for text in ["{", "}"].iter().cloned().map(String::from) {
293+
let mut buf = vec![];
294+
let mut session = Session::new(Default::default(), Some(&mut buf));
295+
let _ = session.format(Input::Text(text));
296+
297+
assert!(session.has_parsing_errors());
298+
}
299+
}
300+
289301
#[test]
290302
fn stdin_disable_all_formatting_test() {
291303
match option_env!("CFG_RELEASE_CHANNEL") {

0 commit comments

Comments
 (0)