Skip to content

Commit

Permalink
Rollup merge of #66847 - dtolnay:_fmt, r=joshtriplett
Browse files Browse the repository at this point in the history
Allow any identifier as format arg name

Previously:

```console
error: invalid format string: invalid argument name `_x`
 --> src/main.rs:2:16
  |
2 |     println!("{_x}", _x=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.
  • Loading branch information
dtolnay committed Nov 30, 2019
2 parents 27710d2 + 423a5d3 commit b14d9c2
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 36 deletions.
33 changes: 17 additions & 16 deletions src/libfmt_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions src/test/ui/fmt/format-string-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!("}");
Expand Down
44 changes: 26 additions & 18 deletions src/test/ui/fmt/format-string-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`
error: invalid format string: invalid argument name `_`
--> $DIR/format-string-error.rs:9:23
|
LL | let _ = format!("{_foo}", _foo = 6usize);
| ^^^^ invalid argument name in format string
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:23
--> $DIR/format-string-error.rs:11:25
|
LL | let _ = format!("{_}", _ = 6usize);
| ^ invalid argument name in format string
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 names cannot start with an underscore
= 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
Expand All @@ -43,15 +51,15 @@ 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
|
= 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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -92,26 +100,26 @@ 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
|
= 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
|
= 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

2 changes: 2 additions & 0 deletions src/test/ui/ifmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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 ");
Expand Down

0 comments on commit b14d9c2

Please sign in to comment.