Skip to content

Commit 08b235b

Browse files
committed
Point at formatting descriptor string when it is invalid
When a formatting string contains an invalid descriptor, point at it instead of the argument: ``` error: unknown format trait `foo` --> $DIR/ifmt-bad-arg.rs:86:17 | LL | println!("{:foo}", 1); | ^^^ | = note: the only appropriate formatting traits are: - ``, which uses the `Display` trait - `?`, which uses the `Debug` trait - `e`, which uses the `LowerExp` trait - `E`, which uses the `UpperExp` trait - `o`, which uses the `Octal` trait - `p`, which uses the `Pointer` trait - `b`, which uses the `Binary` trait - `x`, which uses the `LowerHex` trait - `X`, which uses the `UpperHex` trait ```
1 parent 3a1b3b3 commit 08b235b

File tree

4 files changed

+47
-37
lines changed

4 files changed

+47
-37
lines changed

src/libfmt_macros/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub struct FormatSpec<'a> {
7474
/// this argument, this can be empty or any number of characters, although
7575
/// it is required to be one word.
7676
pub ty: &'a str,
77+
/// The span of the descriptor string (for diagnostics).
78+
pub ty_span: Option<InnerSpan>,
7779
}
7880

7981
/// Enum describing where an argument for a format can be located.
@@ -475,6 +477,7 @@ impl<'a> Parser<'a> {
475477
width: CountImplied,
476478
width_span: None,
477479
ty: &self.input[..0],
480+
ty_span: None,
478481
};
479482
if !self.consume(':') {
480483
return spec;
@@ -548,6 +551,7 @@ impl<'a> Parser<'a> {
548551
spec.precision_span = sp;
549552
}
550553
}
554+
let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
551555
// Optional radix followed by the actual format specifier
552556
if self.consume('x') {
553557
if self.consume('?') {
@@ -567,6 +571,11 @@ impl<'a> Parser<'a> {
567571
spec.ty = "?";
568572
} else {
569573
spec.ty = self.word();
574+
let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
575+
let this = self;
576+
spec.ty_span = ty_span_start
577+
.and_then(|s| ty_span_end.map(|e| (s, e)))
578+
.map(|(start, end)| this.to_span_index(start).to(this.to_span_index(end)));
570579
}
571580
spec
572581
}

src/libsyntax_ext/format.rs

+34-33
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::collections::hash_map::Entry;
2121

2222
#[derive(PartialEq)]
2323
enum ArgumentType {
24-
Placeholder(String),
24+
Placeholder(&'static str),
2525
Count,
2626
}
2727

@@ -244,7 +244,36 @@ impl<'a, 'b> Context<'a, 'b> {
244244
parse::ArgumentNamed(s) => Named(s),
245245
};
246246

247-
let ty = Placeholder(arg.format.ty.to_string());
247+
let ty = Placeholder(match &arg.format.ty[..] {
248+
"" => "Display",
249+
"?" => "Debug",
250+
"e" => "LowerExp",
251+
"E" => "UpperExp",
252+
"o" => "Octal",
253+
"p" => "Pointer",
254+
"b" => "Binary",
255+
"x" => "LowerHex",
256+
"X" => "UpperHex",
257+
_ => {
258+
let fmtsp = self.fmtsp;
259+
let mut err = self.ecx.struct_span_err(
260+
arg.format.ty_span.map(|sp| fmtsp.from_inner(sp)).unwrap_or(fmtsp),
261+
&format!("unknown format trait `{}`", arg.format.ty),
262+
);
263+
err.note("the only appropriate formatting traits are:\n\
264+
- ``, which uses the `Display` trait\n\
265+
- `?`, which uses the `Debug` trait\n\
266+
- `e`, which uses the `LowerExp` trait\n\
267+
- `E`, which uses the `UpperExp` trait\n\
268+
- `o`, which uses the `Octal` trait\n\
269+
- `p`, which uses the `Pointer` trait\n\
270+
- `b`, which uses the `Binary` trait\n\
271+
- `x`, which uses the `LowerHex` trait\n\
272+
- `X`, which uses the `UpperHex` trait");
273+
err.emit();
274+
"<invalid>"
275+
}
276+
});
248277
self.verify_arg_type(pos, ty);
249278
self.curpiece += 1;
250279
}
@@ -588,6 +617,7 @@ impl<'a, 'b> Context<'a, 'b> {
588617
width: parse::CountImplied,
589618
width_span: None,
590619
ty: arg.format.ty,
620+
ty_span: arg.format.ty_span,
591621
},
592622
};
593623

@@ -759,37 +789,8 @@ impl<'a, 'b> Context<'a, 'b> {
759789
sp = ecx.with_def_site_ctxt(sp);
760790
let arg = ecx.expr_ident(sp, arg);
761791
let trait_ = match *ty {
762-
Placeholder(ref tyname) => {
763-
match &tyname[..] {
764-
"" => "Display",
765-
"?" => "Debug",
766-
"e" => "LowerExp",
767-
"E" => "UpperExp",
768-
"o" => "Octal",
769-
"p" => "Pointer",
770-
"b" => "Binary",
771-
"x" => "LowerHex",
772-
"X" => "UpperHex",
773-
_ => {
774-
let mut err = ecx.struct_span_err(
775-
sp,
776-
&format!("unknown format trait `{}`", *tyname),
777-
);
778-
err.note("the only appropriate formatting traits are:\n\
779-
- ``, which uses the `Display` trait\n\
780-
- `?`, which uses the `Debug` trait\n\
781-
- `e`, which uses the `LowerExp` trait\n\
782-
- `E`, which uses the `UpperExp` trait\n\
783-
- `o`, which uses the `Octal` trait\n\
784-
- `p`, which uses the `Pointer` trait\n\
785-
- `b`, which uses the `Binary` trait\n\
786-
- `x`, which uses the `LowerHex` trait\n\
787-
- `X`, which uses the `UpperHex` trait");
788-
err.emit();
789-
return DummyResult::raw_expr(sp, true);
790-
}
791-
}
792-
}
792+
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
793+
Placeholder(trait_) => trait_,
793794
Count => {
794795
let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
795796
return ecx.expr_call_global(macsp, path, vec![arg]);

src/test/ui/if/ifmt-bad-arg.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,10 @@ LL | println!("{} {:07$} {}", 1, 3.2, 4);
257257
= note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
258258

259259
error: unknown format trait `foo`
260-
--> $DIR/ifmt-bad-arg.rs:86:24
260+
--> $DIR/ifmt-bad-arg.rs:86:17
261261
|
262262
LL | println!("{:foo}", 1);
263-
| ^
263+
| ^^^
264264
|
265265
= note: the only appropriate formatting traits are:
266266
- ``, which uses the `Display` trait

src/test/ui/if/ifmt-unknown-trait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: unknown format trait `notimplemented`
2-
--> $DIR/ifmt-unknown-trait.rs:2:34
2+
--> $DIR/ifmt-unknown-trait.rs:2:16
33
|
44
LL | format!("{:notimplemented}", "3");
5-
| ^^^
5+
| ^^^^^^^^^^^^^^
66
|
77
= note: the only appropriate formatting traits are:
88
- ``, which uses the `Display` trait

0 commit comments

Comments
 (0)