Skip to content

Commit 2aec4e8

Browse files
Rollup merge of rust-lang#52649 - estebank:fmt-span, r=oli-obk
Point spans to inner elements of format strings - Point at missing positional specifiers in string literal ``` error: invalid reference to positional arguments 3, 4 and 5 (there are 3 arguments) --> $DIR/ifmt-bad-arg.rs:34:38 | LL | format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2); | ^^ ^^ ^^ | = note: positional arguments are zero-based ``` - Point at named formatting specifier in string literal ``` error: there is no argument named `foo` --> $DIR/ifmt-bad-arg.rs:37:17 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); | ^^^^^ ``` - Update label for formatting string in "multiple unused formatting arguments" to be more correct ``` error: multiple unused formatting arguments --> $DIR/ifmt-bad-arg.rs:42:17 | LL | format!("", 1, 2); //~ ERROR: multiple unused formatting arguments | -- ^ ^ | | | multiple missing formatting specifiers ``` - When using `printf` string formatting, provide a structured suggestion instead of a note ``` error: multiple unused formatting arguments --> $DIR/format-foreign.rs:12:30 | LL | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments | -------------- ^^^^^^^^ ^^^^^^^ ^ | | | multiple missing formatting specifiers | = note: printf formatting not supported; see the documentation for `std::fmt` help: format specifiers in Rust are written using `{}` | LL | println!("{:.2$} {}!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments | ^^^^^^ ^^ ```
2 parents 662fb06 + 9a893cc commit 2aec4e8

File tree

8 files changed

+494
-116
lines changed

8 files changed

+494
-116
lines changed

src/libfmt_macros/lib.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ pub struct Parser<'a> {
154154
style: Option<usize>,
155155
/// How many newlines have been seen in the string so far, to adjust the error spans
156156
seen_newlines: usize,
157+
/// Start and end byte offset of every successfuly parsed argument
158+
pub arg_places: Vec<(usize, usize)>,
157159
}
158160

159161
impl<'a> Iterator for Parser<'a> {
@@ -168,9 +170,13 @@ impl<'a> Iterator for Parser<'a> {
168170
if self.consume('{') {
169171
Some(String(self.string(pos + 1)))
170172
} else {
171-
let ret = Some(NextArgument(self.argument()));
172-
self.must_consume('}');
173-
ret
173+
let mut arg = self.argument();
174+
if let Some(arg_pos) = self.must_consume('}').map(|end| {
175+
(pos + raw + 1, end + raw + 2)
176+
}) {
177+
self.arg_places.push(arg_pos);
178+
}
179+
Some(NextArgument(arg))
174180
}
175181
}
176182
'}' => {
@@ -211,6 +217,7 @@ impl<'a> Parser<'a> {
211217
curarg: 0,
212218
style,
213219
seen_newlines: 0,
220+
arg_places: vec![],
214221
}
215222
}
216223

@@ -271,20 +278,22 @@ impl<'a> Parser<'a> {
271278

272279
/// Forces consumption of the specified character. If the character is not
273280
/// found, an error is emitted.
274-
fn must_consume(&mut self, c: char) {
281+
fn must_consume(&mut self, c: char) -> Option<usize> {
275282
self.ws();
276283
let raw = self.style.unwrap_or(0);
277284

278285
let padding = raw + self.seen_newlines;
279286
if let Some(&(pos, maybe)) = self.cur.peek() {
280287
if c == maybe {
281288
self.cur.next();
289+
Some(pos)
282290
} else {
283291
let pos = pos + padding + 1;
284292
self.err(format!("expected `{:?}`, found `{:?}`", c, maybe),
285293
format!("expected `{}`", c),
286294
pos,
287295
pos);
296+
None
288297
}
289298
} else {
290299
let msg = format!("expected `{:?}` but string was terminated", c);
@@ -302,6 +311,7 @@ impl<'a> Parser<'a> {
302311
} else {
303312
self.err(msg, format!("expected `{:?}`", c), pos, pos);
304313
}
314+
None
305315
}
306316
}
307317

0 commit comments

Comments
 (0)