Skip to content

Commit bf7d1b5

Browse files
committed
Move emit_stashed_diagnostic call in rustfmt.
This call was added to `parse_crate_mod` in #121487, to fix a case where a stashed diagnostic wasn't emitted. But there is another path where a stashed diagnostic might fail to be emitted if there's a parse error, if the `build` call in `parse_crate_inner` fails before `parse_crate_mod` is reached. So this commit moves the `emit_stashed_diagnostic` call outwards, from `parse_crate_mod` to `format_project`, just after the `Parser::parse_crate` call. This should be far out enough to catch any parsing errors. Fixes #121517.
1 parent 8c0b1fc commit bf7d1b5

File tree

5 files changed

+35
-19
lines changed

5 files changed

+35
-19
lines changed

src/tools/rustfmt/src/formatting.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,29 @@ fn format_project<T: FormatHandler>(
109109
let main_file = input.file_name();
110110
let input_is_stdin = main_file == FileName::Stdin;
111111

112-
let parse_session = ParseSess::new(config)?;
112+
let mut parse_session = ParseSess::new(config)?;
113113
if config.skip_children() && parse_session.ignore_file(&main_file) {
114114
return Ok(FormatReport::new());
115115
}
116116

117117
// Parse the crate.
118118
let mut report = FormatReport::new();
119119
let directory_ownership = input.to_directory_ownership();
120-
let krate = match Parser::parse_crate(input, &parse_session) {
121-
Ok(krate) => krate,
122-
// Surface parse error via Session (errors are merged there from report)
123-
Err(e) => {
124-
let forbid_verbose = input_is_stdin || e != ParserError::ParsePanicError;
120+
121+
// rustfmt doesn't use `run_compiler` like other tools, so it must emit any
122+
// stashed diagnostics itself, otherwise the `DiagCtxt` will assert when
123+
// dropped. The final result here combines the parsing result and the
124+
// `emit_stashed_diagnostics` result.
125+
let parse_res = Parser::parse_crate(input, &parse_session);
126+
let stashed_res = parse_session.emit_stashed_diagnostics();
127+
let krate = match (parse_res, stashed_res) {
128+
(Ok(krate), None) => krate,
129+
(parse_res, _) => {
130+
// Surface parse error via Session (errors are merged there from report).
131+
let forbid_verbose = match parse_res {
132+
Err(e) if e != ParserError::ParsePanicError => true,
133+
_ => input_is_stdin,
134+
};
125135
should_emit_verbose(forbid_verbose, config, || {
126136
eprintln!("The Rust parser panicked");
127137
});

src/tools/rustfmt/src/parse/parser.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -162,22 +162,14 @@ impl<'a> Parser<'a> {
162162

163163
fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
164164
let mut parser = AssertUnwindSafe(&mut self.parser);
165-
166-
// rustfmt doesn't use `run_compiler` like other tools, so it must emit
167-
// any stashed diagnostics itself, otherwise the `DiagCtxt` will assert
168-
// when dropped. The final result here combines the parsing result and
169-
// the `emit_stashed_diagnostics` result.
170-
let parse_res = catch_unwind(move || parser.parse_crate_mod());
171-
let stashed_res = self.parser.dcx().emit_stashed_diagnostics();
172165
let err = Err(ParserError::ParsePanicError);
173-
match (parse_res, stashed_res) {
174-
(Ok(Ok(k)), None) => Ok(k),
175-
(Ok(Ok(_)), Some(_guar)) => err,
176-
(Ok(Err(db)), _) => {
166+
match catch_unwind(move || parser.parse_crate_mod()) {
167+
Ok(Ok(k)) => Ok(k),
168+
Ok(Err(db)) => {
177169
db.emit();
178170
err
179171
}
180-
(Err(_), _) => err,
172+
Err(_) => err,
181173
}
182174
}
183175
}

src/tools/rustfmt/src/parse/session.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
66
use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter};
77
use rustc_errors::translation::Translate;
88
use rustc_errors::{
9-
ColorConfig, DiagCtxt, Diagnostic, DiagnosticBuilder, Level as DiagnosticLevel,
9+
ColorConfig, DiagCtxt, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Level as DiagnosticLevel,
1010
};
1111
use rustc_session::parse::ParseSess as RawParseSess;
1212
use rustc_span::{
@@ -230,6 +230,10 @@ impl ParseSess {
230230
self.ignore_path_set.as_ref().is_match(path)
231231
}
232232

233+
pub(crate) fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
234+
self.parse_sess.dcx.emit_stashed_diagnostics()
235+
}
236+
233237
pub(crate) fn set_silent_emitter(&mut self) {
234238
self.parse_sess.dcx = DiagCtxt::with_emitter(silent_emitter());
235239
}

src/tools/rustfmt/src/test/parser.rs

+7
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,10 @@ fn crate_parsing_stashed_diag() {
6262
let filename = "tests/parser/stashed-diag.rs";
6363
assert_parser_error(filename);
6464
}
65+
66+
#[test]
67+
fn crate_parsing_stashed_diag2() {
68+
// See also https://github.com/rust-lang/rust/issues/121517
69+
let filename = "tests/parser/stashed-diag2.rs";
70+
assert_parser_error(filename);
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait Trait<'1> { s> {}
2+
3+
fn main() {}

0 commit comments

Comments
 (0)