@@ -146,16 +146,13 @@ fn parse_args<'a>(
146146 if p. token == token:: Eof {
147147 break ;
148148 } // accept trailing commas
149- if named || ( p. token . is_ident ( ) && p. look_ahead ( 1 , |t| * t == token:: Eq ) ) {
149+ if p. token . is_ident ( ) && p. look_ahead ( 1 , |t| * t == token:: Eq ) {
150150 named = true ;
151151 let name = if let token:: Ident ( name, _) = p. token . kind {
152152 p. bump ( ) ;
153153 name
154154 } else {
155- return Err ( ecx. struct_span_err (
156- p. token . span ,
157- "expected ident, positional arguments cannot follow named arguments" ,
158- ) ) ;
155+ unreachable ! ( ) ;
159156 } ;
160157
161158 p. expect ( & token:: Eq ) ?;
@@ -176,6 +173,17 @@ fn parse_args<'a>(
176173 args. push ( e) ;
177174 } else {
178175 let e = p. parse_expr ( ) ?;
176+ if named {
177+ let mut err = ecx. struct_span_err (
178+ e. span ,
179+ "positional arguments cannot follow named arguments" ,
180+ ) ;
181+ err. span_label ( e. span , "positional arguments must be before named arguments" ) ;
182+ for ( _, pos) in & names {
183+ err. span_label ( args[ * pos] . span , "named argument" ) ;
184+ }
185+ err. emit ( ) ;
186+ }
179187 args. push ( e) ;
180188 }
181189 }
@@ -721,13 +729,14 @@ pub fn expand_format_args_nl<'cx>(
721729
722730/// Take the various parts of `format_args!(efmt, args..., name=names...)`
723731/// and construct the appropriate formatting expression.
724- pub fn expand_preparsed_format_args ( ecx : & mut ExtCtxt < ' _ > ,
725- sp : Span ,
726- efmt : P < ast:: Expr > ,
727- args : Vec < P < ast:: Expr > > ,
728- names : FxHashMap < Symbol , usize > ,
729- append_newline : bool )
730- -> P < ast:: Expr > {
732+ pub fn expand_preparsed_format_args (
733+ ecx : & mut ExtCtxt < ' _ > ,
734+ sp : Span ,
735+ efmt : P < ast:: Expr > ,
736+ args : Vec < P < ast:: Expr > > ,
737+ names : FxHashMap < Symbol , usize > ,
738+ append_newline : bool ,
739+ ) -> P < ast:: Expr > {
731740 // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
732741 // `ArgumentType` does not derive `Clone`.
733742 let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
@@ -906,6 +915,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
906915 . map ( |span| fmt. span . from_inner ( * span) )
907916 . collect ( ) ;
908917
918+ let named_pos: FxHashSet < usize > = names. values ( ) . cloned ( ) . collect ( ) ;
919+
909920 let mut cx = Context {
910921 ecx,
911922 args,
@@ -971,14 +982,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
971982 }
972983
973984 // Make sure that all arguments were used and all arguments have types.
974- let num_pos_args = cx. args . len ( ) - cx. names . len ( ) ;
975-
976985 let errs = cx. arg_types
977986 . iter ( )
978987 . enumerate ( )
979988 . filter ( |( i, ty) | ty. is_empty ( ) && !cx. count_positions . contains_key ( & i) )
980989 . map ( |( i, _) | {
981- let msg = if i >= num_pos_args {
990+ let msg = if named_pos . contains ( & i ) {
982991 // named argument
983992 "named argument never used"
984993 } else {
0 commit comments