@@ -772,8 +772,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
772772 // `ArgumentType` does not derive `Clone`.
773773 let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
774774 let arg_unique_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
775+
775776 let mut macsp = ecx. call_site ( ) ;
776777 macsp = macsp. apply_mark ( ecx. current_expansion . mark ) ;
778+
777779 let msg = "format argument must be a string literal" ;
778780 let fmt_sp = efmt. span ;
779781 let fmt = match expr_to_spanned_string ( ecx, efmt, msg) {
@@ -796,11 +798,46 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
796798 return DummyResult :: raw_expr ( sp) ;
797799 }
798800 } ;
801+
799802 let is_literal = match ecx. codemap ( ) . span_to_snippet ( fmt_sp) {
800803 Ok ( ref s) if s. starts_with ( "\" " ) || s. starts_with ( "r#" ) => true ,
801804 _ => false ,
802805 } ;
803806
807+ let fmt_str = & * fmt. node . 0 . as_str ( ) ;
808+ let str_style = match fmt. node . 1 {
809+ ast:: StrStyle :: Cooked => None ,
810+ ast:: StrStyle :: Raw ( raw) => Some ( raw as usize ) ,
811+ } ;
812+
813+ let mut parser = parse:: Parser :: new ( fmt_str, str_style) ;
814+
815+ let mut unverified_pieces = Vec :: new ( ) ;
816+ while let Some ( piece) = parser. next ( ) {
817+ if !parser. errors . is_empty ( ) {
818+ break ;
819+ } else {
820+ unverified_pieces. push ( piece) ;
821+ }
822+ }
823+
824+ if !parser. errors . is_empty ( ) {
825+ let err = parser. errors . remove ( 0 ) ;
826+ let sp = fmt. span . from_inner_byte_pos ( err. start , err. end ) ;
827+ let mut e = ecx. struct_span_err ( sp, & format ! ( "invalid format string: {}" ,
828+ err. description) ) ;
829+ e. span_label ( sp, err. label + " in format string" ) ;
830+ if let Some ( note) = err. note {
831+ e. note ( & note) ;
832+ }
833+ e. emit ( ) ;
834+ return DummyResult :: raw_expr ( sp) ;
835+ }
836+
837+ let arg_spans = parser. arg_places . iter ( )
838+ . map ( |& ( start, end) | fmt. span . from_inner_byte_pos ( start, end) )
839+ . collect ( ) ;
840+
804841 let mut cx = Context {
805842 ecx,
806843 args,
@@ -815,42 +852,22 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
815852 count_positions_count : 0 ,
816853 count_args_index_offset : 0 ,
817854 literal : String :: new ( ) ,
818- pieces : Vec :: new ( ) ,
819- str_pieces : Vec :: new ( ) ,
855+ pieces : Vec :: with_capacity ( unverified_pieces . len ( ) ) ,
856+ str_pieces : Vec :: with_capacity ( unverified_pieces . len ( ) ) ,
820857 all_pieces_simple : true ,
821858 macsp,
822859 fmtsp : fmt. span ,
823860 invalid_refs : Vec :: new ( ) ,
824- arg_spans : Vec :: new ( ) ,
861+ arg_spans,
825862 is_literal,
826863 } ;
827864
828- let fmt_str = & * fmt. node . 0 . as_str ( ) ;
829- let str_style = match fmt. node . 1 {
830- ast:: StrStyle :: Cooked => None ,
831- ast:: StrStyle :: Raw ( raw) => Some ( raw as usize ) ,
832- } ;
833- let mut parser = parse:: Parser :: new ( fmt_str, str_style) ;
834- let mut unverified_pieces = vec ! [ ] ;
835- let mut pieces = vec ! [ ] ;
836-
837- while let Some ( piece) = parser. next ( ) {
838- if !parser. errors . is_empty ( ) {
839- break ;
840- }
841- unverified_pieces. push ( piece) ;
842- }
843-
844- cx. arg_spans = parser. arg_places . iter ( )
845- . map ( |& ( start, end) | fmt. span . from_inner_byte_pos ( start, end) )
846- . collect ( ) ;
847-
848865 // This needs to happen *after* the Parser has consumed all pieces to create all the spans
849- for mut piece in unverified_pieces {
866+ let pieces = unverified_pieces. into_iter ( ) . map ( | mut piece| {
850867 cx. verify_piece ( & piece) ;
851868 cx. resolve_name_inplace ( & mut piece) ;
852- pieces . push ( piece) ;
853- }
869+ piece
870+ } ) . collect :: < Vec < _ > > ( ) ;
854871
855872 let numbered_position_args = pieces. iter ( ) . any ( |arg : & parse:: Piece | {
856873 match * arg {
@@ -867,6 +884,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
867884 cx. build_index_map ( ) ;
868885
869886 let mut arg_index_consumed = vec ! [ 0usize ; cx. arg_index_map. len( ) ] ;
887+
870888 for piece in pieces {
871889 if let Some ( piece) = cx. build_piece ( & piece, & mut arg_index_consumed) {
872890 let s = cx. build_literal_string ( ) ;
@@ -875,18 +893,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
875893 }
876894 }
877895
878- if !parser. errors . is_empty ( ) {
879- let err = parser. errors . remove ( 0 ) ;
880- let sp = cx. fmtsp . from_inner_byte_pos ( err. start , err. end ) ;
881- let mut e = cx. ecx . struct_span_err ( sp, & format ! ( "invalid format string: {}" ,
882- err. description) ) ;
883- e. span_label ( sp, err. label + " in format string" ) ;
884- if let Some ( note) = err. note {
885- e. note ( & note) ;
886- }
887- e. emit ( ) ;
888- return DummyResult :: raw_expr ( sp) ;
889- }
890896 if !cx. literal . is_empty ( ) {
891897 let s = cx. build_literal_string ( ) ;
892898 cx. str_pieces . push ( s) ;
@@ -898,24 +904,25 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
898904
899905 // Make sure that all arguments were used and all arguments have types.
900906 let num_pos_args = cx. args . len ( ) - cx. names . len ( ) ;
901- let mut errs = vec ! [ ] ;
902- for ( i, ty) in cx. arg_types . iter ( ) . enumerate ( ) {
903- if ty. len ( ) == 0 {
904- if cx. count_positions . contains_key ( & i) {
905- continue ;
906- }
907- let msg = if i >= num_pos_args {
908- // named argument
909- "named argument never used"
910- } else {
911- // positional argument
912- "argument never used"
913- } ;
914- errs. push ( ( cx. args [ i] . span , msg) ) ;
915- }
916- }
907+
908+ let errs = cx. arg_types
909+ . iter ( )
910+ . enumerate ( )
911+ . filter ( |( i, ty) | ty. is_empty ( ) && !cx. count_positions . contains_key ( & i) )
912+ . map ( |( i, _) | {
913+ let msg = if i >= num_pos_args {
914+ // named argument
915+ "named argument never used"
916+ } else {
917+ // positional argument
918+ "argument never used"
919+ } ;
920+ ( cx. args [ i] . span , msg)
921+ } )
922+ . collect :: < Vec < _ > > ( ) ;
923+
917924 let errs_len = errs. len ( ) ;
918- if errs_len > 0 {
925+ if !errs . is_empty ( ) {
919926 let args_used = cx. arg_types . len ( ) - errs_len;
920927 let args_unused = errs_len;
921928
0 commit comments