@@ -14,8 +14,7 @@ use self::Position::*;
1414use fmt_macros as parse;
1515
1616use syntax:: ast;
17- use syntax:: ext:: base;
18- use syntax:: ext:: base:: * ;
17+ use syntax:: ext:: base:: { self , * } ;
1918use syntax:: ext:: build:: AstBuilder ;
2019use syntax:: feature_gate;
2120use syntax:: parse:: token;
@@ -24,6 +23,7 @@ use syntax::symbol::Symbol;
2423use syntax:: tokenstream;
2524use syntax_pos:: { MultiSpan , Span , DUMMY_SP } ;
2625
26+ use std:: borrow:: Cow ;
2727use std:: collections:: hash_map:: Entry ;
2828use std:: collections:: { HashMap , HashSet } ;
2929
@@ -143,8 +143,10 @@ fn parse_args(ecx: &mut ExtCtxt,
143143 ecx. span_err ( sp, "requires at least a format string argument" ) ;
144144 return None ;
145145 }
146+
146147 let fmtstr = panictry ! ( p. parse_expr( ) ) ;
147148 let mut named = false ;
149+
148150 while p. token != token:: Eof {
149151 if !p. eat ( & token:: Comma ) {
150152 ecx. span_err ( p. span , "expected token: `,`" ) ;
@@ -264,11 +266,11 @@ impl<'a, 'b> Context<'a, 'b> {
264266 }
265267 }
266268
267- fn describe_num_args ( & self ) -> String {
269+ fn describe_num_args ( & self ) -> Cow < str > {
268270 match self . args . len ( ) {
269- 0 => "no arguments were given" . to_string ( ) ,
270- 1 => "there is 1 argument" . to_string ( ) ,
271- x => format ! ( "there are {} arguments" , x) ,
271+ 0 => "no arguments were given" . into ( ) ,
272+ 1 => "there is 1 argument" . into ( ) ,
273+ x => format ! ( "there are {} arguments" , x) . into ( ) ,
272274 }
273275 }
274276
@@ -772,8 +774,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
772774 // `ArgumentType` does not derive `Clone`.
773775 let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
774776 let arg_unique_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
777+
775778 let mut macsp = ecx. call_site ( ) ;
776779 macsp = macsp. apply_mark ( ecx. current_expansion . mark ) ;
780+
777781 let msg = "format argument must be a string literal" ;
778782 let fmt_sp = efmt. span ;
779783 let fmt = match expr_to_spanned_string ( ecx, efmt, msg) {
@@ -796,11 +800,46 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
796800 return DummyResult :: raw_expr ( sp) ;
797801 }
798802 } ;
803+
799804 let is_literal = match ecx. codemap ( ) . span_to_snippet ( fmt_sp) {
800805 Ok ( ref s) if s. starts_with ( "\" " ) || s. starts_with ( "r#" ) => true ,
801806 _ => false ,
802807 } ;
803808
809+ let fmt_str = & * fmt. node . 0 . as_str ( ) ;
810+ let str_style = match fmt. node . 1 {
811+ ast:: StrStyle :: Cooked => None ,
812+ ast:: StrStyle :: Raw ( raw) => Some ( raw as usize ) ,
813+ } ;
814+
815+ let mut parser = parse:: Parser :: new ( fmt_str, str_style) ;
816+
817+ let mut unverified_pieces = Vec :: new ( ) ;
818+ while let Some ( piece) = parser. next ( ) {
819+ if !parser. errors . is_empty ( ) {
820+ break ;
821+ } else {
822+ unverified_pieces. push ( piece) ;
823+ }
824+ }
825+
826+ if !parser. errors . is_empty ( ) {
827+ let err = parser. errors . remove ( 0 ) ;
828+ let sp = fmt. span . from_inner_byte_pos ( err. start , err. end ) ;
829+ let mut e = ecx. struct_span_err ( sp, & format ! ( "invalid format string: {}" ,
830+ err. description) ) ;
831+ e. span_label ( sp, err. label + " in format string" ) ;
832+ if let Some ( note) = err. note {
833+ e. note ( & note) ;
834+ }
835+ e. emit ( ) ;
836+ return DummyResult :: raw_expr ( sp) ;
837+ }
838+
839+ let arg_spans = parser. arg_places . iter ( )
840+ . map ( |& ( start, end) | fmt. span . from_inner_byte_pos ( start, end) )
841+ . collect ( ) ;
842+
804843 let mut cx = Context {
805844 ecx,
806845 args,
@@ -815,42 +854,22 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
815854 count_positions_count : 0 ,
816855 count_args_index_offset : 0 ,
817856 literal : String :: new ( ) ,
818- pieces : Vec :: new ( ) ,
819- str_pieces : Vec :: new ( ) ,
857+ pieces : Vec :: with_capacity ( unverified_pieces . len ( ) ) ,
858+ str_pieces : Vec :: with_capacity ( unverified_pieces . len ( ) ) ,
820859 all_pieces_simple : true ,
821860 macsp,
822861 fmtsp : fmt. span ,
823862 invalid_refs : Vec :: new ( ) ,
824- arg_spans : Vec :: new ( ) ,
863+ arg_spans,
825864 is_literal,
826865 } ;
827866
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-
848867 // This needs to happen *after* the Parser has consumed all pieces to create all the spans
849- for mut piece in unverified_pieces {
868+ let pieces = unverified_pieces. into_iter ( ) . map ( | mut piece| {
850869 cx. verify_piece ( & piece) ;
851870 cx. resolve_name_inplace ( & mut piece) ;
852- pieces . push ( piece) ;
853- }
871+ piece
872+ } ) . collect :: < Vec < _ > > ( ) ;
854873
855874 let numbered_position_args = pieces. iter ( ) . any ( |arg : & parse:: Piece | {
856875 match * arg {
@@ -867,6 +886,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
867886 cx. build_index_map ( ) ;
868887
869888 let mut arg_index_consumed = vec ! [ 0usize ; cx. arg_index_map. len( ) ] ;
889+
870890 for piece in pieces {
871891 if let Some ( piece) = cx. build_piece ( & piece, & mut arg_index_consumed) {
872892 let s = cx. build_literal_string ( ) ;
@@ -875,18 +895,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
875895 }
876896 }
877897
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- }
890898 if !cx. literal . is_empty ( ) {
891899 let s = cx. build_literal_string ( ) ;
892900 cx. str_pieces . push ( s) ;
@@ -898,24 +906,25 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
898906
899907 // Make sure that all arguments were used and all arguments have types.
900908 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- }
909+
910+ let errs = cx. arg_types
911+ . iter ( )
912+ . enumerate ( )
913+ . filter ( |( i, ty) | ty. is_empty ( ) && !cx. count_positions . contains_key ( & i) )
914+ . map ( |( i, _) | {
915+ let msg = if i >= num_pos_args {
916+ // named argument
917+ "named argument never used"
918+ } else {
919+ // positional argument
920+ "argument never used"
921+ } ;
922+ ( cx. args [ i] . span , msg)
923+ } )
924+ . collect :: < Vec < _ > > ( ) ;
925+
917926 let errs_len = errs. len ( ) ;
918- if errs_len > 0 {
927+ if !errs . is_empty ( ) {
919928 let args_used = cx. arg_types . len ( ) - errs_len;
920929 let args_unused = errs_len;
921930
0 commit comments