Overhaul how stashed diagnostics work, again.
Stashed errors used to be counted as errors, but could then be cancelled, leading to `ErrorGuaranteed` soundness holes. #120828 changed that, closing the soundness hole. But it introduced other difficulties because you sometimes have to account for pending stashed errors when making decisions about whether errors have occured/will occur and it's easy to overlook these. This commit aims for a middle ground. - Stashed errors (not warnings) are counted immediately as emitted errors, avoiding the possibility of forgetting to consider them. - The ability to cancel (or downgrade) stashed errors is eliminated, by disallowing the use of `steal_diagnostic` with errors, and introducing the more restrictive methods `try_steal_{modify,replace}_and_emit_err` that can be used instead. Other things: - `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both return `Option<ErrorGuaranteed>`, which enables the removal of two `delayed_bug` calls and one `Ty::new_error_with_message` call. This is possible because we store error guarantees in `DiagCtxt::stashed_diagnostics`. - Storing the guarantees also saves us having to maintain a counter. - Calls to the `stashed_err_count` method are no longer necessary alongside calls to `has_errors`, which is a nice simplification, and eliminates two more `span_delayed_bug` calls and one FIXME comment. - Tests are added for three of the four fixed PRs mentioned below. - `issue-121108.rs`'s output improved slightly, omitting a non-useful error message. Fixes #121451. Fixes #121477. Fixes #121504. Fixes #121508.
This commit is contained in:
parent
ec25d6db53
commit
260ae70140
29 changed files with 406 additions and 295 deletions
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::TraitObjectSyntax;
|
||||
use rustc_errors::{codes::*, Diag, EmissionGuarantee, StashKey};
|
||||
use rustc_errors::{codes::*, Diag, EmissionGuarantee, Level, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
|
||||
|
@ -237,7 +237,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
// check if the impl trait that we are considering is a impl of a local trait
|
||||
self.maybe_lint_blanket_trait_impl(self_ty, &mut diag);
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
match diag.level() {
|
||||
Level::Error => {
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
}
|
||||
Level::DelayedBug => {
|
||||
diag.emit();
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
|
||||
|
|
|
@ -1350,8 +1350,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
|
|||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
if ty.references_error() {
|
||||
// If there is already another error, do not emit an error for not using a type parameter.
|
||||
// Without the `stashed_err_count` part this can fail (#120856).
|
||||
assert!(tcx.dcx().has_errors().is_some() || tcx.dcx().stashed_err_count() > 0);
|
||||
assert!(tcx.dcx().has_errors().is_some());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -596,10 +596,11 @@ fn infer_placeholder_type<'a>(
|
|||
// then the user may have written e.g. `const A = 42;`.
|
||||
// In this case, the parser has stashed a diagnostic for
|
||||
// us to improve in typeck so we do that now.
|
||||
match tcx.dcx().steal_diagnostic(span, StashKey::ItemNoType) {
|
||||
Some(mut err) => {
|
||||
let guar = tcx
|
||||
.dcx()
|
||||
.try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| {
|
||||
if !ty.references_error() {
|
||||
// Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
|
||||
// Only suggest adding `:` if it was missing (and suggested by parsing diagnostic).
|
||||
let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
|
||||
|
||||
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
|
||||
|
@ -622,12 +623,8 @@ fn infer_placeholder_type<'a>(
|
|||
));
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
// diagnostic stashing loses the information of whether something is a hard error.
|
||||
Ty::new_error_with_message(tcx, span, "ItemNoType is a hard error")
|
||||
}
|
||||
None => {
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let mut diag = bad_placeholder(tcx, vec![span], kind);
|
||||
|
||||
if !ty.references_error() {
|
||||
|
@ -645,10 +642,9 @@ fn infer_placeholder_type<'a>(
|
|||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ty::new_error(tcx, diag.emit())
|
||||
}
|
||||
}
|
||||
diag.emit()
|
||||
});
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
|
||||
fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue