diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e8b97966314..163170a1d1a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -197,7 +197,7 @@ fn do_mir_borrowck<'tcx>( // Gather the upvars of a closure, if any. let tables = tcx.typeck_opt_const_arg(def); if let Some(e) = tables.tainted_by_errors { - infcx.set_tainted_by_errors(); + infcx.set_tainted_by_errors(e); errors.set_tainted_by_errors(e); } let upvars: Vec<_> = tables diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index f8856b56d14..4a12e1b1b92 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -303,7 +303,10 @@ pub(crate) fn compute_regions<'cx, 'tcx>( if !nll_errors.is_empty() { // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(); + infcx.set_tainted_by_errors(infcx.tcx.sess.delay_span_bug( + body.span, + "`compute_regions` tainted `infcx` with errors but did not emit any errors", + )); } let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 16c40cf1299..83b95fe0e91 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -115,7 +115,7 @@ pub trait AstConv<'tcx> { /// (e.g., resolve) that is translated into a ty-error. This is /// used to help suppress derived errors typeck might otherwise /// report. - fn set_tainted_by_errors(&self); + fn set_tainted_by_errors(&self, e: ErrorGuaranteed); fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); } @@ -2620,8 +2620,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } Res::Err => { - self.set_tainted_by_errors(); - self.tcx().ty_error() + let e = self + .tcx() + .sess + .delay_span_bug(path.span, "path with `Res:Err` but no error emitted"); + self.set_tainted_by_errors(e); + self.tcx().ty_error_with_guaranteed(e) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 2f64a88f03a..a738ee4a148 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -518,7 +518,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { ty } - fn set_tainted_by_errors(&self) { + fn set_tainted_by_errors(&self, _: ErrorGuaranteed) { // There's no obvious place to track this, so just let it go. } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 174b4331382..fc05cbf276e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1544,7 +1544,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // Mark that we've failed to coerce the types here to suppress // any superfluous errors we might encounter while trying to // emit or provide suggestions on how to fix the initial error. - fcx.set_tainted_by_errors(); + fcx.set_tainted_by_errors( + fcx.tcx.sess.delay_span_bug(cause.span, "coercion error but no error emitted"), + ); let (expected, found) = if label_expression_as_expected { // In the case where this is a "forced unit", like // `break`, we want to call the `()` "expected" diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 9ca7730daa6..5a34ab40174 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -154,7 +154,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(e) => e, }; - self.set_tainted_by_errors(); + self.set_tainted_by_errors(self.tcx.sess.delay_span_bug( + expr.span, + "`TypeError` when attempting coercion but no error emitted", + )); let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); let expr_ty = self.resolve_vars_with_obligations(checked_ty); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 13a03b33de8..752d2e0ff78 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -527,12 +527,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { - self.set_tainted_by_errors(); - tcx.ty_error() + let e = + self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + tcx.ty_error_with_guaranteed(e) } Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { - report_unexpected_variant_res(tcx, res, qpath, expr.span); - tcx.ty_error() + let e = report_unexpected_variant_res(tcx, res, qpath, expr.span); + tcx.ty_error_with_guaranteed(e) } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; @@ -1962,7 +1964,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_span: Span, ) { if variant.is_recovered() { - self.set_tainted_by_errors(); + self.set_tainted_by_errors( + self.tcx + .sess + .delay_span_bug(expr_span, "parser recovered but no error was emitted"), + ); return; } let mut err = self.err_ctxt().type_error_struct_with_diag( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0d9189b12f6..c2a5c5b6c1b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -140,8 +140,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); - if ty.references_error() { - self.set_tainted_by_errors(); + if let Err(e) = ty.error_reported() { + self.set_tainted_by_errors(e); } } @@ -1148,9 +1148,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { explicit_late_bound = ExplicitLateBound::Yes; } - if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct { + if let Err(GenericArgCountMismatch { reported: Some(e), .. }) = arg_count.correct { infer_args_for_err.insert(index); - self.set_tainted_by_errors(); // See issue #53251. + self.set_tainted_by_errors(e); // See issue #53251. } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 6847b03f431..91063b43d61 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -512,8 +512,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) } - self.set_tainted_by_errors(); let tcx = self.tcx; + // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` + self.set_tainted_by_errors( + tcx.sess.delay_span_bug(call_span, "no errors reported for args"), + ); // Get the argument span in the context of the call span so that // suggestions and labels are (more) correct when an arg is a @@ -1208,7 +1211,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); let variant = match def { Res::Err => { - self.set_tainted_by_errors(); + self.set_tainted_by_errors( + self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"), + ); return None; } Res::Def(DefKind::Variant, _) => match ty.kind() { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index d5e4b6de581..177d521d280 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -4,6 +4,7 @@ mod checks; mod suggestions; pub use _impl::*; +use rustc_errors::ErrorGuaranteed; pub use suggestions::*; use crate::coercion::DynamicCoerceMany; @@ -289,8 +290,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() + fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + self.infcx.set_tainted_by_errors(e) } fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 51cc2e7882d..334d6d0aa6c 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -53,7 +53,7 @@ use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{struct_span_err, MultiSpan}; +use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; @@ -428,7 +428,12 @@ impl<'tcx> EnclosingBreakables<'tcx> { } } -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) { +fn report_unexpected_variant_res( + tcx: TyCtxt<'_>, + res: Res, + qpath: &hir::QPath<'_>, + span: Span, +) -> ErrorGuaranteed { struct_span_err!( tcx.sess, span, @@ -437,7 +442,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<' res.descr(), rustc_hir_pretty::qpath_to_string(qpath), ) - .emit(); + .emit() } /// Controls whether the arguments are tupled. This is used for the call diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index eb10f3e2c10..a62d4356130 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -839,12 +839,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = path_resolution; match res { Res::Err => { - self.set_tainted_by_errors(); - return tcx.ty_error(); + let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + return tcx.ty_error_with_guaranteed(e); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => { - report_unexpected_variant_res(tcx, res, qpath, pat.span); - return tcx.ty_error(); + let e = report_unexpected_variant_res(tcx, res, qpath, pat.span); + return tcx.ty_error_with_guaranteed(e); } Res::SelfCtor(..) | Res::Def( @@ -985,9 +986,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let on_error = || { + let on_error = |e| { for pat in subpats { - self.check_pat(pat, tcx.ty_error(), def_bm, ti); + self.check_pat(pat, tcx.ty_error_with_guaranteed(e), def_bm, ti); } }; let report_unexpected_res = |res: Res| { @@ -1014,36 +1015,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(pat.span, "not a tuple variant or struct"); } } - err.emit(); - on_error(); + let e = err.emit(); + on_error(e); + e }; // Resolve the path and check the definition for errors. let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { - self.set_tainted_by_errors(); - on_error(); - return self.tcx.ty_error(); + let e = tcx.sess.delay_span_bug(pat.span, "`Res:Err` but no error emitted"); + self.set_tainted_by_errors(e); + on_error(e); + return tcx.ty_error_with_guaranteed(e); } // Type-check the path. let (pat_ty, res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); if !pat_ty.is_fn() { - report_unexpected_res(res); - return tcx.ty_error(); + let e = report_unexpected_res(res); + return tcx.ty_error_with_guaranteed(e); } let variant = match res { Res::Err => { - self.set_tainted_by_errors(); - on_error(); - return tcx.ty_error(); + let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + on_error(e); + return tcx.ty_error_with_guaranteed(e); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { - report_unexpected_res(res); - return tcx.ty_error(); + let e = report_unexpected_res(res); + return tcx.ty_error_with_guaranteed(e); } Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), _ => bug!("unexpected pattern resolution: {:?}", res), @@ -1082,9 +1086,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else { // Pattern has wrong number of fields. - self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err); - on_error(); - return tcx.ty_error(); + let e = self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err); + on_error(e); + return tcx.ty_error_with_guaranteed(e); } pat_ty } @@ -1098,7 +1102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [ty::FieldDef], expected: Ty<'tcx>, had_err: bool, - ) { + ) -> ErrorGuaranteed { let subpats_ending = pluralize!(subpats.len()); let fields_ending = pluralize!(fields.len()); @@ -1245,7 +1249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - err.emit(); + err.emit() } fn check_pat_tuple( diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index aa6fed13611..b9ed6b28c22 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -34,7 +34,7 @@ pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; @@ -1224,8 +1224,9 @@ impl<'tcx> InferCtxt<'tcx> { if self.tcx.sess.err_count() > self.err_count_on_creation { // errors reported since this infcx was made - self.set_tainted_by_errors(); - return self.tainted_by_errors.get(); + let e = self.tcx.sess.has_errors().unwrap(); + self.set_tainted_by_errors(e); + return Some(e); } None @@ -1233,11 +1234,9 @@ impl<'tcx> InferCtxt<'tcx> { /// Set the "tainted by errors" flag to true. We call this when we /// observe an error from a prior pass. - pub fn set_tainted_by_errors(&self) { - debug!("set_tainted_by_errors()"); - self.tainted_by_errors.set(Some( - self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"), - )); + pub fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + debug!("set_tainted_by_errors(ErrorGuaranteed)"); + self.tainted_by_errors.set(Some(e)); } pub fn skip_region_resolution(&self) { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 8c8445a4d9e..bd3c5780b89 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -116,9 +116,9 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } - (&ty::Error(_), _) | (_, &ty::Error(_)) => { - infcx.set_tainted_by_errors(); - Ok(self.tcx().ty_error()) + (&ty::Error(e), _) | (_, &ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + Ok(self.tcx().ty_error_with_guaranteed(e)) } (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index b84a1c447ff..ad0785d3817 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -532,9 +532,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, ) { - self.set_tainted_by_errors(); let tcx = self.tcx; let mut span = obligation.cause.span; + // FIXME: statically guarantee this by tainting after the diagnostic is emitted + self.set_tainted_by_errors( + tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"), + ); let mut err = match *error { SelectionError::Unimplemented => {