@@ -14,18 +14,18 @@ use self::Position::*;
14
14
use fmt_macros as parse;
15
15
16
16
use syntax:: ast;
17
- use syntax:: ext:: base:: * ;
18
17
use syntax:: ext:: base;
18
+ use syntax:: ext:: base:: * ;
19
19
use syntax:: ext:: build:: AstBuilder ;
20
20
use syntax:: feature_gate;
21
21
use syntax:: parse:: token;
22
22
use syntax:: ptr:: P ;
23
23
use syntax:: symbol:: Symbol ;
24
- use syntax_pos:: { Span , MultiSpan , DUMMY_SP } ;
25
24
use syntax:: tokenstream;
25
+ use syntax_pos:: { MultiSpan , Span , DUMMY_SP } ;
26
26
27
- use std:: collections:: { HashMap , HashSet } ;
28
27
use std:: collections:: hash_map:: Entry ;
28
+ use std:: collections:: { HashMap , HashSet } ;
29
29
30
30
#[ derive( PartialEq ) ]
31
31
enum ArgumentType {
@@ -111,9 +111,11 @@ struct Context<'a, 'b: 'a> {
111
111
/// still existed in this phase of processing.
112
112
/// Used only for `all_pieces_simple` tracking in `build_piece`.
113
113
curarg : usize ,
114
+ /// Current piece being evaluated, used for error reporting.
114
115
curpiece : usize ,
115
- /// Keep track of invalid references to positional arguments
116
- invalid_refs : Vec < usize > ,
116
+ /// Keep track of invalid references to positional arguments.
117
+ invalid_refs : Vec < ( usize , usize ) > ,
118
+ /// Spans of all the formatting arguments, in order.
117
119
arg_spans : Vec < Span > ,
118
120
}
119
121
@@ -157,15 +159,20 @@ fn parse_args(ecx: &mut ExtCtxt,
157
159
i
158
160
}
159
161
_ if named => {
160
- ecx. span_err ( p. span ,
161
- "expected ident, positional arguments \
162
- cannot follow named arguments") ;
162
+ ecx. span_err (
163
+ p. span ,
164
+ "expected ident, positional arguments cannot follow named arguments" ,
165
+ ) ;
163
166
return None ;
164
167
}
165
168
_ => {
166
- ecx. span_err ( p. span ,
167
- & format ! ( "expected ident for named argument, found `{}`" ,
168
- p. this_token_to_string( ) ) ) ;
169
+ ecx. span_err (
170
+ p. span ,
171
+ & format ! (
172
+ "expected ident for named argument, found `{}`" ,
173
+ p. this_token_to_string( )
174
+ ) ,
175
+ ) ;
169
176
return None ;
170
177
}
171
178
} ;
@@ -267,34 +274,47 @@ impl<'a, 'b> Context<'a, 'b> {
267
274
/// errors for the case where all arguments are positional and for when
268
275
/// there are named arguments or numbered positional arguments in the
269
276
/// format string.
270
- fn report_invalid_references ( & self , numbered_position_args : bool , arg_places : & [ ( usize , usize ) ] ) {
277
+ fn report_invalid_references ( & self , numbered_position_args : bool ) {
271
278
let mut e;
272
- let sps = arg_places. iter ( )
273
- . map ( |& ( start, end) | self . fmtsp . from_inner_byte_pos ( start, end) )
274
- . collect :: < Vec < _ > > ( ) ;
275
- let sp = MultiSpan :: from_spans ( sps) ;
276
- let mut refs: Vec < _ > = self . invalid_refs
279
+ let sp = MultiSpan :: from_spans ( self . arg_spans . clone ( ) ) ;
280
+ let mut refs: Vec < _ > = self
281
+ . invalid_refs
277
282
. iter ( )
278
- . map ( |r| r. to_string ( ) )
283
+ . map ( |( r , pos ) | ( r. to_string ( ) , self . arg_spans . get ( * pos ) ) )
279
284
. collect ( ) ;
280
285
281
286
if self . names . is_empty ( ) && !numbered_position_args {
282
- e = self . ecx . mut_span_err ( sp,
283
- & format ! ( "{} positional argument{} in format string, but {}" ,
287
+ e = self . ecx . mut_span_err (
288
+ sp,
289
+ & format ! (
290
+ "{} positional argument{} in format string, but {}" ,
284
291
self . pieces. len( ) ,
285
292
if self . pieces. len( ) > 1 { "s" } else { "" } ,
286
- self . describe_num_args( ) ) ) ;
293
+ self . describe_num_args( )
294
+ ) ,
295
+ ) ;
287
296
} else {
288
- let arg_list = match refs. len ( ) {
297
+ let ( arg_list, sp ) = match refs. len ( ) {
289
298
1 => {
290
- let reg = refs. pop ( ) . unwrap ( ) ;
291
- format ! ( "argument {}" , reg)
292
- } ,
299
+ let ( reg, pos) = refs. pop ( ) . unwrap ( ) ;
300
+ (
301
+ format ! ( "argument {}" , reg) ,
302
+ MultiSpan :: from_span ( * pos. unwrap_or ( & self . fmtsp ) ) ,
303
+ )
304
+ }
293
305
_ => {
306
+ let pos =
307
+ MultiSpan :: from_spans ( refs. iter ( ) . map ( |( _, p) | * p. unwrap ( ) ) . collect ( ) ) ;
308
+ let mut refs: Vec < String > = refs. iter ( ) . map ( |( s, _) | s. to_owned ( ) ) . collect ( ) ;
294
309
let reg = refs. pop ( ) . unwrap ( ) ;
295
- format ! ( "arguments {head} and {tail}" ,
296
- tail=reg,
297
- head=refs. join( ", " ) )
310
+ (
311
+ format ! (
312
+ "arguments {head} and {tail}" ,
313
+ tail = reg,
314
+ head = refs. join( ", " )
315
+ ) ,
316
+ pos,
317
+ )
298
318
}
299
319
} ;
300
320
@@ -314,7 +334,7 @@ impl<'a, 'b> Context<'a, 'b> {
314
334
match arg {
315
335
Exact ( arg) => {
316
336
if self . args . len ( ) <= arg {
317
- self . invalid_refs . push ( arg) ;
337
+ self . invalid_refs . push ( ( arg, self . curpiece ) ) ;
318
338
return ;
319
339
}
320
340
match ty {
@@ -520,33 +540,27 @@ impl<'a, 'b> Context<'a, 'b> {
520
540
let prec = self . build_count ( arg. format . precision ) ;
521
541
let width = self . build_count ( arg. format . width ) ;
522
542
let path = self . ecx . path_global ( sp, Context :: rtpath ( self . ecx , "FormatSpec" ) ) ;
523
- let fmt =
524
- self . ecx . expr_struct ( sp,
543
+ let fmt = self . ecx . expr_struct (
544
+ sp,
525
545
path,
526
- vec ! [ self . ecx
527
- . field_imm( sp, self . ecx. ident_of( "fill" ) , fill) ,
528
- self . ecx. field_imm( sp,
529
- self . ecx. ident_of( "align" ) ,
530
- align) ,
531
- self . ecx. field_imm( sp,
532
- self . ecx. ident_of( "flags" ) ,
533
- flags) ,
534
- self . ecx. field_imm( sp,
535
- self . ecx. ident_of( "precision" ) ,
536
- prec) ,
537
- self . ecx. field_imm( sp,
538
- self . ecx. ident_of( "width" ) ,
539
- width) ] ) ;
546
+ vec ! [
547
+ self . ecx. field_imm( sp, self . ecx. ident_of( "fill" ) , fill) ,
548
+ self . ecx. field_imm( sp, self . ecx. ident_of( "align" ) , align) ,
549
+ self . ecx. field_imm( sp, self . ecx. ident_of( "flags" ) , flags) ,
550
+ self . ecx. field_imm( sp, self . ecx. ident_of( "precision" ) , prec) ,
551
+ self . ecx. field_imm( sp, self . ecx. ident_of( "width" ) , width) ,
552
+ ] ,
553
+ ) ;
540
554
541
555
let path = self . ecx . path_global ( sp, Context :: rtpath ( self . ecx , "Argument" ) ) ;
542
- Some ( self . ecx . expr_struct ( sp,
556
+ Some ( self . ecx . expr_struct (
557
+ sp,
543
558
path,
544
- vec ! [ self . ecx. field_imm( sp,
545
- self . ecx. ident_of( "position" ) ,
546
- pos) ,
547
- self . ecx. field_imm( sp,
548
- self . ecx. ident_of( "format" ) ,
549
- fmt) ] ) )
559
+ vec ! [
560
+ self . ecx. field_imm( sp, self . ecx. ident_of( "position" ) , pos) ,
561
+ self . ecx. field_imm( sp, self . ecx. ident_of( "format" ) , fmt) ,
562
+ ] ,
563
+ ) )
550
564
}
551
565
}
552
566
}
@@ -559,9 +573,9 @@ impl<'a, 'b> Context<'a, 'b> {
559
573
let mut pats = Vec :: new ( ) ;
560
574
let mut heads = Vec :: new ( ) ;
561
575
562
- let names_pos: Vec < _ > = ( 0 ..self . args . len ( ) ) . map ( |i| {
563
- self . ecx . ident_of ( & format ! ( "arg{}" , i) ) . gensym ( )
564
- } ) . collect ( ) ;
576
+ let names_pos: Vec < _ > = ( 0 ..self . args . len ( ) )
577
+ . map ( |i| self . ecx . ident_of ( & format ! ( "arg{}" , i) ) . gensym ( ) )
578
+ . collect ( ) ;
565
579
566
580
// First, build up the static array which will become our precompiled
567
581
// format "string"
@@ -705,10 +719,11 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt,
705
719
}
706
720
}
707
721
708
- pub fn expand_format_args_nl < ' cx > ( ecx : & ' cx mut ExtCtxt ,
722
+ pub fn expand_format_args_nl < ' cx > (
723
+ ecx : & ' cx mut ExtCtxt ,
709
724
mut sp : Span ,
710
- tts : & [ tokenstream:: TokenTree ] )
711
- -> Box < dyn base:: MacResult + ' cx > {
725
+ tts : & [ tokenstream:: TokenTree ] ,
726
+ ) -> Box < dyn base:: MacResult + ' cx > {
712
727
//if !ecx.ecfg.enable_allow_internal_unstable() {
713
728
714
729
// For some reason, the only one that actually works for `println` is the first check
@@ -759,7 +774,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
759
774
let sugg_fmt = match args. len ( ) {
760
775
0 => "{}" . to_string ( ) ,
761
776
_ => format ! ( "{}{{}}" , "{} " . repeat( args. len( ) ) ) ,
762
-
763
777
} ;
764
778
err. span_suggestion (
765
779
fmt_sp. shrink_to_lo ( ) ,
@@ -768,7 +782,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
768
782
) ;
769
783
err. emit ( ) ;
770
784
return DummyResult :: raw_expr ( sp) ;
771
- } ,
785
+ }
772
786
} ;
773
787
774
788
let mut cx = Context {
@@ -862,7 +876,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
862
876
}
863
877
864
878
if cx. invalid_refs . len ( ) >= 1 {
865
- cx. report_invalid_references ( numbered_position_args, & parser . arg_places ) ;
879
+ cx. report_invalid_references ( numbered_position_args) ;
866
880
}
867
881
868
882
// Make sure that all arguments were used and all arguments have types.
@@ -894,7 +908,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
894
908
} else {
895
909
let mut diag = cx. ecx . struct_span_err (
896
910
errs. iter ( ) . map ( |& ( sp, _) | sp) . collect :: < Vec < Span > > ( ) ,
897
- "multiple unused formatting arguments"
911
+ "multiple unused formatting arguments" ,
898
912
) ;
899
913
diag. span_label ( cx. fmtsp , "multiple missing formatting arguments" ) ;
900
914
diag
0 commit comments