]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #64080 - estebank:parse-format-comma, r=zackmdavis
authorbors <bors@rust-lang.org>
Sat, 14 Sep 2019 06:10:08 +0000 (06:10 +0000)
committerbors <bors@rust-lang.org>
Sat, 14 Sep 2019 06:10:08 +0000 (06:10 +0000)
Be accurate on `format!` parse error expectations

Fix https://github.com/rust-lang/rust/issues/57277.

1  2 
src/libsyntax_ext/format.rs

index dec84c8286292bb03c2ee7287e42ada09dcbab6b,d9ca693aca5046581d9dbd6501c8baec20430907..5bfbdc999174dc325fe1857b6090a597553a2292
@@@ -11,7 -11,7 +11,7 @@@ use syntax::ext::base::{self, *}
  use syntax::parse::token;
  use syntax::ptr::P;
  use syntax::symbol::{Symbol, sym};
 -use syntax::tokenstream;
 +use syntax::tokenstream::TokenStream;
  use syntax_pos::{MultiSpan, Span};
  
  use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@@ -126,7 -126,7 +126,7 @@@ struct Context<'a, 'b> 
  fn parse_args<'a>(
      ecx: &mut ExtCtxt<'a>,
      sp: Span,
 -    tts: &[tokenstream::TokenTree]
 +    tts: TokenStream,
  ) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> {
      let mut args = Vec::<P<ast::Expr>>::new();
      let mut names = FxHashMap::<Symbol, usize>::default();
      }
  
      let fmtstr = p.parse_expr()?;
+     let mut first = true;
      let mut named = false;
  
      while p.token != token::Eof {
          if !p.eat(&token::Comma) {
-             let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
-             err.span_label(p.token.span, "expected `,`");
-             p.maybe_annotate_with_ascription(&mut err, false);
-             return Err(err);
+             if first {
+                 // After `format!(""` we always expect *only* a comma...
+                 let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+                 err.span_label(p.token.span, "expected `,`");
+                 p.maybe_annotate_with_ascription(&mut err, false);
+                 return Err(err);
+             } else {
+                 // ...after that delegate to `expect` to also include the other expected tokens.
+                 return Err(p.expect(&token::Comma).err().unwrap());
+             }
          }
+         first = false;
          if p.token == token::Eof {
              break;
          } // accept trailing commas
@@@ -291,7 -299,7 +299,7 @@@ impl<'a, 'b> Context<'a, 'b> 
                  &format!(
                      "{} positional argument{} in format string, but {}",
                      count,
 -                    if count > 1 { "s" } else { "" },
 +                    if count != 1 { "s" } else { "" },
                      self.describe_num_args(),
                  ),
              );
          // But the nested match expression is proved to perform not as well
          // as series of let's; the first approach does.
          let pat = self.ecx.pat_tuple(self.fmtsp, pats);
 -        let arm = self.ecx.arm(self.fmtsp, vec![pat], args_array);
 +        let arm = self.ecx.arm(self.fmtsp, pat, args_array);
          let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads));
          let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]);
  
  fn expand_format_args_impl<'cx>(
      ecx: &'cx mut ExtCtxt<'_>,
      mut sp: Span,
 -    tts: &[tokenstream::TokenTree],
 +    tts: TokenStream,
      nl: bool,
  ) -> Box<dyn base::MacResult + 'cx> {
      sp = ecx.with_def_site_ctxt(sp);
  pub fn expand_format_args<'cx>(
      ecx: &'cx mut ExtCtxt<'_>,
      sp: Span,
 -    tts: &[tokenstream::TokenTree],
 +    tts: TokenStream,
  ) -> Box<dyn base::MacResult + 'cx> {
      expand_format_args_impl(ecx, sp, tts, false)
  }
  pub fn expand_format_args_nl<'cx>(
      ecx: &'cx mut ExtCtxt<'_>,
      sp: Span,
 -    tts: &[tokenstream::TokenTree],
 +    tts: TokenStream,
  ) -> Box<dyn base::MacResult + 'cx> {
      expand_format_args_impl(ecx, sp, tts, true)
  }