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

@ -233,10 +233,10 @@ impl<'tcx> ConstEvalErr<'tcx> {
rustc_session::lint::builtin::CONST_ERR, rustc_session::lint::builtin::CONST_ERR,
hir_id, hir_id,
tcx.span, tcx.span,
message,
|lint| { |lint| {
let mut lint = lint.build(message); finish(lint, Some(err_msg));
finish(&mut lint, Some(err_msg)); lint
lint.emit();
}, },
); );
ErrorHandled::Linted ErrorHandled::Linted

View File

@ -358,6 +358,17 @@ impl<S: Into<String>> From<S> for DiagnosticMessage {
} }
} }
/// A workaround for "good path" ICEs when formatting types in disables lints.
///
/// Delays formatting until `.into(): DiagnosticMessage` is used.
pub struct DelayDm<F>(pub F);
impl<F: FnOnce() -> String> From<DelayDm<F>> for DiagnosticMessage {
fn from(DelayDm(f): DelayDm<F>) -> Self {
DiagnosticMessage::from(f())
}
}
/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but /// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the /// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the
/// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be /// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be

View File

@ -1,6 +1,6 @@
use crate::snippet::Style; use crate::snippet::Style;
use crate::{ use crate::{
CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
}; };
use rustc_ast as ast; use rustc_ast as ast;
@ -209,7 +209,12 @@ pub trait AddToDiagnostic {
#[rustc_diagnostic_item = "DecorateLint"] #[rustc_diagnostic_item = "DecorateLint"]
pub trait DecorateLint<'a, G: EmissionGuarantee> { pub trait DecorateLint<'a, G: EmissionGuarantee> {
/// Decorate and emit a lint. /// Decorate and emit a lint.
fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>); fn decorate_lint<'b>(
self,
diag: &'b mut DiagnosticBuilder<'a, G>,
) -> &'b mut DiagnosticBuilder<'a, G>;
fn msg(&self) -> DiagnosticMessage;
} }
#[must_use] #[must_use]

View File

@ -642,27 +642,3 @@ macro_rules! struct_span_err {
macro_rules! error_code { macro_rules! error_code {
($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }}; ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
} }
/// Wrapper around a `DiagnosticBuilder` for creating lints.
pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
#[rustc_lint_diagnostics]
/// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> {
self.0.set_primary_message(msg);
self.0.set_is_lint();
self.0
}
/// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`.
pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> {
LintDiagnosticBuilder(err)
}
}
impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> {
pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> {
LintDiagnosticBuilder(self.0.forget_guarantee())
}
}

View File

@ -30,7 +30,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::sync::{self, Lock, Lrc};
use rustc_data_structures::AtomicRef; use rustc_data_structures::AtomicRef;
pub use rustc_error_messages::{ pub use rustc_error_messages::{
fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle, fallback_fluent_bundle, fluent, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
DEFAULT_LOCALE_RESOURCES, DEFAULT_LOCALE_RESOURCES,
}; };
@ -374,7 +374,7 @@ pub use diagnostic::{
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay, AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
}; };
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder}; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
use std::backtrace::Backtrace; use std::backtrace::Backtrace;
/// A handler deals with errors and other compiler output. /// A handler deals with errors and other compiler output.

View File

@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
LATE_BOUND_LIFETIME_ARGUMENTS, LATE_BOUND_LIFETIME_ARGUMENTS,
args.args[0].hir_id(), args.args[0].hir_id(),
multispan, multispan,
|lint| { msg,
lint.build(msg).emit(); |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); tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
if let Some(variant_def_id) = variant_resolution { if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { tcx.struct_span_lint_hir(
let mut err = lint.build("ambiguous associated item"); AMBIGUOUS_ASSOCIATED_ITEMS,
let mut could_refer_to = |kind: DefKind, def_id, also| { hir_ref_id,
let note_msg = format!( span,
"`{}` could{} refer to the {} defined here", "ambiguous associated item",
assoc_ident, |lint| {
also, let mut could_refer_to = |kind: DefKind, def_id, also| {
kind.descr(def_id) 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, ""); lint
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();
});
} }
Ok((ty, kind, item.def_id)) Ok((ty, kind, item.def_id))
} }
@ -3079,15 +3084,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
BARE_TRAIT_OBJECTS, BARE_TRAIT_OBJECTS,
self_ty.hir_id, self_ty.hir_id,
self_ty.span, self_ty.span,
msg,
|lint| { |lint| {
let mut diag = lint.build(msg); lint.multipart_suggestion_verbose(
diag.multipart_suggestion_verbose(
"use `dyn`", "use `dyn`",
sugg, sugg,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); self.maybe_lint_blanket_trait_impl(&self_ty, lint);
diag.emit(); lint
}, },
); );
} }

View File

@ -33,7 +33,7 @@ use super::FnCtxt;
use crate::hir::def_id::DefId; use crate::hir::def_id::DefId;
use crate::type_error_struct; use crate::type_error_struct;
use hir::def_id::LOCAL_CRATE; 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_hir as hir;
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
use rustc_middle::mir::Mutability; use rustc_middle::mir::Mutability;
@ -754,19 +754,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
} else { } else {
("", lint::builtin::TRIVIAL_CASTS) ("", lint::builtin::TRIVIAL_CASTS)
}; };
fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| { fcx.tcx.struct_span_lint_hir(
err.build(&format!( lint,
"trivial {}cast: `{}` as `{}`", self.expr.hir_id,
adjective, self.span,
fcx.ty_to_string(t_expr), DelayDm(|| {
fcx.ty_to_string(t_cast) format!(
)) "trivial {}cast: `{}` as `{}`",
.help(&format!( adjective,
"cast can be replaced by coercion; this might \ fcx.ty_to_string(t_expr),
require {type_asc_or}a temporary variable" fcx.ty_to_string(t_cast)
)) )
.emit(); }),
}); |lint| {
lint.help(format!(
"cast can be replaced by coercion; this might \
require {type_asc_or}a temporary variable"
))
},
);
} }
#[instrument(skip(fcx), level = "debug")] #[instrument(skip(fcx), level = "debug")]
@ -1074,12 +1080,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::CENUM_IMPL_DROP_CAST, lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id, self.expr.hir_id,
self.span, self.span,
|err| { DelayDm(|| format!(
err.build(&format!( "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
"cannot cast enum `{}` into integer `{}` because it implements `Drop`", self.expr_ty, self.cast_ty
self.expr_ty, self.cast_ty )),
)) |lint| {
.emit(); lint
}, },
); );
} }
@ -1090,12 +1096,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::LOSSY_PROVENANCE_CASTS, lint::builtin::LOSSY_PROVENANCE_CASTS,
self.expr.hir_id, self.expr.hir_id,
self.span, self.span,
|err| { DelayDm(|| format!(
let mut err = err.build(&format!(
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`", "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty self.expr_ty, self.cast_ty
)); )),
|lint| {
let msg = "use `.addr()` to obtain the address of a pointer"; let msg = "use `.addr()` to obtain the address of a pointer";
let expr_prec = self.expr.precedence().order(); let expr_prec = self.expr.precedence().order();
@ -1114,9 +1119,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(cast_span, format!(").addr(){scalar_cast}")), (cast_span, format!(").addr(){scalar_cast}")),
]; ];
err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
} else { } else {
err.span_suggestion( lint.span_suggestion(
cast_span, cast_span,
msg, msg,
format!(".addr(){scalar_cast}"), 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 \ "if you can't comply with strict provenance and need to expose the pointer \
provenance you can use `.expose_addr()` instead" provenance you can use `.expose_addr()` instead"
); );
err.emit(); lint
}, },
); );
} }
@ -1139,24 +1144,24 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::FUZZY_PROVENANCE_CASTS, lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id, self.expr.hir_id,
self.span, self.span,
|err| { DelayDm(|| format!(
let mut err = err.build(&format!( "strict provenance disallows casting integer `{}` to pointer `{}`",
"strict provenance disallows casting integer `{}` to pointer `{}`", self.expr_ty, self.cast_ty
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 msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
let suggestions = vec![ let suggestions = vec![
(self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")), (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
(self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")), (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
]; ];
err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
err.help( lint.help(
"if you can't comply with strict provenance and don't have a pointer with \ "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" 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(); .emit();
} }
None => { None => {
tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { tcx.struct_span_lint_hir(
lint.build("use of calling convention not supported on this target").emit(); 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, UNINHABITED_STATIC,
tcx.hir().local_def_id_to_hir_id(def_id), tcx.hir().local_def_id_to_hir_id(def_id),
span, span,
"static of uninhabited type",
|lint| { |lint| {
lint.build("static of uninhabited type") lint
.note("uninhabited statics cannot be initialized, and any access would be an immediate error") .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, REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span, span,
"zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|lint| { |lint| {
let note = if non_exhaustive { let note = if non_exhaustive {
"is marked with `#[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" "contains private fields"
}; };
let field_ty = tcx.def_path_str_with_substs(def_id, substs); 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}, \ .note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future.")) 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); 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);
let msg = format!("unreachable {}", kind); self.tcx().struct_span_lint_hir(
lint.build(&msg) lint::builtin::UNREACHABLE_CODE,
.span_label(span, &msg) id,
.span_label( span,
&msg,
|lint| {
lint.span_label(span, &msg).span_label(
orig_span, orig_span,
custom_note custom_note
.unwrap_or("any code following this expression is unreachable"), .unwrap_or("any code following this expression is unreachable"),
) )
.emit(); },
}) )
} }
} }
} }

View File

@ -6,7 +6,7 @@
use self::drop_ranges::DropRanges; use self::drop_ranges::DropRanges;
use super::FnCtxt; use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::pluralize; use rustc_errors::{pluralize, DelayDm};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -610,33 +610,33 @@ fn check_must_not_suspend_def(
rustc_session::lint::builtin::MUST_NOT_SUSPEND, rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id, hir_id,
data.source_span, data.source_span,
|lint| { DelayDm(|| {
let msg = format!( format!(
"{}`{}`{} held across a suspend point, but should not be", "{}`{}`{} held across a suspend point, but should not be",
data.descr_pre, data.descr_pre,
tcx.def_path_str(def_id), tcx.def_path_str(def_id),
data.descr_post, data.descr_post,
); )
let mut err = lint.build(&msg); }),
|lint| {
// add span pointing to the offending yield/await // 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 // Add optional reason note
if let Some(note) = attr.value_str() { if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better // 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 // Add some quick suggestions on what to do
// FIXME: can `drop` work as a suggestion here as well? // FIXME: can `drop` work as a suggestion here as well?
err.span_help( lint.span_help(
data.source_span, data.source_span,
"consider using a block (`{ ... }`) \ "consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point", 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, lint::builtin::ASM_SUB_REGISTER,
expr.hir_id, expr.hir_id,
spans, spans,
"formatting may not be suitable for sub-register argument",
|lint| { |lint| {
let msg = "formatting may not be suitable for sub-register argument"; lint.span_label(expr.span, "for this argument");
let mut err = lint.build(msg); lint.help(&format!(
err.span_label(expr.span, "for this argument");
err.help(&format!(
"use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`", "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}`", "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, prelude_or_array_lint,
self_expr.hir_id, self_expr.hir_id,
self_expr.span, self_expr.span,
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| { |lint| {
let sp = self_expr.span; 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 derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment { let autoref = match pick.autoref_or_ptr_adjustment {
@ -133,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
lint.emit(); lint
}, },
); );
} else { } else {
@ -143,6 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint, prelude_or_array_lint,
call_expr.hir_id, call_expr.hir_id,
call_expr.span, call_expr.span,
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| { |lint| {
let sp = call_expr.span; let sp = call_expr.span;
let trait_name = self.trait_path_or_bare_name( 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), 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); let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise { if precise {
let args = args 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; return;
} }
self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| { self.tcx.struct_span_lint_hir(
// "type" refers to either a type or, more likely, a trait from which RUST_2021_PRELUDE_COLLISIONS,
// the associated function or method is from. expr_id,
let container_id = pick.item.container_id(self.tcx); span,
let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id); format!(
let trait_generics = self.tcx.generics_of(container_id); "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 = let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
if trait_generics.params.len() <= trait_generics.has_self as usize { {
trait_path trait_path
} else { } else {
let counts = trait_generics.own_counts(); let counts = trait_generics.own_counts();
@ -282,44 +282,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) )
}; };
let mut lint = lint.build(&format!( let mut self_ty_name = self_ty_span
"trait-associated function `{}` will become ambiguous in Rust 2021", .find_ancestor_inside(span)
method_name.name .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 // Get the number of generics the self type has (if an Adt) unless we can determine that
.find_ancestor_inside(span) // the user has written the self type with generics already which we (naively) do by looking
.and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) // for a "<" in `self_ty_name`.
.unwrap_or_else(|| self_ty.to_string()); if !self_ty_name.contains('<') {
if let Adt(def, _) = self_ty.kind() {
// Get the number of generics the self type has (if an Adt) unless we can determine that let generics = self.tcx.generics_of(def.did());
// the user has written the self type with generics already which we (naively) do by looking if !generics.params.is_empty() {
// for a "<" in `self_ty_name`. let counts = generics.own_counts();
if !self_ty_name.contains('<') { self_ty_name += &format!(
if let Adt(def, _) = self_ty.kind() { "<{}>",
let generics = self.tcx.generics_of(def.did()); std::iter::repeat("'_")
if !generics.params.is_empty() { .take(counts.lifetimes)
let counts = generics.own_counts(); .chain(
self_ty_name += &format!( std::iter::repeat("_").take(counts.types + counts.consts)
"<{}>", )
std::iter::repeat("'_") .collect::<Vec<_>>()
.take(counts.lifetimes) .join(", ")
.chain(std::iter::repeat("_").take(counts.types + counts.consts)) );
.collect::<Vec<_>>() }
.join(", ")
);
} }
} }
} lint.span_suggestion(
lint.span_suggestion( span,
span, "disambiguate the associated function",
"disambiguate the associated function", format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), Applicability::MachineApplicable,
Applicability::MachineApplicable, );
);
lint.emit(); lint
}); },
);
} }
fn trait_path_or_bare_name( fn trait_path_or_bare_name(

View File

@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::TYVAR_BEHIND_RAW_POINTER, lint::builtin::TYVAR_BEHIND_RAW_POINTER,
scope_expr_id, scope_expr_id,
span, span,
|lint| { "type annotations needed",
lint.build("type annotations needed").emit(); |lint| lint,
},
); );
} }
} else { } else {
@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
stable_pick: &Pick<'_>, stable_pick: &Pick<'_>,
unstable_candidates: &[(Candidate<'tcx>, Symbol)], unstable_candidates: &[(Candidate<'tcx>, Symbol)],
) { ) {
let def_kind = stable_pick.item.kind.as_def_kind();
self.tcx.struct_span_lint_hir( self.tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS, lint::builtin::UNSTABLE_NAME_COLLISIONS,
self.scope_expr_id, self.scope_expr_id,
self.span, 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| { |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) { match (stable_pick.item.kind, stable_pick.item.container) {
(ty::AssocKind::Fn, _) => { (ty::AssocKind::Fn, _) => {
// FIXME: This should be a `span_suggestion` instead of `help` // FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only // However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing // highlights the method name, so we can't use it. Also consider reusing
// the code from `report_method_error()`. // the code from `report_method_error()`.
diag.help(&format!( lint.help(&format!(
"call with fully qualified syntax `{}(...)` to keep using the current \ "call with fully qualified syntax `{}(...)` to keep using the current \
method", method",
self.tcx.def_path_str(stable_pick.item.def_id), 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) => { (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
let def_id = stable_pick.item.container_id(self.tcx); let def_id = stable_pick.item.container_id(self.tcx);
diag.span_suggestion( lint.span_suggestion(
self.span, self.span,
"use the fully qualified path to the associated const", "use the fully qualified path to the associated const",
format!( format!(
@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} }
if self.tcx.sess.is_nightly_build() { if self.tcx.sess.is_nightly_build() {
for (candidate, feature) in unstable_candidates { for (candidate, feature) in unstable_candidates {
diag.help(&format!( lint.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`", "add `#![feature({})]` to the crate attributes to enable `{}`",
feature, feature,
self.tcx.def_path_str(candidate.item.def_id), 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<_>>(), &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
); );
self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| { self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| {
let mut lint = build.build("some fields are not explicitly listed");
lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
lint.help( lint.help(
"ensure that all fields are mentioned explicitly by adding the suggested fields", "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", "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
ty, ty,
)); ));
lint.emit();
lint
}); });
} }

View File

@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
closure_hir_id, closure_hir_id,
closure_head_span, closure_head_span,
reasons.migration_message(),
|lint| { |lint| {
let mut diagnostics_builder = lint.build(
&reasons.migration_message(),
);
for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
// Labels all the usage of the captured variable and why they are responsible // Labels all the usage of the captured variable and why they are responsible
// for migration being needed // for migration being needed
@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info { match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
let cause_span = self.tcx.hir().span(*capture_expr_id); 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), self.tcx.hir().name(*var_hir_id),
captured_name, captured_name,
)); ));
} }
UpvarMigrationInfo::CapturingNothing { use_span } => { 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), self.tcx.hir().name(*var_hir_id),
)); ));
} }
@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info { match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { 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), self.tcx.hir().name(*var_hir_id),
captured_name, captured_name,
)); ));
} }
UpvarMigrationInfo::CapturingNothing { use_span: _ } => { 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), v = self.tcx.hir().name(*var_hir_id),
)); ));
} }
@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info { match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
let var_name = self.tcx.hir().name(*var_hir_id); 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} \ in Rust 2018, this closure implements {missing_trait} \
as `{var_name}` implements {missing_trait}, but in Rust 2021, \ as `{var_name}` implements {missing_trait}, but in Rust 2021, \
this closure will no longer implement {missing_trait} \ 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!( let diagnostic_msg = format!(
"add a dummy let to cause {} to be fully captured", "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. // We take the indentation from the next non-empty line.
let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); 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; 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(), closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
&diagnostic_msg, &diagnostic_msg,
format!("\n{indent}{migration_string};"), format!("\n{indent}{migration_string};"),
@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// braces, but with more than just the opening // braces, but with more than just the opening
// brace on the first line. We put the `let` // brace on the first line. We put the `let`
// directly after the `{`. // directly after the `{`.
diagnostics_builder.span_suggestion( lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(), closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
&diagnostic_msg, &diagnostic_msg,
format!(" {migration_string};"), format!(" {migration_string};"),
@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else { } else {
// This is a closure without braces around the body. // This is a closure without braces around the body.
// We add braces to add the `let` before the body. // We add braces to add the `let` before the body.
diagnostics_builder.multipart_suggestion( lint.multipart_suggestion(
&diagnostic_msg, &diagnostic_msg,
vec![ vec![
(closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")), (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
} else { } else {
diagnostics_builder.span_suggestion( lint.span_suggestion(
closure_span, closure_span,
&diagnostic_msg, &diagnostic_msg,
migration_string, 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; continue;
} }
let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; 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) {
let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet)
format!("unused import: `{}`", snippet) } else {
} else { "unused import".to_owned()
"unused import".to_owned() };
}; tcx.struct_span_lint_hir(
lint.build(&msg).emit(); lint::builtin::UNUSED_IMPORTS,
}); item.hir_id(),
path.span,
msg,
|lint| lint,
);
} }
unused_crates_lint(tcx); unused_crates_lint(tcx);

View File

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

View File

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

View File

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

View File

@ -118,37 +118,41 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
// to an array or to a slice. // to an array or to a slice.
_ => bug!("array type coerced to something other than array or slice"), _ => bug!("array type coerced to something other than array or slice"),
}; };
cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| { cx.struct_span_lint(
let mut diag = lint.build(fluent::lint::array_into_iter); ARRAY_INTO_ITER,
diag.set_arg("target", target); call.ident.span,
diag.span_suggestion( fluent::lint::array_into_iter,
call.ident.span, |diag| {
fluent::lint::use_iter_suggestion, diag.set_arg("target", target);
"iter",
Applicability::MachineApplicable,
);
if self.for_expr_span == expr.span {
diag.span_suggestion( diag.span_suggestion(
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), call.ident.span,
fluent::lint::remove_into_iter_suggestion, fluent::lint::use_iter_suggestion,
"", "iter",
Applicability::MaybeIncorrect, Applicability::MachineApplicable,
); );
} else if receiver_ty.is_array() { if self.for_expr_span == expr.span {
diag.multipart_suggestion( diag.span_suggestion(
fluent::lint::use_explicit_into_iter_suggestion, receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
vec![ fluent::lint::remove_into_iter_suggestion,
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()), "",
( Applicability::MaybeIncorrect,
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), );
")".into(), } else if receiver_ty.is_array() {
), diag.multipart_suggestion(
], fluent::lint::use_explicit_into_iter_suggestion,
Applicability::MaybeIncorrect, vec![
); (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
} (
diag.emit(); receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
}) ")".into(),
),
],
Applicability::MaybeIncorrect,
);
}
diag
},
)
} }
} }
} }

View File

@ -33,8 +33,8 @@ use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{ use rustc_errors::{
fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
LintDiagnosticBuilder, MultiSpan, DiagnosticStyledString, MultiSpan,
}; };
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir; use rustc_hir as hir;
@ -103,9 +103,12 @@ impl EarlyLintPass for WhileTrue {
&& !lit.span.from_expansion() && !lit.span.from_expansion()
{ {
let condition_span = e.span.with_hi(cond.span.hi()); let condition_span = e.span.with_hi(cond.span.hi());
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_while_true) WHILE_TRUE,
.span_suggestion_short( condition_span,
fluent::lint::builtin_while_true,
|lint| {
lint.span_suggestion_short(
condition_span, condition_span,
fluent::lint::suggestion, fluent::lint::suggestion,
format!( format!(
@ -117,8 +120,8 @@ impl EarlyLintPass for WhileTrue {
), ),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit(); },
}) )
} }
} }
} }
@ -154,9 +157,12 @@ impl BoxPointers {
for leaf in ty.walk() { for leaf in ty.walk() {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if leaf_ty.is_box() { if leaf_ty.is_box() {
cx.struct_span_lint(BOX_POINTERS, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit(); BOX_POINTERS,
}); span,
fluent::lint::builtin_box_pointers,
|lint| lint.set_arg("ty", ty),
);
} }
} }
} }
@ -255,19 +261,21 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
if cx.tcx.find_field_index(ident, &variant) if cx.tcx.find_field_index(ident, &variant)
== Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results())) == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
{ {
cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| { cx.struct_span_lint(
let suggested_ident = NON_SHORTHAND_FIELD_PATTERNS,
format!("{}{}", binding_annot.prefix_str(), ident); fieldpat.span,
lint.build(fluent::lint::builtin_non_shorthand_field_patterns) fluent::lint::builtin_non_shorthand_field_patterns,
.set_arg("ident", ident.clone()) |lint| {
.span_suggestion( let suggested_ident =
format!("{}{}", binding_annot.prefix_str(), ident);
lint.set_arg("ident", ident.clone()).span_suggestion(
fieldpat.span, fieldpat.span,
fluent::lint::suggestion, fluent::lint::suggestion,
suggested_ident, suggested_ident,
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit(); },
}); );
} }
} }
} }
@ -307,14 +315,17 @@ impl UnsafeCode {
&self, &self,
cx: &EarlyContext<'_>, cx: &EarlyContext<'_>,
span: Span, span: Span,
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, ()>,
) { ) {
// This comes from a macro that has `#[allow_internal_unsafe]`. // This comes from a macro that has `#[allow_internal_unsafe]`.
if span.allows_unsafe() { if span.allows_unsafe() {
return; return;
} }
cx.struct_span_lint(UNSAFE_CODE, span, decorate); cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate);
} }
fn report_overridden_symbol_name( fn report_overridden_symbol_name(
@ -323,8 +334,8 @@ impl UnsafeCode {
span: Span, span: Span,
msg: DiagnosticMessage, msg: DiagnosticMessage,
) { ) {
self.report_unsafe(cx, span, |lint| { self.report_unsafe(cx, span, msg, |lint| {
lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit(); lint.note(fluent::lint::builtin_overridden_symbol_name)
}) })
} }
@ -334,8 +345,8 @@ impl UnsafeCode {
span: Span, span: Span,
msg: DiagnosticMessage, msg: DiagnosticMessage,
) { ) {
self.report_unsafe(cx, span, |lint| { self.report_unsafe(cx, span, msg, |lint| {
lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit(); lint.note(fluent::lint::builtin_overridden_symbol_section)
}) })
} }
} }
@ -343,9 +354,12 @@ impl UnsafeCode {
impl EarlyLintPass for UnsafeCode { impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if attr.has_name(sym::allow_internal_unsafe) { if attr.has_name(sym::allow_internal_unsafe) {
self.report_unsafe(cx, attr.span, |lint| { self.report_unsafe(
lint.build(fluent::lint::builtin_allow_internal_unsafe).emit(); cx,
}); attr.span,
fluent::lint::builtin_allow_internal_unsafe,
|lint| lint,
);
} }
} }
@ -353,24 +367,20 @@ impl EarlyLintPass for UnsafeCode {
if let ast::ExprKind::Block(ref blk, _) = e.kind { if let ast::ExprKind::Block(ref blk, _) = e.kind {
// Don't warn about generated blocks; that'll just pollute the output. // Don't warn about generated blocks; that'll just pollute the output.
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
self.report_unsafe(cx, blk.span, |lint| { self.report_unsafe(cx, blk.span, fluent::lint::builtin_unsafe_block, |lint| lint);
lint.build(fluent::lint::builtin_unsafe_block).emit();
});
} }
} }
} }
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind { match it.kind {
ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
.report_unsafe(cx, it.span, |lint| { self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_trait, |lint| lint)
lint.build(fluent::lint::builtin_unsafe_trait).emit(); }
}),
ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
.report_unsafe(cx, it.span, |lint| { self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_impl, |lint| lint)
lint.build(fluent::lint::builtin_unsafe_impl).emit(); }
}),
ast::ItemKind::Fn(..) => { ast::ItemKind::Fn(..) => {
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
@ -463,9 +473,7 @@ impl EarlyLintPass for UnsafeCode {
FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method, FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method, FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
}; };
self.report_unsafe(cx, span, |lint| { self.report_unsafe(cx, span, msg, |lint| lint);
lint.build(msg).emit();
});
} }
} }
} }
@ -566,12 +574,12 @@ impl MissingDoc {
let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id)); let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
let has_doc = attrs.iter().any(has_doc); let has_doc = attrs.iter().any(has_doc);
if !has_doc { if !has_doc {
cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_missing_doc) MISSING_DOCS,
.set_arg("article", article) cx.tcx.def_span(def_id),
.set_arg("desc", desc) fluent::lint::builtin_missing_doc,
.emit(); |lint| lint.set_arg("article", article).set_arg("desc", desc),
}); );
} }
} }
} }
@ -758,9 +766,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
) )
.is_ok() .is_ok()
{ {
cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_missing_copy_impl).emit(); MISSING_COPY_IMPLEMENTATIONS,
}) item.span,
fluent::lint::builtin_missing_copy_impl,
|lint| lint,
)
} }
} }
} }
@ -834,11 +845,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
} }
if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) { if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_missing_debug_impl) MISSING_DEBUG_IMPLEMENTATIONS,
.set_arg("debug", cx.tcx.def_path_str(debug)) item.span,
.emit(); fluent::lint::builtin_missing_debug_impl,
}); |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
);
} }
} }
} }
@ -906,24 +918,26 @@ impl EarlyLintPass for AnonymousParameters {
for arg in sig.decl.inputs.iter() { for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty { if ident.name == kw::Empty {
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| { let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip { let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
(snip.as_str(), Applicability::MachineApplicable) (snip.as_str(), Applicability::MachineApplicable)
} else { } else {
("<type>", Applicability::HasPlaceholders) ("<type>", Applicability::HasPlaceholders)
}; };
cx.struct_span_lint(
lint.build(fluent::lint::builtin_anonymous_params) ANONYMOUS_PARAMETERS,
.span_suggestion( arg.pat.span,
fluent::lint::builtin_anonymous_params,
|lint| {
lint.span_suggestion(
arg.pat.span, arg.pat.span,
fluent::lint::suggestion, fluent::lint::suggestion,
format!("_: {}", ty_snip), format!("_: {}", ty_snip),
appl, appl,
) )
.emit(); },
}) )
} }
} }
} }
@ -958,38 +972,44 @@ impl EarlyLintPass for DeprecatedAttr {
_, _,
) = gate ) = gate
{ {
cx.struct_span_lint(DEPRECATED, attr.span, |lint| { // FIXME(davidtwco) translatable deprecated attr
// FIXME(davidtwco) translatable deprecated attr cx.struct_span_lint(
lint.build(fluent::lint::builtin_deprecated_attr_link) DEPRECATED,
.set_arg("name", name) attr.span,
.set_arg("reason", reason) fluent::lint::builtin_deprecated_attr_link,
.set_arg("link", link) |lint| {
.span_suggestion_short( lint.set_arg("name", name)
attr.span, .set_arg("reason", reason)
suggestion.map(|s| s.into()).unwrap_or( .set_arg("link", link)
fluent::lint::builtin_deprecated_attr_default_suggestion, .span_suggestion_short(
), attr.span,
"", suggestion.map(|s| s.into()).unwrap_or(
Applicability::MachineApplicable, fluent::lint::builtin_deprecated_attr_default_suggestion,
) ),
.emit(); "",
}); Applicability::MachineApplicable,
)
},
);
} }
return; return;
} }
} }
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
cx.struct_span_lint(DEPRECATED, attr.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_deprecated_attr_used) DEPRECATED,
.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path)) attr.span,
.span_suggestion_short( fluent::lint::builtin_deprecated_attr_used,
attr.span, |lint| {
fluent::lint::builtin_deprecated_attr_default_suggestion, lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
"", .span_suggestion_short(
Applicability::MachineApplicable, attr.span,
) fluent::lint::builtin_deprecated_attr_default_suggestion,
.emit(); "",
}); Applicability::MachineApplicable,
)
},
);
} }
} }
} }
@ -1016,20 +1036,21 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
let span = sugared_span.take().unwrap_or(attr.span); let span = sugared_span.take().unwrap_or(attr.span);
if is_doc_comment || attr.has_name(sym::doc) { if is_doc_comment || attr.has_name(sym::doc) {
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { cx.struct_span_lint(
let mut err = lint.build(fluent::lint::builtin_unused_doc_comment); UNUSED_DOC_COMMENTS,
err.set_arg("kind", node_kind); span,
err.span_label(node_span, fluent::lint::label); fluent::lint::builtin_unused_doc_comment,
match attr.kind { |lint| {
AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { lint.set_arg("kind", node_kind).span_label(node_span, fluent::lint::label).help(
err.help(fluent::lint::plain_help); match attr.kind {
} AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
AttrKind::DocComment(CommentKind::Block, _) => { fluent::lint::plain_help
err.help(fluent::lint::block_help); }
} AttrKind::DocComment(CommentKind::Block, _) => fluent::lint::block_help,
} },
err.emit(); )
}); },
);
} }
} }
} }
@ -1143,9 +1164,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
match param.kind { match param.kind {
GenericParamKind::Lifetime { .. } => {} GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_no_mangle_generic) NO_MANGLE_GENERIC_ITEMS,
.span_suggestion_short( span,
fluent::lint::builtin_no_mangle_generic,
|lint| {
lint.span_suggestion_short(
no_mangle_attr.span, no_mangle_attr.span,
fluent::lint::suggestion, fluent::lint::suggestion,
"", "",
@ -1153,8 +1177,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
// fix may be to monomorphize source by hand // fix may be to monomorphize source by hand
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
) )
.emit(); },
}); );
break; break;
} }
} }
@ -1170,27 +1194,29 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
if cx.sess().contains_name(attrs, sym::no_mangle) { if cx.sess().contains_name(attrs, sym::no_mangle) {
// Const items do not refer to a particular location in memory, and therefore // Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to // don't have anything to attach a symbol to
cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| { cx.struct_span_lint(
let mut err = lint.build(fluent::lint::builtin_const_no_mangle); NO_MANGLE_CONST_ITEMS,
it.span,
// account for "pub const" (#45562) fluent::lint::builtin_const_no_mangle,
let start = cx |lint| {
.tcx // account for "pub const" (#45562)
.sess let start = cx
.source_map() .tcx
.span_to_snippet(it.span) .sess
.map(|snippet| snippet.find("const").unwrap_or(0)) .source_map()
.unwrap_or(0) as u32; .span_to_snippet(it.span)
// `const` is 5 chars .map(|snippet| snippet.find("const").unwrap_or(0))
let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); .unwrap_or(0) as u32;
err.span_suggestion( // `const` is 5 chars
const_span, let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
fluent::lint::suggestion, lint.span_suggestion(
"pub static", const_span,
Applicability::MachineApplicable, fluent::lint::suggestion,
); "pub static",
err.emit(); Applicability::MachineApplicable,
}); )
},
);
} }
} }
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
@ -1250,9 +1276,12 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
{ {
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_mutable_transmutes).emit(); MUTABLE_TRANSMUTES,
}); expr.span,
fluent::lint::builtin_mutable_transmutes,
|lint| lint,
);
} }
} }
@ -1300,9 +1329,12 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
if attr.has_name(sym::feature) { if attr.has_name(sym::feature) {
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
for item in items { for item in items {
cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_unstable_features).emit(); UNSTABLE_FEATURES,
}); item.span(),
fluent::lint::builtin_unstable_features,
|lint| lint,
);
} }
} }
} }
@ -1361,21 +1393,25 @@ impl UnreachablePub {
applicability = Applicability::MaybeIncorrect; applicability = Applicability::MaybeIncorrect;
} }
let def_span = cx.tcx.def_span(def_id); let def_span = cx.tcx.def_span(def_id);
cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| { cx.struct_span_lint(
let mut err = lint.build(fluent::lint::builtin_unreachable_pub); UNREACHABLE_PUB,
err.set_arg("what", what); def_span,
fluent::lint::builtin_unreachable_pub,
|lint| {
lint.set_arg("what", what);
err.span_suggestion( lint.span_suggestion(
vis_span, vis_span,
fluent::lint::suggestion, fluent::lint::suggestion,
"pub(crate)", "pub(crate)",
applicability, applicability,
); );
if exportable { if exportable {
err.help(fluent::lint::help); lint.help(fluent::lint::help);
} }
err.emit(); lint
}); },
);
} }
} }
} }
@ -1505,36 +1541,34 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
let mut suggested_changing_assoc_types = false; let mut suggested_changing_assoc_types = false;
if !where_spans.is_empty() { if !where_spans.is_empty() {
cx.lint(TYPE_ALIAS_BOUNDS, |lint| { cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_where_clause, |lint| {
let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause); lint.set_span(where_spans);
err.set_span(where_spans); lint.span_suggestion(
err.span_suggestion(
type_alias_generics.where_clause_span, type_alias_generics.where_clause_span,
fluent::lint::suggestion, fluent::lint::suggestion,
"", "",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
if !suggested_changing_assoc_types { if !suggested_changing_assoc_types {
TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
suggested_changing_assoc_types = true; suggested_changing_assoc_types = true;
} }
err.emit(); lint
}); });
} }
if !inline_spans.is_empty() { if !inline_spans.is_empty() {
cx.lint(TYPE_ALIAS_BOUNDS, |lint| { cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_generic_bounds, |lint| {
let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds); lint.set_span(inline_spans);
err.set_span(inline_spans); lint.multipart_suggestion(
err.multipart_suggestion(
fluent::lint::suggestion, fluent::lint::suggestion,
inline_sugg, inline_sugg,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
if !suggested_changing_assoc_types { if !suggested_changing_assoc_types {
TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
} }
err.emit(); lint
}); });
} }
} }
@ -1633,12 +1667,15 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
TypeWellFormedFromEnv(..) => continue, TypeWellFormedFromEnv(..) => continue,
}; };
if predicate.is_global() { if predicate.is_global() {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_trivial_bounds) TRIVIAL_BOUNDS,
.set_arg("predicate_kind_name", predicate_kind_name) span,
.set_arg("predicate", predicate) fluent::lint::builtin_trivial_bounds,
.emit(); |lint| {
}); lint.set_arg("predicate_kind_name", predicate_kind_name)
.set_arg("predicate", predicate)
},
);
} }
} }
} }
@ -1754,15 +1791,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
replace, replace,
}); });
} else { } else {
cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| { cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| {
lint.build(msg) lint.span_suggestion(
.span_suggestion( pat.span,
pat.span, suggestion,
suggestion, replace,
replace, Applicability::MachineApplicable,
Applicability::MachineApplicable, )
)
.emit();
}); });
} }
} else { } else {
@ -1774,15 +1809,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
replace: replace.to_string(), replace: replace.to_string(),
}); });
} else { } else {
cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| { cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| {
lint.build(msg) lint.span_suggestion_short(
.span_suggestion_short( join,
join, suggestion,
suggestion, replace,
replace, Applicability::MachineApplicable,
Applicability::MachineApplicable, )
)
.emit();
}); });
} }
}; };
@ -1863,9 +1896,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
let attrs = cx.tcx.hir().attrs(it.hir_id()); let attrs = cx.tcx.hir().attrs(it.hir_id());
if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_unnameable_test_items).emit(); UNNAMEABLE_TEST_ITEMS,
}); attr.span,
fluent::lint::builtin_unnameable_test_items,
|lint| lint,
);
} }
} }
@ -1981,18 +2017,19 @@ impl KeywordIdents {
return; return;
} }
cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_keyword_idents) KEYWORD_IDENTS,
.set_arg("kw", ident.clone()) ident.span,
.set_arg("next", next_edition) fluent::lint::builtin_keyword_idents,
.span_suggestion( |lint| {
lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
ident.span, ident.span,
fluent::lint::suggestion, fluent::lint::suggestion,
format!("r#{}", ident), format!("r#{}", ident),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit(); },
}); );
} }
} }
@ -2243,10 +2280,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
} }
if !lint_spans.is_empty() { if !lint_spans.is_empty() {
cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| { cx.struct_span_lint(
lint.build(fluent::lint::builtin_explicit_outlives) EXPLICIT_OUTLIVES_REQUIREMENTS,
.set_arg("count", bound_count) lint_spans.clone(),
.multipart_suggestion( fluent::lint::builtin_explicit_outlives,
|lint| {
lint.set_arg("count", bound_count).multipart_suggestion(
fluent::lint::suggestion, fluent::lint::suggestion,
lint_spans lint_spans
.into_iter() .into_iter()
@ -2254,8 +2293,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit(); },
}); );
} }
} }
} }
@ -2302,18 +2341,24 @@ impl EarlyLintPass for IncompleteFeatures {
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
.filter(|(&name, _)| features.incomplete(name)) .filter(|(&name, _)| features.incomplete(name))
.for_each(|(&name, &span)| { .for_each(|(&name, &span)| {
cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| { cx.struct_span_lint(
let mut builder = lint.build(fluent::lint::builtin_incomplete_features); INCOMPLETE_FEATURES,
builder.set_arg("name", name); span,
if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) { fluent::lint::builtin_incomplete_features,
builder.set_arg("n", n); |lint| {
builder.note(fluent::lint::note); lint.set_arg("name", name);
} if let Some(n) =
if HAS_MIN_FEATURES.contains(&name) { rustc_feature::find_feature_issue(name, GateIssue::Language)
builder.help(fluent::lint::help); {
} lint.set_arg("n", n);
builder.emit(); lint.note(fluent::lint::note);
}) }
if HAS_MIN_FEATURES.contains(&name) {
lint.help(fluent::lint::help);
}
lint
},
)
}); });
} }
} }
@ -2628,28 +2673,37 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
{ {
// FIXME(davidtwco): make translatable // FIXME(davidtwco): make translatable
cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| { cx.struct_span_lint(
let mut err = lint.build(&format!( INVALID_VALUE,
"the type `{}` does not permit {}", expr.span,
conjured_ty, DelayDm(|| {
match init { format!(
InitKind::Zeroed => "zero-initialization", "the type `{}` does not permit {}",
InitKind::Uninit => "being left uninitialized", conjured_ty,
}, match init {
)); InitKind::Zeroed => "zero-initialization",
err.span_label(expr.span, "this code causes undefined behavior when executed"); InitKind::Uninit => "being left uninitialized",
err.span_label( },
expr.span, )
"help: use `MaybeUninit<T>` instead, \ }),
|lint| {
lint.span_label(
expr.span,
"this code causes undefined behavior when executed",
);
lint.span_label(
expr.span,
"help: use `MaybeUninit<T>` instead, \
and only call `assume_init` after initialization is done", and only call `assume_init` after initialization is done",
); );
if let Some(span) = span { if let Some(span) = span {
err.span_note(span, &msg); lint.span_note(span, &msg);
} else { } else {
err.note(&msg); lint.note(&msg);
} }
err.emit(); lint
}); },
);
} }
} }
} }
@ -2995,31 +3049,35 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
SymbolName::Link(_, annot_span) => fi.span.to(annot_span), SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
}; };
// Finally, emit the diagnostic. // Finally, emit the diagnostic.
let msg = if orig.get_name() == this_fi.ident.name {
fluent::lint::builtin_clashing_extern_same_name
} else {
fluent::lint::builtin_clashing_extern_diff_name
};
tcx.struct_span_lint_hir( tcx.struct_span_lint_hir(
CLASHING_EXTERN_DECLARATIONS, CLASHING_EXTERN_DECLARATIONS,
this_fi.hir_id(), this_fi.hir_id(),
get_relevant_span(this_fi), get_relevant_span(this_fi),
msg,
|lint| { |lint| {
let mut expected_str = DiagnosticStyledString::new(); let mut expected_str = DiagnosticStyledString::new();
expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false); expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
let mut found_str = DiagnosticStyledString::new(); let mut found_str = DiagnosticStyledString::new();
found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
lint.build(if orig.get_name() == this_fi.ident.name { lint.set_arg("this_fi", this_fi.ident.name)
fluent::lint::builtin_clashing_extern_same_name .set_arg("orig", orig.get_name())
} else { .span_label(
fluent::lint::builtin_clashing_extern_diff_name get_relevant_span(orig_fi),
}) fluent::lint::previous_decl_label,
.set_arg("this_fi", this_fi.ident.name) )
.set_arg("orig", orig.get_name()) .span_label(
.span_label( get_relevant_span(this_fi),
get_relevant_span(orig_fi), fluent::lint::mismatch_label,
fluent::lint::previous_decl_label, )
) // FIXME(davidtwco): translatable expected/found
.span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label) .note_expected_found(&"", expected_str, &"", found_str)
// FIXME(davidtwco): translatable expected/found
.note_expected_found(&"", expected_str, &"", found_str)
.emit();
}, },
); );
} }
@ -3100,11 +3158,12 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
if is_null_ptr(cx, expr_deref) { if is_null_ptr(cx, expr_deref) {
cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| { cx.struct_span_lint(
let mut err = lint.build(fluent::lint::builtin_deref_nullptr); DEREF_NULLPTR,
err.span_label(expr.span, fluent::lint::label); expr.span,
err.emit(); fluent::lint::builtin_deref_nullptr,
}); |lint| lint.span_label(expr.span, fluent::lint::label),
);
} }
} }
} }
@ -3214,9 +3273,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
cx.lookup_with_diagnostics( cx.lookup_with_diagnostics(
NAMED_ASM_LABELS, NAMED_ASM_LABELS,
Some(target_spans), Some(target_spans),
|diag| { fluent::lint::builtin_asm_labels,
diag.build(fluent::lint::builtin_asm_labels).emit(); |lint| lint,
},
BuiltinLintDiagnostics::NamedAsmLabel( BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm" "only local labels of the form `<number>:` should be used in inline asm"
.to_string(), .to_string(),
@ -3288,16 +3346,14 @@ impl EarlyLintPass for SpecialModuleName {
} }
match item.ident.name.as_str() { match item.ident.name.as_str() {
"lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| {
lint.build("found module declaration for lib.rs") lint
.note("lib.rs is the root of this crate's library target") .note("lib.rs is the root of this crate's library target")
.help("to refer to it from other targets, use the library's name as the path") .help("to refer to it from other targets, use the library's name as the path")
.emit()
}), }),
"main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| {
lint.build("found module declaration for main.rs") lint
.note("a binary crate cannot be used as library") .note("a binary crate cannot be used as library")
.emit()
}), }),
_ => continue _ => continue
} }
@ -3317,24 +3373,27 @@ impl EarlyLintPass for UnexpectedCfgs {
for &(name, value) in cfg { for &(name, value) in cfg {
if let Some(names_valid) = &check_cfg.names_valid { if let Some(names_valid) = &check_cfg.names_valid {
if !names_valid.contains(&name) { if !names_valid.contains(&name) {
cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| { cx.lookup(
diag.build(fluent::lint::builtin_unexpected_cli_config_name) UNEXPECTED_CFGS,
.help(fluent::lint::help) None::<MultiSpan>,
.set_arg("name", name) fluent::lint::builtin_unexpected_cli_config_name,
.emit(); |diag| diag.help(fluent::lint::help).set_arg("name", name),
}); );
} }
} }
if let Some(value) = value { if let Some(value) = value {
if let Some(values) = &check_cfg.values_valid.get(&name) { if let Some(values) = &check_cfg.values_valid.get(&name) {
if !values.contains(&value) { if !values.contains(&value) {
cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| { cx.lookup(
diag.build(fluent::lint::builtin_unexpected_cli_config_value) UNEXPECTED_CFGS,
.help(fluent::lint::help) None::<MultiSpan>,
.set_arg("name", name) fluent::lint::builtin_unexpected_cli_config_value,
.set_arg("value", value) |diag| {
.emit(); diag.help(fluent::lint::help)
}); .set_arg("name", name)
.set_arg("value", value)
},
);
} }
} }
} }

View File

@ -25,10 +25,8 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync; use rustc_data_structures::sync;
use rustc_errors::add_elided_lifetime_in_path_suggestion; use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder, DiagnosticMessage};
use rustc_errors::{ use rustc_errors::{Applicability, DecorateLint, MultiSpan, SuggestionStyle};
Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle,
};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::def_id::{CrateNum, DefId};
@ -580,13 +578,14 @@ pub trait LintContext: Sized {
&self, &self,
lint: &'static Lint, lint: &'static Lint,
span: Option<impl Into<MultiSpan>>, span: Option<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, ()>,
diagnostic: BuiltinLintDiagnostics, diagnostic: BuiltinLintDiagnostics,
) { ) {
self.lookup(lint, span, |lint| { // We first generate a blank diagnostic.
// We first generate a blank diagnostic. self.lookup(lint, span, msg,|db| {
let mut db = lint.build("");
// Now, set up surrounding context. // Now, set up surrounding context.
let sess = self.sess(); let sess = self.sess();
match diagnostic { match diagnostic {
@ -660,7 +659,7 @@ pub trait LintContext: Sized {
) => { ) => {
add_elided_lifetime_in_path_suggestion( add_elided_lifetime_in_path_suggestion(
sess.source_map(), sess.source_map(),
&mut db, db,
n, n,
path_span, path_span,
incl_angl_brckt, incl_angl_brckt,
@ -696,7 +695,7 @@ pub trait LintContext: Sized {
} }
} }
BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => {
stability::deprecation_suggestion(&mut db, "macro", suggestion, span) stability::deprecation_suggestion(db, "macro", suggestion, span)
} }
BuiltinLintDiagnostics::UnusedDocComment(span) => { BuiltinLintDiagnostics::UnusedDocComment(span) => {
db.span_label(span, "rustdoc does not generate documentation for macro invocations"); db.span_label(span, "rustdoc does not generate documentation for macro invocations");
@ -867,7 +866,7 @@ pub trait LintContext: Sized {
} }
} }
// Rewrap `db`, and pass control to the user. // Rewrap `db`, and pass control to the user.
decorate(LintDiagnosticBuilder::new(db)); decorate(db)
}); });
} }
@ -877,7 +876,10 @@ pub trait LintContext: Sized {
&self, &self,
lint: &'static Lint, lint: &'static Lint,
span: Option<S>, span: Option<S>,
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, ()>,
); );
/// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
@ -888,31 +890,39 @@ pub trait LintContext: Sized {
span: S, span: S,
decorator: impl for<'a> DecorateLint<'a, ()>, decorator: impl for<'a> DecorateLint<'a, ()>,
) { ) {
self.lookup(lint, Some(span), |diag| decorator.decorate_lint(diag)); self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag));
} }
fn struct_span_lint<S: Into<MultiSpan>>( fn struct_span_lint<S: Into<MultiSpan>>(
&self, &self,
lint: &'static Lint, lint: &'static Lint,
span: S, span: S,
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, ()>,
) { ) {
self.lookup(lint, Some(span), decorate); self.lookup(lint, Some(span), msg, decorate);
} }
/// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
/// generated by `#[derive(LintDiagnostic)]`). /// generated by `#[derive(LintDiagnostic)]`).
fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) { fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) {
self.lookup(lint, None as Option<Span>, |diag| decorator.decorate_lint(diag)); self.lookup(lint, None as Option<Span>, decorator.msg(), |diag| {
decorator.decorate_lint(diag)
});
} }
/// Emit a lint at the appropriate level, with no associated span. /// Emit a lint at the appropriate level, with no associated span.
fn lint( fn lint(
&self, &self,
lint: &'static Lint, lint: &'static Lint,
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, ()>,
) { ) {
self.lookup(lint, None as Option<Span>, decorate); self.lookup(lint, None as Option<Span>, msg, decorate);
} }
/// This returns the lint level for the given lint at the current location. /// This returns the lint level for the given lint at the current location.
@ -975,13 +985,16 @@ impl<'tcx> LintContext for LateContext<'tcx> {
&self, &self,
lint: &'static Lint, lint: &'static Lint,
span: Option<S>, span: Option<S>,
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 hir_id = self.last_node_with_lint_attrs; let hir_id = self.last_node_with_lint_attrs;
match span { match span {
Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, decorate), Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg, decorate),
None => self.tcx.struct_lint_node(lint, hir_id, decorate), None => self.tcx.struct_lint_node(lint, hir_id, msg, decorate),
} }
} }
@ -1006,9 +1019,12 @@ impl LintContext for EarlyContext<'_> {
&self, &self,
lint: &'static Lint, lint: &'static Lint,
span: Option<S>, span: Option<S>,
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, ()>,
) { ) {
self.builder.struct_lint(lint, span.map(|s| s.into()), decorate) self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate)
} }
fn get_lint_level(&self, lint: &'static Lint) -> Level { fn get_lint_level(&self, lint: &'static Lint) -> Level {

View File

@ -43,9 +43,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
self.context.lookup_with_diagnostics( self.context.lookup_with_diagnostics(
lint_id.lint, lint_id.lint,
Some(span), Some(span),
|lint| { msg,
lint.build(msg).emit(); |lint| lint,
},
diagnostic, diagnostic,
); );
} }

View File

@ -50,26 +50,24 @@ fn enforce_mem_discriminant(
) { ) {
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
if is_non_enum(ty_param) { if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| { cx.struct_span_lint(
builder ENUM_INTRINSICS_NON_ENUMS,
.build(fluent::lint::enum_intrinsics_mem_discriminant) expr_span,
.set_arg("ty_param", ty_param) fluent::lint::enum_intrinsics_mem_discriminant,
.span_note(args_span, fluent::lint::note) |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::lint::note),
.emit(); );
});
} }
} }
fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) { fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
if is_non_enum(ty_param) { if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| { cx.struct_span_lint(
builder ENUM_INTRINSICS_NON_ENUMS,
.build(fluent::lint::enum_intrinsics_mem_variant) span,
.set_arg("ty_param", ty_param) fluent::lint::enum_intrinsics_mem_variant,
.note(fluent::lint::note) |lint| lint.set_arg("ty_param", ty_param).note(fluent::lint::note),
.emit(); );
});
} }
} }

View File

@ -43,17 +43,17 @@ fn emit_unfulfilled_expectation_lint(
builtin::UNFULFILLED_LINT_EXPECTATIONS, builtin::UNFULFILLED_LINT_EXPECTATIONS,
hir_id, hir_id,
expectation.emission_span, expectation.emission_span,
|diag| { fluent::lint::expectation,
let mut diag = diag.build(fluent::lint::expectation); |lint| {
if let Some(rationale) = expectation.reason { if let Some(rationale) = expectation.reason {
diag.note(rationale.as_str()); lint.note(rationale.as_str());
} }
if expectation.is_unfulfilled_lint_expectations { if expectation.is_unfulfilled_lint_expectations {
diag.note(fluent::lint::note); lint.note(fluent::lint::note);
} }
diag.emit(); lint
}, },
); );
} }

View File

@ -60,52 +60,56 @@ impl HiddenUnicodeCodepoints {
}) })
.collect(); .collect();
cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| { cx.struct_span_lint(
let mut err = lint.build(fluent::lint::hidden_unicode_codepoints); TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
err.set_arg("label", label); span,
err.set_arg("count", spans.len()); fluent::lint::hidden_unicode_codepoints,
err.span_label(span, fluent::lint::label); |lint| {
err.note(fluent::lint::note); lint.set_arg("label", label);
if point_at_inner_spans { lint.set_arg("count", spans.len());
for (c, span) in &spans { lint.span_label(span, fluent::lint::label);
err.span_label(*span, format!("{:?}", c)); lint.note(fluent::lint::note);
if point_at_inner_spans {
for (c, span) in &spans {
lint.span_label(*span, format!("{:?}", c));
}
} }
} if point_at_inner_spans && !spans.is_empty() {
if point_at_inner_spans && !spans.is_empty() { lint.multipart_suggestion_with_style(
err.multipart_suggestion_with_style( fluent::lint::suggestion_remove,
fluent::lint::suggestion_remove, spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), Applicability::MachineApplicable,
Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways,
SuggestionStyle::HideCodeAlways, );
); lint.multipart_suggestion(
err.multipart_suggestion( fluent::lint::suggestion_escape,
fluent::lint::suggestion_escape, spans
spans .into_iter()
.into_iter() .map(|(c, span)| {
.map(|(c, span)| { let c = format!("{:?}", c);
let c = format!("{:?}", c); (span, c[1..c.len() - 1].to_string())
(span, c[1..c.len() - 1].to_string()) })
}) .collect(),
.collect(), Applicability::MachineApplicable,
Applicability::MachineApplicable, );
); } else {
} else { // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We // should do the same here to provide the same good suggestions as we do for
// should do the same here to provide the same good suggestions as we do for // literals above.
// literals above. lint.set_arg(
err.set_arg( "escaped",
"escaped", spans
spans .into_iter()
.into_iter() .map(|(c, _)| format!("{:?}", c))
.map(|(c, _)| format!("{:?}", c)) .collect::<Vec<String>>()
.collect::<Vec<String>>() .join(", "),
.join(", "), );
); lint.note(fluent::lint::suggestion_remove);
err.note(fluent::lint::suggestion_remove); lint.note(fluent::lint::no_suggestion_note_escape);
err.note(fluent::lint::no_suggestion_note_escape); }
} lint
err.emit(); },
}); );
} }
} }
impl EarlyLintPass for HiddenUnicodeCodepoints { impl EarlyLintPass for HiddenUnicodeCodepoints {

View File

@ -34,13 +34,16 @@ impl LateLintPass<'_> for DefaultHashTypes {
Some(sym::HashSet) => "FxHashSet", Some(sym::HashSet) => "FxHashSet",
_ => return, _ => return,
}; };
cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::default_hash_types) DEFAULT_HASH_TYPES,
.set_arg("preferred", replace) path.span,
.set_arg("used", cx.tcx.item_name(def_id)) fluent::lint::default_hash_types,
.note(fluent::lint::note) |lint| {
.emit(); lint.set_arg("preferred", replace)
}); .set_arg("used", cx.tcx.item_name(def_id))
.note(fluent::lint::note)
},
);
} }
} }
@ -80,12 +83,12 @@ impl LateLintPass<'_> for QueryStability {
if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) { if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
let def_id = instance.def_id(); let def_id = instance.def_id();
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::query_instability) POTENTIAL_QUERY_INSTABILITY,
.set_arg("query", cx.tcx.item_name(def_id)) span,
.note(fluent::lint::note) fluent::lint::query_instability,
.emit(); |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::lint::note),
}) )
} }
} }
} }
@ -123,15 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
let span = path.span.with_hi( let span = path.span.with_hi(
segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
); );
cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint::tykind_kind, |lint| {
lint.build(fluent::lint::tykind_kind) lint
.span_suggestion( .span_suggestion(
span, span,
fluent::lint::suggestion, fluent::lint::suggestion,
"ty", "ty",
Applicability::MaybeIncorrect, // ty maybe needs an import Applicability::MaybeIncorrect, // ty maybe needs an import
) )
.emit();
}); });
} }
} }
@ -140,76 +142,77 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
match &ty.kind { match &ty.kind {
TyKind::Path(QPath::Resolved(_, path)) => { TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) { if lint_ty_kind_usage(cx, &path.res) {
cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { let hir = cx.tcx.hir();
let hir = cx.tcx.hir(); let span = match hir.find(hir.get_parent_node(ty.hir_id)) {
match hir.find(hir.get_parent_node(ty.hir_id)) { Some(Node::Pat(Pat {
Some(Node::Pat(Pat { kind:
kind: PatKind::Path(qpath)
PatKind::Path(qpath) | PatKind::TupleStruct(qpath, ..)
| PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..),
| PatKind::Struct(qpath, ..), ..
.. })) => {
})) => { if let QPath::TypeRelative(qpath_ty, ..) = qpath
if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id
&& qpath_ty.hir_id == ty.hir_id {
{ Some(path.span)
lint.build(fluent::lint::tykind_kind) } else {
.span_suggestion( None
path.span,
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
.emit();
return;
}
} }
Some(Node::Expr(Expr {
kind: ExprKind::Path(qpath),
..
})) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
lint.build(fluent::lint::tykind_kind)
.span_suggestion(
path.span,
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
.emit();
return;
}
}
// Can't unify these two branches because qpath below is `&&` and above is `&`
// and `A | B` paths don't play well together with adjustments, apparently.
Some(Node::Expr(Expr {
kind: ExprKind::Struct(qpath, ..),
..
})) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
lint.build(fluent::lint::tykind_kind)
.span_suggestion(
path.span,
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
.emit();
return;
}
}
_ => {}
} }
lint.build(fluent::lint::tykind).help(fluent::lint::help).emit(); Some(Node::Expr(Expr {
}) kind: ExprKind::Path(qpath),
..
})) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
Some(path.span)
} else {
None
}
}
// Can't unify these two branches because qpath below is `&&` and above is `&`
// and `A | B` paths don't play well together with adjustments, apparently.
Some(Node::Expr(Expr {
kind: ExprKind::Struct(qpath, ..),
..
})) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
Some(path.span)
} else {
None
}
}
_ => None
};
match span {
Some(span) => {
cx.struct_span_lint(
USAGE_OF_TY_TYKIND,
path.span,
fluent::lint::tykind_kind,
|lint| lint.span_suggestion(
span,
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
)
},
None => cx.struct_span_lint(
USAGE_OF_TY_TYKIND,
path.span,
fluent::lint::tykind,
|lint| lint.help(fluent::lint::help)
)
}
} else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
if path.segments.len() > 1 { if path.segments.len() > 1 {
cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| { cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint::ty_qualified, |lint| {
lint.build(fluent::lint::ty_qualified) lint
.set_arg("ty", t.clone()) .set_arg("ty", t.clone())
.span_suggestion( .span_suggestion(
path.span, path.span,
@ -218,7 +221,6 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
// The import probably needs to be changed // The import probably needs to be changed
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
) )
.emit();
}) })
} }
} }
@ -308,11 +310,8 @@ impl EarlyLintPass for LintPassImpl {
cx.struct_span_lint( cx.struct_span_lint(
LINT_PASS_IMPL_WITHOUT_MACRO, LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span, lint_pass.path.span,
|lint| { fluent::lint::lintpass_by_hand,
lint.build(fluent::lint::lintpass_by_hand) |lint| lint.help(fluent::lint::help),
.help(fluent::lint::help)
.emit();
},
) )
} }
} }
@ -349,12 +348,12 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
if is_doc_keyword(v) { if is_doc_keyword(v) {
return; return;
} }
cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::non_existant_doc_keyword) EXISTING_DOC_KEYWORD,
.set_arg("keyword", v) attr.span,
.help(fluent::lint::help) fluent::lint::non_existant_doc_keyword,
.emit(); |lint| lint.set_arg("keyword", v).help(fluent::lint::help),
}); );
} }
} }
} }
@ -412,9 +411,12 @@ impl LateLintPass<'_> for Diagnostics {
} }
debug!(?found_impl); debug!(?found_impl);
if !found_parent_with_attr && !found_impl { if !found_parent_with_attr && !found_impl {
cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::diag_out_of_impl).emit(); DIAGNOSTIC_OUTSIDE_OF_IMPL,
}) span,
fluent::lint::diag_out_of_impl,
|lint| lint,
)
} }
let mut found_diagnostic_message = false; let mut found_diagnostic_message = false;
@ -430,9 +432,12 @@ impl LateLintPass<'_> for Diagnostics {
} }
debug!(?found_diagnostic_message); debug!(?found_diagnostic_message);
if !found_parent_with_attr && !found_diagnostic_message { if !found_parent_with_attr && !found_diagnostic_message {
cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::untranslatable_diag).emit(); UNTRANSLATABLE_DIAGNOSTIC,
}) span,
fluent::lint::untranslatable_diag,
|lint| lint,
)
} }
} }
} }
@ -464,8 +469,8 @@ impl LateLintPass<'_> for BadOptAccess {
let Some(literal) = item.literal() && let Some(literal) = item.literal() &&
let ast::LitKind::Str(val, _) = literal.kind let ast::LitKind::Str(val, _) = literal.kind
{ {
cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, |lint| { cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint|
lint.build(val.as_str()).emit(); } lint
); );
} }
} }

View File

@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan}; use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::Symbol; use rustc_span::Symbol;
@ -128,48 +128,41 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
init.span, init.span,
"this binding will immediately drop the value assigned to it".to_string(), "this binding will immediately drop the value assigned to it".to_string(),
); );
cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| { cx.struct_span_lint(
build_and_emit_lint( LET_UNDERSCORE_LOCK,
lint, span,
local, "non-binding let on a synchronization lock",
init.span, |lint| build_lint(lint, local, init.span),
"non-binding let on a synchronization lock", )
)
})
} else { } else {
cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { cx.struct_span_lint(
build_and_emit_lint( LET_UNDERSCORE_DROP,
lint, local.span,
local, "non-binding let on a type that implements `Drop`",
init.span, |lint| build_lint(lint, local, init.span),
"non-binding let on a type that implements `Drop`", )
);
})
} }
} }
} }
} }
fn build_and_emit_lint( fn build_lint<'a, 'b>(
lint: LintDiagnosticBuilder<'_, ()>, lint: &'a mut DiagnosticBuilder<'b, ()>,
local: &hir::Local<'_>, local: &hir::Local<'_>,
init_span: rustc_span::Span, init_span: rustc_span::Span,
msg: &str, ) -> &'a mut DiagnosticBuilder<'b, ()> {
) { lint.span_suggestion_verbose(
lint.build(msg) local.pat.span,
.span_suggestion_verbose( "consider binding to an unused variable to avoid immediately dropping the value",
local.pat.span, "_unused",
"consider binding to an unused variable to avoid immediately dropping the value", Applicability::MachineApplicable,
"_unused", )
Applicability::MachineApplicable, .multipart_suggestion(
) "consider immediately dropping the value",
.multipart_suggestion( vec![
"consider immediately dropping the value", (local.span.until(init_span), "drop(".to_string()),
vec![ (init_span.shrink_to_hi(), ")".to_string()),
(local.span.until(init_span), "drop(".to_string()), ],
(init_span.shrink_to_hi(), ")".to_string()), Applicability::MachineApplicable,
], )
Applicability::MachineApplicable,
)
.emit();
} }

View File

@ -3,7 +3,7 @@ use crate::late::unerased_lint_store;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{intravisit, HirId}; use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
@ -214,14 +214,14 @@ impl<'s> LintLevelsBuilder<'s> {
self.struct_lint( self.struct_lint(
FORBIDDEN_LINT_GROUPS, FORBIDDEN_LINT_GROUPS,
Some(src.span().into()), Some(src.span().into()),
|diag_builder| { format!(
let mut diag_builder = diag_builder.build(&format!( "{}({}) incompatible with previous forbid",
"{}({}) incompatible with previous forbid", level.as_str(),
level.as_str(), src.name(),
src.name(), ),
)); |lint| {
decorate_diag(&mut diag_builder); decorate_diag(lint);
diag_builder.emit(); lint
}, },
); );
} }
@ -466,20 +466,18 @@ impl<'s> LintLevelsBuilder<'s> {
lvl, lvl,
src, src,
Some(sp.into()), Some(sp.into()),
format!(
"lint name `{}` is deprecated \
and may not have an effect in the future.",
name
),
|lint| { |lint| {
let msg = format!( lint.span_suggestion(
"lint name `{}` is deprecated \ sp,
and may not have an effect in the future.", "change it to",
name new_lint_name,
); Applicability::MachineApplicable,
lint.build(&msg) )
.span_suggestion(
sp,
"change it to",
new_lint_name,
Applicability::MachineApplicable,
)
.emit();
}, },
); );
@ -533,17 +531,17 @@ impl<'s> LintLevelsBuilder<'s> {
renamed_lint_level, renamed_lint_level,
src, src,
Some(sp.into()), Some(sp.into()),
msg,
|lint| { |lint| {
let mut err = lint.build(msg);
if let Some(new_name) = &renamed { if let Some(new_name) = &renamed {
err.span_suggestion( lint.span_suggestion(
sp, sp,
"use the new name", "use the new name",
new_name, new_name,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
err.emit(); lint
}, },
); );
} }
@ -555,23 +553,30 @@ impl<'s> LintLevelsBuilder<'s> {
Some(self.current_specs()), Some(self.current_specs()),
self.sess, self.sess,
); );
struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| { let name = if let Some(tool_ident) = tool_ident {
let name = if let Some(tool_ident) = tool_ident { format!("{}::{}", tool_ident.name, name)
format!("{}::{}", tool_ident.name, name) } else {
} else { name.to_string()
name.to_string() };
}; struct_lint_level(
let mut db = lint.build(format!("unknown lint: `{}`", name)); self.sess,
if let Some(suggestion) = suggestion { lint,
db.span_suggestion( level,
sp, src,
"did you mean", Some(sp.into()),
suggestion, format!("unknown lint: `{}`", name),
Applicability::MachineApplicable, |lint| {
); if let Some(suggestion) = suggestion {
} lint.span_suggestion(
db.emit(); sp,
}); "did you mean",
suggestion,
Applicability::MachineApplicable,
);
}
lint
},
);
} }
} }
// If this lint was renamed, apply the new lint instead of ignoring the attribute. // If this lint was renamed, apply the new lint instead of ignoring the attribute.
@ -621,14 +626,12 @@ impl<'s> LintLevelsBuilder<'s> {
lint_level, lint_level,
lint_src, lint_src,
Some(lint_attr_span.into()), Some(lint_attr_span.into()),
|lint| { format!(
let mut db = lint.build(&format!( "{}({}) is ignored unless specified at crate level",
"{}({}) is ignored unless specified at crate level", level.as_str(),
level.as_str(), lint_attr_name
lint_attr_name ),
)); |lint| lint,
db.emit();
},
); );
// don't set a separate error for every lint in the group // don't set a separate error for every lint in the group
break; break;
@ -665,13 +668,21 @@ impl<'s> LintLevelsBuilder<'s> {
if !self.sess.features_untracked().enabled(feature) { if !self.sess.features_untracked().enabled(feature) {
let lint = builtin::UNKNOWN_LINTS; let lint = builtin::UNKNOWN_LINTS;
let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS); let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| { struct_lint_level(
let mut db = self.sess,
lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower())); lint,
db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),)); level,
add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature); src,
db.emit(); Some(span.into()),
}); format!("unknown lint: `{}`", lint_id.lint.name_lower()),
|lint| {
lint.note(
&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),),
);
add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
lint
},
);
return false; return false;
} }
} }
@ -694,10 +705,13 @@ impl<'s> LintLevelsBuilder<'s> {
&self, &self,
lint: &'static Lint, lint: &'static Lint,
span: Option<MultiSpan>, span: Option<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(lint); let (level, src) = self.lint_level(lint);
struct_lint_level(self.sess, lint, level, src, span, decorate) struct_lint_level(self.sess, lint, level, src, span, msg, decorate)
} }
/// Registers the ID provided with the current set of lints stored in /// Registers the ID provided with the current set of lints stored in

View File

@ -90,14 +90,17 @@ fn lint_cstring_as_ptr(
if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
if let ty::Adt(adt, _) = substs.type_at(0).kind() { if let ty::Adt(adt, _) = substs.type_at(0).kind() {
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| { cx.struct_span_lint(
diag.build(fluent::lint::cstring_ptr) TEMPORARY_CSTRING_AS_PTR,
.span_label(as_ptr_span, fluent::lint::as_ptr_label) as_ptr_span,
.span_label(unwrap.span, fluent::lint::unwrap_label) fluent::lint::cstring_ptr,
.note(fluent::lint::note) |diag| {
.help(fluent::lint::help) diag.span_label(as_ptr_span, fluent::lint::as_ptr_label)
.emit(); .span_label(unwrap.span, fluent::lint::unwrap_label)
}); .note(fluent::lint::note)
.help(fluent::lint::help)
},
);
} }
} }
} }

View File

@ -180,15 +180,21 @@ impl EarlyLintPass for NonAsciiIdents {
continue; continue;
} }
has_non_ascii_idents = true; has_non_ascii_idents = true;
cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::identifier_non_ascii_char).emit(); NON_ASCII_IDENTS,
}); sp,
fluent::lint::identifier_non_ascii_char,
|lint| lint,
);
if check_uncommon_codepoints if check_uncommon_codepoints
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
{ {
cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::identifier_uncommon_codepoints).emit(); UNCOMMON_CODEPOINTS,
}) sp,
fluent::lint::identifier_uncommon_codepoints,
|lint| lint,
)
} }
} }
@ -216,13 +222,16 @@ impl EarlyLintPass for NonAsciiIdents {
.entry(skeleton_sym) .entry(skeleton_sym)
.and_modify(|(existing_symbol, existing_span, existing_is_ascii)| { .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
if !*existing_is_ascii || !is_ascii { if !*existing_is_ascii || !is_ascii {
cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::confusable_identifier_pair) CONFUSABLE_IDENTS,
.set_arg("existing_sym", *existing_symbol) sp,
.set_arg("sym", symbol) fluent::lint::confusable_identifier_pair,
.span_label(*existing_span, fluent::lint::label) |lint| {
.emit(); lint.set_arg("existing_sym", *existing_symbol)
}); .set_arg("sym", symbol)
.span_label(*existing_span, fluent::lint::label)
},
);
} }
if *existing_is_ascii && !is_ascii { if *existing_is_ascii && !is_ascii {
*existing_symbol = symbol; *existing_symbol = symbol;
@ -322,22 +331,25 @@ impl EarlyLintPass for NonAsciiIdents {
} }
for ((sp, ch_list), script_set) in lint_reports { for ((sp, ch_list), script_set) in lint_reports {
cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { cx.struct_span_lint(
let mut includes = String::new(); MIXED_SCRIPT_CONFUSABLES,
for (idx, ch) in ch_list.into_iter().enumerate() { sp,
if idx != 0 { fluent::lint::mixed_script_confusables,
includes += ", "; |lint| {
let mut includes = String::new();
for (idx, ch) in ch_list.into_iter().enumerate() {
if idx != 0 {
includes += ", ";
}
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
includes += &char_info;
} }
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); lint.set_arg("set", script_set.to_string())
includes += &char_info; .set_arg("includes", includes)
} .note(fluent::lint::includes_note)
lint.build(fluent::lint::mixed_script_confusables) .note(fluent::lint::note)
.set_arg("set", script_set.to_string()) },
.set_arg("includes", includes) );
.note(fluent::lint::includes_note)
.note(fluent::lint::note)
.emit();
});
} }
} }
} }

View File

@ -119,21 +119,19 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
arg_span = expn.call_site; arg_span = expn.call_site;
} }
cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| { cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint::non_fmt_panic, |lint| {
let mut l = lint.build(fluent::lint::non_fmt_panic); lint.set_arg("name", symbol);
l.set_arg("name", symbol); lint.note(fluent::lint::note);
l.note(fluent::lint::note); lint.note(fluent::lint::more_info_note);
l.note(fluent::lint::more_info_note);
if !is_arg_inside_call(arg_span, span) { if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from. // No clue where this argument is coming from.
l.emit(); return lint;
return;
} }
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`. // A case of `panic!(format!(..))`.
l.note(fluent::lint::supports_fmt_note); lint.note(fluent::lint::supports_fmt_note);
if let Some((open, close, _)) = find_delimiters(cx, arg_span) { if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
l.multipart_suggestion( lint.multipart_suggestion(
fluent::lint::supports_fmt_suggestion, fluent::lint::supports_fmt_suggestion,
vec![ vec![
(arg_span.until(open.shrink_to_hi()), "".into()), (arg_span.until(open.shrink_to_hi()), "".into()),
@ -180,15 +178,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
}; };
if suggest_display { if suggest_display {
l.span_suggestion_verbose( lint.span_suggestion_verbose(
arg_span.shrink_to_lo(), arg_span.shrink_to_lo(),
fluent::lint::display_suggestion, fluent::lint::display_suggestion,
"\"{}\", ", "\"{}\", ",
fmt_applicability, fmt_applicability,
); );
} else if suggest_debug { } else if suggest_debug {
l.set_arg("ty", ty); lint.set_arg("ty", ty);
l.span_suggestion_verbose( lint.span_suggestion_verbose(
arg_span.shrink_to_lo(), arg_span.shrink_to_lo(),
fluent::lint::debug_suggestion, fluent::lint::debug_suggestion,
"\"{:?}\", ", "\"{:?}\", ",
@ -198,8 +196,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_panic_any { if suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) { if let Some((open, close, del)) = find_delimiters(cx, span) {
l.set_arg("already_suggested", suggest_display || suggest_debug); lint.set_arg("already_suggested", suggest_display || suggest_debug);
l.multipart_suggestion( lint.multipart_suggestion(
fluent::lint::panic_suggestion, fluent::lint::panic_suggestion,
if del == '(' { if del == '(' {
vec![(span.until(open), "std::panic::panic_any".into())] vec![(span.until(open), "std::panic::panic_any".into())]
@ -214,7 +212,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
} }
} }
} }
l.emit(); lint
}); });
} }
@ -258,26 +256,30 @@ fn check_panic_str<'tcx>(
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
.collect(), .collect(),
}; };
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| { cx.struct_span_lint(
let mut l = lint.build(fluent::lint::non_fmt_panic_unused); NON_FMT_PANICS,
l.set_arg("count", n_arguments); arg_spans,
l.note(fluent::lint::note); fluent::lint::non_fmt_panic_unused,
if is_arg_inside_call(arg.span, span) { |lint| {
l.span_suggestion( lint.set_arg("count", n_arguments);
arg.span.shrink_to_hi(), lint.note(fluent::lint::note);
fluent::lint::add_args_suggestion, if is_arg_inside_call(arg.span, span) {
", ...", lint.span_suggestion(
Applicability::HasPlaceholders, arg.span.shrink_to_hi(),
); fluent::lint::add_args_suggestion,
l.span_suggestion( ", ...",
arg.span.shrink_to_lo(), Applicability::HasPlaceholders,
fluent::lint::add_fmt_suggestion, );
"\"{}\", ", lint.span_suggestion(
Applicability::MachineApplicable, arg.span.shrink_to_lo(),
); fluent::lint::add_fmt_suggestion,
} "\"{}\", ",
l.emit(); Applicability::MachineApplicable,
}); );
}
lint
},
);
} else { } else {
let brace_spans: Option<Vec<_>> = let brace_spans: Option<Vec<_>> =
snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| { snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
@ -287,20 +289,24 @@ fn check_panic_str<'tcx>(
.collect() .collect()
}); });
let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2); let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| { cx.struct_span_lint(
let mut l = lint.build(fluent::lint::non_fmt_panic_braces); NON_FMT_PANICS,
l.set_arg("count", count); brace_spans.unwrap_or_else(|| vec![span]),
l.note(fluent::lint::note); fluent::lint::non_fmt_panic_braces,
if is_arg_inside_call(arg.span, span) { |lint| {
l.span_suggestion( lint.set_arg("count", count);
arg.span.shrink_to_lo(), lint.note(fluent::lint::note);
fluent::lint::suggestion, if is_arg_inside_call(arg.span, span) {
"\"{}\", ", lint.span_suggestion(
Applicability::MachineApplicable, arg.span.shrink_to_lo(),
); fluent::lint::suggestion,
} "\"{}\", ",
l.emit(); Applicability::MachineApplicable,
}); );
}
lint
},
);
} }
} }

View File

@ -136,26 +136,30 @@ impl NonCamelCaseTypes {
let name = ident.name.as_str(); let name = ident.name.as_str();
if !is_camel_case(name) { if !is_camel_case(name) {
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| { cx.struct_span_lint(
let mut err = lint.build(fluent::lint::non_camel_case_type); NON_CAMEL_CASE_TYPES,
let cc = to_camel_case(name); ident.span,
// We cannot provide meaningful suggestions fluent::lint::non_camel_case_type,
// if the characters are in the category of "Lowercase Letter". |lint| {
if *name != cc { let cc = to_camel_case(name);
err.span_suggestion( // We cannot provide meaningful suggestions
ident.span, // if the characters are in the category of "Lowercase Letter".
fluent::lint::suggestion, if *name != cc {
to_camel_case(name), lint.span_suggestion(
Applicability::MaybeIncorrect, ident.span,
); fluent::lint::suggestion,
} else { to_camel_case(name),
err.span_label(ident.span, fluent::lint::label); Applicability::MaybeIncorrect,
} );
} else {
lint.span_label(ident.span, fluent::lint::label);
}
err.set_arg("sort", sort); lint.set_arg("sort", sort);
err.set_arg("name", name); lint.set_arg("name", name);
err.emit(); lint
}) },
)
} }
} }
} }
@ -280,9 +284,8 @@ impl NonSnakeCase {
let name = ident.name.as_str(); let name = ident.name.as_str();
if !is_snake_case(name) { if !is_snake_case(name) {
cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| { cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint::non_snake_case, |lint| {
let sc = NonSnakeCase::to_snake_case(name); let sc = NonSnakeCase::to_snake_case(name);
let mut err = lint.build(fluent::lint::non_snake_case);
// We cannot provide meaningful suggestions // We cannot provide meaningful suggestions
// if the characters are in the category of "Uppercase Letter". // if the characters are in the category of "Uppercase Letter".
if name != sc { if name != sc {
@ -297,30 +300,30 @@ impl NonSnakeCase {
if sc_ident.name.can_be_raw() { if sc_ident.name.can_be_raw() {
(fluent::lint::rename_or_convert_suggestion, sc_ident.to_string()) (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
} else { } else {
err.note(fluent::lint::cannot_convert_note); lint.note(fluent::lint::cannot_convert_note);
(fluent::lint::rename_suggestion, String::new()) (fluent::lint::rename_suggestion, String::new())
} }
} else { } else {
(fluent::lint::convert_suggestion, sc.clone()) (fluent::lint::convert_suggestion, sc.clone())
}; };
err.span_suggestion( lint.span_suggestion(
ident.span, ident.span,
message, message,
suggestion, suggestion,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
err.help(fluent::lint::help); lint.help(fluent::lint::help);
} }
} else { } else {
err.span_label(ident.span, fluent::lint::label); lint.span_label(ident.span, fluent::lint::label);
} }
err.set_arg("sort", sort); lint.set_arg("sort", sort);
err.set_arg("name", name); lint.set_arg("name", name);
err.set_arg("sc", sc); lint.set_arg("sc", sc);
err.emit(); lint
}); });
} }
} }
@ -478,26 +481,30 @@ impl NonUpperCaseGlobals {
fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) { fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
let name = ident.name.as_str(); let name = ident.name.as_str();
if name.chars().any(|c| c.is_lowercase()) { if name.chars().any(|c| c.is_lowercase()) {
cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| { cx.struct_span_lint(
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); NON_UPPER_CASE_GLOBALS,
let mut err = lint.build(fluent::lint::non_upper_case_global); ident.span,
// We cannot provide meaningful suggestions fluent::lint::non_upper_case_global,
// if the characters are in the category of "Lowercase Letter". |lint| {
if *name != uc { let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
err.span_suggestion( // We cannot provide meaningful suggestions
ident.span, // if the characters are in the category of "Lowercase Letter".
fluent::lint::suggestion, if *name != uc {
uc, lint.span_suggestion(
Applicability::MaybeIncorrect, ident.span,
); fluent::lint::suggestion,
} else { uc,
err.span_label(ident.span, fluent::lint::label); Applicability::MaybeIncorrect,
} );
} else {
lint.span_label(ident.span, fluent::lint::label);
}
err.set_arg("sort", sort); lint.set_arg("sort", sort);
err.set_arg("name", name); lint.set_arg("name", name);
err.emit(); lint
}) },
)
} }
} }
} }

View File

@ -90,13 +90,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
} }
let expr_span = expr.span; let expr_span = expr.span;
let span = expr_span.with_lo(receiver.span.hi()); let span = expr_span.with_lo(receiver.span.hi());
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint::noop_method_call, |lint| {
lint.build(fluent::lint::noop_method_call) lint.set_arg("method", call.ident.name)
.set_arg("method", call.ident.name)
.set_arg("receiver_ty", receiver_ty) .set_arg("receiver_ty", receiver_ty)
.span_label(span, fluent::lint::label) .span_label(span, fluent::lint::label)
.note(fluent::lint::note) .note(fluent::lint::note)
.emit();
}); });
} }
} }

View File

@ -29,18 +29,20 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
} }
} }
if let Some(t) = path_for_pass_by_value(cx, &inner_ty) { if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::pass_by_value) PASS_BY_VALUE,
.set_arg("ty", t.clone()) ty.span,
.span_suggestion( fluent::lint::pass_by_value,
|lint| {
lint.set_arg("ty", t.clone()).span_suggestion(
ty.span, ty.span,
fluent::lint::suggestion, fluent::lint::suggestion,
t, t,
// Changing type of function argument // Changing type of function argument
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
) )
.emit(); },
}) )
} }
} }
_ => {} _ => {}

View File

@ -48,11 +48,18 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
return; return;
} }
cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::redundant_semicolons) REDUNDANT_SEMICOLONS,
.set_arg("multiple", multiple) span,
.span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect) fluent::lint::redundant_semicolons,
.emit(); |lint| {
}); lint.set_arg("multiple", multiple).span_suggestion(
span,
fluent::lint::suggestion,
"",
Applicability::MaybeIncorrect,
)
},
);
} }
} }

View File

@ -100,15 +100,18 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
if trait_predicate.trait_ref.self_ty().is_impl_trait() { if trait_predicate.trait_ref.self_ty().is_impl_trait() {
continue; continue;
} }
cx.struct_span_lint(DROP_BOUNDS, span, |lint| { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { continue;
return };
}; cx.struct_span_lint(
lint.build(fluent::lint::drop_trait_constraints) DROP_BOUNDS,
.set_arg("predicate", predicate) span,
.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) fluent::lint::drop_trait_constraints,
.emit(); |lint| {
}); lint.set_arg("predicate", predicate)
.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
},
);
} }
} }
} }
@ -119,14 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
}; };
for bound in &bounds[..] { for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id(); let def_id = bound.trait_ref.trait_def_id();
if cx.tcx.lang_items().drop_trait() == def_id { if cx.tcx.lang_items().drop_trait() == def_id
cx.struct_span_lint(DYN_DROP, bound.span, |lint| { && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { {
return cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint::drop_glue, |lint| {
}; lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
lint.build(fluent::lint::drop_glue)
.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
.emit();
}); });
} }
} }

View File

@ -144,12 +144,18 @@ fn lint_overflowing_range_endpoint<'tcx>(
// We can suggest using an inclusive range // We can suggest using an inclusive range
// (`..=`) instead only if it is the `end` that is // (`..=`) instead only if it is the `end` that is
// overflowing and only by 1. // overflowing and only by 1.
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max
cx.struct_span_lint(OVERFLOWING_LITERALS, struct_expr.span, |lint| { && let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span)
let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); {
err.set_arg("ty", ty); cx.struct_span_lint(
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { OVERFLOWING_LITERALS,
struct_expr.span,
fluent::lint::range_endpoint_out_of_range,
|lint| {
use ast::{LitIntType, LitKind}; use ast::{LitIntType, LitKind};
lint.set_arg("ty", ty);
// We need to preserve the literal's suffix, // We need to preserve the literal's suffix,
// as it may determine typing information. // as it may determine typing information.
let suffix = match lit.node { let suffix = match lit.node {
@ -159,16 +165,17 @@ fn lint_overflowing_range_endpoint<'tcx>(
_ => bug!(), _ => bug!(),
}; };
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
err.span_suggestion( lint.span_suggestion(
struct_expr.span, struct_expr.span,
fluent::lint::suggestion, fluent::lint::suggestion,
suggestion, suggestion,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
err.emit();
overwritten = true; overwritten = true;
}
}); lint
},
);
} }
overwritten overwritten
} }
@ -221,52 +228,58 @@ fn report_bin_hex_error(
negative: bool, negative: bool,
) { ) {
let size = Integer::from_attr(&cx.tcx, ty).size(); let size = Integer::from_attr(&cx.tcx, ty).size();
cx.struct_span_lint(OVERFLOWING_LITERALS, expr.span, |lint| { cx.struct_span_lint(
let (t, actually) = match ty { OVERFLOWING_LITERALS,
attr::IntType::SignedInt(t) => { expr.span,
let actually = if negative { fluent::lint::overflowing_bin_hex,
-(size.sign_extend(val) as i128) |lint| {
} else { let (t, actually) = match ty {
size.sign_extend(val) as i128 attr::IntType::SignedInt(t) => {
}; let actually = if negative {
(t.name_str(), actually.to_string()) -(size.sign_extend(val) as i128)
} } else {
attr::IntType::UnsignedInt(t) => { size.sign_extend(val) as i128
let actually = size.truncate(val); };
(t.name_str(), actually.to_string()) (t.name_str(), actually.to_string())
} }
}; attr::IntType::UnsignedInt(t) => {
let mut err = lint.build(fluent::lint::overflowing_bin_hex); let actually = size.truncate(val);
if negative { (t.name_str(), actually.to_string())
// If the value is negative, }
// emits a note about the value itself, apart from the literal. };
err.note(fluent::lint::negative_note);
err.note(fluent::lint::negative_becomes_note); if negative {
} else { // If the value is negative,
err.note(fluent::lint::positive_note); // emits a note about the value itself, apart from the literal.
} lint.note(fluent::lint::negative_note);
if let Some(sugg_ty) = lint.note(fluent::lint::negative_becomes_note);
get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
{
err.set_arg("suggestion_ty", sugg_ty);
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
err.span_suggestion(
expr.span,
fluent::lint::suggestion,
format!("{}{}", sans_suffix, sugg_ty),
Applicability::MachineApplicable,
);
} else { } else {
err.help(fluent::lint::help); lint.note(fluent::lint::positive_note);
} }
} if let Some(sugg_ty) =
err.set_arg("ty", t); get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
err.set_arg("lit", repr_str); {
err.set_arg("dec", val); lint.set_arg("suggestion_ty", sugg_ty);
err.set_arg("actually", actually); if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
err.emit(); let (sans_suffix, _) = repr_str.split_at(pos);
}); lint.span_suggestion(
expr.span,
fluent::lint::suggestion,
format!("{}{}", sans_suffix, sugg_ty),
Applicability::MachineApplicable,
);
} else {
lint.help(fluent::lint::help);
}
}
lint.set_arg("ty", t)
.set_arg("lit", repr_str)
.set_arg("dec", val)
.set_arg("actually", actually);
lint
},
);
} }
// This function finds the next fitting type and generates a suggestion string. // This function finds the next fitting type and generates a suggestion string.
@ -349,26 +362,27 @@ fn lint_int_literal<'tcx>(
return; return;
} }
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_int, |lint| {
let mut err = lint.build(fluent::lint::overflowing_int); lint.set_arg("ty", t.name_str())
err.set_arg("ty", t.name_str()); .set_arg(
err.set_arg( "lit",
"lit", cx.sess()
cx.sess() .source_map()
.source_map() .span_to_snippet(lit.span)
.span_to_snippet(lit.span) .expect("must get snippet from literal"),
.expect("must get snippet from literal"), )
); .set_arg("min", min)
err.set_arg("min", min); .set_arg("max", max)
err.set_arg("max", max); .note(fluent::lint::note);
err.note(fluent::lint::note);
if let Some(sugg_ty) = if let Some(sugg_ty) =
get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
{ {
err.set_arg("suggestion_ty", sugg_ty); lint.set_arg("suggestion_ty", sugg_ty);
err.help(fluent::lint::help); lint.help(fluent::lint::help);
} }
err.emit();
lint
}); });
} }
} }
@ -393,16 +407,19 @@ fn lint_uint_literal<'tcx>(
match par_e.kind { match par_e.kind {
hir::ExprKind::Cast(..) => { hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::only_cast_u8_to_char) OVERFLOWING_LITERALS,
.span_suggestion( par_e.span,
fluent::lint::only_cast_u8_to_char,
|lint| {
lint.span_suggestion(
par_e.span, par_e.span,
fluent::lint::suggestion, fluent::lint::suggestion,
format!("'\\u{{{:X}}}'", lit_val), format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit(); },
}); );
return; return;
} }
} }
@ -424,9 +441,8 @@ fn lint_uint_literal<'tcx>(
); );
return; return;
} }
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_uint, |lint| {
lint.build(fluent::lint::overflowing_uint) lint.set_arg("ty", t.name_str())
.set_arg("ty", t.name_str())
.set_arg( .set_arg(
"lit", "lit",
cx.sess() cx.sess()
@ -437,7 +453,6 @@ fn lint_uint_literal<'tcx>(
.set_arg("min", min) .set_arg("min", min)
.set_arg("max", max) .set_arg("max", max)
.note(fluent::lint::note) .note(fluent::lint::note)
.emit();
}); });
} }
} }
@ -467,19 +482,22 @@ fn lint_literal<'tcx>(
_ => bug!(), _ => bug!(),
}; };
if is_infinite == Ok(true) { if is_infinite == Ok(true) {
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::overflowing_literal) OVERFLOWING_LITERALS,
.set_arg("ty", t.name_str()) e.span,
.set_arg( fluent::lint::overflowing_literal,
"lit", |lint| {
cx.sess() lint.set_arg("ty", t.name_str())
.source_map() .set_arg(
.span_to_snippet(lit.span) "lit",
.expect("must get snippet from literal"), cx.sess()
) .source_map()
.note(fluent::lint::note) .span_to_snippet(lit.span)
.emit(); .expect("must get snippet from literal"),
}); )
.note(fluent::lint::note)
},
);
} }
} }
_ => {} _ => {}
@ -497,9 +515,12 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
} }
hir::ExprKind::Binary(binop, ref l, ref r) => { hir::ExprKind::Binary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) { if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::unused_comparisons).emit(); UNUSED_COMPARISONS,
}); e.span,
fluent::lint::unused_comparisons,
|lint| lint,
);
} }
} }
hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit), hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
@ -1150,25 +1171,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS, CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
}; };
self.cx.struct_span_lint(lint, sp, |lint| { self.cx.struct_span_lint(lint, sp, fluent::lint::improper_ctypes, |lint| {
let item_description = match self.mode { let item_description = match self.mode {
CItemKind::Declaration => "block", CItemKind::Declaration => "block",
CItemKind::Definition => "fn", CItemKind::Definition => "fn",
}; };
let mut diag = lint.build(fluent::lint::improper_ctypes); lint.set_arg("ty", ty);
diag.set_arg("ty", ty); lint.set_arg("desc", item_description);
diag.set_arg("desc", item_description); lint.span_label(sp, fluent::lint::label);
diag.span_label(sp, fluent::lint::label);
if let Some(help) = help { if let Some(help) = help {
diag.help(help); lint.help(help);
} }
diag.note(note); lint.note(note);
if let ty::Adt(def, _) = ty.kind() { if let ty::Adt(def, _) = ty.kind() {
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
diag.span_note(sp, fluent::lint::note); lint.span_note(sp, fluent::lint::note);
} }
} }
diag.emit(); lint
}); });
} }
@ -1381,11 +1401,8 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
cx.struct_span_lint( cx.struct_span_lint(
VARIANT_SIZE_DIFFERENCES, VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span, enum_definition.variants[largest_index].span,
|lint| { fluent::lint::variant_size_differences,
lint.build(fluent::lint::variant_size_differences) |lint| lint.set_arg("largest", largest),
.set_arg("largest", largest)
.emit();
},
); );
} }
} }
@ -1493,25 +1510,16 @@ impl InvalidAtomicOrdering {
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
&& let Some((ordering_arg, invalid_ordering)) = match method { && let Some((ordering_arg, invalid_ordering, msg)) = match method {
sym::load => Some((&args[0], sym::Release)), sym::load => Some((&args[0], sym::Release, fluent::lint::atomic_ordering_load)),
sym::store => Some((&args[1], sym::Acquire)), sym::store => Some((&args[1], sym::Acquire, fluent::lint::atomic_ordering_store)),
_ => None, _ => None,
} }
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg) && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
&& (ordering == invalid_ordering || ordering == sym::AcqRel) && (ordering == invalid_ordering || ordering == sym::AcqRel)
{ {
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
if method == sym::load { lint.help(fluent::lint::help)
diag.build(fluent::lint::atomic_ordering_load)
.help(fluent::lint::help)
.emit()
} else {
debug_assert_eq!(method, sym::store);
diag.build(fluent::lint::atomic_ordering_store)
.help(fluent::lint::help)
.emit();
}
}); });
} }
} }
@ -1523,10 +1531,9 @@ impl InvalidAtomicOrdering {
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)) && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
&& Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
{ {
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint::atomic_ordering_fence, |lint| {
diag.build(fluent::lint::atomic_ordering_fence) lint
.help(fluent::lint::help) .help(fluent::lint::help)
.emit();
}); });
} }
} }

View File

@ -154,9 +154,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}; };
if let Some(must_use_op) = must_use_op { if let Some(must_use_op) = must_use_op {
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint::unused_op, |lint| {
lint.build(fluent::lint::unused_op) lint.set_arg("op", must_use_op)
.set_arg("op", must_use_op)
.span_label(expr.span, fluent::lint::label) .span_label(expr.span, fluent::lint::label)
.span_suggestion_verbose( .span_suggestion_verbose(
expr.span.shrink_to_lo(), expr.span.shrink_to_lo(),
@ -164,14 +163,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
"let _ = ", "let _ = ",
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit();
}); });
op_warned = true; op_warned = true;
} }
if !(type_permits_lack_of_use || fn_warned || op_warned) { if !(type_permits_lack_of_use || fn_warned || op_warned) {
cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| { cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint::unused_result, |lint| {
lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit(); lint.set_arg("ty", ty)
}); });
} }
@ -267,29 +265,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
} }
}, },
ty::Closure(..) => { ty::Closure(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(
// FIXME(davidtwco): this isn't properly translatable because of the UNUSED_MUST_USE,
// pre/post strings span,
lint.build(fluent::lint::unused_closure) fluent::lint::unused_closure,
.set_arg("count", plural_len) |lint| {
.set_arg("pre", descr_pre) // FIXME(davidtwco): this isn't properly translatable because of the
.set_arg("post", descr_post) // pre/post strings
.note(fluent::lint::note) lint.set_arg("count", plural_len)
.emit(); .set_arg("pre", descr_pre)
}); .set_arg("post", descr_post)
.note(fluent::lint::note)
},
);
true true
} }
ty::Generator(..) => { ty::Generator(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(
// FIXME(davidtwco): this isn't properly translatable because of the UNUSED_MUST_USE,
// pre/post strings span,
lint.build(fluent::lint::unused_generator) fluent::lint::unused_generator,
.set_arg("count", plural_len) |lint| {
.set_arg("pre", descr_pre) // FIXME(davidtwco): this isn't properly translatable because of the
.set_arg("post", descr_post) // pre/post strings
.note(fluent::lint::note) lint.set_arg("count", plural_len)
.emit(); .set_arg("pre", descr_pre)
}); .set_arg("post", descr_post)
.note(fluent::lint::note)
},
);
true true
} }
_ => false, _ => false,
@ -309,18 +313,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post_path: &str, descr_post_path: &str,
) -> bool { ) -> bool {
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint::unused_def, |lint| {
// FIXME(davidtwco): this isn't properly translatable because of the pre/post // FIXME(davidtwco): this isn't properly translatable because of the pre/post
// strings // strings
let mut err = lint.build(fluent::lint::unused_def); lint.set_arg("pre", descr_pre_path);
err.set_arg("pre", descr_pre_path); lint.set_arg("post", descr_post_path);
err.set_arg("post", descr_post_path); lint.set_arg("def", cx.tcx.def_path_str(def_id));
err.set_arg("def", cx.tcx.def_path_str(def_id));
// check for #[must_use = "..."] // check for #[must_use = "..."]
if let Some(note) = attr.value_str() { if let Some(note) = attr.value_str() {
err.note(note.as_str()); lint.note(note.as_str());
} }
err.emit(); lint
}); });
true true
} else { } else {
@ -357,25 +360,34 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
if let hir::StmtKind::Semi(expr) = s.kind { if let hir::StmtKind::Semi(expr) = s.kind {
if let hir::ExprKind::Path(_) = expr.kind { if let hir::ExprKind::Path(_) = expr.kind {
cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| { let ty = cx.typeck_results().expr_ty(expr);
let ty = cx.typeck_results().expr_ty(expr); if ty.needs_drop(cx.tcx, cx.param_env) {
if ty.needs_drop(cx.tcx, cx.param_env) { cx.struct_span_lint(
let mut lint = lint.build(fluent::lint::path_statement_drop); PATH_STATEMENTS,
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { s.span,
lint.span_suggestion( fluent::lint::path_statement_drop,
s.span, |lint| {
fluent::lint::suggestion, if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
format!("drop({});", snippet), lint.span_suggestion(
Applicability::MachineApplicable, s.span,
); fluent::lint::suggestion,
} else { format!("drop({});", snippet),
lint.span_help(s.span, fluent::lint::suggestion); Applicability::MachineApplicable,
} );
lint.emit(); } else {
} else { lint.span_help(s.span, fluent::lint::suggestion);
lint.build(fluent::lint::path_statement_no_effect).emit(); }
} lint
}); },
);
} else {
cx.struct_span_lint(
PATH_STATEMENTS,
s.span,
fluent::lint::path_statement_no_effect,
|lint| lint,
);
}
} }
} }
} }
@ -545,22 +557,21 @@ trait UnusedDelimLint {
} else { } else {
MultiSpan::from(value_span) MultiSpan::from(value_span)
}; };
cx.struct_span_lint(self.lint(), primary_span, |lint| { cx.struct_span_lint(self.lint(), primary_span, fluent::lint::unused_delim, |lint| {
let mut db = lint.build(fluent::lint::unused_delim); lint.set_arg("delim", Self::DELIM_STR);
db.set_arg("delim", Self::DELIM_STR); lint.set_arg("item", msg);
db.set_arg("item", msg);
if let Some((lo, hi)) = spans { if let Some((lo, hi)) = spans {
let replacement = vec![ let replacement = vec![
(lo, if keep_space.0 { " ".into() } else { "".into() }), (lo, if keep_space.0 { " ".into() } else { "".into() }),
(hi, if keep_space.1 { " ".into() } else { "".into() }), (hi, if keep_space.1 { " ".into() } else { "".into() }),
]; ];
db.multipart_suggestion( lint.multipart_suggestion(
fluent::lint::suggestion, fluent::lint::suggestion,
replacement, replacement,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
db.emit(); lint
}); });
} }
@ -1128,9 +1139,12 @@ impl UnusedImportBraces {
ast::UseTreeKind::Nested(_) => return, ast::UseTreeKind::Nested(_) => return,
}; };
cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| { cx.struct_span_lint(
lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit(); UNUSED_IMPORT_BRACES,
}); item.span,
fluent::lint::unused_import_braces,
|lint| lint.set_arg("node", node_name),
);
} }
} }
} }
@ -1179,15 +1193,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
for adj in cx.typeck_results().expr_adjustments(e) { for adj in cx.typeck_results().expr_adjustments(e) {
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| { cx.struct_span_lint(
lint.build(match m { UNUSED_ALLOCATION,
e.span,
match m {
adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation, adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
adjustment::AutoBorrowMutability::Mut { .. } => { adjustment::AutoBorrowMutability::Mut { .. } => {
fluent::lint::unused_allocation_mut fluent::lint::unused_allocation_mut
} }
}) },
.emit(); |lint| lint,
}); );
} }
} }
} }

View File

@ -96,38 +96,43 @@ impl<'a> LintDiagnosticDerive<'a> {
let body = builder.body(&variant); let body = builder.body(&variant);
let diag = &builder.parent.diag; let diag = &builder.parent.diag;
let init = match builder.slug.value_ref() {
quote! {
#preamble
#body
#diag
}
});
let msg = builder.each_variant(&mut structure, |mut builder, variant| {
// HACK(wafflelapkin): initialize slug (???)
let _preamble = builder.preamble(&variant);
match builder.slug.value_ref() {
None => { None => {
span_err(builder.span, "diagnostic slug not specified") span_err(builder.span, "diagnostic slug not specified")
.help(&format!( .help(&format!(
"specify the slug as the first argument to the attribute, such as \ "specify the slug as the first argument to the attribute, such as \
`#[diag(typeck::example_error)]`", `#[diag(typeck::example_error)]`",
)) ))
.emit(); .emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error(); return DiagnosticDeriveError::ErrorHandled.to_compile_error();
} }
Some(slug) => { Some(slug) => quote! { rustc_errors::fluent::#slug.into() },
quote! {
let mut #diag = #diag.build(rustc_errors::fluent::#slug);
}
}
};
quote! {
#init
#preamble
#body
#diag.emit();
} }
}); });
let diag = &builder.diag; let diag = &builder.diag;
structure.gen_impl(quote! { structure.gen_impl(quote! {
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self { gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) { fn decorate_lint<'__b>(self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
use rustc_errors::IntoDiagnosticArg; use rustc_errors::IntoDiagnosticArg;
#implementation #implementation
} }
fn msg(&self) -> rustc_errors::DiagnosticMessage {
#msg
}
} }
}) })
} }

View File

@ -2,7 +2,7 @@ use std::cmp;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; 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_hir::HirId;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_query_system::ich::StableHashingContext; use rustc_query_system::ich::StableHashingContext;
@ -283,7 +283,11 @@ pub fn struct_lint_level<'s, 'd>(
level: Level, level: Level,
src: LintLevelSource, src: LintLevelSource,
span: Option<MultiSpan>, 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 // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
// the "real" work. // the "real" work.
@ -293,7 +297,13 @@ pub fn struct_lint_level<'s, 'd>(
level: Level, level: Level,
src: LintLevelSource, src: LintLevelSource,
span: Option<MultiSpan>, 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. // Check for future incompatibility lints and issue a stronger warning.
let future_incompatible = lint.future_incompatible; 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(""), (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 // 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 // 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. // 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 { if let Level::Expect(_) = level {
let name = lint.name_lower(); let name = lint.name_lower();
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false }); err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
decorate(LintDiagnosticBuilder::new(err));
decorate(&mut err);
err.emit();
return; return;
} }
explain_lint_level_source(lint, level, src, &mut err);
let name = lint.name_lower(); let name = lint.name_lower();
let is_force_warn = matches!(level, Level::ForceWarn(_)); let is_force_warn = matches!(level, Level::ForceWarn(_));
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); 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. // Finally, run `decorate`.
decorate(LintDiagnosticBuilder::new(err)); 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. /// Returns whether `span` originates in a foreign crate's external macro.

View File

@ -253,13 +253,12 @@ fn late_report_deprecation(
return; return;
} }
let method_span = method_span.unwrap_or(span); let method_span = method_span.unwrap_or(span);
tcx.struct_span_lint_hir(lint, hir_id, method_span, |lint| { tcx.struct_span_lint_hir(lint, hir_id, method_span, message, |diag| {
let mut diag = lint.build(message);
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) { if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
let kind = tcx.def_kind(def_id).descr(def_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), unmarked: impl FnOnce(Span, DefId),
) -> bool { ) -> bool {
let soft_handler = |lint, span, msg: &_| { let soft_handler = |lint, span, msg: &_| {
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint)
lint.build(msg).emit();
})
}; };
let eval_result = let eval_result =
self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable); 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::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal}; use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
use rustc_data_structures::vec_map::VecMap; 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 as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
@ -2857,7 +2859,9 @@ impl<'tcx> TyCtxt<'tcx> {
span: impl Into<MultiSpan>, span: impl Into<MultiSpan>,
decorator: impl for<'a> DecorateLint<'a, ()>, 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( pub fn struct_span_lint_hir(
@ -2865,10 +2869,13 @@ impl<'tcx> TyCtxt<'tcx> {
lint: &'static Lint, lint: &'static Lint,
hir_id: HirId, hir_id: HirId,
span: impl Into<MultiSpan>, 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); 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 /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
@ -2879,17 +2886,20 @@ impl<'tcx> TyCtxt<'tcx> {
id: HirId, id: HirId,
decorator: impl for<'a> DecorateLint<'a, ()>, 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( pub fn struct_lint_node(
self, self,
lint: &'static Lint, lint: &'static Lint,
id: HirId, 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); 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]> { pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {

View File

@ -89,15 +89,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
UNSAFE_OP_IN_UNSAFE_FN, UNSAFE_OP_IN_UNSAFE_FN,
self.hir_context, self.hir_context,
span, span,
|lint| { format!("{} is unsafe and requires unsafe block (error E0133)", description,),
lint.build(&format!( |lint| lint.span_label(span, kind.simple_description()).note(note),
"{} is unsafe and requires unsafe block (error E0133)",
description,
))
.span_label(span, kind.simple_description())
.note(note)
.emit();
},
) )
} }
SafetyContext::Safe => { SafetyContext::Safe => {
@ -125,14 +118,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
enclosing_unsafe: Option<(Span, &'static str)>, enclosing_unsafe: Option<(Span, &'static str)>,
) { ) {
let block_span = self.tcx.sess.source_map().guess_head_span(block_span); 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 msg = "unnecessary `unsafe` block"; self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
let mut db = lint.build(msg); lint.span_label(block_span, msg);
db.span_label(block_span, msg);
if let Some((span, kind)) = enclosing_unsafe { 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
}); });
} }

View File

@ -36,16 +36,20 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let sp = tcx.def_span(def_id); let sp = tcx.def_span(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(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| { tcx.struct_span_lint_hir(
let mut db = lint.build("function cannot return without recursing"); UNCONDITIONAL_RECURSION,
db.span_label(sp, "cannot return without recursing"); hir_id,
// offer some help to the programmer. sp,
for call_span in vis.reachable_recursive_calls { "function cannot return without recursing",
db.span_label(call_span, "recursive call site"); |lint| {
} lint.span_label(sp, "cannot return without recursing");
db.help("a `loop` may express intention better if this is on purpose"); // offer some help to the programmer.
db.emit(); 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")
},
);
} }
} }

View File

@ -7,7 +7,7 @@ use super::{PatCtxt, PatternError};
use rustc_arena::TypedArena; use rustc_arena::TypedArena;
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_errors::{ use rustc_errors::{
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, MultiSpan, ErrorGuaranteed, MultiSpan,
}; };
use rustc_hir as hir; 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_end = affix.last().unwrap().unwrap().0;
let span = span_start.to(span_end); let span = span_start.to(span_end);
let cnt = affix.len(); let cnt = affix.len();
cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| { let s = pluralize!(cnt);
let s = pluralize!(cnt); cx.tcx.struct_span_lint_hir(
let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain")); IRREFUTABLE_LET_PATTERNS,
diag.note(&format!( top,
"{these} pattern{s} will always match", span,
these = pluralize!("this", cnt), format!("{kind} irrefutable pattern{s} in let chain"),
)); |lint| {
diag.help(&format!( lint.note(format!(
"consider moving {} {suggestion}", "{these} pattern{s} will always match",
if cnt > 1 { "them" } else { "it" } these = pluralize!("this", cnt),
)); ))
diag.emit() .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 { 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. // 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, BINDINGS_WITH_VARIANT_NAME,
p.hir_id, p.hir_id,
p.span, 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| { |lint| {
let ty_path = cx.tcx.def_path_str(edef.did()); let ty_path = cx.tcx.def_path_str(edef.did());
let mut err = lint.build(&format!( lint.code(error_code!(E0170));
"pattern binding `{}` is named the same as one \
of the variants of the type `{}`",
ident, ty_path
));
err.code(error_code!(E0170));
// If this is an irrefutable pattern, and there's > 1 variant, // If this is an irrefutable pattern, and there's > 1 variant,
// then we can't actually match on this. Applying the below // then we can't actually match on this. Applying the below
// suggestion would produce code that breaks on `check_irrefutable`. // suggestion would produce code that breaks on `check_irrefutable`.
if rf == Refutable || variant_count == 1 { if rf == Refutable || variant_count == 1 {
err.span_suggestion( lint.span_suggestion(
p.span, p.span,
"to match on the variant, qualify the path", "to match on the variant, qualify the path",
format!("{}::{}", ty_path, ident), format!("{}::{}", ty_path, ident),
Applicability::MachineApplicable, 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>) { fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| { tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
let mut err = lint.build("unreachable pattern");
if let Some(catchall) = catchall { if let Some(catchall) = catchall {
// We had a catchall pattern, hint at that. // We had a catchall pattern, hint at that.
err.span_label(span, "unreachable pattern"); lint.span_label(span, "unreachable pattern");
err.span_label(catchall, "matches any value"); lint.span_label(catchall, "matches any value");
} }
err.emit(); lint
}); });
} }
@ -621,6 +626,11 @@ fn irrefutable_let_patterns(
count: usize, count: usize,
span: Span, span: Span,
) { ) {
let span = match source {
LetSource::LetElse(span) => span,
_ => span,
};
macro_rules! emit_diag { macro_rules! emit_diag {
( (
$lint:expr, $lint:expr,
@ -630,18 +640,23 @@ fn irrefutable_let_patterns(
) => {{ ) => {{
let s = pluralize!(count); let s = pluralize!(count);
let these = pluralize!("this", count); let these = pluralize!("this", count);
let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name)); tcx.struct_span_lint_hir(
diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix)); IRREFUTABLE_LET_PATTERNS,
diag.help(concat!("consider ", $help_sufix)); id,
diag.emit() 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 { match source {
LetSource::LetElse(span) => span,
_ => span,
};
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
LetSource::GenericLet => { LetSource::GenericLet => {
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`"); 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" "instead using a `loop { ... }` with a `let` inside it"
); );
} }
}); };
} }
fn is_let_irrefutable<'p, 'tcx>( fn is_let_irrefutable<'p, 'tcx>(

View File

@ -1,3 +1,4 @@
use rustc_errors::DelayDm;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@ -205,9 +206,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH, lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id, self.id,
self.span, self.span,
|lint| { msg,
lint.build(&msg).emit(); |lint| lint,
},
); );
} else { } else {
debug!( debug!(
@ -286,9 +286,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id, id,
span, span,
|lint| { "floating-point types cannot be used in patterns",
lint.build("floating-point types cannot be used in patterns").emit(); |lint| lint,
},
); );
} }
PatKind::Constant { value: cv } PatKind::Constant { value: cv }
@ -340,15 +339,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH, lint::builtin::INDIRECT_STRUCTURAL_MATCH,
id, id,
span, span,
|lint| { DelayDm(|| {
let msg = format!( format!(
"to use a constant of type `{}` in a pattern, \ "to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`", `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
cv.ty(), cv.ty(),
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 // 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, lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id, self.id,
self.span, self.span,
|lint| {lint.build(&msg).emit();}, msg,
|lint| lint,
); );
} }
PatKind::Constant { value: cv } PatKind::Constant { value: cv }
@ -556,9 +556,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::POINTER_STRUCTURAL_MATCH, lint::builtin::POINTER_STRUCTURAL_MATCH,
id, id,
span, span,
|lint| { msg,
lint.build(msg).emit(); |lint| lint,
},
); );
} }
PatKind::Constant { value: cv } PatKind::Constant { value: cv }
@ -594,9 +593,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
id, id,
span, span,
|lint| { msg,
lint.build(&msg).emit(); |lint| lint,
},
); );
} }

View File

@ -299,10 +299,10 @@ impl IntRange {
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
hir_id, hir_id,
pcx.span, pcx.span,
"multiple patterns overlap on their endpoints",
|lint| { |lint| {
let mut err = lint.build("multiple patterns overlap on their endpoints");
for (int_range, span) in overlaps { for (int_range, span) in overlaps {
err.span_label( lint.span_label(
span, span,
&format!( &format!(
"this range overlaps on `{}`...", "this range overlaps on `{}`...",
@ -310,9 +310,9 @@ impl IntRange {
), ),
); );
} }
err.span_label(pcx.span, "... with this range"); lint.span_label(pcx.span, "... with this range");
err.note("you likely meant to write mutually exclusive ranges"); lint.note("you likely meant to write mutually exclusive ranges");
err.emit(); lint
}, },
); );
} }

View File

@ -754,9 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
hir_id: HirId, hir_id: HirId,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>, 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 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.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
lint.help( lint.help(
"ensure that all variants are matched explicitly by adding the suggested match arms", "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", "the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
scrut_ty, scrut_ty,
)); ));
lint.emit(); lint
}); });
} }

View File

@ -1,4 +1,4 @@
use rustc_errors::{DiagnosticBuilder, LintDiagnosticBuilder}; use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
@ -63,7 +63,10 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
place: &Place<'tcx>, place: &Place<'tcx>,
const_item: DefId, const_item: DefId,
location: Location, location: Location,
decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) -> DiagnosticBuilder<'b, ()>, msg: impl Into<DiagnosticMessage>,
decorate: impl for<'a, 'b> FnOnce(
&'a mut DiagnosticBuilder<'b, ()>,
) -> &'a mut DiagnosticBuilder<'b, ()>,
) { ) {
// Don't lint on borrowing/assigning when a dereference is involved. // Don't lint on borrowing/assigning when a dereference is involved.
// If we 'leave' the temporary via a dereference, we must // If we 'leave' the temporary via a dereference, we must
@ -84,10 +87,10 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
CONST_ITEM_MUTATION, CONST_ITEM_MUTATION,
lint_root, lint_root,
source_info.span, source_info.span,
msg,
|lint| { |lint| {
decorate(lint) decorate(lint)
.span_note(self.tcx.def_span(const_item), "`const` item defined here") .span_note(self.tcx.def_span(const_item), "`const` item defined here")
.emit();
}, },
); );
} }
@ -102,10 +105,8 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// so emitting a lint would be redundant. // so emitting a lint would be redundant.
if !lhs.projection.is_empty() { if !lhs.projection.is_empty() {
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) { if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
self.lint_const_item_usage(&lhs, def_id, loc, |lint| { self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
let mut lint = lint.build("attempting to modify a `const` item"); lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified");
lint
}) })
} }
} }
@ -137,8 +138,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
}); });
let lint_loc = let lint_loc =
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
self.lint_const_item_usage(place, def_id, lint_loc, |lint| { self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
let mut lint = lint.build("taking a mutable reference to a `const` item");
lint lint
.note("each usage of a `const` item creates a new temporary") .note("each usage of a `const` item creates a new temporary")
.note("the mutable reference will refer to this temporary, not the original `const` item"); .note("the mutable reference will refer to this temporary, not the original `const` item");

View File

@ -33,21 +33,27 @@ struct PackedRefChecker<'a, 'tcx> {
fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| { // FIXME: when we make this a hard error, this should have its
// FIXME: when we make this a hard error, this should have its // own error code.
// own error code.
let extra = if tcx.generics_of(def_id).own_requires_monomorphization() { let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
"with type or const parameters" "with type or const parameters"
} else { } else {
"that does not derive `Copy`" "that does not derive `Copy`"
}; };
let message = format!( let message = format!(
"`{}` can't be derived on this `#[repr(packed)]` struct {}", "`{}` can't be derived on this `#[repr(packed)]` struct {}",
tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")), tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
extra extra
); );
lint.build(message).emit();
}); tcx.struct_span_lint_hir(
UNALIGNED_REFERENCES,
lint_hir_id,
tcx.def_span(def_id),
message,
|lint| lint,
);
} }
impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
@ -86,8 +92,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
UNALIGNED_REFERENCES, UNALIGNED_REFERENCES,
lint_root, lint_root,
source_info.span, source_info.span,
"reference to packed field is unaligned",
|lint| { |lint| {
lint.build("reference to packed field is unaligned") lint
.note( .note(
"fields of packed structs are not properly aligned, and creating \ "fields of packed structs are not properly aligned, and creating \
a misaligned reference is undefined behavior (even if that \ a misaligned reference is undefined behavior (even if that \
@ -98,7 +105,6 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
reference with a raw pointer and use `read_unaligned`/`write_unaligned` \ reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
(loads and stores via `*p` must be properly aligned even when using raw pointers)" (loads and stores via `*p` must be properly aligned even when using raw pointers)"
) )
.emit();
}, },
); );
} }

View File

@ -489,21 +489,20 @@ fn unsafety_check_result<'tcx>(
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) { fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id)); let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| { let msg = "unnecessary `unsafe` block";
let msg = "unnecessary `unsafe` block"; tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
let mut db = lint.build(msg); lint.span_label(span, msg);
db.span_label(span, msg);
match kind { match kind {
UnusedUnsafe::Unused => {} UnusedUnsafe::Unused => {}
UnusedUnsafe::InUnsafeBlock(id) => { UnusedUnsafe::InUnsafeBlock(id) => {
db.span_label( lint.span_label(
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)), tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
"because it's nested under this `unsafe` block", "because it's nested under this `unsafe` block",
); );
} }
} }
db.emit(); lint
}); });
} }
@ -543,15 +542,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
UNSAFE_OP_IN_UNSAFE_FN, UNSAFE_OP_IN_UNSAFE_FN,
lint_root, lint_root,
source_info.span, source_info.span,
|lint| { format!("{} is unsafe and requires unsafe block (error E0133)", description,),
lint.build(&format!( |lint| lint.span_label(source_info.span, description).note(note),
"{} is unsafe and requires unsafe block (error E0133)",
description,
))
.span_label(source_info.span, description)
.note(note)
.emit();
},
), ),
} }
} }

View File

@ -347,10 +347,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
panic: AssertKind<impl std::fmt::Debug>, panic: AssertKind<impl std::fmt::Debug>,
) { ) {
if let Some(lint_root) = self.lint_root(source_info) { if let Some(lint_root) = self.lint_root(source_info) {
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
let mut err = lint.build(message); lint.span_label(source_info.span, format!("{:?}", panic))
err.span_label(source_info.span, format!("{:?}", panic));
err.emit();
}); });
} }
} }

View File

@ -106,14 +106,12 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
.lint_root; .lint_root;
let span = terminator.source_info.span; let span = terminator.source_info.span;
tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| { let msg = match fn_def_id {
let msg = match fn_def_id { Some(_) => "call to foreign function with FFI-unwind ABI",
Some(_) => "call to foreign function with FFI-unwind ABI", None => "call to function pointer with FFI-unwind ABI",
None => "call to function pointer with FFI-unwind ABI", };
}; tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
let mut db = lint.build(msg); lint.span_label(span, msg)
db.span_label(span, msg);
db.emit();
}); });
tainted = true; tainted = true;

View File

@ -179,11 +179,15 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| { self.tcx.struct_span_lint_hir(
lint.build("taking a reference to a function item does not give a function pointer") FUNCTION_ITEM_REFERENCES,
.span_suggestion( lint_root,
span,
"taking a reference to a function item does not give a function pointer",
|lint| {
lint.span_suggestion(
span, span,
&format!("cast `{}` to obtain a function pointer", ident), format!("cast `{}` to obtain a function pointer", ident),
format!( format!(
"{} as {}{}fn({}{}){}", "{} as {}{}fn({}{}){}",
if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) }, if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
@ -195,7 +199,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
), ),
Applicability::Unspecified, Applicability::Unspecified,
) )
.emit(); },
}); );
} }
} }

View File

@ -370,10 +370,13 @@ impl CheckAttrVisitor<'_> {
b.push_str(&(allowed_target.to_string() + "s")); b.push_str(&(allowed_target.to_string() + "s"));
b b
}); });
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { self.tcx.struct_span_lint_hir(
lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names)) UNUSED_ATTRIBUTES,
.emit(); hir_id,
}); attr.span,
&format!("`#[{name}]` only has an effect on {}", supported_names),
|lint| lint,
);
} }
} }
@ -877,25 +880,31 @@ impl CheckAttrVisitor<'_> {
hir_id: HirId, hir_id: HirId,
) -> bool { ) -> bool {
if hir_id != CRATE_HIR_ID { if hir_id != CRATE_HIR_ID {
self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| { self.tcx.struct_span_lint_hir(
let mut err = lint.build(fluent::passes::attr_crate_level); INVALID_DOC_ATTRIBUTES,
if attr.style == AttrStyle::Outer hir_id,
&& self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID meta.span(),
{ fluent::passes::attr_crate_level,
if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { |err| {
src.insert(1, '!'); if attr.style == AttrStyle::Outer
err.span_suggestion_verbose( && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
attr.span, {
fluent::passes::suggestion, if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
src, src.insert(1, '!');
Applicability::MaybeIncorrect, err.span_suggestion_verbose(
); attr.span,
} else { fluent::passes::suggestion,
err.span_help(attr.span, fluent::passes::help); src,
Applicability::MaybeIncorrect,
);
} else {
err.span_help(attr.span, fluent::passes::help);
}
} }
} err.note(fluent::passes::note);
err.note(fluent::passes::note).emit(); err
}); },
);
return false; return false;
} }
true true

View File

@ -4,7 +4,7 @@
use itertools::Itertools; use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, Applicability, MultiSpan}; use rustc_errors::{pluralize, Applicability, DelayDm, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
@ -184,13 +184,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
lint::builtin::DEAD_CODE, lint::builtin::DEAD_CODE,
assign.hir_id, assign.hir_id,
assign.span, assign.span,
|lint| { DelayDm(|| format!(
lint.build(&format!(
"useless assignment of {} of type `{}` to itself", "useless assignment of {} of type `{}` to itself",
if is_field_assign { "field" } else { "variable" }, if is_field_assign { "field" } else { "variable" },
self.typeck_results().expr_ty(lhs), self.typeck_results().expr_ty(lhs),
)) )),
.emit(); |lint| {
lint
}, },
) )
} }
@ -717,6 +718,26 @@ impl<'tcx> DeadVisitor<'tcx> {
}) })
.collect(); .collect();
let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
let span_len = dead_codes.len();
let names = match &names[..] {
_ if span_len > 6 => String::new(),
[name] => format!("`{name}` "),
[names @ .., last] => {
format!(
"{} and `{last}` ",
names.iter().map(|name| format!("`{name}`")).join(", ")
)
}
[] => unreachable!(),
};
let msg = format!(
"{these}{descr}{s} {names}{are} never {participle}",
these = if span_len > 6 { "multiple " } else { "" },
s = pluralize!(span_len),
are = pluralize!("is", span_len),
);
tcx.struct_span_lint_hir( tcx.struct_span_lint_hir(
if is_positional { if is_positional {
lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
@ -725,27 +746,8 @@ impl<'tcx> DeadVisitor<'tcx> {
}, },
tcx.hir().local_def_id_to_hir_id(first_id), tcx.hir().local_def_id_to_hir_id(first_id),
MultiSpan::from_spans(spans.clone()), MultiSpan::from_spans(spans.clone()),
|lint| { msg,
let descr = tcx.def_kind(first_id).descr(first_id.to_def_id()); |err| {
let span_len = dead_codes.len();
let names = match &names[..] {
_ if span_len > 6 => String::new(),
[name] => format!("`{name}` "),
[names @ .., last] => {
format!(
"{} and `{last}` ",
names.iter().map(|name| format!("`{name}`")).join(", ")
)
}
[] => unreachable!(),
};
let mut err = lint.build(&format!(
"{these}{descr}{s} {names}{are} never {participle}",
these = if span_len > 6 { "multiple " } else { "" },
s = pluralize!(span_len),
are = pluralize!("is", span_len),
));
if is_positional { if is_positional {
err.multipart_suggestion( err.multipart_suggestion(
&format!( &format!(
@ -791,7 +793,7 @@ impl<'tcx> DeadVisitor<'tcx> {
); );
err.note(&msg); err.note(&msg);
} }
err.emit(); err
}, },
); );
} }

View File

@ -1319,14 +1319,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// that we do not emit the same warning twice if the uninhabited type // that we do not emit the same warning twice if the uninhabited type
// is indeed `!`. // is indeed `!`.
let msg = format!("unreachable {}", descr);
self.ir.tcx.struct_span_lint_hir( self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNREACHABLE_CODE, lint::builtin::UNREACHABLE_CODE,
expr_id, expr_id,
expr_span, expr_span,
|lint| { &msg,
let msg = format!("unreachable {}", descr); |diag| {
lint.build(&msg) diag.span_label(expr_span, &msg)
.span_label(expr_span, &msg)
.span_label(orig_span, "any code following this expression is unreachable") .span_label(orig_span, "any code following this expression is unreachable")
.span_note( .span_note(
orig_span, orig_span,
@ -1335,7 +1335,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
orig_ty orig_ty
), ),
) )
.emit();
}, },
); );
} }
@ -1491,14 +1490,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_ASSIGNMENTS, lint::builtin::UNUSED_ASSIGNMENTS,
var_hir_id, var_hir_id,
vec![span], vec![span],
|lint| { format!("value captured by `{}` is never read", name),
lint.build(&format!( |lint| lint.help("did you mean to capture by reference instead?"),
"value captured by `{}` is never read",
name
))
.help("did you mean to capture by reference instead?")
.emit();
},
); );
} }
} }
@ -1508,11 +1501,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_VARIABLES, lint::builtin::UNUSED_VARIABLES,
var_hir_id, var_hir_id,
vec![span], vec![span],
|lint| { format!("unused variable: `{}`", name),
lint.build(&format!("unused variable: `{}`", name)) |lint| lint.help("did you mean to capture by reference instead?"),
.help("did you mean to capture by reference instead?")
.emit();
},
); );
} }
} }
@ -1601,20 +1591,17 @@ impl<'tcx> Liveness<'_, 'tcx> {
.into_iter() .into_iter()
.map(|(_, _, ident_span)| ident_span) .map(|(_, _, ident_span)| ident_span)
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
|lint| { format!("variable `{}` is assigned to, but never used", name),
lint.build(&format!("variable `{}` is assigned to, but never used", name)) |lint| lint.note(&format!("consider using `_{}` instead", name)),
.note(&format!("consider using `_{}` instead", name))
.emit();
},
) )
} else if can_remove { } else if can_remove {
self.ir.tcx.struct_span_lint_hir( self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES, lint::builtin::UNUSED_VARIABLES,
first_hir_id, first_hir_id,
hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(), hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
format!("unused variable: `{}`", name),
|lint| { |lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name)); lint.multipart_suggestion(
err.multipart_suggestion(
"try removing the field", "try removing the field",
hir_ids_and_spans hir_ids_and_spans
.iter() .iter()
@ -1629,8 +1616,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
}) })
.collect(), .collect(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); )
err.emit();
}, },
); );
} else { } else {
@ -1661,14 +1647,13 @@ impl<'tcx> Liveness<'_, 'tcx> {
.iter() .iter()
.map(|(_, pat_span, _)| *pat_span) .map(|(_, pat_span, _)| *pat_span)
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
format!("unused variable: `{}`", name),
|lint| { |lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name)); lint.multipart_suggestion(
err.multipart_suggestion(
"try ignoring the field", "try ignoring the field",
shorthands, shorthands,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); )
err.emit();
}, },
); );
} else { } else {
@ -1684,17 +1669,16 @@ impl<'tcx> Liveness<'_, 'tcx> {
.iter() .iter()
.map(|(_, _, ident_span)| *ident_span) .map(|(_, _, ident_span)| *ident_span)
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
format!("unused variable: `{}`", name),
|lint| { |lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name)); if self.has_added_lit_match_name_span(&name, opt_body, lint) {
if self.has_added_lit_match_name_span(&name, opt_body, &mut err) { lint.span_label(pat.span, "unused variable");
err.span_label(pat.span, "unused variable");
} }
err.multipart_suggestion( lint.multipart_suggestion(
"if this is intentional, prefix it with an underscore", "if this is intentional, prefix it with an underscore",
non_shorthands, non_shorthands,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); )
err.emit();
}, },
); );
} }
@ -1758,11 +1742,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_ASSIGNMENTS, lint::builtin::UNUSED_ASSIGNMENTS,
hir_id, hir_id,
spans, spans,
|lint| { message(&name),
lint.build(&message(&name)) |lint| lint.help("maybe it is overwritten before being read?"),
.help("maybe it is overwritten before being read?")
.emit();
},
) )
} }
} }

View File

@ -65,9 +65,13 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust { if abi == Abi::Rust {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id); let span = tcx.def_span(def_id);
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| { tcx.struct_span_lint_hir(
lint.build("Rust ABI is unsupported in naked functions").emit(); UNDEFINED_NAKED_FUNCTION_ABI,
}); hir_id,
span,
"Rust ABI is unsupported in naked functions",
|lint| lint,
);
} }
} }

View File

@ -752,10 +752,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
INEFFECTIVE_UNSTABLE_TRAIT_IMPL, INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id(), item.hir_id(),
span, span,
|lint| {lint "an `#[unstable]` annotation here has no effect",
.build("an `#[unstable]` annotation here has no effect") |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
.emit();}
); );
} }
} }
@ -1081,11 +1079,16 @@ fn unnecessary_partially_stable_feature_lint(
implies: Symbol, implies: Symbol,
since: Symbol, since: Symbol,
) { ) {
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { tcx.struct_span_lint_hir(
lint.build(&format!( lint::builtin::STABLE_FEATURES,
hir::CRATE_HIR_ID,
span,
format!(
"the feature `{feature}` has been partially stabilized since {since} and is succeeded \ "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
by the feature `{implies}`" by the feature `{implies}`"
)) ),
|lint| {
lint
.span_suggestion( .span_suggestion(
span, span,
&format!( &format!(
@ -1100,8 +1103,8 @@ fn unnecessary_partially_stable_feature_lint(
"", "",
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
) )
.emit(); },
}); );
} }
fn unnecessary_stable_feature_lint( fn unnecessary_stable_feature_lint(
@ -1113,12 +1116,8 @@ fn unnecessary_stable_feature_lint(
if since.as_str() == VERSION_PLACEHOLDER { if since.as_str() == VERSION_PLACEHOLDER {
since = rust_version_symbol(); since = rust_version_symbol();
} }
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| {
lint.build(&format!( lint
"the feature `{feature}` has been stable since {since} and no longer requires an \
attribute to enable",
))
.emit();
}); });
} }

View File

@ -235,14 +235,18 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
.emit() .emit()
} }
Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() { Err(ErrorHandled::TooGeneric) => {
NotConstEvaluatable::MentionsInfer let err = if uv.has_infer_types_or_consts() {
NotConstEvaluatable::MentionsInfer
} else if uv.has_param_types_or_consts() { } else if uv.has_param_types_or_consts() {
NotConstEvaluatable::MentionsParam NotConstEvaluatable::MentionsParam
} else { } else {
let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?")); let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
NotConstEvaluatable::Error(guar) NotConstEvaluatable::Error(guar)
}), };
Err(err)
},
Err(ErrorHandled::Linted) => { Err(ErrorHandled::Linted) => {
let reported = let reported =
infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint"); infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
@ -250,23 +254,23 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
} }
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
Ok(_) => { Ok(_) => {
if uv.substs.has_param_types_or_consts() { if uv.substs.has_param_types_or_consts() {
assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst)); assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic { if mir_body.is_polymorphic {
let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) }; let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
tcx.struct_span_lint_hir( tcx.struct_span_lint_hir(
lint::builtin::CONST_EVALUATABLE_UNCHECKED, lint::builtin::CONST_EVALUATABLE_UNCHECKED,
tcx.hir().local_def_id_to_hir_id(local_def_id), tcx.hir().local_def_id_to_hir_id(local_def_id),
span, span,
|err| { "cannot use constants which depend on generic parameters in types",
err.build("cannot use constants which depend on generic parameters in types").emit(); |err| err
}) )
} }
} }
Ok(()) Ok(())
}, },
} }
} }

View File

@ -14,7 +14,7 @@ use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause}; use crate::traits::{self, Obligation, ObligationCause};
use hir::def::DefKind; use hir::def::DefKind;
use rustc_errors::{FatalError, MultiSpan}; use rustc_errors::{DelayDm, FatalError, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
@ -164,37 +164,42 @@ fn lint_object_unsafe_trait(
) { ) {
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
// It's also hard to get a use site span, so we use the method definition span. // It's also hard to get a use site span, so we use the method definition span.
tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| { tcx.struct_span_lint_hir(
let mut err = lint.build(&format!( WHERE_CLAUSES_OBJECT_SAFETY,
"the trait `{}` cannot be made into an object", hir::CRATE_HIR_ID,
tcx.def_path_str(trait_def_id) span,
)); DelayDm(|| format!("the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id))),
let node = tcx.hir().get_if_local(trait_def_id); |err| {
let mut spans = MultiSpan::from_span(span); let node = tcx.hir().get_if_local(trait_def_id);
if let Some(hir::Node::Item(item)) = node { let mut spans = MultiSpan::from_span(span);
spans.push_span_label(item.ident.span, "this trait cannot be made into an object..."); if let Some(hir::Node::Item(item)) = node {
spans.push_span_label(span, format!("...because {}", violation.error_msg())); spans.push_span_label(
} else { item.ident.span,
spans.push_span_label( "this trait cannot be made into an object...",
span, );
format!( spans.push_span_label(span, format!("...because {}", violation.error_msg()));
"the trait cannot be made into an object because {}", } else {
violation.error_msg() spans.push_span_label(
), span,
format!(
"the trait cannot be made into an object because {}",
violation.error_msg()
),
);
};
err.span_note(
spans,
"for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
call to be resolvable dynamically; for more information visit \
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
); );
}; if node.is_some() {
err.span_note( // Only provide the help if its a local trait, otherwise it's not
spans, violation.solution(err);
"for a trait to be \"object safe\" it needs to allow building a vtable to allow the \ }
call to be resolvable dynamically; for more information visit \ err
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>", },
); );
if node.is_some() {
// Only provide the help if its a local trait, otherwise it's not
violation.solution(&mut err);
}
err.emit();
});
} }
fn sized_trait_bound_spans<'tcx>( fn sized_trait_bound_spans<'tcx>(

View File

@ -6,6 +6,7 @@
//! //!
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
use hir::LangItem; use hir::LangItem;
use rustc_errors::DelayDm;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
@ -825,13 +826,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
DEREF_INTO_DYN_SUPERTRAIT, DEREF_INTO_DYN_SUPERTRAIT,
obligation.cause.body_id, obligation.cause.body_id,
obligation.cause.span, obligation.cause.span,
|lint| { DelayDm(|| format!(
lint.build(&format!( "`{}` implements `Deref` with supertrait `{}` as output",
"`{}` implements `Deref` with supertrait `{}` as output", source, deref_output_ty
source, )),
deref_output_ty |lint| lint,
)).emit();
},
); );
return; return;
} }

View File

@ -17,7 +17,7 @@ use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause}; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder}; use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::{self, ImplSubject, TyCtxt}; use rustc_middle::ty::{self, ImplSubject, TyCtxt};
use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{InternalSubsts, SubstsRef};
@ -350,26 +350,12 @@ fn report_conflicting_impls(
// Work to be done after we've built the DiagnosticBuilder. We have to define it // Work to be done after we've built the DiagnosticBuilder. We have to define it
// now because the struct_lint methods don't return back the DiagnosticBuilder // now because the struct_lint methods don't return back the DiagnosticBuilder
// that's passed in. // that's passed in.
fn decorate<G: EmissionGuarantee>( fn decorate<'a, 'b, G: EmissionGuarantee>(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
overlap: OverlapError, overlap: OverlapError,
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
impl_span: Span, impl_span: Span,
err: LintDiagnosticBuilder<'_, G>, err: &'b mut DiagnosticBuilder<'a, G>,
) -> G { ) -> &'b mut DiagnosticBuilder<'a, G> {
let msg = format!(
"conflicting implementations of trait `{}`{}{}",
overlap.trait_desc,
overlap
.self_desc
.clone()
.map_or_else(String::new, |ty| { format!(" for type `{}`", ty) }),
match used_to_be_allowed {
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
_ => "",
}
);
let mut err = err.build(&msg);
match tcx.span_of_impl(overlap.with_impl) { match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => { Ok(span) => {
err.span_label(span, "first implementation here"); err.span_label(span, "first implementation here");
@ -384,7 +370,9 @@ fn report_conflicting_impls(
} }
Err(cname) => { Err(cname) => {
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) { let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s), Some(s) => {
format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
}
None => format!("conflicting implementation in crate `{}`", cname), None => format!("conflicting implementation in crate `{}`", cname),
}; };
err.note(&msg); err.note(&msg);
@ -392,28 +380,33 @@ fn report_conflicting_impls(
} }
for cause in &overlap.intercrate_ambiguity_causes { for cause in &overlap.intercrate_ambiguity_causes {
cause.add_intercrate_ambiguity_hint(&mut err); cause.add_intercrate_ambiguity_hint(err);
} }
if overlap.involves_placeholder { if overlap.involves_placeholder {
coherence::add_placeholder_note(&mut err); coherence::add_placeholder_note(err);
} }
err.emit() err
} }
let msg = format!(
"conflicting implementations of trait `{}`{}{}",
overlap.trait_desc,
overlap.self_desc.as_deref().map_or_else(String::new, |ty| format!(" for type `{ty}`")),
match used_to_be_allowed {
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
_ => "",
}
);
match used_to_be_allowed { match used_to_be_allowed {
None => { None => {
let reported = if overlap.with_impl.is_local() let reported = if overlap.with_impl.is_local()
|| tcx.orphan_check_impl(impl_def_id).is_ok() || tcx.orphan_check_impl(impl_def_id).is_ok()
{ {
let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); let mut err = struct_span_err!(tcx.sess, impl_span, E0119, "{msg}",);
Some(decorate( decorate(tcx, overlap, impl_span, &mut err);
tcx, Some(err.emit())
overlap,
used_to_be_allowed,
impl_span,
LintDiagnosticBuilder::new(err),
))
} else { } else {
Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check")) Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
}; };
@ -428,9 +421,8 @@ fn report_conflicting_impls(
lint, lint,
tcx.hir().local_def_id_to_hir_id(impl_def_id), tcx.hir().local_def_id_to_hir_id(impl_def_id),
impl_span, impl_span,
|ldb| { msg,
decorate(tcx, overlap, used_to_be_allowed, impl_span, ldb); |err| decorate(tcx, overlap, impl_span, err),
},
); );
} }
}; };

View File

@ -404,12 +404,8 @@ pub(crate) fn run_global_ctxt(
tcx.struct_lint_node( tcx.struct_lint_node(
crate::lint::MISSING_CRATE_LEVEL_DOCS, crate::lint::MISSING_CRATE_LEVEL_DOCS,
DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(), DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(),
|lint| { "no documentation found for this crate's top-level module",
let mut diag = |lint| lint.help(help),
lint.build("no documentation found for this crate's top-level module");
diag.help(&help);
diag.emit();
},
); );
} }

View File

@ -813,11 +813,8 @@ impl<'tcx> ExtraInfo<'tcx> {
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
hir_id, hir_id,
self.sp, self.sp,
|lint| { msg,
let mut diag = lint.build(msg); |lint| lint.help(help),
diag.help(help);
diag.emit();
},
); );
} }
} }

View File

@ -71,16 +71,14 @@ impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> {
let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| { let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| {
let sp = super::source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs) let sp = super::source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs)
.unwrap_or_else(|| item.attr_span(cx.tcx)); .unwrap_or_else(|| item.attr_span(cx.tcx));
cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, |lint| { cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| {
lint.build(msg) lint.note("bare URLs are not automatically turned into clickable links")
.note("bare URLs are not automatically turned into clickable links")
.span_suggestion( .span_suggestion(
sp, sp,
"use an automatic link instead", "use an automatic link instead",
format!("<{}>", url), format!("<{}>", url),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
.emit();
}); });
}; };

View File

@ -2,7 +2,7 @@
use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{ use rustc_errors::{
emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler, emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
LazyFallbackBundle, LintDiagnosticBuilder, LazyFallbackBundle,
}; };
use rustc_parse::parse_stream_from_source_str; use rustc_parse::parse_stream_from_source_str;
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
@ -97,48 +97,10 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
None => (item.attr_span(self.cx.tcx), false), None => (item.attr_span(self.cx.tcx), false),
}; };
// lambda that will use the lint to start a new diagnostic and add let msg = if buffer.has_errors {
// a suggestion to it when needed. "could not parse code block as Rust code"
let diag_builder = |lint: LintDiagnosticBuilder<'_, ()>| { } else {
let explanation = if is_ignore { "Rust code block is empty"
"`ignore` code blocks require valid Rust code for syntax highlighting; \
mark blocks that do not contain Rust code as text"
} else {
"mark blocks that do not contain Rust code as text"
};
let msg = if buffer.has_errors {
"could not parse code block as Rust code"
} else {
"Rust code block is empty"
};
let mut diag = lint.build(msg);
if precise_span {
if is_ignore {
// giving an accurate suggestion is hard because `ignore` might not have come first in the list.
// just give a `help` instead.
diag.span_help(
sp.from_inner(InnerSpan::new(0, 3)),
&format!("{}: ```text", explanation),
);
} else if empty_block {
diag.span_suggestion(
sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(),
explanation,
"text",
Applicability::MachineApplicable,
);
}
} else if empty_block || is_ignore {
diag.help(&format!("{}: ```text", explanation));
}
// FIXME(#67563): Provide more context for these errors by displaying the spans inline.
for message in buffer.messages.iter() {
diag.note(message);
}
diag.emit();
}; };
// Finally build and emit the completed diagnostic. // Finally build and emit the completed diagnostic.
@ -148,7 +110,42 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
crate::lint::INVALID_RUST_CODEBLOCKS, crate::lint::INVALID_RUST_CODEBLOCKS,
hir_id, hir_id,
sp, sp,
diag_builder, msg,
|lint| {
let explanation = if is_ignore {
"`ignore` code blocks require valid Rust code for syntax highlighting; \
mark blocks that do not contain Rust code as text"
} else {
"mark blocks that do not contain Rust code as text"
};
if precise_span {
if is_ignore {
// giving an accurate suggestion is hard because `ignore` might not have come first in the list.
// just give a `help` instead.
lint.span_help(
sp.from_inner(InnerSpan::new(0, 3)),
&format!("{}: ```text", explanation),
);
} else if empty_block {
lint.span_suggestion(
sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(),
explanation,
"text",
Applicability::MachineApplicable,
);
}
} else if empty_block || is_ignore {
lint.help(&format!("{}: ```text", explanation));
}
// FIXME(#67563): Provide more context for these errors by displaying the spans inline.
for message in buffer.messages.iter() {
lint.note(message);
}
lint
},
); );
} }
} }

View File

@ -125,9 +125,8 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
crate::lint::MISSING_DOC_CODE_EXAMPLES, crate::lint::MISSING_DOC_CODE_EXAMPLES,
hir_id, hir_id,
sp, sp,
|lint| { "missing code example in this documentation",
lint.build("missing code example in this documentation").emit(); |lint| lint,
},
); );
} }
} else if tests.found_tests > 0 } else if tests.found_tests > 0
@ -137,9 +136,8 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
crate::lint::PRIVATE_DOC_TESTS, crate::lint::PRIVATE_DOC_TESTS,
hir_id, hir_id,
item.attr_span(cx.tcx), item.attr_span(cx.tcx),
|lint| { "documentation test in private item",
lint.build("documentation test in private item").emit(); |lint| lint,
},
); );
} }
} }

View File

@ -1609,9 +1609,7 @@ fn report_diagnostic(
let sp = item.attr_span(tcx); let sp = item.attr_span(tcx);
tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| { tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| {
let mut diag = lint.build(msg);
let span = let span =
super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| { super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
if dox.as_bytes().get(link_range.start) == Some(&b'`') if dox.as_bytes().get(link_range.start) == Some(&b'`')
@ -1624,7 +1622,7 @@ fn report_diagnostic(
}); });
if let Some(sp) = span { if let Some(sp) = span {
diag.set_span(sp); lint.set_span(sp);
} else { } else {
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
// ^ ~~~~ // ^ ~~~~
@ -1634,7 +1632,7 @@ fn report_diagnostic(
let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
// Print the line containing the `link_range` and manually mark it with '^'s. // Print the line containing the `link_range` and manually mark it with '^'s.
diag.note(&format!( lint.note(&format!(
"the link appears in this line:\n\n{line}\n\ "the link appears in this line:\n\n{line}\n\
{indicator: <before$}{indicator:^<found$}", {indicator: <before$}{indicator:^<found$}",
line = line, line = line,
@ -1644,9 +1642,9 @@ fn report_diagnostic(
)); ));
} }
decorate(&mut diag, span); decorate(lint, span);
diag.emit(); lint
}); });
} }

View File

@ -240,9 +240,8 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
Some(sp) => sp, Some(sp) => sp,
None => item.attr_span(tcx), None => item.attr_span(tcx),
}; };
tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| { tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| {
use rustc_lint_defs::Applicability; use rustc_lint_defs::Applicability;
let mut diag = lint.build(msg);
// If a tag looks like `<this>`, it might actually be a generic. // If a tag looks like `<this>`, it might actually be a generic.
// We don't try to detect stuff `<like, this>` because that's not valid HTML, // We don't try to detect stuff `<like, this>` because that's not valid HTML,
// and we don't try to detect stuff `<like this>` because that's not valid Rust. // and we don't try to detect stuff `<like this>` because that's not valid Rust.
@ -305,11 +304,10 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<')
|| (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>')
{ {
diag.emit(); return lint;
return;
} }
// multipart form is chosen here because ``Vec<i32>`` would be confusing. // multipart form is chosen here because ``Vec<i32>`` would be confusing.
diag.multipart_suggestion( lint.multipart_suggestion(
"try marking as source code", "try marking as source code",
vec![ vec![
(generics_sp.shrink_to_lo(), String::from("`")), (generics_sp.shrink_to_lo(), String::from("`")),
@ -318,7 +316,8 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
diag.emit()
lint
}); });
}; };

View File

@ -4,12 +4,12 @@ error: this URL is not a hyperlink
LL | /// https://somewhere.com LL | /// https://somewhere.com
| ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>` | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
| |
= note: bare URLs are not automatically turned into clickable links
note: the lint level is defined here note: the lint level is defined here
--> $DIR/bare-urls.rs:3:9 --> $DIR/bare-urls.rs:3:9
| |
LL | #![deny(rustdoc::bare_urls)] LL | #![deny(rustdoc::bare_urls)]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
= note: bare URLs are not automatically turned into clickable links
error: this URL is not a hyperlink error: this URL is not a hyperlink
--> $DIR/bare-urls.rs:7:5 --> $DIR/bare-urls.rs:7:5

View File

@ -8,12 +8,12 @@ error: unknown attribute `compile-fail`. Did you mean `compile_fail`?
9 | | /// ``` 9 | | /// ```
| |_______^ | |_______^
| |
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
note: the lint level is defined here note: the lint level is defined here
--> $DIR/check-attr-test.rs:3:9 --> $DIR/check-attr-test.rs:3:9
| |
3 | #![deny(rustdoc::invalid_codeblock_attributes)] 3 | #![deny(rustdoc::invalid_codeblock_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
error: unknown attribute `compilefail`. Did you mean `compile_fail`? error: unknown attribute `compilefail`. Did you mean `compile_fail`?
--> $DIR/check-attr-test.rs:5:1 --> $DIR/check-attr-test.rs:5:1

View File

@ -10,12 +10,12 @@ LL | | /// boo
LL | | /// ``` LL | | /// ```
| |_______^ | |_______^
| |
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
note: the lint level is defined here note: the lint level is defined here
--> $DIR/check-attr.rs:1:9 --> $DIR/check-attr.rs:1:9
| |
LL | #![deny(rustdoc::invalid_codeblock_attributes)] LL | #![deny(rustdoc::invalid_codeblock_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
error: unknown attribute `compilefail`. Did you mean `compile_fail`? error: unknown attribute `compilefail`. Did you mean `compile_fail`?
--> $DIR/check-attr.rs:3:1 --> $DIR/check-attr.rs:3:1

View File

@ -4,8 +4,8 @@ warning: unexpected `cfg` condition value
LL | #[cfg(feature = "invalid")] LL | #[cfg(feature = "invalid")]
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
| |
= note: `#[warn(unexpected_cfgs)]` on by default
= note: expected values for `feature` are: test = note: expected values for `feature` are: test
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted warning: 1 warning emitted

View File

@ -32,8 +32,8 @@ LL | | //! let x = 12;
LL | | //! ``` LL | | //! ```
| |_______^ | |_______^
| |
= note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(rustdoc::all)]`
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
= note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(rustdoc::all)]`
error: unknown attribute `testharness`. Did you mean `test_harness`? error: unknown attribute `testharness`. Did you mean `test_harness`?
--> $DIR/check-fail.rs:16:1 --> $DIR/check-fail.rs:16:1

View File

@ -24,14 +24,14 @@ LL | pub fn foo() {}
warning: no documentation found for this crate's top-level module warning: no documentation found for this crate's top-level module
| |
= help: The following guide may be of use:
https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
note: the lint level is defined here note: the lint level is defined here
--> $DIR/check.rs:10:9 --> $DIR/check.rs:10:9
| |
LL | #![warn(rustdoc::all)] LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]` = note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
= help: The following guide may be of use:
https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
warning: missing code example in this documentation warning: missing code example in this documentation
--> $DIR/check.rs:5:1 --> $DIR/check.rs:5:1

View File

@ -4,12 +4,12 @@ error: unresolved link to `v2`
LL | /// [v2] LL | /// [v2]
| ^^ no item named `v2` in scope | ^^ no item named `v2` in scope
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
note: the lint level is defined here note: the lint level is defined here
--> $DIR/deny-intra-link-resolution-failure.rs:1:9 --> $DIR/deny-intra-link-resolution-failure.rs:1:9
| |
LL | #![deny(rustdoc::broken_intra_doc_links)] LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,12 +4,12 @@ error: this URL is not a hyperlink
LL | ... a http://link.com LL | ... a http://link.com
| ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>` | ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>`
| |
= note: bare URLs are not automatically turned into clickable links
note: the lint level is defined here note: the lint level is defined here
--> $DIR/diagnostic-width.rs:2:9 --> $DIR/diagnostic-width.rs:2:9
| |
LL | ...ny(rustdoc::bare_url... LL | ...ny(rustdoc::bare_url...
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
= note: bare URLs are not automatically turned into clickable links
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,14 +4,14 @@ error: unknown `doc` attribute `as_ptr`
LL | #[doc(as_ptr)] LL | #[doc(as_ptr)]
| ^^^^^^ | ^^^^^^
| |
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here note: the lint level is defined here
--> $DIR/doc-attr.rs:2:9 --> $DIR/doc-attr.rs:2:9
| |
LL | #![deny(warnings)] LL | #![deny(warnings)]
| ^^^^^^^^ | ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
error: invalid `doc` attribute error: invalid `doc` attribute
--> $DIR/doc-attr.rs:12:7 --> $DIR/doc-attr.rs:12:7

View File

@ -4,9 +4,9 @@ warning: unknown `doc` attribute `include`
LL | #[doc(include = "external-cross-doc.md")] LL | #[doc(include = "external-cross-doc.md")]
| ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
| |
= note: `#[warn(invalid_doc_attributes)]` 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! = 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 #82730 <https://github.com/rust-lang/rust/issues/82730> = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `#[warn(invalid_doc_attributes)]` on by default
warning: 1 warning emitted warning: 1 warning emitted

View File

@ -4,16 +4,16 @@ error: unknown `doc` attribute `spotlight`
LL | #[doc(spotlight)] LL | #[doc(spotlight)]
| ^^^^^^^^^ help: use `notable_trait` instead | ^^^^^^^^^ help: use `notable_trait` instead
| |
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `doc(spotlight)` was renamed to `doc(notable_trait)`
= note: `doc(spotlight)` is now a no-op
note: the lint level is defined here note: the lint level is defined here
--> $DIR/doc-spotlight.rs:2:9 --> $DIR/doc-spotlight.rs:2:9
| |
LL | #![deny(warnings)] LL | #![deny(warnings)]
| ^^^^^^^^ | ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `doc(spotlight)` was renamed to `doc(notable_trait)`
= note: `doc(spotlight)` is now a no-op
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,13 +4,13 @@ error: `#[doc(test(...)]` takes a list of attributes
LL | #![doc(test)] LL | #![doc(test)]
| ^^^^ | ^^^^
| |
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here note: the lint level is defined here
--> $DIR/doc-test-attr.rs:2:9 --> $DIR/doc-test-attr.rs:2:9
| |
LL | #![deny(invalid_doc_attributes)] LL | #![deny(invalid_doc_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
error: `#[doc(test(...)]` takes a list of attributes error: `#[doc(test(...)]` takes a list of attributes
--> $DIR/doc-test-attr.rs:7:8 --> $DIR/doc-test-attr.rs:7:8

View File

@ -7,12 +7,12 @@ LL | | //! foo'b'
LL | | //! ``` LL | | //! ```
| |_______^ | |_______^
| |
= note: error from rustc: prefix `foo` is unknown
note: the lint level is defined here note: the lint level is defined here
--> $DIR/doctest-edition.rs:3:9 --> $DIR/doctest-edition.rs:3:9
| |
LL | #![deny(rustdoc::invalid_rust_codeblocks)] LL | #![deny(rustdoc::invalid_rust_codeblocks)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: error from rustc: prefix `foo` is unknown
help: mark blocks that do not contain Rust code as text help: mark blocks that do not contain Rust code as text
| |
LL | //! ```text LL | //! ```text

View File

@ -4,14 +4,14 @@ error: unknown lint: `rustdoc::missing_doc_code_examples`
LL | #![allow(rustdoc::missing_doc_code_examples)] LL | #![allow(rustdoc::missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: the `rustdoc::missing_doc_code_examples` lint is unstable
= note: see issue #101730 <https://github.com/rust-lang/rust/issues/101730> for more information
= help: add `#![feature(rustdoc_missing_doc_code_examples)]` to the crate attributes to enable
note: the lint level is defined here note: the lint level is defined here
--> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:1:9 --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:1:9
| |
LL | #![deny(unknown_lints)] LL | #![deny(unknown_lints)]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
= note: the `rustdoc::missing_doc_code_examples` lint is unstable
= note: see issue #101730 <https://github.com/rust-lang/rust/issues/101730> for more information
= help: add `#![feature(rustdoc_missing_doc_code_examples)]` to the crate attributes to enable
error: unknown lint: `rustdoc::missing_doc_code_examples` error: unknown lint: `rustdoc::missing_doc_code_examples`
--> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:4:1 --> $DIR/feature-gate-rustdoc_missing_doc_code_examples.rs:4:1

View File

@ -7,13 +7,13 @@ LL | | /// let heart = '❤️';
LL | | /// ``` LL | | /// ```
| |_______^ | |_______^
| |
= note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
help: `ignore` code blocks require valid Rust code for syntax highlighting; mark blocks that do not contain Rust code as text: ```text help: `ignore` code blocks require valid Rust code for syntax highlighting; mark blocks that do not contain Rust code as text: ```text
--> $DIR/ignore-block-help.rs:3:5 --> $DIR/ignore-block-help.rs:3:5
| |
LL | /// ```ignore (to-prevent-tidy-error) LL | /// ```ignore (to-prevent-tidy-error)
| ^^^ | ^^^
= note: error from rustc: character literal may only contain one codepoint = note: error from rustc: character literal may only contain one codepoint
= note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
warning: 1 warning emitted warning: 1 warning emitted

View File

@ -4,12 +4,12 @@ error: unresolved link to `NonExistentStruct`
LL | /// This [test][NonExistentStruct<i32>] thing! LL | /// This [test][NonExistentStruct<i32>] thing!
| ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope | ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
note: the lint level is defined here note: the lint level is defined here
--> $DIR/html-as-generics-intra-doc.rs:2:9 --> $DIR/html-as-generics-intra-doc.rs:2:9
| |
LL | #![deny(rustdoc::broken_intra_doc_links)] LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: unresolved link to `NonExistentStruct2` error: unresolved link to `NonExistentStruct2`
--> $DIR/html-as-generics-intra-doc.rs:17:11 --> $DIR/html-as-generics-intra-doc.rs:17:11

View File

@ -4,12 +4,12 @@ error: unresolved link to `before_but_limited_to_module`
LL | /// [before_but_limited_to_module] LL | /// [before_but_limited_to_module]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `before_but_limited_to_module` in scope | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `before_but_limited_to_module` in scope
| |
= note: `macro_rules` named `before_but_limited_to_module` exists in this crate, but it is not in scope at this link's location
note: the lint level is defined here note: the lint level is defined here
--> $DIR/macro-rules-error.rs:5:9 --> $DIR/macro-rules-error.rs:5:9
| |
LL | #![deny(rustdoc::broken_intra_doc_links)] LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `macro_rules` named `before_but_limited_to_module` exists in this crate, but it is not in scope at this link's location
error: unresolved link to `after` error: unresolved link to `after`
--> $DIR/macro-rules-error.rs:15:6 --> $DIR/macro-rules-error.rs:15:6

View File

@ -4,12 +4,12 @@ error: unresolved link to `T`
LL | //! [[T]::rotate_left] LL | //! [[T]::rotate_left]
| ^ no item named `T` in scope | ^ no item named `T` in scope
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
note: the lint level is defined here note: the lint level is defined here
--> $DIR/non-path-primitives.rs:1:9 --> $DIR/non-path-primitives.rs:1:9
| |
LL | #![deny(rustdoc::broken_intra_doc_links)] LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: unresolved link to `Z` error: unresolved link to `Z`
--> $DIR/non-path-primitives.rs:14:5 --> $DIR/non-path-primitives.rs:14:5

View File

@ -4,8 +4,8 @@ warning: public documentation for `private_from_crate_level` links to private it
LL | //! [my_module] LL | //! [my_module]
| ^^^^^^^^^ this item is private | ^^^^^^^^^ this item is private
| |
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
= note: this link will resolve properly if you pass `--document-private-items` = note: this link will resolve properly if you pass `--document-private-items`
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: 1 warning emitted warning: 1 warning emitted

View File

@ -4,8 +4,8 @@ warning: public documentation for `DocMe` links to private item `DontDocMe`
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^ this item is private | ^^^^^^^^^ this item is private
| |
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
= note: this link resolves only because you passed `--document-private-items`, but will break without = note: this link resolves only because you passed `--document-private-items`, but will break without
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: public documentation for `DocMe` links to private item `DontDocMe::f` warning: public documentation for `DocMe` links to private item `DontDocMe::f`
--> $DIR/private.rs:7:23 --> $DIR/private.rs:7:23

View File

@ -4,8 +4,8 @@ warning: public documentation for `DocMe` links to private item `DontDocMe`
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^ this item is private | ^^^^^^^^^ this item is private
| |
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
= note: this link will resolve properly if you pass `--document-private-items` = note: this link will resolve properly if you pass `--document-private-items`
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: public documentation for `DocMe` links to private item `DontDocMe::f` warning: public documentation for `DocMe` links to private item `DontDocMe::f`
--> $DIR/private.rs:7:23 --> $DIR/private.rs:7:23

View File

@ -4,12 +4,12 @@ error: unresolved link to `i`
LL | /// arr[i] LL | /// arr[i]
| ^ no item named `i` in scope | ^ no item named `i` in scope
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
note: the lint level is defined here note: the lint level is defined here
--> $DIR/span-ice-55723.rs:1:9 --> $DIR/span-ice-55723.rs:1:9
| |
LL | #![deny(rustdoc::broken_intra_doc_links)] LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,12 +4,12 @@ warning: unresolved link to `Oooops`
LL | /// [Oooops] LL | /// [Oooops]
| ^^^^^^ no item named `Oooops` in scope | ^^^^^^ no item named `Oooops` in scope
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
note: the lint level is defined here note: the lint level is defined here
--> $DIR/through-proc-macro.rs:7:9 --> $DIR/through-proc-macro.rs:7:9
| |
LL | #![warn(rustdoc::broken_intra_doc_links)] LL | #![warn(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: 1 warning emitted warning: 1 warning emitted

View File

@ -4,13 +4,13 @@ error: unknown disambiguator `foo`
LL | //! Linking to [foo@banana] and [`bar@banana!()`]. LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^ | ^^^
| |
= note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
note: the lint level is defined here note: the lint level is defined here
--> $DIR/unknown-disambiguator.rs:2:9 --> $DIR/unknown-disambiguator.rs:2:9
| |
LL | #![deny(warnings)] LL | #![deny(warnings)]
| ^^^^^^^^ | ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
= note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `bar` error: unknown disambiguator `bar`
--> $DIR/unknown-disambiguator.rs:4:35 --> $DIR/unknown-disambiguator.rs:4:35

View File

@ -4,12 +4,12 @@ error: unresolved link to `zip`
LL | /// See [zip] crate. LL | /// See [zip] crate.
| ^^^ no item named `zip` in scope | ^^^ no item named `zip` in scope
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
note: the lint level is defined here note: the lint level is defined here
--> $DIR/unused-extern-crate.rs:2:9 --> $DIR/unused-extern-crate.rs:2:9
| |
LL | #![deny(rustdoc::broken_intra_doc_links)] LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,8 +4,8 @@ warning: unresolved link to `error`
LL | /// [error] LL | /// [error]
| ^^^^^ no item named `error` in scope | ^^^^^ no item named `error` in scope
| |
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: unresolved link to `error1` warning: unresolved link to `error1`
--> $DIR/warning-crlf.rs:12:11 --> $DIR/warning-crlf.rs:12:11

View File

@ -4,15 +4,15 @@ error: this attribute can only be applied at the crate level
LL | #[doc(test(no_crate_inject))] LL | #[doc(test(no_crate_inject))]
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
| |
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
note: the lint level is defined here note: the lint level is defined here
--> $DIR/invalid-doc-attr.rs:2:9 --> $DIR/invalid-doc-attr.rs:2:9
| |
LL | #![deny(warnings)] LL | #![deny(warnings)]
| ^^^^^^^^ | ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
help: to apply to the crate, use an inner attribute help: to apply to the crate, use an inner attribute
| |
LL | #![doc(test(no_crate_inject))] LL | #![doc(test(no_crate_inject))]

View File

@ -7,10 +7,10 @@ LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->si
LL | | /// ``` LL | | /// ```
| |_______^ | |_______^
| |
= note: error from rustc: unknown start of token: \
= note: error from rustc: unknown start of token: \
= note: error from rustc: unknown start of token: \
= note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
= note: error from rustc: unknown start of token: \
= note: error from rustc: unknown start of token: \
= note: error from rustc: unknown start of token: \
help: mark blocks that do not contain Rust code as text help: mark blocks that do not contain Rust code as text
| |
LL | /// ```text LL | /// ```text

Some files were not shown because too many files have changed in this diff Show More