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

@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
LATE_BOUND_LIFETIME_ARGUMENTS,
args.args[0].hir_id(),
multispan,
|lint| {
lint.build(msg).emit();
},
msg,
|lint| lint,
);
}

View file

@ -2010,30 +2010,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
let mut err = lint.build("ambiguous associated item");
let mut could_refer_to = |kind: DefKind, def_id, also| {
let note_msg = format!(
"`{}` could{} refer to the {} defined here",
assoc_ident,
also,
kind.descr(def_id)
tcx.struct_span_lint_hir(
AMBIGUOUS_ASSOCIATED_ITEMS,
hir_ref_id,
span,
"ambiguous associated item",
|lint| {
let mut could_refer_to = |kind: DefKind, def_id, also| {
let note_msg = format!(
"`{}` could{} refer to the {} defined here",
assoc_ident,
also,
kind.descr(def_id)
);
lint.span_note(tcx.def_span(def_id), &note_msg);
};
could_refer_to(DefKind::Variant, variant_def_id, "");
could_refer_to(kind, item.def_id, " also");
lint.span_suggestion(
span,
"use fully-qualified syntax",
format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
Applicability::MachineApplicable,
);
err.span_note(tcx.def_span(def_id), &note_msg);
};
could_refer_to(DefKind::Variant, variant_def_id, "");
could_refer_to(kind, item.def_id, " also");
err.span_suggestion(
span,
"use fully-qualified syntax",
format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
Applicability::MachineApplicable,
);
err.emit();
});
lint
},
);
}
Ok((ty, kind, item.def_id))
}
@ -3079,15 +3084,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
msg,
|lint| {
let mut diag = lint.build(msg);
diag.multipart_suggestion_verbose(
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
lint
},
);
}

View file

@ -33,7 +33,7 @@ use super::FnCtxt;
use crate::hir::def_id::DefId;
use crate::type_error_struct;
use hir::def_id::LOCAL_CRATE;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
use rustc_middle::mir::Mutability;
@ -754,19 +754,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
} else {
("", lint::builtin::TRIVIAL_CASTS)
};
fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
err.build(&format!(
"trivial {}cast: `{}` as `{}`",
adjective,
fcx.ty_to_string(t_expr),
fcx.ty_to_string(t_cast)
))
.help(&format!(
"cast can be replaced by coercion; this might \
require {type_asc_or}a temporary variable"
))
.emit();
});
fcx.tcx.struct_span_lint_hir(
lint,
self.expr.hir_id,
self.span,
DelayDm(|| {
format!(
"trivial {}cast: `{}` as `{}`",
adjective,
fcx.ty_to_string(t_expr),
fcx.ty_to_string(t_cast)
)
}),
|lint| {
lint.help(format!(
"cast can be replaced by coercion; this might \
require {type_asc_or}a temporary variable"
))
},
);
}
#[instrument(skip(fcx), level = "debug")]
@ -1074,12 +1080,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id,
self.span,
|err| {
err.build(&format!(
"cannot cast enum `{}` into integer `{}` because it implements `Drop`",
self.expr_ty, self.cast_ty
))
.emit();
DelayDm(|| format!(
"cannot cast enum `{}` into integer `{}` because it implements `Drop`",
self.expr_ty, self.cast_ty
)),
|lint| {
lint
},
);
}
@ -1090,12 +1096,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::LOSSY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
|err| {
let mut err = err.build(&format!(
DelayDm(|| format!(
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty
));
)),
|lint| {
let msg = "use `.addr()` to obtain the address of a pointer";
let expr_prec = self.expr.precedence().order();
@ -1114,9 +1119,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(cast_span, format!(").addr(){scalar_cast}")),
];
err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
} else {
err.span_suggestion(
lint.span_suggestion(
cast_span,
msg,
format!(".addr(){scalar_cast}"),
@ -1124,12 +1129,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
err.help(
lint.help(
"if you can't comply with strict provenance and need to expose the pointer \
provenance you can use `.expose_addr()` instead"
);
err.emit();
lint
},
);
}
@ -1139,24 +1144,24 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
|err| {
let mut err = err.build(&format!(
"strict provenance disallows casting integer `{}` to pointer `{}`",
self.expr_ty, self.cast_ty
));
DelayDm(|| format!(
"strict provenance disallows casting integer `{}` to pointer `{}`",
self.expr_ty, self.cast_ty
)),
|lint| {
let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
let suggestions = vec![
(self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
(self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
];
err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
err.help(
lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
lint.help(
"if you can't comply with strict provenance and don't have a pointer with \
the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
);
err.emit();
lint
},
);
}

View file

@ -48,9 +48,13 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
.emit();
}
None => {
tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
lint.build("use of calling convention not supported on this target").emit();
});
tcx.struct_span_lint_hir(
UNSUPPORTED_CALLING_CONVENTIONS,
hir_id,
span,
"use of calling convention not supported on this target",
|lint| lint,
);
}
}
@ -510,10 +514,10 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
UNINHABITED_STATIC,
tcx.hir().local_def_id_to_hir_id(def_id),
span,
"static of uninhabited type",
|lint| {
lint.build("static of uninhabited type")
lint
.note("uninhabited statics cannot be initialized, and any access would be an immediate error")
.emit();
},
);
}
@ -1437,6 +1441,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
"zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|lint| {
let note = if non_exhaustive {
"is marked with `#[non_exhaustive]`"
@ -1444,10 +1449,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
"contains private fields"
};
let field_ty = tcx.def_path_str_with_substs(def_id, substs);
lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
lint
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future."))
.emit();
},
)
}

View file

@ -58,17 +58,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
let msg = format!("unreachable {}", kind);
lint.build(&msg)
.span_label(span, &msg)
.span_label(
let msg = format!("unreachable {}", kind);
self.tcx().struct_span_lint_hir(
lint::builtin::UNREACHABLE_CODE,
id,
span,
&msg,
|lint| {
lint.span_label(span, &msg).span_label(
orig_span,
custom_note
.unwrap_or("any code following this expression is unreachable"),
)
.emit();
})
},
)
}
}
}

View file

@ -6,7 +6,7 @@
use self::drop_ranges::DropRanges;
use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::pluralize;
use rustc_errors::{pluralize, DelayDm};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
@ -610,33 +610,33 @@ fn check_must_not_suspend_def(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
|lint| {
let msg = format!(
DelayDm(|| {
format!(
"{}`{}`{} held across a suspend point, but should not be",
data.descr_pre,
tcx.def_path_str(def_id),
data.descr_post,
);
let mut err = lint.build(&msg);
)
}),
|lint| {
// add span pointing to the offending yield/await
err.span_label(data.yield_span, "the value is held across this suspend point");
lint.span_label(data.yield_span, "the value is held across this suspend point");
// Add optional reason note
if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better
err.span_note(data.source_span, note.as_str());
lint.span_note(data.source_span, note.as_str());
}
// Add some quick suggestions on what to do
// FIXME: can `drop` work as a suggestion here as well?
err.span_help(
lint.span_help(
data.source_span,
"consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point",
);
err.emit();
lint
},
);

View file

@ -328,17 +328,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
lint::builtin::ASM_SUB_REGISTER,
expr.hir_id,
spans,
"formatting may not be suitable for sub-register argument",
|lint| {
let msg = "formatting may not be suitable for sub-register argument";
let mut err = lint.build(msg);
err.span_label(expr.span, "for this argument");
err.help(&format!(
lint.span_label(expr.span, "for this argument");
lint.help(&format!(
"use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
));
err.help(&format!(
lint.help(&format!(
"or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
));
err.emit();
lint
},
);
}

View file

@ -82,14 +82,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
self_expr.hir_id,
self_expr.span,
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| {
let sp = self_expr.span;
let mut lint = lint.build(&format!(
"trait method `{}` will become ambiguous in Rust 2021",
segment.ident.name
));
let derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment {
@ -133,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
lint.emit();
lint
},
);
} else {
@ -143,6 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
call_expr.hir_id,
call_expr.span,
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| {
let sp = call_expr.span;
let trait_name = self.trait_path_or_bare_name(
@ -151,11 +148,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pick.item.container_id(self.tcx),
);
let mut lint = lint.build(&format!(
"trait method `{}` will become ambiguous in Rust 2021",
segment.ident.name
));
let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise {
let args = args
@ -202,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
lint.emit();
lint
},
);
}
@ -257,15 +249,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
// "type" refers to either a type or, more likely, a trait from which
// the associated function or method is from.
let container_id = pick.item.container_id(self.tcx);
let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
let trait_generics = self.tcx.generics_of(container_id);
self.tcx.struct_span_lint_hir(
RUST_2021_PRELUDE_COLLISIONS,
expr_id,
span,
format!(
"trait-associated function `{}` will become ambiguous in Rust 2021",
method_name.name
),
|lint| {
// "type" refers to either a type or, more likely, a trait from which
// the associated function or method is from.
let container_id = pick.item.container_id(self.tcx);
let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
let trait_generics = self.tcx.generics_of(container_id);
let trait_name =
if trait_generics.params.len() <= trait_generics.has_self as usize {
let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
{
trait_path
} else {
let counts = trait_generics.own_counts();
@ -282,44 +282,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
};
let mut lint = lint.build(&format!(
"trait-associated function `{}` will become ambiguous in Rust 2021",
method_name.name
));
let mut self_ty_name = self_ty_span
.find_ancestor_inside(span)
.and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
.unwrap_or_else(|| self_ty.to_string());
let mut self_ty_name = self_ty_span
.find_ancestor_inside(span)
.and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
.unwrap_or_else(|| self_ty.to_string());
// Get the number of generics the self type has (if an Adt) unless we can determine that
// the user has written the self type with generics already which we (naively) do by looking
// for a "<" in `self_ty_name`.
if !self_ty_name.contains('<') {
if let Adt(def, _) = self_ty.kind() {
let generics = self.tcx.generics_of(def.did());
if !generics.params.is_empty() {
let counts = generics.own_counts();
self_ty_name += &format!(
"<{}>",
std::iter::repeat("'_")
.take(counts.lifetimes)
.chain(std::iter::repeat("_").take(counts.types + counts.consts))
.collect::<Vec<_>>()
.join(", ")
);
// Get the number of generics the self type has (if an Adt) unless we can determine that
// the user has written the self type with generics already which we (naively) do by looking
// for a "<" in `self_ty_name`.
if !self_ty_name.contains('<') {
if let Adt(def, _) = self_ty.kind() {
let generics = self.tcx.generics_of(def.did());
if !generics.params.is_empty() {
let counts = generics.own_counts();
self_ty_name += &format!(
"<{}>",
std::iter::repeat("'_")
.take(counts.lifetimes)
.chain(
std::iter::repeat("_").take(counts.types + counts.consts)
)
.collect::<Vec<_>>()
.join(", ")
);
}
}
}
}
lint.span_suggestion(
span,
"disambiguate the associated function",
format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
Applicability::MachineApplicable,
);
lint.span_suggestion(
span,
"disambiguate the associated function",
format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
Applicability::MachineApplicable,
);
lint.emit();
});
lint
},
);
}
fn trait_path_or_bare_name(

View file

@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
scope_expr_id,
span,
|lint| {
lint.build("type annotations needed").emit();
},
"type annotations needed",
|lint| lint,
);
}
} else {
@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
stable_pick: &Pick<'_>,
unstable_candidates: &[(Candidate<'tcx>, Symbol)],
) {
let def_kind = stable_pick.item.kind.as_def_kind();
self.tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
self.scope_expr_id,
self.span,
format!(
"{} {} with this name may be added to the standard library in the future",
def_kind.article(),
def_kind.descr(stable_pick.item.def_id),
),
|lint| {
let def_kind = stable_pick.item.kind.as_def_kind();
let mut diag = lint.build(&format!(
"{} {} with this name may be added to the standard library in the future",
def_kind.article(),
def_kind.descr(stable_pick.item.def_id),
));
match (stable_pick.item.kind, stable_pick.item.container) {
(ty::AssocKind::Fn, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
// the code from `report_method_error()`.
diag.help(&format!(
lint.help(&format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
self.tcx.def_path_str(stable_pick.item.def_id),
@ -1383,7 +1382,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
(ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
let def_id = stable_pick.item.container_id(self.tcx);
diag.span_suggestion(
lint.span_suggestion(
self.span,
"use the fully qualified path to the associated const",
format!(
@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
if self.tcx.sess.is_nightly_build() {
for (candidate, feature) in unstable_candidates {
diag.help(&format!(
lint.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
self.tcx.def_path_str(candidate.item.def_id),
@ -1407,7 +1406,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
diag.emit();
lint
},
);
}

View file

@ -1790,10 +1790,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
);
self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| {
let mut lint = build.build("some fields are not explicitly listed");
self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| {
lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
lint.help(
"ensure that all fields are mentioned explicitly by adding the suggested fields",
);
@ -1801,7 +1799,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
ty,
));
lint.emit();
lint
});
}

View file

@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
closure_hir_id,
closure_head_span,
reasons.migration_message(),
|lint| {
let mut diagnostics_builder = lint.build(
&reasons.migration_message(),
);
for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
// Labels all the usage of the captured variable and why they are responsible
// for migration being needed
@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
let cause_span = self.tcx.hir().span(*capture_expr_id);
diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
}
UpvarMigrationInfo::CapturingNothing { use_span } => {
diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
self.tcx.hir().name(*var_hir_id),
));
}
@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
}
UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
v = self.tcx.hir().name(*var_hir_id),
));
}
@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
let var_name = self.tcx.hir().name(*var_hir_id);
diagnostics_builder.span_label(closure_head_span, format!("\
lint.span_label(closure_head_span, format!("\
in Rust 2018, this closure implements {missing_trait} \
as `{var_name}` implements {missing_trait}, but in Rust 2021, \
this closure will no longer implement {missing_trait} \
@ -814,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
let diagnostic_msg = format!(
"add a dummy let to cause {} to be fully captured",
@ -857,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We take the indentation from the next non-empty line.
let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default();
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
diagnostics_builder.span_suggestion(
lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
&diagnostic_msg,
format!("\n{indent}{migration_string};"),
@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// braces, but with more than just the opening
// brace on the first line. We put the `let`
// directly after the `{`.
diagnostics_builder.span_suggestion(
lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
&diagnostic_msg,
format!(" {migration_string};"),
@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// This is a closure without braces around the body.
// We add braces to add the `let` before the body.
diagnostics_builder.multipart_suggestion(
lint.multipart_suggestion(
&diagnostic_msg,
vec![
(closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
} else {
diagnostics_builder.span_suggestion(
lint.span_suggestion(
closure_span,
&diagnostic_msg,
migration_string,
@ -895,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
diagnostics_builder.emit();
lint
},
);
}

View file

@ -29,14 +29,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
continue;
}
let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
format!("unused import: `{}`", snippet)
} else {
"unused import".to_owned()
};
lint.build(&msg).emit();
});
let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
format!("unused import: `{}`", snippet)
} else {
"unused import".to_owned()
};
tcx.struct_span_lint_hir(
lint::builtin::UNUSED_IMPORTS,
item.hir_id(),
path.span,
msg,
|lint| lint,
);
}
unused_crates_lint(tcx);

View file

@ -2,7 +2,7 @@
//! crate or pertains to a type defined in this crate.
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_middle::ty::subst::GenericArgKind;
@ -412,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>(
lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
tcx.hir().local_def_id_to_hir_id(impl_def_id),
tcx.def_span(impl_def_id),
|err| {
let item_span = tcx.def_span(self_type_did);
let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
let mut err = err.build(&format!(
DelayDm(|| {
format!(
"cross-crate traits with a default impl, like `{}`, \
should not be specialized",
tcx.def_path_str(trait_ref.def_id),
));
)
}),
|lint| {
let item_span = tcx.def_span(self_type_did);
let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
err.note(&format!("`{}` is mentioned multiple times", arg));
lint.note(&format!("`{}` is mentioned multiple times", arg));
}
ty::util::NotUniqueParam::NotParam(arg) => {
err.note(&format!("`{}` is not a generic parameter", arg));
lint.note(&format!("`{}` is not a generic parameter", arg));
}
}
err.span_note(
lint.span_note(
item_span,
&format!(
"try using the same sequence of generic parameters as the {} definition",
self_descr,
),
);
err.emit();
)
},
);
}

View file

@ -2067,11 +2067,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
no_sanitize_span,
|lint| {
lint.build("`no_sanitize` will have no effect after inlining")
.span_note(inline_span, "inlining requested here")
.emit();
},
"`no_sanitize` will have no effect after inlining",
|lint| lint.span_note(inline_span, "inlining requested here"),
)
}
}

View file

@ -266,9 +266,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
param.hir_id,
param.span,
|lint| {
lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
},
TYPE_DEFAULT_NOT_ALLOWED,
|lint| lint,
);
}
Defaults::Deny => {