diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs index cff50ff9912..7428a9d13ff 100644 --- a/compiler/rustc_lint/src/panic_fmt.rs +++ b/compiler/rustc_lint/src/panic_fmt.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_middle::ty; use rustc_parse_format::{ParseMode, Parser, Piece}; -use rustc_span::sym; +use rustc_span::{sym, InnerSpan}; declare_lint! { /// The `panic_fmt` lint detects `panic!("..")` with `{` or `}` in the string literal. @@ -71,7 +71,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc }; let mut fmt_parser = - Parser::new(fmt.as_ref(), style, snippet, false, ParseMode::Format); + Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format); let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count(); @@ -115,8 +115,22 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc l.emit(); }); } else { - cx.struct_span_lint(PANIC_FMT, expn.call_site, |lint| { - let mut l = lint.build("panic message contains a brace"); + let brace_spans: Option> = snippet + .filter(|s| s.starts_with('"') || s.starts_with("r#")) + .map(|s| { + s.char_indices() + .filter(|&(_, c)| c == '{' || c == '}') + .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", + }; + cx.struct_span_lint(PANIC_FMT, brace_spans.unwrap_or(vec![expn.call_site]), |lint| { + let mut l = lint.build(msg); l.note("this message is not used as a format string, but will be in a future Rust version"); if expn.call_site.contains(arg.span) { l.span_suggestion( diff --git a/src/test/ui/panic-brace.rs b/src/test/ui/panic-brace.rs index e74b6ad96c2..d38d8ac4deb 100644 --- a/src/test/ui/panic-brace.rs +++ b/src/test/ui/panic-brace.rs @@ -1,10 +1,18 @@ // build-pass (FIXME(62277): should be check-pass) +const C: &str = "abc {}"; +static S: &str = "{bla}"; + #[allow(unreachable_code)] fn main() { panic!("here's a brace: {"); //~ WARN panic message contains a brace std::panic!("another one: }"); //~ WARN panic message contains a brace core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder - assert!(false, "{:03x} {test} bla"); //~ WARN panic message contains unused formatting placeholders - debug_assert!(false, "{{}} bla"); //~ WARN panic message contains a brace + assert!(false, "{:03x} {test} bla"); + //~^ WARN panic message contains unused formatting placeholders + debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces + panic!(C); // No warning (yet) + panic!(S); // No warning (yet) + panic!(concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder + panic!(concat!("{", "{")); //~ WARN panic message contains braces } diff --git a/src/test/ui/panic-brace.stderr b/src/test/ui/panic-brace.stderr index 23ae31d00eb..16795ed3d36 100644 --- a/src/test/ui/panic-brace.stderr +++ b/src/test/ui/panic-brace.stderr @@ -1,8 +1,8 @@ warning: panic message contains a brace - --> $DIR/panic-brace.rs:5:5 + --> $DIR/panic-brace.rs:8:29 | LL | panic!("here's a brace: {"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = note: `#[warn(panic_fmt)]` on by default = note: this message is not used as a format string, but will be in a future Rust version @@ -12,10 +12,10 @@ LL | panic!("{}", "here's a brace: {"); | ^^^^^ warning: panic message contains a brace - --> $DIR/panic-brace.rs:6:5 + --> $DIR/panic-brace.rs:9:31 | LL | std::panic!("another one: }"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = note: this message is not used as a format string, but will be in a future Rust version help: add a "{}" format string to use the message literally @@ -24,7 +24,7 @@ LL | std::panic!("{}", "another one: }"); | ^^^^^ warning: panic message contains an unused formatting placeholder - --> $DIR/panic-brace.rs:7:25 + --> $DIR/panic-brace.rs:10:25 | LL | core::panic!("Hello {}"); | ^^ @@ -40,7 +40,7 @@ LL | core::panic!("{}", "Hello {}"); | ^^^^^ warning: panic message contains unused formatting placeholders - --> $DIR/panic-brace.rs:8:21 + --> $DIR/panic-brace.rs:11:21 | LL | assert!(false, "{:03x} {test} bla"); | ^^^^^^ ^^^^^^ @@ -55,11 +55,11 @@ help: or add a "{}" format string to use the message literally LL | assert!(false, "{}", "{:03x} {test} bla"); | ^^^^^ -warning: panic message contains a brace - --> $DIR/panic-brace.rs:9:5 +warning: panic message contains braces + --> $DIR/panic-brace.rs:13:27 | LL | debug_assert!(false, "{{}} bla"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ | = note: this message is not used as a format string, but will be in a future Rust version help: add a "{}" format string to use the message literally @@ -67,5 +67,33 @@ help: add a "{}" format string to use the message literally LL | debug_assert!(false, "{}", "{{}} bla"); | ^^^^^ -warning: 5 warnings emitted +warning: panic message contains an unused formatting placeholder + --> $DIR/panic-brace.rs:16:12 + | +LL | panic!(concat!("{", "}")); + | ^^^^^^^^^^^^^^^^^ + | + = note: this message is not used as a format string when given without arguments, but will be in a future Rust version +help: add the missing argument(s) + | +LL | panic!(concat!("{", "}"), ...); + | ^^^^^ +help: or add a "{}" format string to use the message literally + | +LL | panic!("{}", concat!("{", "}")); + | ^^^^^ + +warning: panic message contains braces + --> $DIR/panic-brace.rs:17:5 + | +LL | panic!(concat!("{", "{")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this message is not used as a format string, but will be in a future Rust version +help: add a "{}" format string to use the message literally + | +LL | panic!("{}", concat!("{", "{")); + | ^^^^^ + +warning: 7 warnings emitted