@@ -14,8 +14,7 @@ use self::Position::*;
14
14
use fmt_macros as parse;
15
15
16
16
use syntax:: ast;
17
- use syntax:: ext:: base;
18
- use syntax:: ext:: base:: * ;
17
+ use syntax:: ext:: base:: { self , * } ;
19
18
use syntax:: ext:: build:: AstBuilder ;
20
19
use syntax:: feature_gate;
21
20
use syntax:: parse:: token;
@@ -24,6 +23,7 @@ use syntax::symbol::Symbol;
24
23
use syntax:: tokenstream;
25
24
use syntax_pos:: { MultiSpan , Span , DUMMY_SP } ;
26
25
26
+ use std:: borrow:: Cow ;
27
27
use std:: collections:: hash_map:: Entry ;
28
28
use std:: collections:: { HashMap , HashSet } ;
29
29
@@ -143,8 +143,10 @@ fn parse_args(ecx: &mut ExtCtxt,
143
143
ecx. span_err ( sp, "requires at least a format string argument" ) ;
144
144
return None ;
145
145
}
146
+
146
147
let fmtstr = panictry ! ( p. parse_expr( ) ) ;
147
148
let mut named = false ;
149
+
148
150
while p. token != token:: Eof {
149
151
if !p. eat ( & token:: Comma ) {
150
152
ecx. span_err ( p. span , "expected token: `,`" ) ;
@@ -264,11 +266,11 @@ impl<'a, 'b> Context<'a, 'b> {
264
266
}
265
267
}
266
268
267
- fn describe_num_args ( & self ) -> String {
269
+ fn describe_num_args ( & self ) -> Cow < str > {
268
270
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 ( ) ,
272
274
}
273
275
}
274
276
@@ -772,8 +774,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
772
774
// `ArgumentType` does not derive `Clone`.
773
775
let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
774
776
let arg_unique_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
777
+
775
778
let mut macsp = ecx. call_site ( ) ;
776
779
macsp = macsp. apply_mark ( ecx. current_expansion . mark ) ;
780
+
777
781
let msg = "format argument must be a string literal" ;
778
782
let fmt_sp = efmt. span ;
779
783
let fmt = match expr_to_spanned_string ( ecx, efmt, msg) {
@@ -796,11 +800,46 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
796
800
return DummyResult :: raw_expr ( sp) ;
797
801
}
798
802
} ;
803
+
799
804
let is_literal = match ecx. codemap ( ) . span_to_snippet ( fmt_sp) {
800
805
Ok ( ref s) if s. starts_with ( "\" " ) || s. starts_with ( "r#" ) => true ,
801
806
_ => false ,
802
807
} ;
803
808
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
+
804
843
let mut cx = Context {
805
844
ecx,
806
845
args,
@@ -815,42 +854,22 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
815
854
count_positions_count : 0 ,
816
855
count_args_index_offset : 0 ,
817
856
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 ( ) ) ,
820
859
all_pieces_simple : true ,
821
860
macsp,
822
861
fmtsp : fmt. span ,
823
862
invalid_refs : Vec :: new ( ) ,
824
- arg_spans : Vec :: new ( ) ,
863
+ arg_spans,
825
864
is_literal,
826
865
} ;
827
866
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
-
848
867
// 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| {
850
869
cx. verify_piece ( & piece) ;
851
870
cx. resolve_name_inplace ( & mut piece) ;
852
- pieces . push ( piece) ;
853
- }
871
+ piece
872
+ } ) . collect :: < Vec < _ > > ( ) ;
854
873
855
874
let numbered_position_args = pieces. iter ( ) . any ( |arg : & parse:: Piece | {
856
875
match * arg {
@@ -867,6 +886,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
867
886
cx. build_index_map ( ) ;
868
887
869
888
let mut arg_index_consumed = vec ! [ 0usize ; cx. arg_index_map. len( ) ] ;
889
+
870
890
for piece in pieces {
871
891
if let Some ( piece) = cx. build_piece ( & piece, & mut arg_index_consumed) {
872
892
let s = cx. build_literal_string ( ) ;
@@ -875,18 +895,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
875
895
}
876
896
}
877
897
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
- }
890
898
if !cx. literal . is_empty ( ) {
891
899
let s = cx. build_literal_string ( ) ;
892
900
cx. str_pieces . push ( s) ;
@@ -898,24 +906,25 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
898
906
899
907
// Make sure that all arguments were used and all arguments have types.
900
908
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
+
917
926
let errs_len = errs. len ( ) ;
918
- if errs_len > 0 {
927
+ if !errs . is_empty ( ) {
919
928
let args_used = cx. arg_types . len ( ) - errs_len;
920
929
let args_unused = errs_len;
921
930
0 commit comments