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
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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), ¬e_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), ¬e_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
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue