Skip to content

Commit

Permalink
Split delayed bugs into has-errored and will-error halves.
Browse files Browse the repository at this point in the history
This commit adds new `{span_,}assert_has_errors` methods implementing
the simpler has-errored cases, and leaves the existing
`{span_,}delayed_bug` methods for the will-error cases.

It also converts as many cases as possible to has-errored. I did this by
converting every case to has-errored, then running tests and converting
back to will-error every case that caused an assertion in the test
suite. The test suite doesn't have perfect coverage so it's possible
that there are a few more has-errored cases that will need conversion
back to will-error. Also, some of the will-error cases might actually be
a mixture of has-errored and will-error. But it's hard to do this
perfectly without carefully going through every individual case, which
would be painful, and an imperfect split still gets most of the
benefits.
  • Loading branch information
nnethercote committed Feb 13, 2024
1 parent b3b092d commit 33a6833
Show file tree
Hide file tree
Showing 92 changed files with 266 additions and 200 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ where
pub trait LayoutCalculator {
type TargetDataLayoutRef: Borrow<TargetDataLayout>;

fn delayed_bug(&self, txt: String);
fn assert_has_errors(&self, txt: String);
fn current_data_layout(&self) -> Self::TargetDataLayoutRef;

fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(
Expand Down Expand Up @@ -259,7 +259,7 @@ pub trait LayoutCalculator {
let only_variant = &variants[VariantIdx::new(0)];
for field in only_variant {
if field.is_unsized() {
self.delayed_bug("unsized field in union".to_string());
self.assert_has_errors("unsized field in union".to_string());
}

align = align.max(field.align);
Expand Down Expand Up @@ -1092,7 +1092,7 @@ fn univariant<
for &i in &inverse_memory_index {
let field = &fields[i];
if !sized {
this.delayed_bug(format!(
this.assert_has_errors(format!(
"univariant: field #{} comes after unsized field",
offsets.len(),
));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
sig_id.ok_or_else(|| {
self.tcx
.dcx()
.span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item")
.span_assert_has_errors(span, "LoweringContext: couldn't resolve delegation item")
})
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
}
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err => {
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
}
ExprKind::Err => hir::ExprKind::Err(
self.dcx().span_assert_has_errors(e.span, "lowered ExprKind::Err"),
),
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),

ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_ast_lowering/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ fn make_count<'hir>(
ctx.expr(
sp,
hir::ExprKind::Err(
ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count"),
ctx.dcx().span_assert_has_errors(sp, "lowered bad format_args count"),
),
)
}
Expand Down Expand Up @@ -306,7 +306,9 @@ fn make_format_spec<'hir>(
}
Err(_) => ctx.expr(
sp,
hir::ExprKind::Err(ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count")),
hir::ExprKind::Err(
ctx.dcx().span_assert_has_errors(sp, "lowered bad format_args count"),
),
),
};
let &FormatOptions {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub(super) fn index_hir<'hir>(
if let Node::Err(span) = node.node {
let hir_id = HirId { owner: item.def_id(), local_id };
let msg = format!("ID {hir_id} not encountered when visiting item HIR");
tcx.dcx().span_delayed_bug(*span, msg);
tcx.dcx().span_assert_has_errors(*span, msg);
}
}

Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
None => {
let guar = this.dcx().span_delayed_bug(
let guar = this.dcx().span_assert_has_errors(
span,
"expected to lower type alias type, but it was missing",
);
Expand Down Expand Up @@ -925,7 +925,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
None => {
let guar = this.dcx().span_delayed_bug(
let guar = this.dcx().span_assert_has_errors(
i.span,
"expected to lower associated type, but it was missing",
);
Expand Down Expand Up @@ -1068,7 +1068,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
match block {
Some(block) => self.lower_block_expr(block),
None => self.expr_err(span, self.dcx().span_delayed_bug(span, "no block")),
None => self.expr_err(span, self.dcx().span_assert_has_errors(span, "no block")),
}
}

Expand All @@ -1078,7 +1078,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
&[],
match expr {
Some(expr) => this.lower_expr_mut(expr),
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
None => {
this.expr_err(span, this.dcx().span_assert_has_errors(span, "no block"))
}
},
)
})
Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let res = self.resolver.get_import_res(id).present_items();
let res: SmallVec<_> = res.map(|res| self.lower_res(res)).collect();
if res.is_empty() {
self.dcx().span_delayed_bug(span, "no resolution for an import");
self.dcx().span_assert_has_errors(span, "no resolution for an import");
return smallvec![Res::Err];
}
res
Expand Down Expand Up @@ -1286,7 +1286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => {
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
hir::TyKind::Err(self.dcx().span_assert_has_errors(t.span, "TyKind::Err lowered"))
}
// Lower the anonymous structs or unions in a nested lowering context.
//
Expand Down Expand Up @@ -1499,7 +1499,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
TyKind::CVarArgs => {
let guar = self.dcx().span_delayed_bug(
let guar = self.dcx().span_assert_has_errors(
t.span,
"`TyKind::CVarArgs` should have been handled elsewhere",
);
Expand Down Expand Up @@ -1643,8 +1643,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
old_def_id
} else {
self.dcx()
.span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
self.dcx().span_assert_has_errors(
lifetime.ident.span,
"no def-id for fresh lifetime",
);
continue;
}
}
Expand Down Expand Up @@ -2576,7 +2578,7 @@ impl<'hir> GenericArgsCtor<'hir> {
let span = lcx.lower_span(span);

let Some(host_param_id) = lcx.host_param_id else {
lcx.dcx().span_delayed_bug(
lcx.dcx().span_assert_has_errors(
span,
"no host param id for call in const yet no errors reported",
);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
_,
) => {
// HIR lowering sometimes doesn't catch this in erroneous
// programs, so we need to use span_delayed_bug here. See #82126.
self.dcx().span_delayed_bug(
// programs, so we need to use span_assert_has_errors here. See #82126.
self.dcx().span_assert_has_errors(
hir_arg.span(),
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx, span)
else {
tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
tcx.dcx().span_assert_has_errors(span, format!("failed to normalize {ty:?}"));
continue;
};
constraints.extend(c);
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_borrowck/src/type_check/input_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Equate expected input tys with those in the MIR.
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
if argument_index + 1 >= body.local_decls.len() {
self.tcx()
.dcx()
.span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
self.tcx().dcx().span_assert_has_errors(
body.span,
"found more normalized_input_ty than local_decls",
);
break;
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
if hidden_type.has_non_region_infer() {
let reported = infcx.dcx().span_delayed_bug(
let reported = infcx.dcx().span_assert_has_errors(
decl.hidden_type.span,
format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
Expand Down Expand Up @@ -1089,7 +1089,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);

if result.is_err() {
self.infcx.dcx().span_delayed_bug(
self.infcx.dcx().span_assert_has_errors(
self.body.span,
"failed re-defining predefined opaques in mir typeck",
);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
Some(tcx.fn_sig(did))
} else {
tcx.dcx()
.span_delayed_bug(attr.span, "this attribute can only be applied to functions");
tcx.dcx().span_assert_has_errors(
attr.span,
"this attribute can only be applied to functions",
);
None
}
};
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
if ecx.tcx.is_ctfe_mir_available(def) {
Ok(ecx.tcx.mir_for_ctfe(def))
} else if ecx.tcx.def_kind(def) == DefKind::AssocConst {
let guar = ecx
.tcx
.dcx()
.delayed_bug("This is likely a const item that is missing from its impl");
let guar = ecx.tcx.dcx().assert_has_errors(
"This is likely a const item that is missing from its impl",
);
throw_inval!(AlreadyReported(guar.into()));
} else {
// `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
// `async` functions cannot be `const fn`. This is checked during AST lowering, so there's
// no need to emit duplicate errors here.
if self.ccx.is_async() || body.coroutine.is_some() {
tcx.dcx().span_delayed_bug(body.span, "`async` functions cannot be `const fn`");
tcx.dcx().span_assert_has_errors(body.span, "`async` functions cannot be `const fn`");
return;
}

Expand Down Expand Up @@ -331,7 +331,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
if self.tcx.is_thread_local_static(def_id) {
self.tcx
.dcx()
.span_delayed_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
.span_assert_has_errors(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
}
self.check_op_spanned(ops::StaticAccess, span)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
None if is_parent_const_stable_trait(tcx, def_id) => {
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
// returning `true` unconditionally.
tcx.dcx().span_delayed_bug(
tcx.dcx().span_assert_has_errors(
tcx.def_span(def_id),
"trait implementations cannot be const stable yet",
);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
#[track_caller]
fn fail(&self, location: Location, msg: impl AsRef<str>) {
let span = self.body.source_info(location).span;
// We use `span_delayed_bug` as we might see broken MIR when other errors have already
// We use `span_assert_has_errors` as we might see broken MIR when other errors have already
// occurred.
self.tcx.dcx().span_delayed_bug(
self.tcx.dcx().span_assert_has_errors(
span,
format!(
"broken MIR in {:?} ({}) at {:?}:\n{}",
Expand Down Expand Up @@ -501,7 +501,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {

fn visit_source_scope(&mut self, scope: SourceScope) {
if self.body.source_scopes.get(scope).is_none() {
self.tcx.dcx().span_delayed_bug(
self.tcx.dcx().span_assert_has_errors(
self.body.span,
format!(
"broken MIR in {:?} ({}):\ninvalid source scope {:?}",
Expand Down
31 changes: 28 additions & 3 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,28 @@ impl DiagCtxt {
pub fn set_must_produce_diag(&self) {
self.inner.borrow_mut().must_produce_diag = true;
}

/// Asserts that an error has already been printed.
pub fn assert_has_errors(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
if let Some(guar) = self.has_errors() {
guar
} else {
panic!("`assert_has_errors` failed: {:?}", msg.into());
}
}

/// Asserts that an error has already been printed.
pub fn span_assert_has_errors(
&self,
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
if let Some(guar) = self.has_errors() {
guar
} else {
panic!("`span_assert_has_errors` failed: {:?}, {:?}", msg.into(), sp.into());
}
}
}

// This `impl` block contains only the public diagnostic creation/emission API.
Expand Down Expand Up @@ -1098,14 +1120,14 @@ impl DiagCtxt {
self.create_err(err).emit()
}

/// Ensures that an error is printed. See `Level::DelayedBug`.
/// Ensures that an error will be emitted later. See `Level::DelayedBug`.
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
#[track_caller]
pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
}

/// Ensures that an error is printed. See `Level::DelayedBug`.
/// Ensures that an error will be emitted later. See `Level::DelayedBug`.
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_err`, `span_warn`, etc.
Expand Down Expand Up @@ -1566,8 +1588,11 @@ pub enum Level {

/// This is a strange one: lets you register an error without emitting it. If compilation ends
/// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be
/// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths
/// silently dropped. I.e. "expect more errors will be emitted" semantics. Useful on code paths
/// that should only be reached when compiling erroneous code.
///
/// Note: if you want "expect errors have already been emitted" semantics, use the simpler
/// `DiagCtxt::assert_has_errors` method.
DelayedBug,

/// A `force-warn` lint warning about the code being compiled. Does not prevent compilation
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_expand/src/mbe/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub(super) fn failed_to_match_macro<'cx>(
tracker
.cx
.dcx()
.span_delayed_bug(sp, "Macro matching returned a success on the second try");
.span_assert_has_errors(sp, "Macro matching returned a success on the second try");
}

if let Some(result) = tracker.result {
Expand Down Expand Up @@ -154,7 +154,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
Success(_) => {
// Nonterminal parser recovery might turn failed matches into successful ones,
// but for that it must have emitted an error already
self.cx.dcx().span_delayed_bug(
self.cx.dcx().span_assert_has_errors(
self.root_span,
"should not collect detailed info for successful macro match",
);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// since we should have emitten an error for them earlier, and they will
// not be well-formed!
if polarity == ty::ImplPolarity::Negative {
self.tcx().dcx().span_delayed_bug(
self.tcx().dcx().span_assert_has_errors(
binding.span,
"negative trait bounds should not have bindings",
);
Expand Down Expand Up @@ -1294,7 +1294,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// trait reference.
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
// A cycle error occurred, most likely.
let guar = tcx.dcx().span_delayed_bug(span, "expected cycle error");
let guar = tcx.dcx().span_assert_has_errors(span, "expected cycle error");
return Err(guar);
};

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/astconv/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
false
});
if references_self {
let guar = tcx.dcx().span_delayed_bug(
let guar = tcx.dcx().span_assert_has_errors(
span,
"trait object projection bounds reference `Self`",
);
Expand Down
Loading

0 comments on commit 33a6833

Please sign in to comment.