mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
errors: share SilentEmitter
between rustc and rustfmt
Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
5a1e5449c8
commit
2ee0409f32
@ -10,7 +10,6 @@
|
|||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::{FileLines, FileName, SourceFile, Span};
|
use rustc_span::{FileLines, FileName, SourceFile, Span};
|
||||||
|
|
||||||
use crate::error::TranslateError;
|
|
||||||
use crate::snippet::{
|
use crate::snippet::{
|
||||||
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
|
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
|
||||||
};
|
};
|
||||||
@ -539,18 +538,9 @@ impl Emitter for HumanEmitter {
|
|||||||
/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
|
/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
|
||||||
/// failures of rustc, as witnessed e.g. in issue #89358.
|
/// failures of rustc, as witnessed e.g. in issue #89358.
|
||||||
pub struct SilentEmitter {
|
pub struct SilentEmitter {
|
||||||
|
pub fallback_bundle: LazyFallbackBundle,
|
||||||
pub fatal_dcx: DiagCtxt,
|
pub fatal_dcx: DiagCtxt,
|
||||||
pub fatal_note: String,
|
pub fatal_note: Option<String>,
|
||||||
}
|
|
||||||
|
|
||||||
pub fn silent_translate<'a>(message: &'a DiagMessage) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
|
||||||
match message {
|
|
||||||
DiagMessage::Str(msg) | DiagMessage::Translated(msg) => Ok(Cow::Borrowed(msg)),
|
|
||||||
DiagMessage::FluentIdentifier(identifier, _) => {
|
|
||||||
// Any value works here.
|
|
||||||
Ok(identifier.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Translate for SilentEmitter {
|
impl Translate for SilentEmitter {
|
||||||
@ -559,17 +549,9 @@ impl Translate for SilentEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||||
panic!("silent emitter attempted to translate message")
|
// Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be
|
||||||
}
|
// used but the lock prevents this.
|
||||||
|
&self.fallback_bundle
|
||||||
// Override `translate_message` for the silent emitter because eager translation of
|
|
||||||
// subdiagnostics result in a call to this.
|
|
||||||
fn translate_message<'a>(
|
|
||||||
&'a self,
|
|
||||||
message: &'a DiagMessage,
|
|
||||||
_: &'a FluentArgs<'_>,
|
|
||||||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
|
||||||
silent_translate(message)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,7 +562,9 @@ impl Emitter for SilentEmitter {
|
|||||||
|
|
||||||
fn emit_diagnostic(&mut self, mut diag: DiagInner) {
|
fn emit_diagnostic(&mut self, mut diag: DiagInner) {
|
||||||
if diag.level == Level::Fatal {
|
if diag.level == Level::Fatal {
|
||||||
diag.sub(Level::Note, self.fatal_note.clone(), MultiSpan::new());
|
if let Some(fatal_note) = &self.fatal_note {
|
||||||
|
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
|
||||||
|
}
|
||||||
self.fatal_dcx.emit_diagnostic(diag);
|
self.fatal_dcx.emit_diagnostic(diag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ use emitter::{is_case_difference, DynEmitter, Emitter};
|
|||||||
use registry::Registry;
|
use registry::Registry;
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
|
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::{Lock, Lrc};
|
||||||
use rustc_data_structures::AtomicRef;
|
use rustc_data_structures::AtomicRef;
|
||||||
use rustc_lint_defs::LintExpectationId;
|
use rustc_lint_defs::LintExpectationId;
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
@ -606,29 +606,54 @@ impl DiagCtxt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(emitter: Box<DynEmitter>) -> Self {
|
pub fn new(emitter: Box<DynEmitter>) -> Self {
|
||||||
Self {
|
Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
|
||||||
inner: Lock::new(DiagCtxtInner {
|
|
||||||
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
|
||||||
err_guars: Vec::new(),
|
|
||||||
lint_err_guars: Vec::new(),
|
|
||||||
delayed_bugs: Vec::new(),
|
|
||||||
deduplicated_err_count: 0,
|
|
||||||
deduplicated_warn_count: 0,
|
|
||||||
emitter,
|
|
||||||
must_produce_diag: false,
|
|
||||||
has_printed: false,
|
|
||||||
suppressed_expected_diag: false,
|
|
||||||
taught_diagnostics: Default::default(),
|
|
||||||
emitted_diagnostic_codes: Default::default(),
|
|
||||||
emitted_diagnostics: Default::default(),
|
|
||||||
stashed_diagnostics: Default::default(),
|
|
||||||
future_breakage_diagnostics: Vec::new(),
|
|
||||||
check_unstable_expect_diagnostics: false,
|
|
||||||
unstable_expect_diagnostics: Vec::new(),
|
|
||||||
fulfilled_expectations: Default::default(),
|
|
||||||
ice_file: None,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_silent(&mut self, fallback_bundle: LazyFallbackBundle, fatal_note: Option<String>) {
|
||||||
|
self.wrap_emitter(|old_dcx| {
|
||||||
|
Box::new(emitter::SilentEmitter {
|
||||||
|
fallback_bundle,
|
||||||
|
fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) },
|
||||||
|
fatal_note,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_emitter<F>(&mut self, f: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>,
|
||||||
|
{
|
||||||
|
// A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed
|
||||||
|
// to temporarily swap in place of the real one, which will be used in constructing
|
||||||
|
// its replacement.
|
||||||
|
struct FalseEmitter;
|
||||||
|
|
||||||
|
impl Emitter for FalseEmitter {
|
||||||
|
fn emit_diagnostic(&mut self, _: DiagInner) {
|
||||||
|
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
||||||
|
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl translation::Translate for FalseEmitter {
|
||||||
|
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
|
||||||
|
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||||
|
unimplemented!("false emitter must only used during `wrap_emitter`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter));
|
||||||
|
std::mem::swap(&mut *inner, &mut prev_dcx);
|
||||||
|
let new_emitter = f(prev_dcx);
|
||||||
|
let mut new_dcx = DiagCtxtInner::new(new_emitter);
|
||||||
|
std::mem::swap(&mut *inner, &mut new_dcx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
|
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
|
||||||
@ -1345,6 +1370,30 @@ impl DiagCtxt {
|
|||||||
// `DiagCtxt::foo()` just borrows `inner` and forwards a call to
|
// `DiagCtxt::foo()` just borrows `inner` and forwards a call to
|
||||||
// `DiagCtxtInner::foo`.
|
// `DiagCtxtInner::foo`.
|
||||||
impl DiagCtxtInner {
|
impl DiagCtxtInner {
|
||||||
|
fn new(emitter: Box<DynEmitter>) -> Self {
|
||||||
|
Self {
|
||||||
|
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
||||||
|
err_guars: Vec::new(),
|
||||||
|
lint_err_guars: Vec::new(),
|
||||||
|
delayed_bugs: Vec::new(),
|
||||||
|
deduplicated_err_count: 0,
|
||||||
|
deduplicated_warn_count: 0,
|
||||||
|
emitter,
|
||||||
|
must_produce_diag: false,
|
||||||
|
has_printed: false,
|
||||||
|
suppressed_expected_diag: false,
|
||||||
|
taught_diagnostics: Default::default(),
|
||||||
|
emitted_diagnostic_codes: Default::default(),
|
||||||
|
emitted_diagnostics: Default::default(),
|
||||||
|
stashed_diagnostics: Default::default(),
|
||||||
|
future_breakage_diagnostics: Vec::new(),
|
||||||
|
check_unstable_expect_diagnostics: false,
|
||||||
|
unstable_expect_diagnostics: Vec::new(),
|
||||||
|
fulfilled_expectations: Default::default(),
|
||||||
|
ice_file: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Emit all stashed diagnostics.
|
/// Emit all stashed diagnostics.
|
||||||
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
|
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
|
||||||
let mut guar = None;
|
let mut guar = None;
|
||||||
|
@ -45,9 +45,10 @@ pub struct Compiler {
|
|||||||
pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
|
pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
|
||||||
cfgs.into_iter()
|
cfgs.into_iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
let psess = ParseSess::with_silent_emitter(format!(
|
let psess = ParseSess::with_silent_emitter(
|
||||||
"this error occurred on the command line: `--cfg={s}`"
|
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
|
||||||
));
|
format!("this error occurred on the command line: `--cfg={s}`"),
|
||||||
|
);
|
||||||
let filename = FileName::cfg_spec_source_code(&s);
|
let filename = FileName::cfg_spec_source_code(&s);
|
||||||
|
|
||||||
macro_rules! error {
|
macro_rules! error {
|
||||||
@ -107,9 +108,10 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
|
|||||||
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
|
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
|
||||||
|
|
||||||
for s in specs {
|
for s in specs {
|
||||||
let psess = ParseSess::with_silent_emitter(format!(
|
let psess = ParseSess::with_silent_emitter(
|
||||||
"this error occurred on the command line: `--check-cfg={s}`"
|
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
|
||||||
));
|
format!("this error occurred on the command line: `--check-cfg={s}`"),
|
||||||
|
);
|
||||||
let filename = FileName::cfg_spec_source_code(&s);
|
let filename = FileName::cfg_spec_source_code(&s);
|
||||||
|
|
||||||
macro_rules! error {
|
macro_rules! error {
|
||||||
|
@ -265,14 +265,20 @@ impl ParseSess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_silent_emitter(fatal_note: String) -> Self {
|
pub fn with_silent_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self {
|
||||||
let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
|
let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
|
||||||
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||||
let emitter =
|
let emitter = Box::new(HumanEmitter::new(
|
||||||
Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle));
|
stderr_destination(ColorConfig::Auto),
|
||||||
|
fallback_bundle.clone(),
|
||||||
|
));
|
||||||
let fatal_dcx = DiagCtxt::new(emitter);
|
let fatal_dcx = DiagCtxt::new(emitter);
|
||||||
let dcx =
|
let dcx = DiagCtxt::new(Box::new(SilentEmitter {
|
||||||
DiagCtxt::new(Box::new(SilentEmitter { fatal_dcx, fatal_note })).disable_warnings();
|
fallback_bundle,
|
||||||
|
fatal_dcx,
|
||||||
|
fatal_note: Some(fatal_note),
|
||||||
|
}))
|
||||||
|
.disable_warnings();
|
||||||
ParseSess::with_dcx(dcx, sm)
|
ParseSess::with_dcx(dcx, sm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
|
use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
|
||||||
use rustc_errors::emitter::{stderr_destination, DynEmitter, Emitter, HumanEmitter};
|
use rustc_errors::emitter::{stderr_destination, DynEmitter, Emitter, HumanEmitter, SilentEmitter};
|
||||||
use rustc_errors::translation::Translate;
|
use rustc_errors::translation::Translate;
|
||||||
use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel};
|
use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel};
|
||||||
use rustc_session::parse::ParseSess as RawParseSess;
|
use rustc_session::parse::ParseSess as RawParseSess;
|
||||||
@ -28,41 +27,6 @@ pub(crate) struct ParseSess {
|
|||||||
can_reset_errors: Lrc<AtomicBool>,
|
can_reset_errors: Lrc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emitter which discards every error.
|
|
||||||
struct SilentEmitter;
|
|
||||||
|
|
||||||
impl Translate for SilentEmitter {
|
|
||||||
fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
|
|
||||||
panic!("silent emitter attempted to translate a diagnostic");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override `translate_message` for the silent emitter because eager translation of
|
|
||||||
// subdiagnostics result in a call to this.
|
|
||||||
fn translate_message<'a>(
|
|
||||||
&'a self,
|
|
||||||
message: &'a rustc_errors::DiagMessage,
|
|
||||||
_: &'a rustc_errors::translation::FluentArgs<'_>,
|
|
||||||
) -> Result<Cow<'_, str>, rustc_errors::error::TranslateError<'_>> {
|
|
||||||
rustc_errors::emitter::silent_translate(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Emitter for SilentEmitter {
|
|
||||||
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_diagnostic(&mut self, _diag: DiagInner) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn silent_emitter() -> Box<DynEmitter> {
|
|
||||||
Box::new(SilentEmitter {})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emit errors against every files expect ones specified in the `ignore_path_set`.
|
/// Emit errors against every files expect ones specified in the `ignore_path_set`.
|
||||||
struct SilentOnIgnoredFilesEmitter {
|
struct SilentOnIgnoredFilesEmitter {
|
||||||
ignore_path_set: IntoDynSyncSend<Lrc<IgnorePathSet>>,
|
ignore_path_set: IntoDynSyncSend<Lrc<IgnorePathSet>>,
|
||||||
@ -143,17 +107,23 @@ fn default_dcx(
|
|||||||
ColorConfig::Never
|
ColorConfig::Never
|
||||||
};
|
};
|
||||||
|
|
||||||
let emitter = if hide_parse_errors {
|
|
||||||
silent_emitter()
|
|
||||||
} else {
|
|
||||||
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
|
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
|
||||||
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
|
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
Box::new(
|
let emitter = Box::new(
|
||||||
HumanEmitter::new(stderr_destination(emit_color), fallback_bundle)
|
HumanEmitter::new(stderr_destination(emit_color), fallback_bundle.clone())
|
||||||
.sm(Some(source_map.clone())),
|
.sm(Some(source_map.clone())),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
let emitter: Box<DynEmitter> = if hide_parse_errors {
|
||||||
|
Box::new(SilentEmitter {
|
||||||
|
fallback_bundle,
|
||||||
|
fatal_dcx: DiagCtxt::new(emitter),
|
||||||
|
fatal_note: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
emitter
|
||||||
};
|
};
|
||||||
DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter {
|
DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter {
|
||||||
has_non_ignorable_parser_errors: false,
|
has_non_ignorable_parser_errors: false,
|
||||||
@ -232,7 +202,14 @@ impl ParseSess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_silent_emitter(&mut self) {
|
pub(crate) fn set_silent_emitter(&mut self) {
|
||||||
self.raw_psess.dcx = DiagCtxt::new(silent_emitter());
|
// Ideally this invocation wouldn't be necessary and the fallback bundle in
|
||||||
|
// `self.parse_sess.dcx` could be used, but the lock in `DiagCtxt` prevents this.
|
||||||
|
// See `<rustc_errors::SilentEmitter as Translate>::fallback_fluent_bundle`.
|
||||||
|
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
|
||||||
|
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
self.raw_psess.dcx.make_silent(fallback_bundle, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
|
pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
|
||||||
|
@ -176,7 +176,7 @@ fn rustfmt_emits_error_on_line_overflow_true() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn dont_emit_ICE() {
|
fn dont_emit_ICE() {
|
||||||
let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs"];
|
let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs", "tests/target/issue_6082.rs"];
|
||||||
|
|
||||||
for file in files {
|
for file in files {
|
||||||
let args = [file];
|
let args = [file];
|
||||||
|
5
src/tools/rustfmt/tests/target/issue_6082.rs
Normal file
5
src/tools/rustfmt/tests/target/issue_6082.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
macro_rules! test {
|
||||||
|
($T:ident, $b:lifetime) => {
|
||||||
|
Box<$T<$b>>
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user