Allow any identifier as format arg name
Previously: error: invalid format string: invalid argument name `_x` --> src/main.rs:2:16 | 2 | println!("{_x}", a=0); | ^^ invalid argument name in format string | = note: argument names cannot start with an underscore Not supporting identifiers starting with underscore appears to have been an arbitrary limitation from 2013 in code that was most likely never reviewed: https://github.com/rust-lang/rust/pull/8245/files#diff-0347868ef389c805e97636623e4a4ea6R277 The error message was dutifully improved in #50610 but is there any reason that leading underscore would be a special case? This commit updates the format_args parser to accept identifiers with leading underscores.
This commit is contained in:
parent
f453d1127d
commit
423a5d3e85
@ -442,20 +442,9 @@ impl<'a> Parser<'a> {
|
||||
Some(ArgumentIs(i))
|
||||
} else {
|
||||
match self.cur.peek() {
|
||||
Some(&(_, c)) if c.is_alphabetic() => {
|
||||
Some(&(_, c)) if rustc_lexer::is_id_start(c) => {
|
||||
Some(ArgumentNamed(Symbol::intern(self.word())))
|
||||
}
|
||||
Some(&(pos, c)) if c == '_' => {
|
||||
let invalid_name = self.string(pos);
|
||||
self.err_with_note(format!("invalid argument name `{}`", invalid_name),
|
||||
"invalid argument name",
|
||||
"argument names cannot start with an underscore",
|
||||
self.to_span_index(pos).to(
|
||||
self.to_span_index(pos + invalid_name.len())
|
||||
),
|
||||
);
|
||||
Some(ArgumentNamed(Symbol::intern(invalid_name)))
|
||||
},
|
||||
|
||||
// This is an `ArgumentNext`.
|
||||
// Record the fact and do the resolution after parsing the
|
||||
@ -611,22 +600,34 @@ impl<'a> Parser<'a> {
|
||||
/// Rust identifier, except that it can't start with `_` character.
|
||||
fn word(&mut self) -> &'a str {
|
||||
let start = match self.cur.peek() {
|
||||
Some(&(pos, c)) if c != '_' && rustc_lexer::is_id_start(c) => {
|
||||
Some(&(pos, c)) if rustc_lexer::is_id_start(c) => {
|
||||
self.cur.next();
|
||||
pos
|
||||
}
|
||||
_ => {
|
||||
return &self.input[..0];
|
||||
return "";
|
||||
}
|
||||
};
|
||||
let mut end = None;
|
||||
while let Some(&(pos, c)) = self.cur.peek() {
|
||||
if rustc_lexer::is_id_continue(c) {
|
||||
self.cur.next();
|
||||
} else {
|
||||
return &self.input[start..pos];
|
||||
end = Some(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
&self.input[start..self.input.len()]
|
||||
let end = end.unwrap_or(self.input.len());
|
||||
let word = &self.input[start..end];
|
||||
if word == "_" {
|
||||
self.err_with_note(
|
||||
"invalid argument name `_`",
|
||||
"invalid argument name",
|
||||
"argument name cannot be a single underscore",
|
||||
self.to_span_index(start).to(self.to_span_index(end)),
|
||||
);
|
||||
}
|
||||
word
|
||||
}
|
||||
|
||||
/// Optionally parses an integer at the current position. This doesn't deal
|
||||
|
@ -6,10 +6,12 @@ fn main() {
|
||||
println!("{{}}");
|
||||
println!("}");
|
||||
//~^ ERROR invalid format string: unmatched `}` found
|
||||
let _ = format!("{_foo}", _foo = 6usize);
|
||||
//~^ ERROR invalid format string: invalid argument name `_foo`
|
||||
let _ = format!("{_}", _ = 6usize);
|
||||
//~^ ERROR invalid format string: invalid argument name `_`
|
||||
let _ = format!("{a:_}", a = "", _ = 0);
|
||||
//~^ ERROR invalid format string: invalid argument name `_`
|
||||
let _ = format!("{a:._$}", a = "", _ = 0);
|
||||
//~^ ERROR invalid format string: invalid argument name `_`
|
||||
let _ = format!("{");
|
||||
//~^ ERROR invalid format string: expected `'}'` but string was terminated
|
||||
let _ = format!("}");
|
||||
|
@ -16,24 +16,32 @@ LL | println!("}");
|
||||
|
|
||||
= note: if you intended to print `}`, you can escape it using `}}`
|
||||
|
||||
error: invalid format string: invalid argument name `_foo`
|
||||
--> $DIR/format-string-error.rs:9:23
|
||||
|
|
||||
LL | let _ = format!("{_foo}", _foo = 6usize);
|
||||
| ^^^^ invalid argument name in format string
|
||||
|
|
||||
= note: argument names cannot start with an underscore
|
||||
|
||||
error: invalid format string: invalid argument name `_`
|
||||
--> $DIR/format-string-error.rs:11:23
|
||||
--> $DIR/format-string-error.rs:9:23
|
||||
|
|
||||
LL | let _ = format!("{_}", _ = 6usize);
|
||||
| ^ invalid argument name in format string
|
||||
|
|
||||
= note: argument names cannot start with an underscore
|
||||
= note: argument name cannot be a single underscore
|
||||
|
||||
error: invalid format string: invalid argument name `_`
|
||||
--> $DIR/format-string-error.rs:11:25
|
||||
|
|
||||
LL | let _ = format!("{a:_}", a = "", _ = 0);
|
||||
| ^ invalid argument name in format string
|
||||
|
|
||||
= note: argument name cannot be a single underscore
|
||||
|
||||
error: invalid format string: invalid argument name `_`
|
||||
--> $DIR/format-string-error.rs:13:26
|
||||
|
|
||||
LL | let _ = format!("{a:._$}", a = "", _ = 0);
|
||||
| ^ invalid argument name in format string
|
||||
|
|
||||
= note: argument name cannot be a single underscore
|
||||
|
||||
error: invalid format string: expected `'}'` but string was terminated
|
||||
--> $DIR/format-string-error.rs:13:23
|
||||
--> $DIR/format-string-error.rs:15:23
|
||||
|
|
||||
LL | let _ = format!("{");
|
||||
| -^ expected `'}'` in format string
|
||||
@ -43,7 +51,7 @@ LL | let _ = format!("{");
|
||||
= note: if you intended to print `{`, you can escape it using `{{`
|
||||
|
||||
error: invalid format string: unmatched `}` found
|
||||
--> $DIR/format-string-error.rs:15:22
|
||||
--> $DIR/format-string-error.rs:17:22
|
||||
|
|
||||
LL | let _ = format!("}");
|
||||
| ^ unmatched `}` in format string
|
||||
@ -51,7 +59,7 @@ LL | let _ = format!("}");
|
||||
= note: if you intended to print `}`, you can escape it using `}}`
|
||||
|
||||
error: invalid format string: expected `'}'`, found `'\'`
|
||||
--> $DIR/format-string-error.rs:17:23
|
||||
--> $DIR/format-string-error.rs:19:23
|
||||
|
|
||||
LL | let _ = format!("{\}");
|
||||
| -^ expected `}` in format string
|
||||
@ -61,7 +69,7 @@ LL | let _ = format!("{\}");
|
||||
= note: if you intended to print `{`, you can escape it using `{{`
|
||||
|
||||
error: invalid format string: expected `'}'` but string was terminated
|
||||
--> $DIR/format-string-error.rs:19:35
|
||||
--> $DIR/format-string-error.rs:21:35
|
||||
|
|
||||
LL | let _ = format!("\n\n\n{\n\n\n");
|
||||
| - ^ expected `'}'` in format string
|
||||
@ -71,7 +79,7 @@ LL | let _ = format!("\n\n\n{\n\n\n");
|
||||
= note: if you intended to print `{`, you can escape it using `{{`
|
||||
|
||||
error: invalid format string: expected `'}'` but string was terminated
|
||||
--> $DIR/format-string-error.rs:25:3
|
||||
--> $DIR/format-string-error.rs:27:3
|
||||
|
|
||||
LL | {"###);
|
||||
| -^ expected `'}'` in format string
|
||||
@ -81,7 +89,7 @@ LL | {"###);
|
||||
= note: if you intended to print `{`, you can escape it using `{{`
|
||||
|
||||
error: invalid format string: expected `'}'` but string was terminated
|
||||
--> $DIR/format-string-error.rs:33:1
|
||||
--> $DIR/format-string-error.rs:35:1
|
||||
|
|
||||
LL | {
|
||||
| - because of this opening brace
|
||||
@ -92,7 +100,7 @@ LL | "###);
|
||||
= note: if you intended to print `{`, you can escape it using `{{`
|
||||
|
||||
error: invalid format string: unmatched `}` found
|
||||
--> $DIR/format-string-error.rs:39:2
|
||||
--> $DIR/format-string-error.rs:41:2
|
||||
|
|
||||
LL | }
|
||||
| ^ unmatched `}` in format string
|
||||
@ -100,7 +108,7 @@ LL | }
|
||||
= note: if you intended to print `}`, you can escape it using `}}`
|
||||
|
||||
error: invalid format string: unmatched `}` found
|
||||
--> $DIR/format-string-error.rs:47:9
|
||||
--> $DIR/format-string-error.rs:49:9
|
||||
|
|
||||
LL | }
|
||||
| ^ unmatched `}` in format string
|
||||
@ -108,10 +116,10 @@ LL | }
|
||||
= note: if you intended to print `}`, you can escape it using `}}`
|
||||
|
||||
error: 3 positional arguments in format string, but there are 2 arguments
|
||||
--> $DIR/format-string-error.rs:51:15
|
||||
--> $DIR/format-string-error.rs:53:15
|
||||
|
|
||||
LL | println!("{} {} {}", 1, 2);
|
||||
| ^^ ^^ ^^ - -
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
@ -90,6 +90,7 @@ pub fn main() {
|
||||
t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
|
||||
t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
|
||||
t!(format!("{} {0}", "a"), "a a");
|
||||
t!(format!("{_foo}", _foo = 6usize), "6");
|
||||
t!(format!("{foo_bar}", foo_bar=1), "1");
|
||||
t!(format!("{}", 5 + 5), "10");
|
||||
t!(format!("{:#4}", C), "☃123");
|
||||
@ -125,6 +126,7 @@ pub fn main() {
|
||||
t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
|
||||
t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
|
||||
t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa");
|
||||
t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a=4), "aaaa");
|
||||
t!(format!("{:1$}", "a", 4), "a ");
|
||||
t!(format!("{1:0$}", 4, "a"), "a ");
|
||||
t!(format!("{:a$}", "a", a=4), "a ");
|
||||
|
Loading…
x
Reference in New Issue
Block a user