From 44232a67c320c8df31e2b82ae15d2ec7c83ec759 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 25 Apr 2025 17:43:12 +0800 Subject: [PATCH 1/3] Add ui test parser/issues/invalid-parse-format-issue-139104.rs Signed-off-by: xizheyin --- .../invalid-parse-format-issue-139104.rs | 8 +++ .../invalid-parse-format-issue-139104.stderr | 66 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/ui/parser/issues/invalid-parse-format-issue-139104.rs create mode 100644 tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs new file mode 100644 index 0000000000000..40af62623560a --- /dev/null +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -0,0 +1,8 @@ +fn main() { + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported + println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("xxx{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` +} diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr new file mode 100644 index 0000000000000..d0a8d0998a48a --- /dev/null +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -0,0 +1,66 @@ +error: invalid format string: tuple index access isn't supported + --> $DIR/invalid-parse-format-issue-139104.rs:2:16 + | +LL | println!("{foo:_1.4}", foo = 3.14); + | ^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL - println!("{foo:_1.4}", foo = 3.14); +LL + println!("{0}", foo:_1.4, foo = 3.14); + | + +error: invalid format string: tuple index access isn't supported + --> $DIR/invalid-parse-format-issue-139104.rs:3:16 + | +LL | println!("{foo:1.4_1.4}", foo = 3.14); + | ^^^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL - println!("{foo:1.4_1.4}", foo = 3.14); +LL + println!("{0}", foo:1.4_1.4, foo = 3.14); + | + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:4:23 + | +LL | println!("xxx{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:5:22 + | +LL | println!("{foo:_1.4", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:6:23 + | +LL | println!("xxx{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `0` + --> $DIR/invalid-parse-format-issue-139104.rs:7:21 + | +LL | println!("xxx{ 0", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: aborting due to 6 previous errors + From 64867c68f4eb537215e65268903803f44f1fe6b6 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 25 Apr 2025 17:53:40 +0800 Subject: [PATCH 2/3] Check if format argument is identifier to avoid error err-emit Signed-off-by: xizheyin --- compiler/rustc_parse_format/src/lib.rs | 135 ++++++++++++------ .../invalid-parse-format-issue-139104.rs | 10 +- .../invalid-parse-format-issue-139104.stderr | 52 ++----- 3 files changed, 109 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index c59e6cb5c33f7..c356a97a55a26 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -100,6 +100,30 @@ pub struct Argument<'a> { pub format: FormatSpec<'a>, } +impl<'a> Argument<'a> { + pub fn is_identifier(&self) -> bool { + matches!(self.position, Position::ArgumentNamed(_)) + && matches!( + self.format, + FormatSpec { + fill: None, + fill_span: None, + align: AlignUnknown, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, + precision: CountImplied, + precision_span: None, + width: CountImplied, + width_span: None, + ty: "", + ty_span: None, + }, + ) + } +} + /// Specification for the formatting of an argument in the format string. #[derive(Copy, Clone, Debug, PartialEq)] pub struct FormatSpec<'a> { @@ -894,52 +918,73 @@ impl<'a> Parser<'a> { } fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { - if let Some(end) = self.consume_pos('.') { - let byte_pos = self.to_span_index(end); - let start = InnerOffset(byte_pos.0 + 1); - let field = self.argument(start); - // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any - // deeper nesting, or another type of expression, like method calls, are not supported - if !self.consume('}') { - return; - } - if let ArgumentNamed(_) = arg.position { - match field.position { - ArgumentNamed(_) => { - self.errors.insert( - 0, - ParseError { - description: "field access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - ArgumentIs(_) => { - self.errors.insert( - 0, - ParseError { - description: "tuple index access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - _ => {} - }; + // If the argument is an identifier, it may be a field access. + if arg.is_identifier() { + if let Some(end) = self.consume_pos('.') { + let byte_pos = self.to_span_index(end); + let start = InnerOffset(byte_pos.0 + 1); + let field = self.argument(start); + // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any + // deeper nesting, or another type of expression, like method calls, are not supported + if !self.consume('}') { + return; + } + if let ArgumentNamed(_) = arg.position { + match field.position { + ArgumentNamed(_) => { + self.errors.insert( + 0, + ParseError { + description: "field access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + ArgumentIs(_) => { + self.errors.insert( + 0, + ParseError { + description: "tuple index access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + _ => {} + }; + } } + } else if matches!(arg.position, ArgumentNamed(_) | ArgumentIs(_)) { + let arg_name = match arg.position { + ArgumentNamed(arg_name) => &format!("`{arg_name}`"), + ArgumentIs(arg_index) => &format!("at index `{arg_index}`"), + _ => unreachable!(), + }; + + self.errors.insert( + 0, + ParseError { + description: format!("invalid format string for argument {}", arg_name), + note: None, + label: format!("invalid format specifier for this argument"), + span: InnerSpan::new(arg.position_span.start, arg.position_span.end), + secondary_label: None, + suggestion: Suggestion::None, + }, + ); } } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs index 40af62623560a..0809235bb6dd3 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -1,8 +1,8 @@ fn main() { - println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported - println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: tuple index access isn't supported - println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` - println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` - println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` + println!("xxx{0:_1.4}", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` + println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` println!("xxx{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr index d0a8d0998a48a..ceae8d051e5e2 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -1,56 +1,32 @@ -error: invalid format string: tuple index access isn't supported +error: invalid format string: invalid format string for argument `foo` --> $DIR/invalid-parse-format-issue-139104.rs:2:16 | LL | println!("{foo:_1.4}", foo = 3.14); - | ^^^^^^^^ not supported in format string - | -help: consider using a positional formatting argument instead - | -LL - println!("{foo:_1.4}", foo = 3.14); -LL + println!("{0}", foo:_1.4, foo = 3.14); - | + | ^^^ invalid format specifier for this argument in format string -error: invalid format string: tuple index access isn't supported +error: invalid format string: invalid format string for argument `foo` --> $DIR/invalid-parse-format-issue-139104.rs:3:16 | LL | println!("{foo:1.4_1.4}", foo = 3.14); - | ^^^^^^^^^^^ not supported in format string - | -help: consider using a positional formatting argument instead - | -LL - println!("{foo:1.4_1.4}", foo = 3.14); -LL + println!("{0}", foo:1.4_1.4, foo = 3.14); - | + | ^^^ invalid format specifier for this argument in format string -error: invalid format string: expected `}`, found `.` - --> $DIR/invalid-parse-format-issue-139104.rs:4:23 +error: invalid format string: invalid format string for argument at index `0` + --> $DIR/invalid-parse-format-issue-139104.rs:4:19 | -LL | println!("xxx{0:_1.4", 1.11); - | - ^ expected `}` in format string - | | - | because of this opening brace - | - = note: if you intended to print `{`, you can escape it using `{{` +LL | println!("xxx{0:_1.4}", 1.11); + | ^ invalid format specifier for this argument in format string -error: invalid format string: expected `}`, found `.` - --> $DIR/invalid-parse-format-issue-139104.rs:5:22 +error: invalid format string: invalid format string for argument `foo` + --> $DIR/invalid-parse-format-issue-139104.rs:5:16 | LL | println!("{foo:_1.4", foo = 3.14); - | - ^ expected `}` in format string - | | - | because of this opening brace - | - = note: if you intended to print `{`, you can escape it using `{{` + | ^^^ invalid format specifier for this argument in format string -error: invalid format string: expected `}`, found `.` - --> $DIR/invalid-parse-format-issue-139104.rs:6:23 +error: invalid format string: invalid format string for argument at index `0` + --> $DIR/invalid-parse-format-issue-139104.rs:6:19 | LL | println!("xxx{0:_1.4", 1.11); - | - ^ expected `}` in format string - | | - | because of this opening brace - | - = note: if you intended to print `{`, you can escape it using `{{` + | ^ invalid format specifier for this argument in format string error: invalid format string: expected `}`, found `0` --> $DIR/invalid-parse-format-issue-139104.rs:7:21 From 873ca5fa04b79da80ca779e0e577f06a07cea8d3 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 2 May 2025 22:34:30 +0800 Subject: [PATCH 3/3] Just suggest positional arg and adjust issue0139104 ui test Signed-off-by: xizheyin --- compiler/rustc_parse_format/src/lib.rs | 116 ++++++++---------- .../invalid-parse-format-issue-139104.rs | 17 ++- .../invalid-parse-format-issue-139104.stderr | 96 +++++++++++---- 3 files changed, 134 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index c356a97a55a26..999e715927456 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -918,73 +918,57 @@ impl<'a> Parser<'a> { } fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { - // If the argument is an identifier, it may be a field access. - if arg.is_identifier() { - if let Some(end) = self.consume_pos('.') { - let byte_pos = self.to_span_index(end); - let start = InnerOffset(byte_pos.0 + 1); - let field = self.argument(start); - // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any - // deeper nesting, or another type of expression, like method calls, are not supported - if !self.consume('}') { - return; - } - if let ArgumentNamed(_) = arg.position { - match field.position { - ArgumentNamed(_) => { - self.errors.insert( - 0, - ParseError { - description: "field access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - ArgumentIs(_) => { - self.errors.insert( - 0, - ParseError { - description: "tuple index access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } - _ => {} - }; - } - } - } else if matches!(arg.position, ArgumentNamed(_) | ArgumentIs(_)) { - let arg_name = match arg.position { - ArgumentNamed(arg_name) => &format!("`{arg_name}`"), - ArgumentIs(arg_index) => &format!("at index `{arg_index}`"), - _ => unreachable!(), - }; + // If the argument is not an identifier, it is not a field access. + if !arg.is_identifier() { + return; + } - self.errors.insert( - 0, - ParseError { - description: format!("invalid format string for argument {}", arg_name), - note: None, - label: format!("invalid format specifier for this argument"), - span: InnerSpan::new(arg.position_span.start, arg.position_span.end), - secondary_label: None, - suggestion: Suggestion::None, - }, - ); + if let Some(end) = self.consume_pos('.') { + let byte_pos = self.to_span_index(end); + let start = InnerOffset(byte_pos.0 + 1); + let field = self.argument(start); + // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any + // deeper nesting, or another type of expression, like method calls, are not supported + if !self.consume('}') { + return; + } + if let ArgumentNamed(_) = arg.position { + match field.position { + ArgumentNamed(_) => { + self.errors.insert( + 0, + ParseError { + description: "field access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + ArgumentIs(_) => { + self.errors.insert( + 0, + ParseError { + description: "tuple index access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + _ => {} + }; + } } } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs index 0809235bb6dd3..7644df8be49a0 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -1,8 +1,13 @@ fn main() { - println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` - println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` - println!("xxx{0:_1.4}", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` - println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: invalid format string for argument `foo` - println!("xxx{0:_1.4", 1.11); //~ ERROR invalid format string: invalid format string for argument at index `0` - println!("xxx{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:_1.4}", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{:_1.4}", 3.14); //~ ERROR invalid format string: expected `}`, found `.` + + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{:_1.4", 3.14); //~ ERROR invalid format string: expected `}`, found `.` + + println!("{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:1.4_1.4}", 3.14); //~ ERROR invalid format string: expected `}`, found `.` } diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr index ceae8d051e5e2..202aa450cab71 100644 --- a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -1,42 +1,92 @@ -error: invalid format string: invalid format string for argument `foo` - --> $DIR/invalid-parse-format-issue-139104.rs:2:16 +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:2:22 | LL | println!("{foo:_1.4}", foo = 3.14); - | ^^^ invalid format specifier for this argument in format string + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: invalid format string for argument `foo` - --> $DIR/invalid-parse-format-issue-139104.rs:3:16 +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:3:20 | -LL | println!("{foo:1.4_1.4}", foo = 3.14); - | ^^^ invalid format specifier for this argument in format string +LL | println!("{0:_1.4}", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: invalid format string for argument at index `0` +error: invalid format string: expected `}`, found `.` --> $DIR/invalid-parse-format-issue-139104.rs:4:19 | -LL | println!("xxx{0:_1.4}", 1.11); - | ^ invalid format specifier for this argument in format string +LL | println!("{:_1.4}", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: invalid format string for argument `foo` - --> $DIR/invalid-parse-format-issue-139104.rs:5:16 +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:6:22 | LL | println!("{foo:_1.4", foo = 3.14); - | ^^^ invalid format specifier for this argument in format string + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:7:20 + | +LL | println!("{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` -error: invalid format string: invalid format string for argument at index `0` - --> $DIR/invalid-parse-format-issue-139104.rs:6:19 +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:8:19 + | +LL | println!("{:_1.4", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace | -LL | println!("xxx{0:_1.4", 1.11); - | ^ invalid format specifier for this argument in format string + = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `}`, found `0` - --> $DIR/invalid-parse-format-issue-139104.rs:7:21 + --> $DIR/invalid-parse-format-issue-139104.rs:10:18 + | +LL | println!("{ 0", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:11:25 + | +LL | println!("{foo:1.4_1.4}", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:12:23 | -LL | println!("xxx{ 0", 1.11); - | - ^ expected `}` in format string - | | - | because of this opening brace +LL | println!("{0:1.4_1.4}", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` -error: aborting due to 6 previous errors +error: aborting due to 9 previous errors