about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@commure.com>2018-07-23 00:01:17 -0700
committerEsteban Küber <esteban@commure.com>2018-07-23 08:22:20 -0700
commit42306591b9c0a280da363c83df16b47ad8b04024 (patch)
treefae5b7d860f42b6a3422f8387c67d33125bd8de1
parent38abca8c2d7de08861cd61bc439efdb7cf4de398 (diff)
downloadrust-42306591b9c0a280da363c83df16b47ad8b04024.tar.gz
rust-42306591b9c0a280da363c83df16b47ad8b04024.zip
Point at incorrect named arg in format string
-rw-r--r--src/libsyntax_ext/format.rs21
-rw-r--r--src/test/ui/ifmt-bad-arg.stderr16
2 files changed, 27 insertions, 10 deletions
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 4700f814e58..215e4f5a835 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -111,8 +111,10 @@ struct Context<'a, 'b: 'a> {
     /// still existed in this phase of processing.
     /// Used only for `all_pieces_simple` tracking in `build_piece`.
     curarg: usize,
+    curpiece: usize,
     /// Keep track of invalid references to positional arguments
     invalid_refs: Vec<usize>,
+    arg_spans: Vec<Span>,
 }
 
 /// Parses the arguments from the given list of tokens, returning None
@@ -235,6 +237,7 @@ impl<'a, 'b> Context<'a, 'b> {
 
                 let ty = Placeholder(arg.format.ty.to_string());
                 self.verify_arg_type(pos, ty);
+                self.curpiece += 1;
             }
         }
     }
@@ -347,7 +350,9 @@ impl<'a, 'b> Context<'a, 'b> {
                     Some(e) => *e,
                     None => {
                         let msg = format!("there is no argument named `{}`", name);
-                        self.ecx.span_err(self.fmtsp, &msg[..]);
+                        let sp = *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp);
+                        let mut err = self.ecx.struct_span_err(sp, &msg[..]);
+                        err.emit();
                         return;
                     }
                 };
@@ -773,6 +778,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
         arg_unique_types,
         names,
         curarg: 0,
+        curpiece: 0,
         arg_index_map: Vec::new(),
         count_args: Vec::new(),
         count_positions: HashMap::new(),
@@ -785,6 +791,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
         macsp,
         fmtsp: fmt.span,
         invalid_refs: Vec::new(),
+        arg_spans: Vec::new(),
     };
 
     let fmt_str = &*fmt.node.0.as_str();
@@ -793,12 +800,22 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
         ast::StrStyle::Raw(raw) => Some(raw as usize),
     };
     let mut parser = parse::Parser::new(fmt_str, str_style);
+    let mut unverified_pieces = vec![];
     let mut pieces = vec![];
 
-    while let Some(mut piece) = parser.next() {
+    while let Some(piece) = parser.next() {
         if !parser.errors.is_empty() {
             break;
         }
+        unverified_pieces.push(piece);
+    }
+
+    cx.arg_spans = parser.arg_places.iter()
+        .map(|&(start, end)| fmt.span.from_inner_byte_pos(start, end))
+        .collect();
+
+    // This needs to happen *after* the Parser has consumed all pieces to create all the spans
+    for mut piece in unverified_pieces {
         cx.verify_piece(&piece);
         cx.resolve_name_inplace(&mut piece);
         pieces.push(piece);
diff --git a/src/test/ui/ifmt-bad-arg.stderr b/src/test/ui/ifmt-bad-arg.stderr
index 4ad3c2b6550..2d49c36c06d 100644
--- a/src/test/ui/ifmt-bad-arg.stderr
+++ b/src/test/ui/ifmt-bad-arg.stderr
@@ -57,22 +57,22 @@ LL |     format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2);
    = note: positional arguments are zero-based
 
 error: there is no argument named `foo`
-  --> $DIR/ifmt-bad-arg.rs:37:13
+  --> $DIR/ifmt-bad-arg.rs:37:17
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^
 
 error: there is no argument named `bar`
-  --> $DIR/ifmt-bad-arg.rs:37:13
+  --> $DIR/ifmt-bad-arg.rs:37:26
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |                          ^^^^^
 
 error: there is no argument named `foo`
-  --> $DIR/ifmt-bad-arg.rs:41:13
+  --> $DIR/ifmt-bad-arg.rs:41:14
    |
 LL |     format!("{foo}");                //~ ERROR: no argument named `foo`
-   |             ^^^^^^^
+   |              ^^^^^
 
 error: multiple unused formatting arguments
   --> $DIR/ifmt-bad-arg.rs:42:17
@@ -139,10 +139,10 @@ LL |     format!("", foo=1, 2);           //~ ERROR: positional arguments cannot
    |                        ^
 
 error: there is no argument named `valueb`
-  --> $DIR/ifmt-bad-arg.rs:55:13
+  --> $DIR/ifmt-bad-arg.rs:55:23
    |
 LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
-   |             ^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^
 
 error: named argument never used
   --> $DIR/ifmt-bad-arg.rs:55:51