From e656e52ccb33f92ca8bfd7ad78ee5b028ff61a62 Mon Sep 17 00:00:00 2001 From: IoaNNUwU Date: Tue, 2 Sep 2025 16:15:23 +0200 Subject: [PATCH 1/3] Suggest examples of format specifiers in error messages --- compiler/rustc_builtin_macros/src/format.rs | 27 ++++++++- .../missing-format-specifiers-issue-68293.rs | 34 +++++++++++ ...ssing-format-specifiers-issue-68293.stderr | 59 +++++++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 tests/ui/suggestions/missing-format-specifiers-issue-68293.rs create mode 100644 tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6415e55e0b034..ce9bda10721a4 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -758,8 +758,31 @@ fn report_missing_placeholders( check_foreign!(shell); } } - if !found_foreign && unused.len() == 1 { - diag.span_label(fmt_span, "formatting specifier missing"); + if !found_foreign { + if unused.len() == 1 { + diag.span_label(fmt_span, "formatting specifier missing"); + } + if used.iter().all(|used| !used) { + diag.note("format specifiers use curly braces: `{}`"); + } + + let mut suggest_fixed_fmt = format!("\"{}", &fmt_str[..fmt_str.len() - 1]); + for _ in &unused { + suggest_fixed_fmt.push_str("{}"); + } + suggest_fixed_fmt.push('"'); + + let suggest_fmt_count = if unused.len() == 1 { + "consider adding format specifier".to_string() + } else { + format!("consider adding {} format specifiers", unused.len()) + }; + diag.span_suggestion_verbose( + fmt_span, + suggest_fmt_count, + suggest_fixed_fmt, + Applicability::MaybeIncorrect, + ); } diag.emit(); diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs new file mode 100644 index 0000000000000..e1f8710db5a33 --- /dev/null +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs @@ -0,0 +1,34 @@ +fn no_format_specifier_two_unused_args() { + println!("Hello", "World"); + //~^ ERROR argument never used + //~| NOTE formatting specifier missing + //~| NOTE format specifiers use curly braces: `{}` + //~| NOTE argument never used +} + +fn no_format_specifier_multiple_unused_args() { + println!("list: ", 1, 2, 3); + //~^ ERROR multiple unused formatting arguments + //~| NOTE multiple missing formatting specifiers + //~| NOTE format specifiers use curly braces: `{}` + //~| NOTE argument never used + //~| NOTE argument never used + //~| NOTE argument never used +} + +fn missing_format_specifiers_one_unused_arg() { + println!("list: {}, {}", 1, 2, 3); + //~^ ERROR argument never used + //~| NOTE formatting specifier missing + //~| NOTE argument never used +} + +fn missing_format_specifiers_multiple_unused_args() { + println!("list: {}", 1, 2, 3); + //~^ ERROR multiple unused formatting arguments + //~| NOTE multiple missing formatting specifiers + //~| NOTE argument never used + //~| NOTE argument never used +} + +fn main() { } diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr new file mode 100644 index 0000000000000..654c8b0712a4f --- /dev/null +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr @@ -0,0 +1,59 @@ +error: argument never used + --> $DIR/missing-format-specifiers-issue-68293.rs:2:23 + | +LL | println!("Hello", "World"); + | ------- ^^^^^^^ argument never used + | | + | formatting specifier missing + | + = note: format specifiers use curly braces: `{}` +help: consider adding format specifier + | +LL | println!("Hello{}", "World"); + | ++ + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:10:24 + | +LL | println!("list: ", 1, 2, 3); + | -------- ^ ^ ^ argument never used + | | | | + | | | argument never used + | | argument never used + | multiple missing formatting specifiers + | + = note: format specifiers use curly braces: `{}` +help: consider adding 3 format specifiers + | +LL | println!("list: {}{}{}", 1, 2, 3); + | ++++++ + +error: argument never used + --> $DIR/missing-format-specifiers-issue-68293.rs:20:36 + | +LL | println!("list: {}, {}", 1, 2, 3); + | -------------- ^ argument never used + | | + | formatting specifier missing + | +help: consider adding format specifier + | +LL | println!("list: {}, {}{}", 1, 2, 3); + | ++ + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:27:29 + | +LL | println!("list: {}", 1, 2, 3); + | ---------- ^ ^ argument never used + | | | + | | argument never used + | multiple missing formatting specifiers + | +help: consider adding 2 format specifiers + | +LL | println!("list: {}{}{}", 1, 2, 3); + | ++++ + +error: aborting due to 4 previous errors + From 1e733b389192b48110779bc1cd8edcaed7c43b0e Mon Sep 17 00:00:00 2001 From: IoaNNUwU Date: Tue, 2 Sep 2025 23:53:54 +0200 Subject: [PATCH 2/3] Implement better suggestions based on additional tests and other code paths --- compiler/rustc_builtin_macros/src/format.rs | 58 ++++++++++++------- tests/ui/fmt/ifmt-bad-arg.stderr | 14 +++++ tests/ui/macros/format-unused-lables.stderr | 18 ++++++ tests/ui/mir/unsized-extern-static.stderr | 6 ++ .../missing-format-specifiers-issue-68293.rs | 1 + ...ssing-format-specifiers-issue-68293.stderr | 10 +--- 6 files changed, 78 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index ce9bda10721a4..e5f73188dbdfa 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -565,6 +565,7 @@ fn make_format_args( &used, &args, &pieces, + &invalid_refs, detect_foreign_fmt, str_style, fmt_str, @@ -645,6 +646,7 @@ fn report_missing_placeholders( used: &[bool], args: &FormatArguments, pieces: &[parse::Piece<'_>], + invalid_refs: &[(usize, Option, PositionUsedAs, FormatArgPositionKind)], detect_foreign_fmt: bool, str_style: Option, fmt_str: &str, @@ -758,31 +760,47 @@ fn report_missing_placeholders( check_foreign!(shell); } } - if !found_foreign { - if unused.len() == 1 { - diag.span_label(fmt_span, "formatting specifier missing"); + if !found_foreign && unused.len() == 1 { + diag.span_label(fmt_span, "formatting specifier missing"); + } + + if !found_foreign && invalid_refs.is_empty() { + // Show example if user didn't use any format specifiers + let show_example = used.iter().all(|used| !used); + + if !show_example && unused.len()> 1 { + diag.note(format!("consider adding {} format specifiers", unused.len())); } - if used.iter().all(|used| !used) { + + let original_fmt_str = if fmt_str.len()>= 1 { &fmt_str[..fmt_str.len() - 1] } else { "" }; + + if show_example && unused.len() == 1 { diag.note("format specifiers use curly braces: `{}`"); - } - let mut suggest_fixed_fmt = format!("\"{}", &fmt_str[..fmt_str.len() - 1]); - for _ in &unused { - suggest_fixed_fmt.push_str("{}"); + diag.span_suggestion_verbose( + fmt_span, + "consider adding format specifier", + format!("\"{}{{}}\"", original_fmt_str), + Applicability::MaybeIncorrect, + ); } - suggest_fixed_fmt.push('"'); - let suggest_fmt_count = if unused.len() == 1 { - "consider adding format specifier".to_string() - } else { - format!("consider adding {} format specifiers", unused.len()) - }; - diag.span_suggestion_verbose( - fmt_span, - suggest_fmt_count, - suggest_fixed_fmt, - Applicability::MaybeIncorrect, - ); + if show_example && unused.len()> 1 { + diag.note("format specifiers use curly braces: `{}`"); + + let mut suggest_fixed_fmt = format!("\"{}", original_fmt_str); + for _ in &unused { + suggest_fixed_fmt.push_str("{}"); + } + suggest_fixed_fmt.push('"'); + + diag.span_suggestion_verbose( + fmt_span, + format!("consider adding {} format specifiers", unused.len()), + suggest_fixed_fmt, + Applicability::MaybeIncorrect, + ); + } } diag.emit(); diff --git a/tests/ui/fmt/ifmt-bad-arg.stderr b/tests/ui/fmt/ifmt-bad-arg.stderr index 4344aee83c2b1..6ddc817290155 100644 --- a/tests/ui/fmt/ifmt-bad-arg.stderr +++ b/tests/ui/fmt/ifmt-bad-arg.stderr @@ -62,6 +62,12 @@ LL | format!("", 1, 2); | | | | | argument never used | multiple missing formatting specifiers + | + = note: format specifiers use curly braces: `{}` +help: consider adding 2 format specifiers + | +LL | format!("{}{}", 1, 2); + | ++++ error: argument never used --> $DIR/ifmt-bad-arg.rs:33:22 @@ -102,6 +108,12 @@ LL | format!("", foo=2); | -- ^ named argument never used | | | formatting specifier missing + | + = note: format specifiers use curly braces: `{}` +help: consider adding format specifier + | +LL | format!("{}", foo=2); + | ++ error: multiple unused formatting arguments --> $DIR/ifmt-bad-arg.rs:38:32 @@ -111,6 +123,8 @@ LL | format!("{} {}", 1, 2, foo=1, bar=2); | | | | | named argument never used | multiple missing formatting specifiers + | + = note: consider adding 2 format specifiers error: duplicate argument named `foo` --> $DIR/ifmt-bad-arg.rs:40:29 diff --git a/tests/ui/macros/format-unused-lables.stderr b/tests/ui/macros/format-unused-lables.stderr index fad87fa2aeea8..1c5cdcc2346d4 100644 --- a/tests/ui/macros/format-unused-lables.stderr +++ b/tests/ui/macros/format-unused-lables.stderr @@ -7,6 +7,12 @@ LL | println!("Test", 123, 456, 789); | | | argument never used | | argument never used | multiple missing formatting specifiers + | + = note: format specifiers use curly braces: `{}` +help: consider adding 3 format specifiers + | +LL | println!("Test{}{}{}", 123, 456, 789); + | ++++++ error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:6:9 @@ -19,6 +25,12 @@ LL | 456, | ^^^ argument never used LL | 789 | ^^^ argument never used + | + = note: format specifiers use curly braces: `{}` +help: consider adding 3 format specifiers + | +LL | println!("Test2{}{}{}", + | ++++++ error: named argument never used --> $DIR/format-unused-lables.rs:11:35 @@ -27,6 +39,12 @@ LL | println!("Some stuff", UNUSED="args"); | ------------ ^^^^^^ named argument never used | | | formatting specifier missing + | + = note: format specifiers use curly braces: `{}` +help: consider adding format specifier + | +LL | println!("Some stuff{}", UNUSED="args"); + | ++ error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:14:9 diff --git a/tests/ui/mir/unsized-extern-static.stderr b/tests/ui/mir/unsized-extern-static.stderr index 93aed3549d762..005dc59d78f90 100644 --- a/tests/ui/mir/unsized-extern-static.stderr +++ b/tests/ui/mir/unsized-extern-static.stderr @@ -5,6 +5,12 @@ LL | println!("C", unsafe { &symbol }); | --- ^^^^^^^^^^^^^^^^^^ argument never used | | | formatting specifier missing + | + = note: format specifiers use curly braces: `{}` +help: consider adding format specifier + | +LL | println!("C{}", unsafe { &symbol }); + | ++ error[E0277]: the size for values of type `[i8]` cannot be known at compilation time --> $DIR/unsized-extern-static.rs:6:5 diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs index e1f8710db5a33..2f5e962944153 100644 --- a/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs @@ -29,6 +29,7 @@ fn missing_format_specifiers_multiple_unused_args() { //~| NOTE multiple missing formatting specifiers //~| NOTE argument never used //~| NOTE argument never used + //~| NOTE consider adding 2 format specifiers } fn main() { } diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr index 654c8b0712a4f..961887a7e3faa 100644 --- a/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr @@ -35,11 +35,6 @@ LL | println!("list: {}, {}", 1, 2, 3); | -------------- ^ argument never used | | | formatting specifier missing - | -help: consider adding format specifier - | -LL | println!("list: {}, {}{}", 1, 2, 3); - | ++ error: multiple unused formatting arguments --> $DIR/missing-format-specifiers-issue-68293.rs:27:29 @@ -50,10 +45,7 @@ LL | println!("list: {}", 1, 2, 3); | | argument never used | multiple missing formatting specifiers | -help: consider adding 2 format specifiers - | -LL | println!("list: {}{}{}", 1, 2, 3); - | ++++ + = note: consider adding 2 format specifiers error: aborting due to 4 previous errors From 43a6f56ca78295164dbf964695a43be7e35b1994 Mon Sep 17 00:00:00 2001 From: IoaNNUwU Date: Mon, 8 Sep 2025 19:15:35 +0200 Subject: [PATCH 3/3] Apply requested changes --- compiler/rustc_builtin_macros/src/format.rs | 44 +++++++------------ tests/ui/fmt/ifmt-bad-arg.stderr | 6 +-- tests/ui/macros/format-unused-lables.stderr | 9 ++-- tests/ui/mir/unsized-extern-static.stderr | 3 +- .../missing-format-specifiers-issue-68293.rs | 4 +- ...ssing-format-specifiers-issue-68293.stderr | 6 +-- 6 files changed, 25 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index e5f73188dbdfa..a6c8e7d29cc7a 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -768,38 +768,24 @@ fn report_missing_placeholders( // Show example if user didn't use any format specifiers let show_example = used.iter().all(|used| !used); - if !show_example && unused.len()> 1 { - diag.note(format!("consider adding {} format specifiers", unused.len())); - } - - let original_fmt_str = if fmt_str.len()>= 1 { &fmt_str[..fmt_str.len() - 1] } else { "" }; - - if show_example && unused.len() == 1 { - diag.note("format specifiers use curly braces: `{}`"); + if !show_example { + if unused.len()> 1 { + diag.note(format!("consider adding {} format specifiers", unused.len())); + } + } else { + let original_fmt_str = + if fmt_str.len()>= 1 { &fmt_str[..fmt_str.len() - 1] } else { "" }; - diag.span_suggestion_verbose( - fmt_span, - "consider adding format specifier", - format!("\"{}{{}}\"", original_fmt_str), - Applicability::MaybeIncorrect, - ); - } + let msg = if unused.len() == 1 { + "a format specifier".to_string() + } else { + format!("{} format specifiers", unused.len()) + }; - if show_example && unused.len()> 1 { - diag.note("format specifiers use curly braces: `{}`"); + let sugg = format!("\"{}{}\"", original_fmt_str, "{}".repeat(unused.len())); + let msg = format!("format specifiers use curly braces, consider adding {msg}"); - let mut suggest_fixed_fmt = format!("\"{}", original_fmt_str); - for _ in &unused { - suggest_fixed_fmt.push_str("{}"); - } - suggest_fixed_fmt.push('"'); - - diag.span_suggestion_verbose( - fmt_span, - format!("consider adding {} format specifiers", unused.len()), - suggest_fixed_fmt, - Applicability::MaybeIncorrect, - ); + diag.span_suggestion_verbose(fmt_span, msg, sugg, Applicability::MaybeIncorrect); } } diff --git a/tests/ui/fmt/ifmt-bad-arg.stderr b/tests/ui/fmt/ifmt-bad-arg.stderr index 6ddc817290155..b565b836f211e 100644 --- a/tests/ui/fmt/ifmt-bad-arg.stderr +++ b/tests/ui/fmt/ifmt-bad-arg.stderr @@ -63,8 +63,7 @@ LL | format!("", 1, 2); | | argument never used | multiple missing formatting specifiers | - = note: format specifiers use curly braces: `{}` -help: consider adding 2 format specifiers +help: format specifiers use curly braces, consider adding 2 format specifiers | LL | format!("{}{}", 1, 2); | ++++ @@ -109,8 +108,7 @@ LL | format!("", foo=2); | | | formatting specifier missing | - = note: format specifiers use curly braces: `{}` -help: consider adding format specifier +help: format specifiers use curly braces, consider adding a format specifier | LL | format!("{}", foo=2); | ++ diff --git a/tests/ui/macros/format-unused-lables.stderr b/tests/ui/macros/format-unused-lables.stderr index 1c5cdcc2346d4..90eed8dd86b5a 100644 --- a/tests/ui/macros/format-unused-lables.stderr +++ b/tests/ui/macros/format-unused-lables.stderr @@ -8,8 +8,7 @@ LL | println!("Test", 123, 456, 789); | | argument never used | multiple missing formatting specifiers | - = note: format specifiers use curly braces: `{}` -help: consider adding 3 format specifiers +help: format specifiers use curly braces, consider adding 3 format specifiers | LL | println!("Test{}{}{}", 123, 456, 789); | ++++++ @@ -26,8 +25,7 @@ LL | 456, LL | 789 | ^^^ argument never used | - = note: format specifiers use curly braces: `{}` -help: consider adding 3 format specifiers +help: format specifiers use curly braces, consider adding 3 format specifiers | LL | println!("Test2{}{}{}", | ++++++ @@ -40,8 +38,7 @@ LL | println!("Some stuff", UNUSED="args"); | | | formatting specifier missing | - = note: format specifiers use curly braces: `{}` -help: consider adding format specifier +help: format specifiers use curly braces, consider adding a format specifier | LL | println!("Some stuff{}", UNUSED="args"); | ++ diff --git a/tests/ui/mir/unsized-extern-static.stderr b/tests/ui/mir/unsized-extern-static.stderr index 005dc59d78f90..c0810e650ef12 100644 --- a/tests/ui/mir/unsized-extern-static.stderr +++ b/tests/ui/mir/unsized-extern-static.stderr @@ -6,8 +6,7 @@ LL | println!("C", unsafe { &symbol }); | | | formatting specifier missing | - = note: format specifiers use curly braces: `{}` -help: consider adding format specifier +help: format specifiers use curly braces, consider adding a format specifier | LL | println!("C{}", unsafe { &symbol }); | ++ diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs index 2f5e962944153..29799624d7821 100644 --- a/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs @@ -2,18 +2,18 @@ fn no_format_specifier_two_unused_args() { println!("Hello", "World"); //~^ ERROR argument never used //~| NOTE formatting specifier missing - //~| NOTE format specifiers use curly braces: `{}` //~| NOTE argument never used + //~| HELP format specifiers use curly braces, consider adding a format specifier } fn no_format_specifier_multiple_unused_args() { println!("list: ", 1, 2, 3); //~^ ERROR multiple unused formatting arguments //~| NOTE multiple missing formatting specifiers - //~| NOTE format specifiers use curly braces: `{}` //~| NOTE argument never used //~| NOTE argument never used //~| NOTE argument never used + //~| HELP format specifiers use curly braces, consider adding 3 format specifiers } fn missing_format_specifiers_one_unused_arg() { diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr index 961887a7e3faa..081409789f5a4 100644 --- a/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr @@ -6,8 +6,7 @@ LL | println!("Hello", "World"); | | | formatting specifier missing | - = note: format specifiers use curly braces: `{}` -help: consider adding format specifier +help: format specifiers use curly braces, consider adding a format specifier | LL | println!("Hello{}", "World"); | ++ @@ -22,8 +21,7 @@ LL | println!("list: ", 1, 2, 3); | | argument never used | multiple missing formatting specifiers | - = note: format specifiers use curly braces: `{}` -help: consider adding 3 format specifiers +help: format specifiers use curly braces, consider adding 3 format specifiers | LL | println!("list: {}{}{}", 1, 2, 3); | ++++++

AltStyle によって変換されたページ (->オリジナル) /