Auto merge of #101986 - WaffleLapkin:move_lint_note_to_the_bottom, r=estebank
Move lint level source explanation to the bottom So, uhhhhh r? `@estebank` ## User-facing change "note: `#[warn(...)]` on by default" and such are moved to the bottom of the diagnostic: ```diff - = note: `#[warn(unsupported_calling_conventions)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default ``` Why warning is enabled is the least important thing, so it shouldn't be the first note the user reads, IMO. ## Developer-facing change `struct_span_lint` and similar methods have a different signature. Before: `..., impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>)` After: `..., impl Into<DiagnosticMessage>, impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>) -> &'b mut DiagnosticBuilder<'a, ()>` The reason for this is that `struct_span_lint` needs to edit the diagnostic _after_ `decorate` closure is called. This also makes lint code a little bit nicer in my opinion. Another option is to use `impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) -> DiagnosticBuilder<'a, ()>` altough I don't _really_ see reasons to do `let lint = lint.build(message)` everywhere. ## Subtle problem By moving the message outside of the closure (that may not be called if the lint is disabled) `format!(...)` is executed earlier, possibly formatting `Ty` which may call a query that trims paths that crashes the compiler if there were no warnings... I don't think it's that big of a deal, considering that we move from `format!(...)` to `fluent` (which is lazy by-default) anyway, however this required adding a workaround which is unfortunate. ## P.S. I'm sorry, I do not how to make this PR smaller/easier to review. Changes to the lint API affect SO MUCH 😢
This commit is contained in:
commit
744e397d88
827 changed files with 3370 additions and 3210 deletions
|
@ -89,15 +89,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
|||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
self.hir_context,
|
||||
span,
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} is unsafe and requires unsafe block (error E0133)",
|
||||
description,
|
||||
))
|
||||
.span_label(span, kind.simple_description())
|
||||
.note(note)
|
||||
.emit();
|
||||
},
|
||||
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
|
||||
|lint| lint.span_label(span, kind.simple_description()).note(note),
|
||||
)
|
||||
}
|
||||
SafetyContext::Safe => {
|
||||
|
@ -125,14 +118,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
|||
enclosing_unsafe: Option<(Span, &'static str)>,
|
||||
) {
|
||||
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
|
||||
self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
|
||||
let msg = "unnecessary `unsafe` block";
|
||||
let mut db = lint.build(msg);
|
||||
db.span_label(block_span, msg);
|
||||
let msg = "unnecessary `unsafe` block";
|
||||
self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
|
||||
lint.span_label(block_span, msg);
|
||||
if let Some((span, kind)) = enclosing_unsafe {
|
||||
db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
|
||||
lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
|
||||
}
|
||||
db.emit();
|
||||
lint
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -36,16 +36,20 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
|||
|
||||
let sp = tcx.def_span(def_id);
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
|
||||
let mut db = lint.build("function cannot return without recursing");
|
||||
db.span_label(sp, "cannot return without recursing");
|
||||
// offer some help to the programmer.
|
||||
for call_span in vis.reachable_recursive_calls {
|
||||
db.span_label(call_span, "recursive call site");
|
||||
}
|
||||
db.help("a `loop` may express intention better if this is on purpose");
|
||||
db.emit();
|
||||
});
|
||||
tcx.struct_span_lint_hir(
|
||||
UNCONDITIONAL_RECURSION,
|
||||
hir_id,
|
||||
sp,
|
||||
"function cannot return without recursing",
|
||||
|lint| {
|
||||
lint.span_label(sp, "cannot return without recursing");
|
||||
// offer some help to the programmer.
|
||||
for call_span in vis.reachable_recursive_calls {
|
||||
lint.span_label(call_span, "recursive call site");
|
||||
}
|
||||
lint.help("a `loop` may express intention better if this is on purpose")
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use super::{PatCtxt, PatternError};
|
|||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::{
|
||||
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
|
||||
error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
|
||||
ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
|
@ -347,19 +347,23 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
let span_end = affix.last().unwrap().unwrap().0;
|
||||
let span = span_start.to(span_end);
|
||||
let cnt = affix.len();
|
||||
cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| {
|
||||
let s = pluralize!(cnt);
|
||||
let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain"));
|
||||
diag.note(&format!(
|
||||
"{these} pattern{s} will always match",
|
||||
these = pluralize!("this", cnt),
|
||||
));
|
||||
diag.help(&format!(
|
||||
"consider moving {} {suggestion}",
|
||||
if cnt > 1 { "them" } else { "it" }
|
||||
));
|
||||
diag.emit()
|
||||
});
|
||||
let s = pluralize!(cnt);
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
IRREFUTABLE_LET_PATTERNS,
|
||||
top,
|
||||
span,
|
||||
format!("{kind} irrefutable pattern{s} in let chain"),
|
||||
|lint| {
|
||||
lint.note(format!(
|
||||
"{these} pattern{s} will always match",
|
||||
these = pluralize!("this", cnt),
|
||||
))
|
||||
.help(format!(
|
||||
"consider moving {} {suggestion}",
|
||||
if cnt > 1 { "them" } else { "it" }
|
||||
))
|
||||
},
|
||||
);
|
||||
};
|
||||
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
|
||||
// The chain has a non-zero prefix of irrefutable `let` statements.
|
||||
|
@ -561,26 +565,28 @@ fn check_for_bindings_named_same_as_variants(
|
|||
BINDINGS_WITH_VARIANT_NAME,
|
||||
p.hir_id,
|
||||
p.span,
|
||||
DelayDm(|| format!(
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident, cx.tcx.def_path_str(edef.did())
|
||||
)),
|
||||
|lint| {
|
||||
let ty_path = cx.tcx.def_path_str(edef.did());
|
||||
let mut err = lint.build(&format!(
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident, ty_path
|
||||
));
|
||||
err.code(error_code!(E0170));
|
||||
lint.code(error_code!(E0170));
|
||||
|
||||
// If this is an irrefutable pattern, and there's > 1 variant,
|
||||
// then we can't actually match on this. Applying the below
|
||||
// suggestion would produce code that breaks on `check_irrefutable`.
|
||||
if rf == Refutable || variant_count == 1 {
|
||||
err.span_suggestion(
|
||||
lint.span_suggestion(
|
||||
p.span,
|
||||
"to match on the variant, qualify the path",
|
||||
format!("{}::{}", ty_path, ident),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
|
||||
lint
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -598,14 +604,13 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
|
|||
}
|
||||
|
||||
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
|
||||
tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| {
|
||||
let mut err = lint.build("unreachable pattern");
|
||||
tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
|
||||
if let Some(catchall) = catchall {
|
||||
// We had a catchall pattern, hint at that.
|
||||
err.span_label(span, "unreachable pattern");
|
||||
err.span_label(catchall, "matches any value");
|
||||
lint.span_label(span, "unreachable pattern");
|
||||
lint.span_label(catchall, "matches any value");
|
||||
}
|
||||
err.emit();
|
||||
lint
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -621,6 +626,11 @@ fn irrefutable_let_patterns(
|
|||
count: usize,
|
||||
span: Span,
|
||||
) {
|
||||
let span = match source {
|
||||
LetSource::LetElse(span) => span,
|
||||
_ => span,
|
||||
};
|
||||
|
||||
macro_rules! emit_diag {
|
||||
(
|
||||
$lint:expr,
|
||||
|
@ -630,18 +640,23 @@ fn irrefutable_let_patterns(
|
|||
) => {{
|
||||
let s = pluralize!(count);
|
||||
let these = pluralize!("this", count);
|
||||
let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name));
|
||||
diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix));
|
||||
diag.help(concat!("consider ", $help_sufix));
|
||||
diag.emit()
|
||||
tcx.struct_span_lint_hir(
|
||||
IRREFUTABLE_LET_PATTERNS,
|
||||
id,
|
||||
span,
|
||||
format!("irrefutable {} pattern{s}", $source_name),
|
||||
|lint| {
|
||||
lint.note(&format!(
|
||||
"{these} pattern{s} will always match, so the {}",
|
||||
$note_sufix
|
||||
))
|
||||
.help(concat!("consider ", $help_sufix))
|
||||
},
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
let span = match source {
|
||||
LetSource::LetElse(span) => span,
|
||||
_ => span,
|
||||
};
|
||||
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
|
||||
match source {
|
||||
LetSource::GenericLet => {
|
||||
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
|
||||
}
|
||||
|
@ -677,7 +692,7 @@ fn irrefutable_let_patterns(
|
|||
"instead using a `loop { ... }` with a `let` inside it"
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
fn is_let_irrefutable<'p, 'tcx>(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_errors::DelayDm;
|
||||
use rustc_hir as hir;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
|
@ -205,9 +206,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
self.id,
|
||||
self.span,
|
||||
|lint| {
|
||||
lint.build(&msg).emit();
|
||||
},
|
||||
msg,
|
||||
|lint| lint,
|
||||
);
|
||||
} else {
|
||||
debug!(
|
||||
|
@ -286,9 +286,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
|
||||
id,
|
||||
span,
|
||||
|lint| {
|
||||
lint.build("floating-point types cannot be used in patterns").emit();
|
||||
},
|
||||
"floating-point types cannot be used in patterns",
|
||||
|lint| lint,
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
|
@ -340,15 +339,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
id,
|
||||
span,
|
||||
|lint| {
|
||||
let msg = format!(
|
||||
DelayDm(|| {
|
||||
format!(
|
||||
"to use a constant of type `{}` in a pattern, \
|
||||
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
|
||||
cv.ty(),
|
||||
cv.ty(),
|
||||
);
|
||||
lint.build(&msg).emit();
|
||||
},
|
||||
)
|
||||
}),
|
||||
|lint| lint,
|
||||
);
|
||||
}
|
||||
// Since we are behind a reference, we can just bubble the error up so we get a
|
||||
|
@ -488,7 +487,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
|
||||
self.id,
|
||||
self.span,
|
||||
|lint| {lint.build(&msg).emit();},
|
||||
msg,
|
||||
|lint| lint,
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
|
@ -556,9 +556,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
lint::builtin::POINTER_STRUCTURAL_MATCH,
|
||||
id,
|
||||
span,
|
||||
|lint| {
|
||||
lint.build(msg).emit();
|
||||
},
|
||||
msg,
|
||||
|lint| lint,
|
||||
);
|
||||
}
|
||||
PatKind::Constant { value: cv }
|
||||
|
@ -594,9 +593,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
|||
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
|
||||
id,
|
||||
span,
|
||||
|lint| {
|
||||
lint.build(&msg).emit();
|
||||
},
|
||||
msg,
|
||||
|lint| lint,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -299,10 +299,10 @@ impl IntRange {
|
|||
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
|
||||
hir_id,
|
||||
pcx.span,
|
||||
"multiple patterns overlap on their endpoints",
|
||||
|lint| {
|
||||
let mut err = lint.build("multiple patterns overlap on their endpoints");
|
||||
for (int_range, span) in overlaps {
|
||||
err.span_label(
|
||||
lint.span_label(
|
||||
span,
|
||||
&format!(
|
||||
"this range overlaps on `{}`...",
|
||||
|
@ -310,9 +310,9 @@ impl IntRange {
|
|||
),
|
||||
);
|
||||
}
|
||||
err.span_label(pcx.span, "... with this range");
|
||||
err.note("you likely meant to write mutually exclusive ranges");
|
||||
err.emit();
|
||||
lint.span_label(pcx.span, "... with this range");
|
||||
lint.note("you likely meant to write mutually exclusive ranges");
|
||||
lint
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -754,9 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
|
|||
hir_id: HirId,
|
||||
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
|
||||
) {
|
||||
cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
|
||||
cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
|
||||
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
|
||||
let mut lint = build.build("some variants are not matched explicitly");
|
||||
lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
|
||||
lint.help(
|
||||
"ensure that all variants are matched explicitly by adding the suggested match arms",
|
||||
|
@ -765,7 +764,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
|
|||
"the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
|
||||
scrut_ty,
|
||||
));
|
||||
lint.emit();
|
||||
lint
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue