@@ -111,8 +111,10 @@ struct Context<'a, 'b: 'a> {
111111 /// still existed in this phase of processing.
112112 /// Used only for `all_pieces_simple` tracking in `build_piece`.
113113 curarg : usize ,
114+ curpiece : usize ,
114115 /// Keep track of invalid references to positional arguments
115116 invalid_refs : Vec < usize > ,
117+ arg_spans : Vec < Span > ,
116118}
117119
118120/// Parses the arguments from the given list of tokens, returning None
@@ -235,6 +237,7 @@ impl<'a, 'b> Context<'a, 'b> {
235237
236238 let ty = Placeholder ( arg. format . ty . to_string ( ) ) ;
237239 self . verify_arg_type ( pos, ty) ;
240+ self . curpiece += 1 ;
238241 }
239242 }
240243 }
@@ -347,7 +350,9 @@ impl<'a, 'b> Context<'a, 'b> {
347350 Some ( e) => * e,
348351 None => {
349352 let msg = format ! ( "there is no argument named `{}`" , name) ;
350- self . ecx . span_err ( self . fmtsp , & msg[ ..] ) ;
353+ let sp = * self . arg_spans . get ( self . curpiece ) . unwrap_or ( & self . fmtsp ) ;
354+ let mut err = self . ecx . struct_span_err ( sp, & msg[ ..] ) ;
355+ err. emit ( ) ;
351356 return ;
352357 }
353358 } ;
@@ -773,6 +778,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
773778 arg_unique_types,
774779 names,
775780 curarg : 0 ,
781+ curpiece : 0 ,
776782 arg_index_map : Vec :: new ( ) ,
777783 count_args : Vec :: new ( ) ,
778784 count_positions : HashMap :: new ( ) ,
@@ -785,6 +791,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
785791 macsp,
786792 fmtsp : fmt. span ,
787793 invalid_refs : Vec :: new ( ) ,
794+ arg_spans : Vec :: new ( ) ,
788795 } ;
789796
790797 let fmt_str = & * fmt. node . 0 . as_str ( ) ;
@@ -793,12 +800,22 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
793800 ast:: StrStyle :: Raw ( raw) => Some ( raw as usize ) ,
794801 } ;
795802 let mut parser = parse:: Parser :: new ( fmt_str, str_style) ;
803+ let mut unverified_pieces = vec ! [ ] ;
796804 let mut pieces = vec ! [ ] ;
797805
798- while let Some ( mut piece) = parser. next ( ) {
806+ while let Some ( piece) = parser. next ( ) {
799807 if !parser. errors . is_empty ( ) {
800808 break ;
801809 }
810+ unverified_pieces. push ( piece) ;
811+ }
812+
813+ cx. arg_spans = parser. arg_places . iter ( )
814+ . map ( |& ( start, end) | fmt. span . from_inner_byte_pos ( start, end) )
815+ . collect ( ) ;
816+
817+ // This needs to happen *after* the Parser has consumed all pieces to create all the spans
818+ for mut piece in unverified_pieces {
802819 cx. verify_piece ( & piece) ;
803820 cx. resolve_name_inplace ( & mut piece) ;
804821 pieces. push ( piece) ;
0 commit comments