about summary refs log tree commit diff
path: root/src/libsyntax_ext
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 /src/libsyntax_ext
parent38abca8c2d7de08861cd61bc439efdb7cf4de398 (diff)
downloadrust-42306591b9c0a280da363c83df16b47ad8b04024.tar.gz
rust-42306591b9c0a280da363c83df16b47ad8b04024.zip
Point at incorrect named arg in format string
Diffstat (limited to 'src/libsyntax_ext')
-rw-r--r--src/libsyntax_ext/format.rs21
1 files changed, 19 insertions, 2 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);