@@ -107,6 +107,9 @@ struct Context<'a, 'b> {
107107 arg_spans : Vec < Span > ,
108108 /// All the formatting arguments that have formatting flags set, in order for diagnostics.
109109 arg_with_formatting : Vec < parse:: FormatSpec < ' a > > ,
110+
111+ /// Whether this format string came from a string literal, as opposed to a macro.
112+ is_literal : bool ,
110113}
111114
112115/// Parses the arguments from the given list of tokens, returning the diagnostic
@@ -498,10 +501,59 @@ impl<'a, 'b> Context<'a, 'b> {
498501 self . verify_arg_type ( Exact ( idx) , ty)
499502 }
500503 None => {
501- let msg = format ! ( "there is no argument named `{}`" , name) ;
502- let sp = * self . arg_spans . get ( self . curpiece ) . unwrap_or ( & self . fmtsp ) ;
503- let mut err = self . ecx . struct_span_err ( sp, & msg[ ..] ) ;
504- err. emit ( ) ;
504+ let capture_feature_enabled = self
505+ . ecx
506+ . ecfg
507+ . features
508+ . map_or ( false , |features| features. format_args_capture ) ;
509+
510+ // For the moment capturing variables from format strings expanded from
511+ // literals is disabled (see RFC #2795)
512+ let can_capture = capture_feature_enabled && self . is_literal ;
513+
514+ if can_capture {
515+ // Treat this name as a variable to capture from the surrounding scope
516+ let idx = self . args . len ( ) ;
517+ self . arg_types . push ( Vec :: new ( ) ) ;
518+ self . arg_unique_types . push ( Vec :: new ( ) ) ;
519+ self . args . push (
520+ self . ecx . expr_ident ( self . fmtsp , Ident :: new ( name, self . fmtsp ) ) ,
521+ ) ;
522+ self . names . insert ( name, idx) ;
523+ self . verify_arg_type ( Exact ( idx) , ty)
524+ } else {
525+ let msg = format ! ( "there is no argument named `{}`" , name) ;
526+ let sp = if self . is_literal {
527+ * self . arg_spans . get ( self . curpiece ) . unwrap_or ( & self . fmtsp )
528+ } else {
529+ self . fmtsp
530+ } ;
531+ let mut err = self . ecx . struct_span_err ( sp, & msg[ ..] ) ;
532+
533+ if capture_feature_enabled && !self . is_literal {
534+ err. note ( & format ! (
535+ "did you intend to capture a variable `{}` from \
536+ the surrounding scope?",
537+ name
538+ ) ) ;
539+ err. note (
540+ "for hygiene reasons format_args! cannot capture variables \
541+ when the format string is expanded from a macro",
542+ ) ;
543+ } else if self . ecx . parse_sess ( ) . unstable_features . is_nightly_build ( ) {
544+ err. note ( & format ! (
545+ "did you intend to capture a variable `{}` from \
546+ the surrounding scope?",
547+ name
548+ ) ) ;
549+ err. help (
550+ "add `#![feature(format_args_capture)]` to the crate \
551+ attributes to enable",
552+ ) ;
553+ }
554+
555+ err. emit ( ) ;
556+ }
505557 }
506558 }
507559 }
@@ -951,6 +1003,7 @@ pub fn expand_preparsed_format_args(
9511003 invalid_refs : Vec :: new ( ) ,
9521004 arg_spans,
9531005 arg_with_formatting : Vec :: new ( ) ,
1006+ is_literal : parser. is_literal ,
9541007 } ;
9551008
9561009 // This needs to happen *after* the Parser has consumed all pieces to create all the spans
0 commit comments