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:
bors 2022-10-01 10:44:25 +00:00
commit 744e397d88
827 changed files with 3370 additions and 3210 deletions

View file

@ -2,7 +2,7 @@ use std::cmp;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan};
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan};
use rustc_hir::HirId;
use rustc_index::vec::IndexVec;
use rustc_query_system::ich::StableHashingContext;
@ -283,7 +283,11 @@ pub fn struct_lint_level<'s, 'd>(
level: Level,
src: LintLevelSource,
span: Option<MultiSpan>,
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) + 'd,
msg: impl Into<DiagnosticMessage>,
decorate: impl 'd
+ for<'a, 'b> FnOnce(
&'b mut DiagnosticBuilder<'a, ()>,
) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
// Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
// the "real" work.
@ -293,7 +297,13 @@ pub fn struct_lint_level<'s, 'd>(
level: Level,
src: LintLevelSource,
span: Option<MultiSpan>,
decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) + 'd>,
msg: impl Into<DiagnosticMessage>,
decorate: Box<
dyn 'd
+ for<'a, 'b> FnOnce(
&'b mut DiagnosticBuilder<'a, ()>,
) -> &'b mut DiagnosticBuilder<'a, ()>,
>,
) {
// Check for future incompatibility lints and issue a stronger warning.
let future_incompatible = lint.future_incompatible;
@ -344,6 +354,9 @@ pub fn struct_lint_level<'s, 'd>(
(Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
};
err.set_primary_message(msg);
err.set_is_lint();
// If this code originates in a foreign macro, aka something that this crate
// did not itself author, then it's likely that there's nothing this crate
// can do about it. We probably want to skip the lint entirely.
@ -373,12 +386,12 @@ pub fn struct_lint_level<'s, 'd>(
if let Level::Expect(_) = level {
let name = lint.name_lower();
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
decorate(LintDiagnosticBuilder::new(err));
decorate(&mut err);
err.emit();
return;
}
explain_lint_level_source(lint, level, src, &mut err);
let name = lint.name_lower();
let is_force_warn = matches!(level, Level::ForceWarn(_));
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
@ -417,10 +430,12 @@ pub fn struct_lint_level<'s, 'd>(
}
}
// Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
decorate(LintDiagnosticBuilder::new(err));
// Finally, run `decorate`.
decorate(&mut err);
explain_lint_level_source(lint, level, src, &mut *err);
err.emit()
}
struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
struct_lint_level_impl(sess, lint, level, src, span, msg, Box::new(decorate))
}
/// Returns whether `span` originates in a foreign crate's external macro.

View file

@ -253,13 +253,12 @@ fn late_report_deprecation(
return;
}
let method_span = method_span.unwrap_or(span);
tcx.struct_span_lint_hir(lint, hir_id, method_span, |lint| {
let mut diag = lint.build(message);
tcx.struct_span_lint_hir(lint, hir_id, method_span, message, |diag| {
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
let kind = tcx.def_kind(def_id).descr(def_id);
deprecation_suggestion(&mut diag, kind, suggestion, method_span);
deprecation_suggestion(diag, kind, suggestion, method_span);
}
diag.emit();
diag
});
}
@ -621,9 +620,7 @@ impl<'tcx> TyCtxt<'tcx> {
unmarked: impl FnOnce(Span, DefId),
) -> bool {
let soft_handler = |lint, span, msg: &_| {
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
lint.build(msg).emit();
})
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint)
};
let eval_result =
self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);

View file

@ -35,7 +35,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan};
use rustc_errors::{
DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
@ -2857,7 +2859,9 @@ impl<'tcx> TyCtxt<'tcx> {
span: impl Into<MultiSpan>,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag))
self.struct_span_lint_hir(lint, hir_id, span, decorator.msg(), |diag| {
decorator.decorate_lint(diag)
})
}
pub fn struct_span_lint_hir(
@ -2865,10 +2869,13 @@ impl<'tcx> TyCtxt<'tcx> {
lint: &'static Lint,
hir_id: HirId,
span: impl Into<MultiSpan>,
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
msg: impl Into<DiagnosticMessage>,
decorate: impl for<'a, 'b> FnOnce(
&'b mut DiagnosticBuilder<'a, ()>,
) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
let (level, src) = self.lint_level_at_node(lint, hir_id);
struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate);
struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate);
}
/// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
@ -2879,17 +2886,20 @@ impl<'tcx> TyCtxt<'tcx> {
id: HirId,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag))
self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag))
}
pub fn struct_lint_node(
self,
lint: &'static Lint,
id: HirId,
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
msg: impl Into<DiagnosticMessage>,
decorate: impl for<'a, 'b> FnOnce(
&'b mut DiagnosticBuilder<'a, ()>,
) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
let (level, src) = self.lint_level_at_node(lint, id);
struct_lint_level(self.sess, lint, level, src, None, decorate);
struct_lint_level(self.sess, lint, level, src, None, msg, decorate);
}
pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {