@@ -24,6 +24,7 @@ use syntax_pos::{Span, DUMMY_SP};
24
24
use syntax:: tokenstream;
25
25
26
26
use std:: collections:: HashMap ;
27
+ use std:: collections:: hash_map:: Entry ;
27
28
28
29
#[ derive( PartialEq ) ]
29
30
enum ArgumentType {
@@ -70,6 +71,12 @@ struct Context<'a, 'b:'a> {
70
71
/// mapping in `trans_piece`.
71
72
arg_index_map : Vec < usize > ,
72
73
74
+ count_args_index_offset : usize ,
75
+
76
+ count_args : Vec < Position > ,
77
+ count_positions : HashMap < usize , usize > ,
78
+ count_positions_count : usize ,
79
+
73
80
/// Current position of the implicit positional arg pointer, as if it
74
81
/// still existed in this phase of processing.
75
82
/// Used only for `all_pieces_simple` tracking in `trans_piece`.
@@ -225,7 +232,22 @@ impl<'a, 'b> Context<'a, 'b> {
225
232
self . ecx . span_err ( self . fmtsp , & msg[ ..] ) ;
226
233
return ;
227
234
}
228
- self . arg_types [ arg] . push ( ty) ;
235
+ match ty {
236
+ Placeholder ( _) => {
237
+ self . arg_types [ arg] . push ( ty) ;
238
+ }
239
+ Count => {
240
+ match self . count_positions . entry ( arg) {
241
+ Entry :: Vacant ( e) => {
242
+ let i = self . count_positions_count ;
243
+ e. insert ( i) ;
244
+ self . count_args . push ( Exact ( arg) ) ;
245
+ self . count_positions_count += 1 ;
246
+ }
247
+ Entry :: Occupied ( _) => { }
248
+ }
249
+ }
250
+ }
229
251
}
230
252
231
253
Named ( name) => {
@@ -255,15 +277,17 @@ impl<'a, 'b> Context<'a, 'b> {
255
277
self . arg_index_map . push ( sofar) ;
256
278
sofar += self . arg_types [ i] . len ( ) ;
257
279
}
280
+
281
+ // Record starting index for counts, which appear just
282
+ // after the positional args
283
+ self . count_args_index_offset = sofar;
258
284
}
259
285
260
286
fn rtpath ( ecx : & ExtCtxt , s : & str ) -> Vec < ast:: Ident > {
261
287
ecx. std_path ( & [ "fmt" , "rt" , "v1" , s] )
262
288
}
263
289
264
- fn trans_count ( & self ,
265
- c : parse:: Count ,
266
- arg_index_consumed : & mut Vec < usize > ) -> P < ast:: Expr > {
290
+ fn trans_count ( & self , c : parse:: Count ) -> P < ast:: Expr > {
267
291
let sp = self . macsp ;
268
292
let count = |c, arg| {
269
293
let mut path = Context :: rtpath ( self . ecx , "Count" ) ;
@@ -278,9 +302,12 @@ impl<'a, 'b> Context<'a, 'b> {
278
302
parse:: CountIsParam ( i) => {
279
303
// This needs mapping too, as `i` is referring to a macro
280
304
// argument.
281
- let arg_idx = self . arg_index_map [ i] + arg_index_consumed[ i] ;
282
- arg_index_consumed[ i] += 1 ;
283
- count ( "Param" , Some ( self . ecx . expr_usize ( sp, arg_idx) ) )
305
+ let i = match self . count_positions . get ( & i) {
306
+ Some ( & i) => i,
307
+ None => 0 , // error already emitted elsewhere
308
+ } ;
309
+ let i = i + self . count_args_index_offset ;
310
+ count ( "Param" , Some ( self . ecx . expr_usize ( sp, i) ) )
284
311
}
285
312
parse:: CountImplied => count ( "Implied" , None ) ,
286
313
// should never be the case, names are already resolved
@@ -383,8 +410,8 @@ impl<'a, 'b> Context<'a, 'b> {
383
410
} ;
384
411
let align = self . ecx . expr_path ( align) ;
385
412
let flags = self . ecx . expr_u32 ( sp, arg. format . flags ) ;
386
- let prec = self . trans_count ( arg. format . precision , arg_index_consumed ) ;
387
- let width = self . trans_count ( arg. format . width , arg_index_consumed ) ;
413
+ let prec = self . trans_count ( arg. format . precision ) ;
414
+ let width = self . trans_count ( arg. format . width ) ;
388
415
let path = self . ecx . path_global ( sp, Context :: rtpath ( self . ecx , "FormatSpec" ) ) ;
389
416
let fmt = self . ecx . expr_struct ( sp, path, vec ! (
390
417
self . ecx. field_imm( sp, self . ecx. ident_of( "fill" ) , fill) ,
@@ -431,6 +458,7 @@ impl<'a, 'b> Context<'a, 'b> {
431
458
/// to
432
459
fn into_expr ( mut self ) -> P < ast:: Expr > {
433
460
let mut locals = Vec :: new ( ) ;
461
+ let mut counts = Vec :: new ( ) ;
434
462
let mut pats = Vec :: new ( ) ;
435
463
let mut heads = Vec :: new ( ) ;
436
464
@@ -447,6 +475,10 @@ impl<'a, 'b> Context<'a, 'b> {
447
475
piece_ty,
448
476
self . str_pieces ) ;
449
477
478
+ // Before consuming the expressions, we have to remember spans for
479
+ // count arguments as they are now generated separate from other
480
+ // arguments, hence have no access to the `P<ast::Expr>`'s.
481
+ let spans_pos: Vec < _ > = self . args . iter ( ) . map ( |e| e. span . clone ( ) ) . collect ( ) ;
450
482
451
483
// Right now there is a bug such that for the expression:
452
484
// foo(bar(&1))
@@ -464,11 +496,23 @@ impl<'a, 'b> Context<'a, 'b> {
464
496
}
465
497
heads. push ( self . ecx . expr_addr_of ( e. span , e) ) ;
466
498
}
499
+ for pos in self . count_args {
500
+ let name = self . ecx . ident_of ( & match pos {
501
+ Exact ( i) => format ! ( "__arg{}" , i) ,
502
+ _ => panic ! ( "should never happen" ) ,
503
+ } ) ;
504
+ let span = match pos {
505
+ Exact ( i) => spans_pos[ i] ,
506
+ _ => panic ! ( "should never happen" ) ,
507
+ } ;
508
+ counts. push ( Context :: format_arg ( self . ecx , self . macsp , span, & Count ,
509
+ self . ecx . expr_ident ( span, name) ) ) ;
510
+ }
467
511
468
512
// Now create a vector containing all the arguments
469
- let args = locals. into_iter ( ) . collect ( ) ;
513
+ let args = locals. into_iter ( ) . chain ( counts . into_iter ( ) ) ;
470
514
471
- let args_array = self . ecx . expr_vec ( self . fmtsp , args) ;
515
+ let args_array = self . ecx . expr_vec ( self . fmtsp , args. collect ( ) ) ;
472
516
473
517
// Constructs an AST equivalent to:
474
518
//
@@ -594,6 +638,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
594
638
names : names,
595
639
curarg : 0 ,
596
640
arg_index_map : Vec :: new ( ) ,
641
+ count_args : Vec :: new ( ) ,
642
+ count_positions : HashMap :: new ( ) ,
643
+ count_positions_count : 0 ,
644
+ count_args_index_offset : 0 ,
597
645
literal : String :: new ( ) ,
598
646
pieces : Vec :: new ( ) ,
599
647
str_pieces : Vec :: new ( ) ,
@@ -648,6 +696,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
648
696
let num_pos_args = cx. args . len ( ) - cx. names . len ( ) ;
649
697
for ( i, ty) in cx. arg_types . iter ( ) . enumerate ( ) {
650
698
if ty. len ( ) == 0 {
699
+ if cx. count_positions . contains_key ( & i) {
700
+ continue ;
701
+ }
651
702
let msg = if i >= num_pos_args {
652
703
// named argument
653
704
"named argument never used"
0 commit comments