Skip to content

Commit 9153451

Browse files
authored
Rollup merge of #121301 - davidtwco:rustfmt-silent-emitter, r=pnkfelix
errors: share `SilentEmitter` between rustc and rustfmt Fixes rust-lang/rustfmt#6082. Shares the `SilentEmitter` between rustc and rustfmt, and gives it a fallback bundle (since it can emit diagnostics in some contexts).
2 parents 640648b + 2ee0409 commit 9153451

File tree

7 files changed

+131
-108
lines changed

7 files changed

+131
-108
lines changed

compiler/rustc_errors/src/emitter.rs

+8-24
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use rustc_span::source_map::SourceMap;
1111
use rustc_span::{FileLines, FileName, SourceFile, Span};
1212

13-
use crate::error::TranslateError;
1413
use crate::snippet::{
1514
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
1615
};
@@ -539,18 +538,9 @@ impl Emitter for HumanEmitter {
539538
/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
540539
/// failures of rustc, as witnessed e.g. in issue #89358.
541540
pub struct SilentEmitter {
541+
pub fallback_bundle: LazyFallbackBundle,
542542
pub fatal_dcx: DiagCtxt,
543-
pub fatal_note: String,
544-
}
545-
546-
pub fn silent_translate<'a>(message: &'a DiagMessage) -> Result<Cow<'_, str>, TranslateError<'_>> {
547-
match message {
548-
DiagMessage::Str(msg) | DiagMessage::Translated(msg) => Ok(Cow::Borrowed(msg)),
549-
DiagMessage::FluentIdentifier(identifier, _) => {
550-
// Any value works here.
551-
Ok(identifier.clone())
552-
}
553-
}
543+
pub fatal_note: Option<String>,
554544
}
555545

556546
impl Translate for SilentEmitter {
@@ -559,17 +549,9 @@ impl Translate for SilentEmitter {
559549
}
560550

561551
fn fallback_fluent_bundle(&self) -> &FluentBundle {
562-
panic!("silent emitter attempted to translate message")
563-
}
564-
565-
// Override `translate_message` for the silent emitter because eager translation of
566-
// subdiagnostics result in a call to this.
567-
fn translate_message<'a>(
568-
&'a self,
569-
message: &'a DiagMessage,
570-
_: &'a FluentArgs<'_>,
571-
) -> Result<Cow<'_, str>, TranslateError<'_>> {
572-
silent_translate(message)
552+
// Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be
553+
// used but the lock prevents this.
554+
&self.fallback_bundle
573555
}
574556
}
575557

@@ -580,7 +562,9 @@ impl Emitter for SilentEmitter {
580562

581563
fn emit_diagnostic(&mut self, mut diag: DiagInner) {
582564
if diag.level == Level::Fatal {
583-
diag.sub(Level::Note, self.fatal_note.clone(), MultiSpan::new());
565+
if let Some(fatal_note) = &self.fatal_note {
566+
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
567+
}
584568
self.fatal_dcx.emit_diagnostic(diag);
585569
}
586570
}

compiler/rustc_errors/src/lib.rs

+72-23
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use emitter::{is_case_difference, DynEmitter, Emitter};
6363
use registry::Registry;
6464
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
6565
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
66-
use rustc_data_structures::sync::Lock;
66+
use rustc_data_structures::sync::{Lock, Lrc};
6767
use rustc_data_structures::AtomicRef;
6868
use rustc_lint_defs::LintExpectationId;
6969
use rustc_span::source_map::SourceMap;
@@ -606,29 +606,54 @@ impl DiagCtxt {
606606
}
607607

608608
pub fn new(emitter: Box<DynEmitter>) -> Self {
609-
Self {
610-
inner: Lock::new(DiagCtxtInner {
611-
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
612-
err_guars: Vec::new(),
613-
lint_err_guars: Vec::new(),
614-
delayed_bugs: Vec::new(),
615-
deduplicated_err_count: 0,
616-
deduplicated_warn_count: 0,
617-
emitter,
618-
must_produce_diag: false,
619-
has_printed: false,
620-
suppressed_expected_diag: false,
621-
taught_diagnostics: Default::default(),
622-
emitted_diagnostic_codes: Default::default(),
623-
emitted_diagnostics: Default::default(),
624-
stashed_diagnostics: Default::default(),
625-
future_breakage_diagnostics: Vec::new(),
626-
check_unstable_expect_diagnostics: false,
627-
unstable_expect_diagnostics: Vec::new(),
628-
fulfilled_expectations: Default::default(),
629-
ice_file: None,
630-
}),
609+
Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
610+
}
611+
612+
pub fn make_silent(&mut self, fallback_bundle: LazyFallbackBundle, fatal_note: Option<String>) {
613+
self.wrap_emitter(|old_dcx| {
614+
Box::new(emitter::SilentEmitter {
615+
fallback_bundle,
616+
fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) },
617+
fatal_note,
618+
})
619+
});
620+
}
621+
622+
fn wrap_emitter<F>(&mut self, f: F)
623+
where
624+
F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>,
625+
{
626+
// A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed
627+
// to temporarily swap in place of the real one, which will be used in constructing
628+
// its replacement.
629+
struct FalseEmitter;
630+
631+
impl Emitter for FalseEmitter {
632+
fn emit_diagnostic(&mut self, _: DiagInner) {
633+
unimplemented!("false emitter must only used during `wrap_emitter`")
634+
}
635+
636+
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
637+
unimplemented!("false emitter must only used during `wrap_emitter`")
638+
}
631639
}
640+
641+
impl translation::Translate for FalseEmitter {
642+
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
643+
unimplemented!("false emitter must only used during `wrap_emitter`")
644+
}
645+
646+
fn fallback_fluent_bundle(&self) -> &FluentBundle {
647+
unimplemented!("false emitter must only used during `wrap_emitter`")
648+
}
649+
}
650+
651+
let mut inner = self.inner.borrow_mut();
652+
let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter));
653+
std::mem::swap(&mut *inner, &mut prev_dcx);
654+
let new_emitter = f(prev_dcx);
655+
let mut new_dcx = DiagCtxtInner::new(new_emitter);
656+
std::mem::swap(&mut *inner, &mut new_dcx);
632657
}
633658

634659
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
@@ -1345,6 +1370,30 @@ impl DiagCtxt {
13451370
// `DiagCtxt::foo()` just borrows `inner` and forwards a call to
13461371
// `DiagCtxtInner::foo`.
13471372
impl DiagCtxtInner {
1373+
fn new(emitter: Box<DynEmitter>) -> Self {
1374+
Self {
1375+
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1376+
err_guars: Vec::new(),
1377+
lint_err_guars: Vec::new(),
1378+
delayed_bugs: Vec::new(),
1379+
deduplicated_err_count: 0,
1380+
deduplicated_warn_count: 0,
1381+
emitter,
1382+
must_produce_diag: false,
1383+
has_printed: false,
1384+
suppressed_expected_diag: false,
1385+
taught_diagnostics: Default::default(),
1386+
emitted_diagnostic_codes: Default::default(),
1387+
emitted_diagnostics: Default::default(),
1388+
stashed_diagnostics: Default::default(),
1389+
future_breakage_diagnostics: Vec::new(),
1390+
check_unstable_expect_diagnostics: false,
1391+
unstable_expect_diagnostics: Vec::new(),
1392+
fulfilled_expectations: Default::default(),
1393+
ice_file: None,
1394+
}
1395+
}
1396+
13481397
/// Emit all stashed diagnostics.
13491398
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
13501399
let mut guar = None;

compiler/rustc_interface/src/interface.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ pub struct Compiler {
4545
pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
4646
cfgs.into_iter()
4747
.map(|s| {
48-
let psess = ParseSess::with_silent_emitter(format!(
49-
"this error occurred on the command line: `--cfg={s}`"
50-
));
48+
let psess = ParseSess::with_silent_emitter(
49+
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
50+
format!("this error occurred on the command line: `--cfg={s}`"),
51+
);
5152
let filename = FileName::cfg_spec_source_code(&s);
5253

5354
macro_rules! error {
@@ -107,9 +108,10 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
107108
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
108109

109110
for s in specs {
110-
let psess = ParseSess::with_silent_emitter(format!(
111-
"this error occurred on the command line: `--check-cfg={s}`"
112-
));
111+
let psess = ParseSess::with_silent_emitter(
112+
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
113+
format!("this error occurred on the command line: `--check-cfg={s}`"),
114+
);
113115
let filename = FileName::cfg_spec_source_code(&s);
114116

115117
macro_rules! error {

compiler/rustc_session/src/parse.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -265,14 +265,20 @@ impl ParseSess {
265265
}
266266
}
267267

268-
pub fn with_silent_emitter(fatal_note: String) -> Self {
269-
let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
268+
pub fn with_silent_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self {
269+
let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
270270
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
271-
let emitter =
272-
Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle));
271+
let emitter = Box::new(HumanEmitter::new(
272+
stderr_destination(ColorConfig::Auto),
273+
fallback_bundle.clone(),
274+
));
273275
let fatal_dcx = DiagCtxt::new(emitter);
274-
let dcx =
275-
DiagCtxt::new(Box::new(SilentEmitter { fatal_dcx, fatal_note })).disable_warnings();
276+
let dcx = DiagCtxt::new(Box::new(SilentEmitter {
277+
fallback_bundle,
278+
fatal_dcx,
279+
fatal_note: Some(fatal_note),
280+
}))
281+
.disable_warnings();
276282
ParseSess::with_dcx(dcx, sm)
277283
}
278284

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

+25-48
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use std::borrow::Cow;
21
use std::path::Path;
32
use std::sync::atomic::{AtomicBool, Ordering};
43

54
use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
6-
use rustc_errors::emitter::{stderr_destination, DynEmitter, Emitter, HumanEmitter};
5+
use rustc_errors::emitter::{stderr_destination, DynEmitter, Emitter, HumanEmitter, SilentEmitter};
76
use rustc_errors::translation::Translate;
87
use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel};
98
use rustc_session::parse::ParseSess as RawParseSess;
@@ -28,41 +27,6 @@ pub(crate) struct ParseSess {
2827
can_reset_errors: Lrc<AtomicBool>,
2928
}
3029

31-
/// Emitter which discards every error.
32-
struct SilentEmitter;
33-
34-
impl Translate for SilentEmitter {
35-
fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
36-
None
37-
}
38-
39-
fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
40-
panic!("silent emitter attempted to translate a diagnostic");
41-
}
42-
43-
// Override `translate_message` for the silent emitter because eager translation of
44-
// subdiagnostics result in a call to this.
45-
fn translate_message<'a>(
46-
&'a self,
47-
message: &'a rustc_errors::DiagMessage,
48-
_: &'a rustc_errors::translation::FluentArgs<'_>,
49-
) -> Result<Cow<'_, str>, rustc_errors::error::TranslateError<'_>> {
50-
rustc_errors::emitter::silent_translate(message)
51-
}
52-
}
53-
54-
impl Emitter for SilentEmitter {
55-
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
56-
None
57-
}
58-
59-
fn emit_diagnostic(&mut self, _diag: DiagInner) {}
60-
}
61-
62-
fn silent_emitter() -> Box<DynEmitter> {
63-
Box::new(SilentEmitter {})
64-
}
65-
6630
/// Emit errors against every files expect ones specified in the `ignore_path_set`.
6731
struct SilentOnIgnoredFilesEmitter {
6832
ignore_path_set: IntoDynSyncSend<Lrc<IgnorePathSet>>,
@@ -143,17 +107,23 @@ fn default_dcx(
143107
ColorConfig::Never
144108
};
145109

146-
let emitter = if hide_parse_errors {
147-
silent_emitter()
110+
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
111+
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
112+
false,
113+
);
114+
let emitter = Box::new(
115+
HumanEmitter::new(stderr_destination(emit_color), fallback_bundle.clone())
116+
.sm(Some(source_map.clone())),
117+
);
118+
119+
let emitter: Box<DynEmitter> = if hide_parse_errors {
120+
Box::new(SilentEmitter {
121+
fallback_bundle,
122+
fatal_dcx: DiagCtxt::new(emitter),
123+
fatal_note: None,
124+
})
148125
} else {
149-
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
150-
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
151-
false,
152-
);
153-
Box::new(
154-
HumanEmitter::new(stderr_destination(emit_color), fallback_bundle)
155-
.sm(Some(source_map.clone())),
156-
)
126+
emitter
157127
};
158128
DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter {
159129
has_non_ignorable_parser_errors: false,
@@ -232,7 +202,14 @@ impl ParseSess {
232202
}
233203

234204
pub(crate) fn set_silent_emitter(&mut self) {
235-
self.raw_psess.dcx = DiagCtxt::new(silent_emitter());
205+
// Ideally this invocation wouldn't be necessary and the fallback bundle in
206+
// `self.parse_sess.dcx` could be used, but the lock in `DiagCtxt` prevents this.
207+
// See `<rustc_errors::SilentEmitter as Translate>::fallback_fluent_bundle`.
208+
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
209+
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
210+
false,
211+
);
212+
self.raw_psess.dcx.make_silent(fallback_bundle, None);
236213
}
237214

238215
pub(crate) fn span_to_filename(&self, span: Span) -> FileName {

src/tools/rustfmt/tests/rustfmt/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ fn rustfmt_emits_error_on_line_overflow_true() {
176176
#[test]
177177
#[allow(non_snake_case)]
178178
fn dont_emit_ICE() {
179-
let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs"];
179+
let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs", "tests/target/issue_6082.rs"];
180180

181181
for file in files {
182182
let args = [file];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
macro_rules! test {
2+
($T:ident, $b:lifetime) => {
3+
Box<$T<$b>>
4+
};
5+
}

0 commit comments

Comments
 (0)