diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-11-05 11:55:00 -0800 | 
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-11-05 14:06:38 -0800 | 
| commit | 08b235b5bed1a53311da34fa12966cd42a2a5abe (patch) | |
| tree | 2cbd042c2d9d566b1bc6d62d7b5d02e255d21b17 | |
| parent | 3a1b3b30c6cdd674049b144a3ced7b711de962b2 (diff) | |
| download | rust-08b235b5bed1a53311da34fa12966cd42a2a5abe.tar.gz rust-08b235b5bed1a53311da34fa12966cd42a2a5abe.zip  | |
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
```
| -rw-r--r-- | src/libfmt_macros/lib.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax_ext/format.rs | 67 | ||||
| -rw-r--r-- | src/test/ui/if/ifmt-bad-arg.stderr | 4 | ||||
| -rw-r--r-- | src/test/ui/if/ifmt-unknown-trait.stderr | 4 | 
4 files changed, 47 insertions, 37 deletions
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index d22420e76dc..3896612ea03 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -74,6 +74,8 @@ pub struct FormatSpec<'a> { /// this argument, this can be empty or any number of characters, although /// it is required to be one word. pub ty: &'a str, + /// The span of the descriptor string (for diagnostics). + pub ty_span: Option<InnerSpan>, } /// Enum describing where an argument for a format can be located. @@ -475,6 +477,7 @@ impl<'a> Parser<'a> { width: CountImplied, width_span: None, ty: &self.input[..0], + ty_span: None, }; if !self.consume(':') { return spec; @@ -548,6 +551,7 @@ impl<'a> Parser<'a> { spec.precision_span = sp; } } + let ty_span_start = self.cur.peek().map(|(pos, _)| *pos); // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { @@ -567,6 +571,11 @@ impl<'a> Parser<'a> { spec.ty = "?"; } else { spec.ty = self.word(); + let ty_span_end = self.cur.peek().map(|(pos, _)| *pos); + let this = self; + spec.ty_span = ty_span_start + .and_then(|s| ty_span_end.map(|e| (s, e))) + .map(|(start, end)| this.to_span_index(start).to(this.to_span_index(end))); } spec } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 37310f46f7e..b8d053a2162 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -21,7 +21,7 @@ use std::collections::hash_map::Entry; #[derive(PartialEq)] enum ArgumentType { - Placeholder(String), + Placeholder(&'static str), Count, } @@ -244,7 +244,36 @@ impl<'a, 'b> Context<'a, 'b> { parse::ArgumentNamed(s) => Named(s), }; - let ty = Placeholder(arg.format.ty.to_string()); + let ty = Placeholder(match &arg.format.ty[..] { + "" => "Display", + "?" => "Debug", + "e" => "LowerExp", + "E" => "UpperExp", + "o" => "Octal", + "p" => "Pointer", + "b" => "Binary", + "x" => "LowerHex", + "X" => "UpperHex", + _ => { + let fmtsp = self.fmtsp; + let mut err = self.ecx.struct_span_err( + arg.format.ty_span.map(|sp| fmtsp.from_inner(sp)).unwrap_or(fmtsp), + &format!("unknown format trait `{}`", arg.format.ty), + ); + err.note("the only appropriate formatting traits are:\n\ + - ``, which uses the `Display` trait\n\ + - `?`, which uses the `Debug` trait\n\ + - `e`, which uses the `LowerExp` trait\n\ + - `E`, which uses the `UpperExp` trait\n\ + - `o`, which uses the `Octal` trait\n\ + - `p`, which uses the `Pointer` trait\n\ + - `b`, which uses the `Binary` trait\n\ + - `x`, which uses the `LowerHex` trait\n\ + - `X`, which uses the `UpperHex` trait"); + err.emit(); + "<invalid>" + } + }); self.verify_arg_type(pos, ty); self.curpiece += 1; } @@ -588,6 +617,7 @@ impl<'a, 'b> Context<'a, 'b> { width: parse::CountImplied, width_span: None, ty: arg.format.ty, + ty_span: arg.format.ty_span, }, }; @@ -759,37 +789,8 @@ impl<'a, 'b> Context<'a, 'b> { sp = ecx.with_def_site_ctxt(sp); let arg = ecx.expr_ident(sp, arg); let trait_ = match *ty { - Placeholder(ref tyname) => { - match &tyname[..] { - "" => "Display", - "?" => "Debug", - "e" => "LowerExp", - "E" => "UpperExp", - "o" => "Octal", - "p" => "Pointer", - "b" => "Binary", - "x" => "LowerHex", - "X" => "UpperHex", - _ => { - let mut err = ecx.struct_span_err( - sp, - &format!("unknown format trait `{}`", *tyname), - ); - err.note("the only appropriate formatting traits are:\n\ - - ``, which uses the `Display` trait\n\ - - `?`, which uses the `Debug` trait\n\ - - `e`, which uses the `LowerExp` trait\n\ - - `E`, which uses the `UpperExp` trait\n\ - - `o`, which uses the `Octal` trait\n\ - - `p`, which uses the `Pointer` trait\n\ - - `b`, which uses the `Binary` trait\n\ - - `x`, which uses the `LowerHex` trait\n\ - - `X`, which uses the `UpperHex` trait"); - err.emit(); - return DummyResult::raw_expr(sp, true); - } - } - } + Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true), + Placeholder(trait_) => trait_, Count => { let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]); return ecx.expr_call_global(macsp, path, vec![arg]); diff --git a/src/test/ui/if/ifmt-bad-arg.stderr b/src/test/ui/if/ifmt-bad-arg.stderr index c58cbc31233..7a76f0e7c47 100644 --- a/src/test/ui/if/ifmt-bad-arg.stderr +++ b/src/test/ui/if/ifmt-bad-arg.stderr @@ -257,10 +257,10 @@ LL | println!("{} {:07$} {}", 1, 3.2, 4); = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html error: unknown format trait `foo` - --> $DIR/ifmt-bad-arg.rs:86:24 + --> $DIR/ifmt-bad-arg.rs:86:17 | LL | println!("{:foo}", 1); - | ^ + | ^^^ | = note: the only appropriate formatting traits are: - ``, which uses the `Display` trait diff --git a/src/test/ui/if/ifmt-unknown-trait.stderr b/src/test/ui/if/ifmt-unknown-trait.stderr index 7853b5ca0c9..459432bf4e4 100644 --- a/src/test/ui/if/ifmt-unknown-trait.stderr +++ b/src/test/ui/if/ifmt-unknown-trait.stderr @@ -1,8 +1,8 @@ error: unknown format trait `notimplemented` - --> $DIR/ifmt-unknown-trait.rs:2:34 + --> $DIR/ifmt-unknown-trait.rs:2:16 | LL | format!("{:notimplemented}", "3"); - | ^^^ + | ^^^^^^^^^^^^^^ | = note: the only appropriate formatting traits are: - ``, which uses the `Display` trait  | 
