Skip to content

Commit 7ee4aa7

Browse files
committed
lint: port non-fmt-panic diagnostics
Signed-off-by: David Wood <[email protected]>
1 parent 48e4bf1 commit 7ee4aa7

File tree

5 files changed

+132
-91
lines changed

5 files changed

+132
-91
lines changed

compiler/rustc_error_messages/locales/en-US/lint.ftl

+36
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,39 @@ lint-mixed-script-confusables =
7272
the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
7373
.includes-note = the usage includes {$includes}
7474
.note = please recheck to make sure their usages are indeed what you want
75+
76+
lint-non-fmt-panic = panic message is not a string literal
77+
.note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021
78+
.more-info-note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
79+
.supports-fmt-note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here
80+
.supports-fmt-suggestion = remove the `format!(..)` macro call
81+
.display-suggestion = add a "{"{"}{"}"}" format string to `Display` the message
82+
.debug-suggestion =
83+
add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}`
84+
.panic-suggestion = {$already_suggested ->
85+
[true] or use
86+
*[false] use
87+
} std::panic::panic_any instead
88+
89+
lint-non-fmt-panic-unused =
90+
panic message contains {$count ->
91+
[one] an unused
92+
*[other] unused
93+
} formatting {$count ->
94+
[one] placeholder
95+
*[other] placeholders
96+
}
97+
.note = this message is not used as a format string when given without arguments, but will be in Rust 2021
98+
.add-args-suggestion = add the missing {$count ->
99+
[one] argument
100+
*[other] arguments
101+
}
102+
.add-fmt-suggestion = or add a "{"{"}{"}"}" format string to use the message literally
103+
104+
lint-non-fmt-panic-braces =
105+
panic message contains {$count ->
106+
[one] a brace
107+
*[other] braces
108+
}
109+
.note = this message is not used as a format string, but will be in Rust 2021
110+
.suggestion = add a "{"{"}{"}"}" format string to use the message literally

compiler/rustc_errors/src/diagnostic.rs

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ pub trait IntoDiagnosticArg {
3939
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
4040
}
4141

42+
impl IntoDiagnosticArg for bool {
43+
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
44+
if self {
45+
DiagnosticArgValue::Str(Cow::Borrowed("true"))
46+
} else {
47+
DiagnosticArgValue::Str(Cow::Borrowed("false"))
48+
}
49+
}
50+
}
51+
4252
impl IntoDiagnosticArg for String {
4353
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
4454
DiagnosticArgValue::Str(Cow::Owned(self))

compiler/rustc_lint/src/non_fmt_panic.rs

+34-39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{LateContext, LateLintPass, LintContext};
22
use rustc_ast as ast;
3-
use rustc_errors::{pluralize, Applicability};
3+
use rustc_errors::{fluent, Applicability};
44
use rustc_hir as hir;
55
use rustc_infer::infer::TyCtxtInferExt;
66
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
120120
}
121121

122122
cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
123-
let mut l = lint.build("panic message is not a string literal");
124-
l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol));
125-
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
123+
let mut l = lint.build(fluent::lint::non_fmt_panic);
124+
l.set_arg("name", symbol);
125+
l.note(fluent::lint::note);
126+
l.note(fluent::lint::more_info_note);
126127
if !is_arg_inside_call(arg_span, span) {
127128
// No clue where this argument is coming from.
128129
l.emit();
129130
return;
130131
}
131132
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
132133
// A case of `panic!(format!(..))`.
133-
l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str());
134+
l.note(fluent::lint::supports_fmt_note);
134135
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
135136
l.multipart_suggestion(
136-
"remove the `format!(..)` macro call",
137+
fluent::lint::supports_fmt_suggestion,
137138
vec![
138139
(arg_span.until(open.shrink_to_hi()), "".into()),
139140
(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
153154
);
154155

155156
let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
156-
let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
157-
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
158-
}) == Some(true);
159-
let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
160-
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
161-
}) == Some(true);
157+
let display = is_str
158+
|| cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
159+
infcx
160+
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
161+
.may_apply()
162+
}) == Some(true);
163+
let debug = !display
164+
&& cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
165+
infcx
166+
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
167+
.may_apply()
168+
}) == Some(true);
162169
(display, debug)
163170
});
164171

@@ -175,33 +182,25 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
175182
if suggest_display {
176183
l.span_suggestion_verbose(
177184
arg_span.shrink_to_lo(),
178-
"add a \"{}\" format string to Display the message",
185+
fluent::lint::display_suggestion,
179186
"\"{}\", ",
180187
fmt_applicability,
181188
);
182189
} else if suggest_debug {
190+
l.set_arg("ty", ty);
183191
l.span_suggestion_verbose(
184192
arg_span.shrink_to_lo(),
185-
&format!(
186-
"add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
187-
ty,
188-
),
193+
fluent::lint::debug_suggestion,
189194
"\"{:?}\", ",
190195
fmt_applicability,
191196
);
192197
}
193198

194199
if suggest_panic_any {
195200
if let Some((open, close, del)) = find_delimiters(cx, span) {
201+
l.set_arg("already_suggested", suggest_display || suggest_debug);
196202
l.multipart_suggestion(
197-
&format!(
198-
"{}use std::panic::panic_any instead",
199-
if suggest_display || suggest_debug {
200-
"or "
201-
} else {
202-
""
203-
},
204-
),
203+
fluent::lint::panic_suggestion,
205204
if del == '(' {
206205
vec![(span.until(open), "std::panic::panic_any".into())]
207206
} else {
@@ -260,21 +259,19 @@ fn check_panic_str<'tcx>(
260259
.collect(),
261260
};
262261
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
263-
let mut l = lint.build(match n_arguments {
264-
1 => "panic message contains an unused formatting placeholder",
265-
_ => "panic message contains unused formatting placeholders",
266-
});
267-
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
262+
let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
263+
l.set_arg("count", n_arguments);
264+
l.note(fluent::lint::note);
268265
if is_arg_inside_call(arg.span, span) {
269266
l.span_suggestion(
270267
arg.span.shrink_to_hi(),
271-
&format!("add the missing argument{}", pluralize!(n_arguments)),
268+
fluent::lint::add_args_suggestion,
272269
", ...",
273270
Applicability::HasPlaceholders,
274271
);
275272
l.span_suggestion(
276273
arg.span.shrink_to_lo(),
277-
"or add a \"{}\" format string to use the message literally",
274+
fluent::lint::add_fmt_suggestion,
278275
"\"{}\", ",
279276
Applicability::MachineApplicable,
280277
);
@@ -289,17 +286,15 @@ fn check_panic_str<'tcx>(
289286
.map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
290287
.collect()
291288
});
292-
let msg = match &brace_spans {
293-
Some(v) if v.len() == 1 => "panic message contains a brace",
294-
_ => "panic message contains braces",
295-
};
289+
let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
296290
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
297-
let mut l = lint.build(msg);
298-
l.note("this message is not used as a format string, but will be in Rust 2021");
291+
let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
292+
l.set_arg("count", count);
293+
l.note(fluent::lint::note);
299294
if is_arg_inside_call(arg.span, span) {
300295
l.span_suggestion(
301296
arg.span.shrink_to_lo(),
302-
"add a \"{}\" format string to use the message literally",
297+
fluent::lint::suggestion,
303298
"\"{}\", ",
304299
Applicability::MachineApplicable,
305300
);

src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ LL | panic!({ "foo" });
55
| ^^^^^^^^^
66
|
77
= note: `#[warn(non_fmt_panics)]` on by default
8-
= note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
8+
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
99
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
10-
help: add a "{}" format string to Display the message
10+
help: add a "{}" format string to `Display` the message
1111
|
1212
LL | panic!("{}", { "foo" });
1313
| +++++

0 commit comments

Comments
 (0)