Skip to content
Merged
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7d2eba6
middle: translation in `LintDiagnosticBuilder`
davidtwco Jun 27, 2022
0f4c4c5
lint: port array-into-iter diagnostics
davidtwco Jun 27, 2022
2a69640
lint: port enum intrinsics diagnostics
davidtwco Jun 27, 2022
a0624eb
lint: port expectation diagnostics
davidtwco Jun 27, 2022
fd57269
lint: port hidden unicode codepoints diagnostics
davidtwco Jun 27, 2022
e88916c
lint: port default hash types diagnostics
davidtwco Jun 27, 2022
8139542
lint: port query instability diagnostics
davidtwco Jun 27, 2022
0996a7a
lint: port ty diagnostics
davidtwco Jun 27, 2022
1c3a3e0
lint: port impl `LintPass` by hand diagnostics
davidtwco Jun 27, 2022
674ac60
lint: port non-existant doc keyword diagnostics
davidtwco Jun 27, 2022
4f35c79
lint: port translation migration diagnostics
davidtwco Jun 27, 2022
c29e05e
lint: port `CString` ptr diagnostics
davidtwco Jun 27, 2022
48e4bf1
lint: port non-ascii-idents diagnostics
davidtwco Jun 27, 2022
7ee4aa7
lint: port non-fmt-panic diagnostics
davidtwco Jun 27, 2022
096a69d
lint: port non-standard style diagnostics
davidtwco Jun 27, 2022
855f237
lint: port no-op method call diagnostics
davidtwco Jun 27, 2022
37588d6
lint: port pass-by-value diagnostics
davidtwco Jun 27, 2022
8e83656
lint: port redundant semicolons diagnostics
davidtwco Jun 27, 2022
7ef610c
lint: port drop trait/glue diagnostics
davidtwco Jun 27, 2022
7a9bef4
lint: port overflowing literals diagnostics
davidtwco Jun 27, 2022
e5f2e0e
lint: port improper ctypes diagnostics
davidtwco Jun 28, 2022
14c3016
lint: port variant size difference diagnostics
davidtwco Jun 28, 2022
0602729
lint: port atomic ordering diagnostics
davidtwco Jun 28, 2022
1999a4c
lint: port unused diagnostics
davidtwco Jun 28, 2022
2829f51
lint: port path statement diagnostics
davidtwco Jun 28, 2022
fc4f8d9
lint: port unused delimiter diagnostics
davidtwco Jun 28, 2022
e248338
lint: port unused import braces diagnostics
davidtwco Jun 28, 2022
4f7b10f
lint: port unused allocation diagnostics
davidtwco Jun 28, 2022
588977b
lint: port while true diagnostics
davidtwco Jun 28, 2022
d433c9a
lint: port box pointers diagnostics
davidtwco Jun 28, 2022
4c63a21
lint: port non-shorthand pattern diagnostics
davidtwco Jun 28, 2022
7dffd14
lint: port unsafe diagnostics
davidtwco Jun 28, 2022
82bd2c2
lint: port missing documentation diagnostics
davidtwco Jun 28, 2022
28655bc
lint: port missing copy impl diagnostics
davidtwco Jun 28, 2022
284ec37
lint: port missing debug impl diagnostics
davidtwco Jun 28, 2022
18a48c1
lint: port anonymous parameter diagnostics
davidtwco Jun 28, 2022
e151d66
lint: port deprecated attr diagnostics
davidtwco Jun 28, 2022
a13b70e
lint: port unused doc comment diagnostics
davidtwco Jun 28, 2022
dbdbdb6
lint: port no-mangle diagnostics
davidtwco Jun 28, 2022
d071f50
lint: port mutable transmutes diagnostic
davidtwco Jun 28, 2022
23ee3e0
lint: port unstable feature diagnostics
davidtwco Jun 28, 2022
dbced10
lint: port unreachable `pub` diagnostic
davidtwco Jun 28, 2022
01a64af
lint: port type alias bounds diagnostics
davidtwco Jun 28, 2022
3c9bda5
lint: port trivial bounds diagnostics
davidtwco Jun 28, 2022
3a498a7
lint: port `...` range pattern diagnostics
davidtwco Jun 28, 2022
10f2d3f
lint: port test items diagnostics
davidtwco Jun 28, 2022
1067641
lint: port keyword idents diagnostics
davidtwco Jun 28, 2022
acea23e
lint: port explicit outlives diagnostics
davidtwco Jun 28, 2022
bd8fe82
lint: port incomplete features diagnostics
davidtwco Jun 28, 2022
157cbbc
lint: add todo for invalid value diagnostics
davidtwco Jun 28, 2022
2e563a4
lint: port clashing extern diagnostics
davidtwco Jun 28, 2022
5524ca1
lint: port deref nullptr diagnostics
davidtwco Jun 28, 2022
fedd4c6
lint: port asm labels diagnostics
davidtwco Jun 28, 2022
9ff6c77
tests: avoid inadvertent diffs in diag derive test
davidtwco Jun 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
400 changes: 400 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/lint.ftl

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -31,11 +31,12 @@ pub use unic_langid::{langid, LanguageIdentifier};

// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
fluent_messages! {
borrowck => "../locales/en-US/borrowck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
lint => "../locales/en-US/lint.ftl",
parser => "../locales/en-US/parser.ftl",
privacy => "../locales/en-US/privacy.ftl",
typeck => "../locales/en-US/typeck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
borrowck => "../locales/en-US/borrowck.ftl",
}

pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
84 changes: 83 additions & 1 deletion compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use rustc_error_messages::FluentValue;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{edition::Edition, Span, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
@@ -39,12 +39,94 @@ pub trait IntoDiagnosticArg {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
}

impl IntoDiagnosticArg for bool {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
if self {
DiagnosticArgValue::Str(Cow::Borrowed("true"))
} else {
DiagnosticArgValue::Str(Cow::Borrowed("false"))
}
}
}

impl IntoDiagnosticArg for i8 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for u8 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for i16 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for u16 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for i32 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for u32 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for i64 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for u64 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for i128 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for u128 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for String {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self))
}
}

impl IntoDiagnosticArg for std::num::NonZeroU32 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for Edition {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}

impl IntoDiagnosticArg for Symbol {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_ident_string().into_diagnostic_arg()
2 changes: 1 addition & 1 deletion compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
@@ -529,7 +529,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
applicability: Applicability,
) -> &mut Self);

forward!(pub fn set_primary_message(&mut self, msg: impl Into<String>) -> &mut Self);
forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
forward!(pub fn set_arg(
21 changes: 10 additions & 11 deletions compiler/rustc_lint/src/array_into_iter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
@@ -120,31 +120,30 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
_ => bug!("array type coerced to something other than array or slice"),
};
cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| {
let mut diag = lint.build(&format!(
"this method call resolves to `<&{} as IntoIterator>::into_iter` \
(due to backwards compatibility), \
but will resolve to <{} as IntoIterator>::into_iter in Rust 2021",
target, target,
));
let mut diag = lint.build(fluent::lint::array_into_iter);
diag.set_arg("target", target);
diag.span_suggestion(
call.ident.span,
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
fluent::lint::use_iter_suggestion,
"iter",
Applicability::MachineApplicable,
);
if self.for_expr_span == expr.span {
diag.span_suggestion(
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
"or remove `.into_iter()` to iterate by value",
fluent::lint::remove_into_iter_suggestion,
"",
Applicability::MaybeIncorrect,
);
} else if receiver_ty.is_array() {
diag.multipart_suggestion(
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
fluent::lint::use_explicit_into_iter_suggestion,
vec![
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
(
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
")".into(),
),
],
Applicability::MaybeIncorrect,
);
332 changes: 151 additions & 181 deletions compiler/rustc_lint/src/builtin.rs

Large diffs are not rendered by default.

30 changes: 7 additions & 23 deletions compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{context::LintContext, LateContext, LateLintPass};
use rustc_errors::fluent;
use rustc_hir as hir;
use rustc_middle::ty::{fold::TypeFoldable, Ty};
use rustc_span::{symbol::sym, Span};
@@ -51,19 +52,9 @@ fn enforce_mem_discriminant(
if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
builder
.build(
"the return value of `mem::discriminant` is \
unspecified when called with a non-enum type",
)
.span_note(
args_span,
&format!(
"the argument to `discriminant` should be a \
reference to an enum, but it was passed \
a reference to a `{}`, which is not an enum.",
ty_param,
),
)
.build(fluent::lint::enum_intrinsics_mem_discriminant)
.set_arg("ty_param", ty_param)
.span_note(args_span, fluent::lint::note)
.emit();
});
}
@@ -74,16 +65,9 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp
if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
builder
.build(
"the return value of `mem::variant_count` is \
unspecified when called with a non-enum type",
)
.note(&format!(
"the type parameter of `variant_count` should \
be an enum, but it was instantiated with \
the type `{}`, which is not an enum.",
ty_param,
))
.build(fluent::lint::enum_intrinsics_mem_variant)
.set_arg("ty_param", ty_param)
.note(fluent::lint::note)
.emit();
});
}
5 changes: 3 additions & 2 deletions compiler/rustc_lint/src/expect.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::builtin;
use rustc_errors::fluent;
use rustc_hir::HirId;
use rustc_middle::ty::query::Providers;
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
@@ -43,13 +44,13 @@ fn emit_unfulfilled_expectation_lint(
hir_id,
expectation.emission_span,
|diag| {
let mut diag = diag.build("this lint expectation is unfulfilled");
let mut diag = diag.build(fluent::lint::expectation);
if let Some(rationale) = expectation.reason {
diag.note(rationale.as_str());
}

if expectation.is_unfulfilled_lint_expectations {
diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message");
diag.note(fluent::lint::note);
}

diag.emit();
44 changes: 14 additions & 30 deletions compiler/rustc_lint/src/hidden_unicode_codepoints.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LintContext};
use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
use rustc_ast as ast;
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_errors::{fluent, Applicability, SuggestionStyle};
use rustc_span::{BytePos, Span, Symbol};

declare_lint! {
@@ -61,41 +61,25 @@ impl HiddenUnicodeCodepoints {
.collect();

cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
let mut err = lint.build(&format!(
"unicode codepoint changing visible direction of text present in {}",
label
));
let (an, s) = match spans.len() {
1 => ("an ", ""),
_ => ("", "s"),
};
err.span_label(
span,
&format!(
"this {} contains {}invisible unicode text flow control codepoint{}",
label, an, s,
),
);
let mut err = lint.build(fluent::lint::hidden_unicode_codepoints);
err.set_arg("label", label);
err.set_arg("count", spans.len());
err.span_label(span, fluent::lint::label);
err.note(fluent::lint::note);
if point_at_inner_spans {
for (c, span) in &spans {
err.span_label(*span, format!("{:?}", c));
}
}
err.note(
"these kind of unicode codepoints change the way text flows on applications that \
support them, but can cause confusion because they change the order of \
characters on the screen",
);
if point_at_inner_spans && !spans.is_empty() {
err.multipart_suggestion_with_style(
"if their presence wasn't intentional, you can remove them",
fluent::lint::suggestion_remove,
spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
Applicability::MachineApplicable,
SuggestionStyle::HideCodeAlways,
);
err.multipart_suggestion(
"if you want to keep them but make them visible in your source code, you can \
escape them",
fluent::lint::suggestion_escape,
spans
.into_iter()
.map(|(c, span)| {
@@ -109,16 +93,16 @@ impl HiddenUnicodeCodepoints {
// 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
// literals above.
err.note("if their presence wasn't intentional, you can remove them");
err.note(&format!(
"if you want to keep them but make them visible in your source code, you can \
escape them: {}",
err.set_arg(
"escaped",
spans
.into_iter()
.map(|(c, _)| { format!("{:?}", c) })
.map(|(c, _)| format!("{:?}", c))
.collect::<Vec<String>>()
.join(", "),
));
);
err.note(fluent::lint::suggestion_remove);
err.note(fluent::lint::no_suggestion_note_escape);
}
err.emit();
});
65 changes: 28 additions & 37 deletions compiler/rustc_lint/src/internal.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_hir::def::Res;
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
@@ -36,13 +36,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
_ => return,
};
cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
let msg = format!(
"prefer `{}` over `{}`, it has better performance",
replace,
cx.tcx.item_name(def_id)
);
lint.build(&msg)
.note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
lint.build(fluent::lint::default_hash_types)
.set_arg("preferred", replace)
.set_arg("used", cx.tcx.item_name(def_id))
.note(fluent::lint::note)
.emit();
});
}
@@ -99,12 +96,9 @@ impl LateLintPass<'_> for QueryStability {
let def_id = instance.def_id();
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
let msg = format!(
"using `{}` can result in unstable query results",
cx.tcx.item_name(def_id)
);
lint.build(&msg)
.note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
lint.build(fluent::lint::query_instability)
.set_arg("query", cx.tcx.item_name(def_id))
.note(fluent::lint::note)
.emit();
})
}
@@ -146,10 +140,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
);
cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
lint.build("usage of `ty::TyKind::<kind>`")
lint.build(fluent::lint::tykind_kind)
.span_suggestion(
span,
"try using `ty::<kind>` directly",
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
@@ -175,10 +169,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
lint.build("usage of `ty::TyKind::<kind>`")
lint.build(fluent::lint::tykind_kind)
.span_suggestion(
path.span,
"try using `ty::<kind>` directly",
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
@@ -193,10 +187,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
lint.build("usage of `ty::TyKind::<kind>`")
lint.build(fluent::lint::tykind_kind)
.span_suggestion(
path.span,
"try using `ty::<kind>` directly",
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
@@ -213,10 +207,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
lint.build("usage of `ty::TyKind::<kind>`")
lint.build(fluent::lint::tykind_kind)
.span_suggestion(
path.span,
"try using `ty::<kind>` directly",
fluent::lint::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
@@ -226,15 +220,16 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
}
_ => {}
}
lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit();
lint.build(fluent::lint::tykind).help(fluent::lint::help).emit();
})
} else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
if path.segments.len() > 1 {
cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
lint.build(&format!("usage of qualified `ty::{}`", t))
lint.build(fluent::lint::ty_qualified)
.set_arg("ty", t.clone())
.span_suggestion(
path.span,
"try importing it and using it unqualified",
fluent::lint::suggestion,
t,
// The import probably needs to be changed
Applicability::MaybeIncorrect,
@@ -330,8 +325,8 @@ impl EarlyLintPass for LintPassImpl {
LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span,
|lint| {
lint.build("implementing `LintPass` by hand")
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
lint.build(fluent::lint::lintpass_by_hand)
.help(fluent::lint::help)
.emit();
},
)
@@ -371,13 +366,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
return;
}
cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
lint.build(&format!(
"Found non-existing keyword `{}` used in \
`#[doc(keyword = \"...\")]`",
v,
))
.help("only existing keywords are allowed in core/std")
.emit();
lint.build(fluent::lint::non_existant_doc_keyword)
.set_arg("keyword", v)
.help(fluent::lint::help)
.emit();
});
}
}
@@ -431,8 +423,7 @@ impl LateLintPass<'_> for Diagnostics {
debug!(?found_impl);
if !found_impl {
cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls")
.emit();
lint.build(fluent::lint::diag_out_of_impl).emit();
})
}

@@ -450,7 +441,7 @@ impl LateLintPass<'_> for Diagnostics {
debug!(?found_diagnostic_message);
if !found_diagnostic_message {
cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
lint.build("diagnostics should be created using translatable messages").emit();
lint.build(fluent::lint::untranslatable_diag).emit();
})
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
@@ -521,7 +521,7 @@ impl<'s> LintLevelsBuilder<'s> {
src,
Some(sp.into()),
|lint| {
let mut err = lint.build(&msg);
let mut err = lint.build(msg);
if let Some(new_name) = &renamed {
err.span_suggestion(
sp,
@@ -548,7 +548,7 @@ impl<'s> LintLevelsBuilder<'s> {
} else {
name.to_string()
};
let mut db = lint.build(&format!("unknown lint: `{}`", name));
let mut db = lint.build(format!("unknown lint: `{}`", name));
if let Some(suggestion) = suggestion {
db.span_suggestion(
sp,
17 changes: 7 additions & 10 deletions compiler/rustc_lint/src/methods.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::LateContext;
use crate::LateLintPass;
use crate::LintContext;
use rustc_errors::fluent;
use rustc_hir::{Expr, ExprKind, PathSegment};
use rustc_middle::ty;
use rustc_span::{symbol::sym, ExpnKind, Span};
@@ -88,16 +89,12 @@ fn lint_cstring_as_ptr(
if let ty::Adt(adt, _) = substs.type_at(0).kind() {
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
let mut diag = diag
.build("getting the inner pointer of a temporary `CString`");
diag.span_label(as_ptr_span, "this pointer will be invalid");
diag.span_label(
unwrap.span,
"this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime",
);
diag.note("pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned");
diag.help("for more information, see https://doc.rust-lang.org/reference/destructors.html");
diag.emit();
diag.build(fluent::lint::cstring_ptr)
.span_label(as_ptr_span, fluent::lint::as_ptr_label)
.span_label(unwrap.span, fluent::lint::unwrap_label)
.note(fluent::lint::note)
.help(fluent::lint::help)
.emit();
});
}
}
35 changes: 17 additions & 18 deletions compiler/rustc_lint/src/non_ascii_idents.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::fluent;
use rustc_span::symbol::Symbol;

declare_lint! {
@@ -180,13 +181,13 @@ impl EarlyLintPass for NonAsciiIdents {
}
has_non_ascii_idents = true;
cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
lint.build("identifier contains non-ASCII characters").emit();
lint.build(fluent::lint::identifier_non_ascii_char).emit();
});
if check_uncommon_codepoints
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
{
cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
lint.build("identifier contains uncommon Unicode codepoints").emit();
lint.build(fluent::lint::identifier_uncommon_codepoints).emit();
})
}
}
@@ -216,15 +217,11 @@ impl EarlyLintPass for NonAsciiIdents {
.and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
if !*existing_is_ascii || !is_ascii {
cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
lint.build(&format!(
"identifier pair considered confusable between `{}` and `{}`",
existing_symbol, symbol
))
.span_label(
*existing_span,
"this is where the previous identifier occurred",
)
.emit();
lint.build(fluent::lint::confusable_identifier_pair)
.set_arg("existing_sym", *existing_symbol)
.set_arg("sym", symbol)
.span_label(*existing_span, fluent::lint::label)
.emit();
});
}
if *existing_is_ascii && !is_ascii {
@@ -326,18 +323,20 @@ impl EarlyLintPass for NonAsciiIdents {

for ((sp, ch_list), script_set) in lint_reports {
cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
let message = format!(
"the usage of Script Group `{}` in this crate consists solely of mixed script confusables",
script_set);
let mut note = "the usage includes ".to_string();
let mut includes = String::new();
for (idx, ch) in ch_list.into_iter().enumerate() {
if idx != 0 {
note += ", ";
includes += ", ";
}
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
note += &char_info;
includes += &char_info;
}
lint.build(&message).note(&note).note("please recheck to make sure their usages are indeed what you want").emit();
lint.build(fluent::lint::mixed_script_confusables)
.set_arg("set", script_set.to_string())
.set_arg("includes", includes)
.note(fluent::lint::includes_note)
.note(fluent::lint::note)
.emit();
});
}
}
73 changes: 34 additions & 39 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::{pluralize, Applicability};
use rustc_errors::{fluent, Applicability};
use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::lint::in_external_macro;
@@ -120,20 +120,21 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
}

cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
let mut l = lint.build("panic message is not a string literal");
l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol));
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
let mut l = lint.build(fluent::lint::non_fmt_panic);
l.set_arg("name", symbol);
l.note(fluent::lint::note);
l.note(fluent::lint::more_info_note);
if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from.
l.emit();
return;
}
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`.
l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str());
l.note(fluent::lint::supports_fmt_note);
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
l.multipart_suggestion(
"remove the `format!(..)` macro call",
fluent::lint::supports_fmt_suggestion,
vec![
(arg_span.until(open.shrink_to_hi()), "".into()),
(close.until(arg_span.shrink_to_hi()), "".into()),
@@ -153,12 +154,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
);

let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
}) == Some(true);
let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
}) == Some(true);
let display = is_str
|| cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
infcx
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
.may_apply()
}) == Some(true);
let debug = !display
&& cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
infcx
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
.may_apply()
}) == Some(true);
(display, debug)
});

@@ -175,33 +182,25 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_display {
l.span_suggestion_verbose(
arg_span.shrink_to_lo(),
"add a \"{}\" format string to Display the message",
fluent::lint::display_suggestion,
"\"{}\", ",
fmt_applicability,
);
} else if suggest_debug {
l.set_arg("ty", ty);
l.span_suggestion_verbose(
arg_span.shrink_to_lo(),
&format!(
"add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
ty,
),
fluent::lint::debug_suggestion,
"\"{:?}\", ",
fmt_applicability,
);
}

if suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) {
l.set_arg("already_suggested", suggest_display || suggest_debug);
l.multipart_suggestion(
&format!(
"{}use std::panic::panic_any instead",
if suggest_display || suggest_debug {
"or "
} else {
""
},
),
fluent::lint::panic_suggestion,
if del == '(' {
vec![(span.until(open), "std::panic::panic_any".into())]
} else {
@@ -260,21 +259,19 @@ fn check_panic_str<'tcx>(
.collect(),
};
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
let mut l = lint.build(match n_arguments {
1 => "panic message contains an unused formatting placeholder",
_ => "panic message contains unused formatting placeholders",
});
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
l.set_arg("count", n_arguments);
l.note(fluent::lint::note);
if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)),
fluent::lint::add_args_suggestion,
", ...",
Applicability::HasPlaceholders,
);
l.span_suggestion(
arg.span.shrink_to_lo(),
"or add a \"{}\" format string to use the message literally",
fluent::lint::add_fmt_suggestion,
"\"{}\", ",
Applicability::MachineApplicable,
);
@@ -289,17 +286,15 @@ fn check_panic_str<'tcx>(
.map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
.collect()
});
let msg = match &brace_spans {
Some(v) if v.len() == 1 => "panic message contains a brace",
_ => "panic message contains braces",
};
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| {
let mut l = lint.build(msg);
l.note("this message is not used as a format string, but will be in Rust 2021");
let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
l.set_arg("count", count);
l.note(fluent::lint::note);
if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally",
fluent::lint::suggestion,
"\"{}\", ",
Applicability::MachineApplicable,
);
40 changes: 22 additions & 18 deletions compiler/rustc_lint/src/nonstandard_style.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::FnKind;
@@ -137,22 +137,23 @@ impl NonCamelCaseTypes {

if !is_camel_case(name) {
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
let msg = format!("{} `{}` should have an upper camel case name", sort, name);
let mut err = lint.build(&msg);
let mut err = lint.build(fluent::lint::non_camel_case_type);
let cc = to_camel_case(name);
// We cannot provide meaningful suggestions
// if the characters are in the category of "Lowercase Letter".
if *name != cc {
err.span_suggestion(
ident.span,
"convert the identifier to upper camel case",
fluent::lint::suggestion,
to_camel_case(name),
Applicability::MaybeIncorrect,
);
} else {
err.span_label(ident.span, "should have an UpperCamelCase name");
err.span_label(ident.span, fluent::lint::label);
}

err.set_arg("sort", sort);
err.set_arg("name", name);
err.emit();
})
}
@@ -281,11 +282,10 @@ impl NonSnakeCase {
if !is_snake_case(name) {
cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| {
let sc = NonSnakeCase::to_snake_case(name);
let msg = format!("{} `{}` should have a snake case name", sort, name);
let mut err = lint.build(&msg);
let mut err = lint.build(fluent::lint::non_snake_case);
// We cannot provide meaningful suggestions
// if the characters are in the category of "Uppercase Letter".
if *name != sc {
if name != sc {
// We have a valid span in almost all cases, but we don't have one when linting a crate
// name provided via the command line.
if !ident.span.is_dummy() {
@@ -295,13 +295,13 @@ impl NonSnakeCase {
// Instead, recommend renaming the identifier entirely or, if permitted,
// escaping it to create a raw identifier.
if sc_ident.name.can_be_raw() {
("rename the identifier or convert it to a snake case raw identifier", sc_ident.to_string())
(fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
} else {
err.note(&format!("`{}` cannot be used as a raw identifier", sc));
("rename the identifier", String::new())
err.note(fluent::lint::cannot_convert_note);
(fluent::lint::rename_suggestion, String::new())
}
} else {
("convert the identifier to snake case", sc)
(fluent::lint::convert_suggestion, sc.clone())
};

err.span_suggestion(
@@ -311,12 +311,15 @@ impl NonSnakeCase {
Applicability::MaybeIncorrect,
);
} else {
err.help(&format!("convert the identifier to snake case: `{}`", sc));
err.help(fluent::lint::help);
}
} else {
err.span_label(ident.span, "should have a snake_case name");
err.span_label(ident.span, fluent::lint::label);
}

err.set_arg("sort", sort);
err.set_arg("name", name);
err.set_arg("sc", sc);
err.emit();
});
}
@@ -488,21 +491,22 @@ impl NonUpperCaseGlobals {
if name.chars().any(|c| c.is_lowercase()) {
cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
let mut err =
lint.build(&format!("{} `{}` should have an upper case name", sort, name));
let mut err = lint.build(fluent::lint::non_upper_case_global);
// We cannot provide meaningful suggestions
// if the characters are in the category of "Lowercase Letter".
if *name != uc {
err.span_suggestion(
ident.span,
"convert the identifier to upper case",
fluent::lint::suggestion,
uc,
Applicability::MaybeIncorrect,
);
} else {
err.span_label(ident.span, "should have an UPPER_CASE name");
err.span_label(ident.span, fluent::lint::label);
}

err.set_arg("sort", sort);
err.set_arg("name", name);
err.emit();
})
}
19 changes: 7 additions & 12 deletions compiler/rustc_lint/src/noop_method_call.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ use crate::context::LintContext;
use crate::rustc_middle::ty::TypeFoldable;
use crate::LateContext;
use crate::LateLintPass;
use rustc_errors::fluent;
use rustc_hir::def::DefKind;
use rustc_hir::{Expr, ExprKind};
use rustc_middle::ty;
@@ -80,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
) {
return;
}
let method = &call.ident.name;
let receiver = &elements[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
@@ -90,19 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
return;
}
let expr_span = expr.span;
let note = format!(
"the type `{:?}` which `{}` is being called on is the same as \
the type returned from `{}`, so the method call does not do \
anything and can be removed",
receiver_ty, method, method,
);

let span = expr_span.with_lo(receiver.span.hi());
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
let method = &call.ident.name;
let message =
format!("call to `.{}()` on a reference in this situation does nothing", &method,);
lint.build(&message).span_label(span, "unnecessary method call").note(&note).emit();
lint.build(fluent::lint::noop_method_call)
.set_arg("method", call.ident.name)
.set_arg("receiver_ty", receiver_ty)
.span_label(span, fluent::lint::label)
.note(fluent::lint::note)
.emit();
});
}
}
7 changes: 4 additions & 3 deletions compiler/rustc_lint/src/pass_by_value.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
@@ -30,10 +30,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
}
if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
lint.build(&format!("passing `{}` by reference", t))
lint.build(fluent::lint::pass_by_value)
.set_arg("ty", t.clone())
.span_suggestion(
ty.span,
"try passing by value",
fluent::lint::suggestion,
t,
// Changing type of function argument
Applicability::MaybeIncorrect,
12 changes: 5 additions & 7 deletions compiler/rustc_lint/src/redundant_semicolon.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast::{Block, StmtKind};
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_span::Span;

declare_lint! {
@@ -49,12 +49,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
}

cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
let (msg, rem) = if multiple {
("unnecessary trailing semicolons", "remove these semicolons")
} else {
("unnecessary trailing semicolon", "remove this semicolon")
};
lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit();
lint.build(fluent::lint::redundant_semicolons)
.set_arg("multiple", multiple)
.span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect)
.emit();
});
}
}
21 changes: 8 additions & 13 deletions compiler/rustc_lint/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::LateContext;
use crate::LateLintPass;
use crate::LintContext;
use rustc_errors::fluent;
use rustc_hir as hir;
use rustc_span::symbol::sym;

@@ -103,13 +104,10 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
return
};
let msg = format!(
"bounds on `{}` are most likely incorrect, consider instead \
using `{}` to detect whether a type can be trivially dropped",
predicate,
cx.tcx.def_path_str(needs_drop)
);
lint.build(&msg).emit();
lint.build(fluent::lint::drop_trait_constraints)
.set_arg("predicate", predicate)
.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
.emit();
});
}
}
@@ -126,12 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
return
};
let msg = format!(
"types that do not implement `Drop` can still have drop glue, consider \
instead using `{}` to detect whether a type is trivially dropped",
cx.tcx.def_path_str(needs_drop)
);
lint.build(&msg).emit();
lint.build(fluent::lint::drop_glue)
.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
.emit();
});
}
}
269 changes: 135 additions & 134 deletions compiler/rustc_lint/src/types.rs

Large diffs are not rendered by default.

100 changes: 53 additions & 47 deletions compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
use rustc_ast as ast;
use rustc_ast::util::{classify, parser};
use rustc_ast::{ExprKind, StmtKind};
use rustc_errors::{pluralize, Applicability, MultiSpan};
use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
@@ -155,22 +155,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {

if let Some(must_use_op) = must_use_op {
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
let mut lint = lint.build(&format!("unused {} that must be used", must_use_op));
lint.span_label(expr.span, &format!("the {} produces a value", must_use_op));
lint.span_suggestion_verbose(
expr.span.shrink_to_lo(),
"use `let _ = ...` to ignore the resulting value",
"let _ = ",
Applicability::MachineApplicable,
);
lint.emit();
lint.build(fluent::lint::unused_op)
.set_arg("op", must_use_op)
.span_label(expr.span, fluent::lint::label)
.span_suggestion_verbose(
expr.span.shrink_to_lo(),
fluent::lint::suggestion,
"let _ = ",
Applicability::MachineApplicable,
)
.emit();
});
op_warned = true;
}

if !(type_permits_lack_of_use || fn_warned || op_warned) {
cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
lint.build(&format!("unused result of type `{}`", ty)).emit();
lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit();
});
}

@@ -267,23 +268,27 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
},
ty::Closure(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let mut err = lint.build(&format!(
"unused {}closure{}{} that must be used",
descr_pre, plural_suffix, descr_post,
));
err.note("closures are lazy and do nothing unless called");
err.emit();
// FIXME(davidtwco): this isn't properly translatable becauses of the
// pre/post strings
lint.build(fluent::lint::unused_closure)
.set_arg("count", plural_len)
.set_arg("pre", descr_pre)
.set_arg("post", descr_post)
.note(fluent::lint::note)
.emit();
});
true
}
ty::Generator(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let mut err = lint.build(&format!(
"unused {}generator{}{} that must be used",
descr_pre, plural_suffix, descr_post,
));
err.note("generators are lazy and do nothing unless resumed");
err.emit();
// FIXME(davidtwco): this isn't properly translatable becauses of the
// pre/post strings
lint.build(fluent::lint::unused_generator)
.set_arg("count", plural_len)
.set_arg("pre", descr_pre)
.set_arg("post", descr_post)
.note(fluent::lint::note)
.emit();
});
true
}
@@ -305,13 +310,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
) -> bool {
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!(
"unused {}`{}`{} that must be used",
descr_pre_path,
cx.tcx.def_path_str(def_id),
descr_post_path
);
let mut err = lint.build(&msg);
// FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
// strings
let mut err = lint.build(fluent::lint::unused_def);
err.set_arg("pre", descr_pre_path);
err.set_arg("post", descr_post_path);
err.set_arg("def", cx.tcx.def_path_str(def_id));
// check for #[must_use = "..."]
if let Some(note) = attr.value_str() {
err.note(note.as_str());
@@ -356,20 +360,20 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
let ty = cx.typeck_results().expr_ty(expr);
if ty.needs_drop(cx.tcx, cx.param_env) {
let mut lint = lint.build("path statement drops value");
let mut lint = lint.build(fluent::lint::path_statement_drop);
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
lint.span_suggestion(
s.span,
"use `drop` to clarify the intent",
fluent::lint::suggestion,
format!("drop({});", snippet),
Applicability::MachineApplicable,
);
} else {
lint.span_help(s.span, "use `drop` to clarify the intent");
lint.span_help(s.span, fluent::lint::suggestion);
}
lint.emit();
} else {
lint.build("path statement with no effect").emit();
lint.build(fluent::lint::path_statement_no_effect).emit();
}
});
}
@@ -540,15 +544,19 @@ trait UnusedDelimLint {
}

cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg);
let mut err = lint.build(&span_msg);
let replacement = vec![
(spans.0, if keep_space.0 { " ".into() } else { "".into() }),
(spans.1, if keep_space.1 { " ".into() } else { "".into() }),
];
let suggestion = format!("remove these {}", Self::DELIM_STR);
err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable);
err.emit();
lint.build(fluent::lint::unused_delim)
.set_arg("delim", Self::DELIM_STR)
.set_arg("item", msg)
.multipart_suggestion(
fluent::lint::suggestion,
replacement,
Applicability::MachineApplicable,
)
.emit();
});
}

@@ -1110,7 +1118,7 @@ impl UnusedImportBraces {
};

cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
lint.build(&format!("braces around {} is unnecessary", node_name)).emit();
lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit();
});
}
}
@@ -1161,15 +1169,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
for adj in cx.typeck_results().expr_adjustments(e) {
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
let msg = match m {
adjustment::AutoBorrowMutability::Not => {
"unnecessary allocation, use `&` instead"
}
lint.build(match m {
adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
adjustment::AutoBorrowMutability::Mut { .. } => {
"unnecessary allocation, use `&mut` instead"
fluent::lint::unused_allocation_mut
}
};
lint.build(msg).emit();
})
.emit();
});
}
}
5 changes: 3 additions & 2 deletions compiler/rustc_middle/src/lint.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,8 @@ use std::cmp;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{
Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed, MultiSpan,
Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee,
ErrorGuaranteed, MultiSpan,
};
use rustc_hir::HirId;
use rustc_index::vec::IndexVec;
@@ -231,7 +232,7 @@ pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a,

impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
/// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, G> {
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
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -611,6 +611,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
}
}

impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
}
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum PredicateKind<'tcx> {
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
@@ -550,7 +550,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
id,
span,
|lint| {
lint.build(&msg).emit();
lint.build(msg).emit();
},
);
}
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
@@ -1163,7 +1163,7 @@ impl CheckAttrVisitor<'_> {
hir_id,
meta.span(),
|lint| {
lint.build(&"invalid `doc` attribute").emit();
lint.build("invalid `doc` attribute").emit();
},
);
is_valid = false;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]`
error: found non-existing keyword `tadam` used in `#[doc(keyword = \"...\")]`
--> $DIR/existing_doc_keyword.rs:10:1
|
LL | #[doc(keyword = "tadam")]
2 changes: 2 additions & 0 deletions src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// check-fail
// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]

// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"

// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
// the test is just ignored on stable and beta:
114 changes: 54 additions & 60 deletions src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@ LL | panic!({ "foo" });
| ^^^^^^^^^
|
= note: `#[warn(non_fmt_panics)]` on by default
= note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message
help: add a "{}" format string to `Display` the message
|
LL | panic!("{}", { "foo" });
| +++++
100 changes: 50 additions & 50 deletions src/test/ui/non-fmt-panic.stderr

Large diffs are not rendered by default.