about summary refs log tree commit diff
path: root/compiler/rustc_parse_format
diff options
context:
space:
mode:
authorxizheyin <xizheyin@smail.nju.edu.cn>2025-04-25 17:53:40 +0800
committerxizheyin <xizheyin@smail.nju.edu.cn>2025-04-25 19:07:30 +0800
commit64867c68f4eb537215e65268903803f44f1fe6b6 (patch)
tree5b03dbfce6aafbf1522b659fa2532064fcbefd81 /compiler/rustc_parse_format
parent44232a67c320c8df31e2b82ae15d2ec7c83ec759 (diff)
downloadrust-64867c68f4eb537215e65268903803f44f1fe6b6.tar.gz
rust-64867c68f4eb537215e65268903803f44f1fe6b6.zip
Check if format argument is identifier to avoid error err-emit
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
Diffstat (limited to 'compiler/rustc_parse_format')
-rw-r--r--compiler/rustc_parse_format/src/lib.rs135
1 files changed, 90 insertions, 45 deletions
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index c59e6cb5c33..c356a97a55a 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,
+                },
+            );
         }
     }