Rollup merge of #121206 - nnethercote:top-level-error-handling, r=oli-obk
Top level error handling The interactions between the following things are surprisingly complicated: - `emit_stashed_diagnostics`, - `flush_delayed`, - normal return vs `abort_if_errors`/`FatalError.raise()` unwinding in the call to the closure in `interface::run_compiler`. This PR disentangles it all. r? `@oli-obk`
This commit is contained in:
commit
5c89029585
26 changed files with 174 additions and 155 deletions
|
@ -3,7 +3,7 @@ use rustc_ast::CRATE_NODE_ID;
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_errors::{DiagCtxt, ErrorGuaranteed};
|
||||
use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError};
|
||||
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::find_native_static_library;
|
||||
|
@ -487,7 +487,9 @@ fn collate_raw_dylibs<'a, 'b>(
|
|||
}
|
||||
}
|
||||
}
|
||||
sess.compile_status()?;
|
||||
if let Some(guar) = sess.dcx().has_errors() {
|
||||
return Err(guar);
|
||||
}
|
||||
Ok(dylib_table
|
||||
.into_iter()
|
||||
.map(|(name, imports)| {
|
||||
|
@ -720,10 +722,7 @@ fn link_dwarf_object<'a>(
|
|||
Ok(())
|
||||
}) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
sess.dcx().emit_err(errors::ThorinErrorWrapper(e));
|
||||
sess.dcx().abort_if_errors();
|
||||
}
|
||||
Err(e) => sess.dcx().emit_fatal(errors::ThorinErrorWrapper(e)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -999,7 +998,7 @@ fn link_natively<'a>(
|
|||
sess.dcx().emit_note(errors::CheckInstalledVisualStudio);
|
||||
sess.dcx().emit_note(errors::InsufficientVSCodeProduct);
|
||||
}
|
||||
sess.dcx().abort_if_errors();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -449,10 +449,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let Some(llfn) = cx.declare_c_main(llfty) else {
|
||||
// FIXME: We should be smart and show a better diagnostic here.
|
||||
let span = cx.tcx().def_span(rust_main_def_id);
|
||||
let dcx = cx.tcx().dcx();
|
||||
dcx.emit_err(errors::MultipleMainFunctions { span });
|
||||
dcx.abort_if_errors();
|
||||
bug!();
|
||||
cx.tcx().dcx().emit_fatal(errors::MultipleMainFunctions { span });
|
||||
};
|
||||
|
||||
// `main` should respect same config for frame pointer elimination as rest of code
|
||||
|
|
|
@ -144,16 +144,6 @@ pub const EXIT_FAILURE: i32 = 1;
|
|||
pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
|
||||
?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
|
||||
|
||||
pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T {
|
||||
match result {
|
||||
Err(..) => {
|
||||
sess.dcx().abort_if_errors();
|
||||
panic!("error reported but abort_if_errors didn't abort???");
|
||||
}
|
||||
Ok(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Callbacks {
|
||||
/// Called before creating the compiler instance
|
||||
fn config(&mut self, _config: &mut interface::Config) {}
|
||||
|
@ -349,27 +339,33 @@ fn run_compiler(
|
|||
},
|
||||
};
|
||||
|
||||
callbacks.config(&mut config);
|
||||
|
||||
default_early_dcx.abort_if_errors();
|
||||
drop(default_early_dcx);
|
||||
|
||||
callbacks.config(&mut config);
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = &compiler.sess;
|
||||
let codegen_backend = &*compiler.codegen_backend;
|
||||
|
||||
// This is used for early exits unrelated to errors. E.g. when just
|
||||
// printing some information without compiling, or exiting immediately
|
||||
// after parsing, etc.
|
||||
let early_exit = || {
|
||||
if let Some(guar) = sess.dcx().has_errors() { Err(guar) } else { Ok(()) }
|
||||
};
|
||||
|
||||
// This implements `-Whelp`. It should be handled very early, like
|
||||
// `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because
|
||||
// it must happen after lints are registered, during session creation.
|
||||
if sess.opts.describe_lints {
|
||||
describe_lints(sess);
|
||||
return sess.compile_status();
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format);
|
||||
|
||||
if print_crate_info(&early_dcx, codegen_backend, sess, has_input) == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if !has_input {
|
||||
|
@ -378,16 +374,16 @@ fn run_compiler(
|
|||
|
||||
if !sess.opts.unstable_opts.ls.is_empty() {
|
||||
list_metadata(&early_dcx, sess, &*codegen_backend.metadata_loader());
|
||||
return sess.compile_status();
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.link_only {
|
||||
process_rlink(sess, compiler);
|
||||
return sess.compile_status();
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
let linker = compiler.enter(|queries| {
|
||||
let early_exit = || sess.compile_status().map(|_| None);
|
||||
let early_exit = || early_exit().map(|_| None);
|
||||
queries.parse()?;
|
||||
|
||||
if let Some(ppm) = &sess.opts.pretty {
|
||||
|
@ -659,10 +655,11 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
|
|||
};
|
||||
}
|
||||
};
|
||||
let result = compiler.codegen_backend.link(sess, codegen_results, &outputs);
|
||||
abort_on_err(result, sess);
|
||||
if compiler.codegen_backend.link(sess, codegen_results, &outputs).is_err() {
|
||||
FatalError.raise();
|
||||
}
|
||||
} else {
|
||||
dcx.emit_fatal(RlinkNotAFile {})
|
||||
dcx.emit_fatal(RlinkNotAFile {});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast_pretty::pprust as pprust_ast;
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir_pretty as pprust_hir;
|
||||
use rustc_middle::bug;
|
||||
|
@ -18,7 +19,6 @@ use std::fmt::Write;
|
|||
|
||||
pub use self::PpMode::*;
|
||||
pub use self::PpSourceMode::*;
|
||||
use crate::abort_on_err;
|
||||
|
||||
struct AstNoAnn;
|
||||
|
||||
|
@ -243,7 +243,9 @@ impl<'tcx> PrintExtra<'tcx> {
|
|||
|
||||
pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
||||
if ppm.needs_analysis() {
|
||||
abort_on_err(ex.tcx().analysis(()), sess);
|
||||
if ex.tcx().analysis(()).is_err() {
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
||||
let (src, src_name) = get_source(sess);
|
||||
|
@ -334,7 +336,9 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
ThirTree => {
|
||||
let tcx = ex.tcx();
|
||||
let mut out = String::new();
|
||||
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
|
||||
if rustc_hir_analysis::check_crate(tcx).is_err() {
|
||||
FatalError.raise();
|
||||
}
|
||||
debug!("pretty printing THIR tree");
|
||||
for did in tcx.hir().body_owners() {
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did));
|
||||
|
@ -344,7 +348,9 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
ThirFlat => {
|
||||
let tcx = ex.tcx();
|
||||
let mut out = String::new();
|
||||
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
|
||||
if rustc_hir_analysis::check_crate(tcx).is_err() {
|
||||
FatalError.raise();
|
||||
}
|
||||
debug!("pretty printing THIR flat");
|
||||
for did in tcx.hir().body_owners() {
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did));
|
||||
|
|
|
@ -471,9 +471,10 @@ struct DiagCtxtInner {
|
|||
emitted_diagnostics: FxHashSet<Hash128>,
|
||||
|
||||
/// Stashed diagnostics emitted in one stage of the compiler that may be
|
||||
/// stolen by other stages (e.g. to improve them and add more information).
|
||||
/// The stashed diagnostics count towards the total error count.
|
||||
/// When `.abort_if_errors()` is called, these are also emitted.
|
||||
/// stolen and emitted/cancelled by other stages (e.g. to improve them and
|
||||
/// add more information). All stashed diagnostics must be emitted with
|
||||
/// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped,
|
||||
/// otherwise an assertion failure will occur.
|
||||
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
|
||||
|
||||
future_breakage_diagnostics: Vec<Diagnostic>,
|
||||
|
@ -558,7 +559,9 @@ pub struct DiagCtxtFlags {
|
|||
|
||||
impl Drop for DiagCtxtInner {
|
||||
fn drop(&mut self) {
|
||||
self.emit_stashed_diagnostics();
|
||||
// Any stashed diagnostics should have been handled by
|
||||
// `emit_stashed_diagnostics` by now.
|
||||
assert!(self.stashed_diagnostics.is_empty());
|
||||
|
||||
if self.err_guars.is_empty() {
|
||||
self.flush_delayed()
|
||||
|
@ -750,17 +753,24 @@ impl DiagCtxt {
|
|||
}
|
||||
|
||||
/// Emit all stashed diagnostics.
|
||||
pub fn emit_stashed_diagnostics(&self) {
|
||||
pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow_mut().emit_stashed_diagnostics()
|
||||
}
|
||||
|
||||
/// This excludes lint errors, delayed bugs, and stashed errors.
|
||||
/// This excludes lint errors, delayed bugs and stashed errors.
|
||||
#[inline]
|
||||
pub fn err_count(&self) -> usize {
|
||||
pub fn err_count_excluding_lint_errs(&self) -> usize {
|
||||
self.inner.borrow().err_guars.len()
|
||||
}
|
||||
|
||||
/// This excludes normal errors, lint errors and delayed bugs. Unless
|
||||
/// This excludes delayed bugs and stashed errors.
|
||||
#[inline]
|
||||
pub fn err_count(&self) -> usize {
|
||||
let inner = self.inner.borrow();
|
||||
inner.err_guars.len() + inner.lint_err_guars.len()
|
||||
}
|
||||
|
||||
/// This excludes normal errors, lint errors, and delayed bugs. Unless
|
||||
/// absolutely necessary, avoid using this. It's dubious because stashed
|
||||
/// errors can later be cancelled, so the presence of a stashed error at
|
||||
/// some point of time doesn't guarantee anything -- there are no
|
||||
|
@ -769,27 +779,29 @@ impl DiagCtxt {
|
|||
self.inner.borrow().stashed_err_count
|
||||
}
|
||||
|
||||
/// This excludes lint errors, delayed bugs, and stashed errors.
|
||||
/// This excludes lint errors, delayed bugs, and stashed errors. Unless
|
||||
/// absolutely necessary, prefer `has_errors` to this method.
|
||||
pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow().has_errors_excluding_lint_errors()
|
||||
}
|
||||
|
||||
/// This excludes delayed bugs and stashed errors.
|
||||
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow().has_errors()
|
||||
}
|
||||
|
||||
/// This excludes delayed bugs and stashed errors. Unless absolutely
|
||||
/// necessary, prefer `has_errors` to this method.
|
||||
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow().has_errors_or_lint_errors()
|
||||
}
|
||||
|
||||
/// This excludes stashed errors. Unless absolutely necessary, prefer
|
||||
/// `has_errors` or `has_errors_or_lint_errors` to this method.
|
||||
pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs()
|
||||
/// `has_errors` to this method.
|
||||
pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow().has_errors_or_delayed_bugs()
|
||||
}
|
||||
|
||||
pub fn print_error_count(&self, registry: &Registry) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
|
||||
inner.emit_stashed_diagnostics();
|
||||
// Any stashed diagnostics should have been handled by
|
||||
// `emit_stashed_diagnostics` by now.
|
||||
assert!(inner.stashed_diagnostics.is_empty());
|
||||
|
||||
if inner.treat_err_as_bug() {
|
||||
return;
|
||||
|
@ -864,10 +876,12 @@ impl DiagCtxt {
|
|||
}
|
||||
}
|
||||
|
||||
/// This excludes delayed bugs and stashed errors. Used for early aborts
|
||||
/// after errors occurred -- e.g. because continuing in the face of errors is
|
||||
/// likely to lead to bad results, such as spurious/uninteresting
|
||||
/// additional errors -- when returning an error `Result` is difficult.
|
||||
pub fn abort_if_errors(&self) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.emit_stashed_diagnostics();
|
||||
if !inner.err_guars.is_empty() {
|
||||
if self.has_errors().is_some() {
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
@ -1268,10 +1282,10 @@ impl DiagCtxt {
|
|||
// `DiagCtxtInner::foo`.
|
||||
impl DiagCtxtInner {
|
||||
/// Emit all stashed diagnostics.
|
||||
fn emit_stashed_diagnostics(&mut self) {
|
||||
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let mut guar = None;
|
||||
let has_errors = !self.err_guars.is_empty();
|
||||
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
|
||||
// Decrement the count tracking the stash; emitting will increment it.
|
||||
if diag.is_error() {
|
||||
if diag.is_lint.is_none() {
|
||||
self.stashed_err_count -= 1;
|
||||
|
@ -1284,8 +1298,9 @@ impl DiagCtxtInner {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
self.emit_diagnostic(diag);
|
||||
guar = guar.or(self.emit_diagnostic(diag));
|
||||
}
|
||||
guar
|
||||
}
|
||||
|
||||
// Return value is only `Some` if the level is `Error` or `DelayedBug`.
|
||||
|
@ -1329,7 +1344,7 @@ impl DiagCtxtInner {
|
|||
DelayedBug => {
|
||||
// If we have already emitted at least one error, we don't need
|
||||
// to record the delayed bug, because it'll never be used.
|
||||
return if let Some(guar) = self.has_errors_or_lint_errors() {
|
||||
return if let Some(guar) = self.has_errors() {
|
||||
Some(guar)
|
||||
} else {
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
|
@ -1445,17 +1460,16 @@ impl DiagCtxtInner {
|
|||
.is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
|
||||
}
|
||||
|
||||
fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.err_guars.get(0).copied()
|
||||
}
|
||||
|
||||
fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.has_errors().or_else(|| self.lint_err_guars.get(0).copied())
|
||||
fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.has_errors_excluding_lint_errors().or_else(|| self.lint_err_guars.get(0).copied())
|
||||
}
|
||||
|
||||
fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||
self.has_errors_or_lint_errors()
|
||||
.or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||
fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||
self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`.
|
||||
|
@ -1488,6 +1502,11 @@ impl DiagCtxtInner {
|
|||
}
|
||||
|
||||
fn flush_delayed(&mut self) {
|
||||
// Stashed diagnostics must be emitted before delayed bugs are flushed.
|
||||
// Otherwise, we might ICE prematurely when errors would have
|
||||
// eventually happened.
|
||||
assert!(self.stashed_diagnostics.is_empty());
|
||||
|
||||
if self.delayed_bugs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
|
|||
|
||||
let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone();
|
||||
|
||||
if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() {
|
||||
if sess.dcx().has_errors_or_delayed_bugs().is_some() {
|
||||
// If there have been any errors during compilation, we don't want to
|
||||
// publish this session directory. Rather, we'll just delete it.
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
|||
return;
|
||||
}
|
||||
// This is going to be deleted in finalize_session_directory, so let's not create it.
|
||||
if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() {
|
||||
if sess.dcx().has_errors_or_delayed_bugs().is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ pub fn save_work_product_index(
|
|||
return;
|
||||
}
|
||||
// This is going to be deleted in finalize_session_directory, so let's not create it
|
||||
if sess.dcx().has_errors_or_lint_errors().is_some() {
|
||||
if sess.dcx().has_errors().is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -712,7 +712,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
reported_trait_errors: Default::default(),
|
||||
reported_signature_mismatch: Default::default(),
|
||||
tainted_by_errors: Cell::new(None),
|
||||
err_count_on_creation: tcx.dcx().err_count(),
|
||||
err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(),
|
||||
stashed_err_count_on_creation: tcx.dcx().stashed_err_count(),
|
||||
universe: Cell::new(ty::UniverseIndex::ROOT),
|
||||
intercrate,
|
||||
|
@ -1267,8 +1267,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
if let Some(guar) = self.tainted_by_errors.get() {
|
||||
Some(guar)
|
||||
} else if self.dcx().err_count() > self.err_count_on_creation {
|
||||
// Errors reported since this infcx was made.
|
||||
} else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation {
|
||||
// Errors reported since this infcx was made. Lint errors are
|
||||
// excluded to avoid some being swallowed in the presence of
|
||||
// non-lint errors. (It's arguable whether or not this exclusion is
|
||||
// important.)
|
||||
let guar = self.dcx().has_errors().unwrap();
|
||||
self.set_tainted_by_errors(guar);
|
||||
Some(guar)
|
||||
|
|
|
@ -423,18 +423,43 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
Compiler { sess, codegen_backend, override_queries: config.override_queries };
|
||||
|
||||
rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
|
||||
let r = {
|
||||
let _sess_abort_error = defer(|| {
|
||||
compiler.sess.finish_diagnostics(&config.registry);
|
||||
// There are two paths out of `f`.
|
||||
// - Normal exit.
|
||||
// - Panic, e.g. triggered by `abort_if_errors`.
|
||||
//
|
||||
// We must run `finish_diagnostics` in both cases.
|
||||
let res = {
|
||||
// If `f` panics, `finish_diagnostics` will run during
|
||||
// unwinding because of the `defer`.
|
||||
let mut guar = None;
|
||||
let sess_abort_guard = defer(|| {
|
||||
guar = compiler.sess.finish_diagnostics(&config.registry);
|
||||
});
|
||||
|
||||
f(&compiler)
|
||||
let res = f(&compiler);
|
||||
|
||||
// If `f` doesn't panic, `finish_diagnostics` will run
|
||||
// normally when `sess_abort_guard` is dropped.
|
||||
drop(sess_abort_guard);
|
||||
|
||||
// If `finish_diagnostics` emits errors (e.g. stashed
|
||||
// errors) we can't return an error directly, because the
|
||||
// return type of this function is `R`, not `Result<R, E>`.
|
||||
// But we need to communicate the errors' existence to the
|
||||
// caller, otherwise the caller might mistakenly think that
|
||||
// no errors occurred and return a zero exit code. So we
|
||||
// abort (panic) instead, similar to if `f` had panicked.
|
||||
if guar.is_some() {
|
||||
compiler.sess.dcx().abort_if_errors();
|
||||
}
|
||||
|
||||
res
|
||||
};
|
||||
|
||||
let prof = compiler.sess.prof.clone();
|
||||
|
||||
prof.generic_activity("drop_compiler").run(move || drop(compiler));
|
||||
r
|
||||
|
||||
res
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
|
@ -772,12 +772,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
|||
// lot of annoying errors in the ui tests (basically,
|
||||
// lint warnings and so on -- kindck used to do this abort, but
|
||||
// kindck is gone now). -nmatsakis
|
||||
if let Some(reported) = sess.dcx().has_errors() {
|
||||
return Err(reported);
|
||||
} else if sess.dcx().stashed_err_count() > 0 {
|
||||
// Without this case we sometimes get delayed bug ICEs and I don't
|
||||
// understand why. -nnethercote
|
||||
return Err(sess.dcx().delayed_bug("some stashed error is waiting for use"));
|
||||
//
|
||||
// But we exclude lint errors from this, because lint errors are typically
|
||||
// less serious and we're more likely to want to continue (#87337).
|
||||
if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
sess.time("misc_checking_3", || {
|
||||
|
@ -937,9 +936,7 @@ pub fn start_codegen<'tcx>(
|
|||
|
||||
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
|
||||
if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) {
|
||||
let dcx = tcx.dcx();
|
||||
dcx.emit_err(errors::CantEmitMIR { error });
|
||||
dcx.abort_if_errors();
|
||||
tcx.dcx().emit_fatal(errors::CantEmitMIR { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -222,12 +222,12 @@ impl<'tcx> Queries<'tcx> {
|
|||
|
||||
pub fn codegen_and_build_linker(&'tcx self) -> Result<Linker> {
|
||||
self.global_ctxt()?.enter(|tcx| {
|
||||
// Don't do code generation if there were any errors
|
||||
self.compiler.sess.compile_status()?;
|
||||
|
||||
// If we have any delayed bugs, for example because we created TyKind::Error earlier,
|
||||
// it's likely that codegen will only cause more ICEs, obscuring the original problem
|
||||
self.compiler.sess.dcx().flush_delayed();
|
||||
// Don't do code generation if there were any errors. Likewise if
|
||||
// there were any delayed bugs, because codegen will likely cause
|
||||
// more ICEs, obscuring the original problem.
|
||||
if let Some(guar) = self.compiler.sess.dcx().has_errors_or_delayed_bugs() {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
// Hook for UI tests.
|
||||
Self::check_for_rustc_errors_attr(tcx);
|
||||
|
@ -261,7 +261,9 @@ impl Linker {
|
|||
let (codegen_results, work_products) =
|
||||
codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames);
|
||||
|
||||
sess.compile_status()?;
|
||||
if let Some(guar) = sess.dcx().has_errors() {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
sess.time("serialize_work_products", || {
|
||||
rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
|
||||
|
|
|
@ -926,7 +926,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
what: &str,
|
||||
needs_dep: &dyn Fn(&CrateMetadata) -> bool,
|
||||
) {
|
||||
// don't perform this validation if the session has errors, as one of
|
||||
// Don't perform this validation if the session has errors, as one of
|
||||
// those errors may indicate a circular dependency which could cause
|
||||
// this to stack overflow.
|
||||
if self.dcx().has_errors().is_some() {
|
||||
|
|
|
@ -153,11 +153,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
) -> Self::Const {
|
||||
Const::new_bound(self, debruijn, var, ty)
|
||||
}
|
||||
|
||||
fn expect_error_or_delayed_bug() {
|
||||
let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs());
|
||||
assert!(has_errors.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||
|
|
|
@ -237,7 +237,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
_ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
|
||||
_ => {
|
||||
self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
|
||||
let first_n = pats.iter().enumerate().take(dotdot);
|
||||
|
|
|
@ -817,7 +817,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||
None => {}
|
||||
}
|
||||
|
||||
if let None = qcx.dep_context().sess().dcx().has_errors_or_lint_errors_or_delayed_bugs() {
|
||||
if let None = qcx.dep_context().sess().dcx().has_errors_or_delayed_bugs() {
|
||||
panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::errors::{
|
|||
};
|
||||
use crate::Session;
|
||||
use rustc_ast::{self as ast, attr};
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::path::Path;
|
||||
|
@ -115,7 +116,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
|
|||
}
|
||||
|
||||
if err_count > 0 {
|
||||
sess.dcx().abort_if_errors();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -258,7 +258,8 @@ impl Session {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_miri_unleashed_features(&self) {
|
||||
fn check_miri_unleashed_features(&self) -> Option<ErrorGuaranteed> {
|
||||
let mut guar = None;
|
||||
let unleashed_features = self.miri_unleashed_features.lock();
|
||||
if !unleashed_features.is_empty() {
|
||||
let mut must_err = false;
|
||||
|
@ -279,18 +280,22 @@ impl Session {
|
|||
// If we should err, make sure we did.
|
||||
if must_err && self.dcx().has_errors().is_none() {
|
||||
// We have skipped a feature gate, and not run into other errors... reject.
|
||||
self.dcx().emit_err(errors::NotCircumventFeature);
|
||||
guar = Some(self.dcx().emit_err(errors::NotCircumventFeature));
|
||||
}
|
||||
}
|
||||
guar
|
||||
}
|
||||
|
||||
/// Invoked all the way at the end to finish off diagnostics printing.
|
||||
pub fn finish_diagnostics(&self, registry: &Registry) {
|
||||
self.check_miri_unleashed_features();
|
||||
pub fn finish_diagnostics(&self, registry: &Registry) -> Option<ErrorGuaranteed> {
|
||||
let mut guar = None;
|
||||
guar = guar.or(self.check_miri_unleashed_features());
|
||||
guar = guar.or(self.dcx().emit_stashed_diagnostics());
|
||||
self.dcx().print_error_count(registry);
|
||||
if self.opts.json_future_incompat {
|
||||
self.dcx().emit_future_breakage_report();
|
||||
}
|
||||
guar
|
||||
}
|
||||
|
||||
/// Returns true if the crate is a testing one.
|
||||
|
@ -312,16 +317,6 @@ impl Session {
|
|||
err
|
||||
}
|
||||
|
||||
pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> {
|
||||
// We must include lint errors here.
|
||||
if let Some(reported) = self.dcx().has_errors_or_lint_errors() {
|
||||
self.dcx().emit_stashed_diagnostics();
|
||||
Err(reported)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Record the fact that we called `trimmed_def_paths`, and do some
|
||||
/// checking about whether its cost was justified.
|
||||
pub fn record_trimmed_def_paths(&self) {
|
||||
|
@ -1410,10 +1405,6 @@ impl EarlyDiagCtxt {
|
|||
Self { dcx: DiagCtxt::with_emitter(emitter) }
|
||||
}
|
||||
|
||||
pub fn abort_if_errors(&self) {
|
||||
self.dcx.abort_if_errors()
|
||||
}
|
||||
|
||||
/// Swap out the underlying dcx once we acquire the user's preference on error emission
|
||||
/// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
|
||||
/// previous dcx will be emitted.
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::traits::{
|
|||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
|
||||
MultiSpan, StashKey, StringPart,
|
||||
FatalError, MultiSpan, StashKey, StringPart,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Namespace, Res};
|
||||
|
@ -193,14 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
|
||||
mutate(&mut err);
|
||||
err.emit();
|
||||
|
||||
self.dcx().abort_if_errors();
|
||||
// FIXME: this should be something like `build_overflow_error_fatal`, which returns
|
||||
// `DiagnosticBuilder<', !>`. Then we don't even need anything after that `emit()`.
|
||||
unreachable!(
|
||||
"did not expect compilation to continue after `abort_if_errors`, \
|
||||
since an error was definitely emitted!"
|
||||
);
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
fn build_overflow_error<T>(
|
||||
|
|
|
@ -95,9 +95,6 @@ pub trait Interner: Sized {
|
|||
fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty;
|
||||
fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region;
|
||||
fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const;
|
||||
|
||||
/// Assert that an error has been delayed or emitted.
|
||||
fn expect_error_or_delayed_bug();
|
||||
}
|
||||
|
||||
/// Common capabilities of placeholder kinds
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustc_data_structures::sync::Lrc;
|
|||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::emitter::{DynEmitter, HumanEmitter};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_errors::{codes::*, TerminalUrl};
|
||||
use rustc_errors::{codes::*, ErrorGuaranteed, TerminalUrl};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
|
||||
|
@ -306,7 +306,7 @@ pub(crate) fn run_global_ctxt(
|
|||
show_coverage: bool,
|
||||
render_options: RenderOptions,
|
||||
output_format: OutputFormat,
|
||||
) -> (clean::Crate, RenderOptions, Cache) {
|
||||
) -> Result<(clean::Crate, RenderOptions, Cache), ErrorGuaranteed> {
|
||||
// Certain queries assume that some checks were run elsewhere
|
||||
// (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
|
||||
// so type-check everything other than function bodies in this crate before running lints.
|
||||
|
@ -331,7 +331,10 @@ pub(crate) fn run_global_ctxt(
|
|||
});
|
||||
});
|
||||
|
||||
tcx.dcx().abort_if_errors();
|
||||
if let Some(guar) = tcx.dcx().has_errors() {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
|
||||
tcx.sess.time("check_mod_attrs", || {
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
|
||||
|
@ -452,14 +455,13 @@ pub(crate) fn run_global_ctxt(
|
|||
|
||||
tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc)));
|
||||
|
||||
// We must include lint errors here.
|
||||
if tcx.dcx().has_errors_or_lint_errors().is_some() {
|
||||
rustc_errors::FatalError.raise();
|
||||
if let Some(guar) = tcx.dcx().has_errors() {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate));
|
||||
|
||||
(krate, ctxt.render_options, ctxt.cache)
|
||||
Ok((krate, ctxt.render_options, ctxt.cache))
|
||||
}
|
||||
|
||||
/// Due to <https://github.com/rust-lang/rust/pull/73566>,
|
||||
|
|
|
@ -153,8 +153,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
|
|||
|
||||
collector
|
||||
});
|
||||
// We must include lint errors here.
|
||||
if compiler.sess.dcx().has_errors_or_lint_errors().is_some() {
|
||||
if compiler.sess.dcx().has_errors().is_some() {
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
|
|
|
@ -78,8 +78,7 @@ use std::io::{self, IsTerminal};
|
|||
use std::process;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
|
||||
use rustc_driver::abort_on_err;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_errors::{ErrorGuaranteed, FatalError};
|
||||
use rustc_interface::interface;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
|
||||
|
@ -779,7 +778,7 @@ fn main_args(
|
|||
}
|
||||
|
||||
compiler.enter(|queries| {
|
||||
let mut gcx = abort_on_err(queries.global_ctxt(), sess);
|
||||
let Ok(mut gcx) = queries.global_ctxt() else { FatalError.raise() };
|
||||
if sess.dcx().has_errors().is_some() {
|
||||
sess.dcx().fatal("Compilation failed, aborting rustdoc");
|
||||
}
|
||||
|
@ -787,7 +786,7 @@ fn main_args(
|
|||
gcx.enter(|tcx| {
|
||||
let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
|
||||
core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
|
||||
});
|
||||
})?;
|
||||
info!("finished with rustc");
|
||||
|
||||
if let Some(options) = scrape_examples_options {
|
||||
|
|
|
@ -68,7 +68,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
|
|||
queries: &'tcx rustc_interface::Queries<'tcx>,
|
||||
) -> Compilation {
|
||||
queries.global_ctxt().unwrap().enter(|tcx| {
|
||||
if tcx.sess.compile_status().is_err() {
|
||||
if tcx.sess.dcx().has_errors().is_some() {
|
||||
tcx.dcx().fatal("miri cannot be run on programs that fail compilation");
|
||||
}
|
||||
|
||||
|
|
|
@ -21,5 +21,3 @@ LL | same_output(foo, rpit);
|
|||
|
||||
query stack during panic:
|
||||
end of query stack
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -12,5 +12,3 @@ LL | builder.state().on_entry(|_| {});
|
|||
|
||||
query stack during panic:
|
||||
end of query stack
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -21,5 +21,3 @@ LL | query(get_rpit);
|
|||
|
||||
query stack during panic:
|
||||
end of query stack
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue