p.clear_expected_tokens();
}
- // `Parser::expect` tries to recover using the
- // `Parser::unexpected_try_recover` function. This function is able
- // to recover if the expected token is a closing delimiter.
- //
- // As `,` is not a closing delimiter, it will always return an `Err`
- // variant.
- let mut err = p.expect(&token::Comma).unwrap_err();
-
- match token::TokenKind::Comma.similar_tokens() {
- Some(tks) if tks.contains(&p.token.kind) => {
- // If a similar token is found, then it may be a typo. We
- // consider it as a comma, and continue parsing.
- err.emit();
- p.bump();
+ match p.expect(&token::Comma) {
+ Err(mut err) => {
+ match token::TokenKind::Comma.similar_tokens() {
+ Some(tks) if tks.contains(&p.token.kind) => {
+ // If a similar token is found, then it may be a typo. We
+ // consider it as a comma, and continue parsing.
+ err.emit();
+ p.bump();
+ }
+ // Otherwise stop the parsing and return the error.
+ _ => return Err(err),
+ }
+ }
+ Ok(recovered) => {
+ assert!(recovered);
}
- // Otherwise stop the parsing and return the error.
- _ => return Err(err),
}
}
first = false;
self.ecx.expr_match(self.macsp, head, vec![arm])
};
- let ident = Ident::from_str_and_span("args", self.macsp);
- let args_slice = self.ecx.expr_ident(self.macsp, ident);
+ let args_slice = self.ecx.expr_addr_of(self.macsp, args_match);
// Now create the fmt::Arguments struct with all our locals we created.
let (fn_name, fn_args) = if self.all_pieces_simple {
// nonstandard placeholders, if there are any.
let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);
- ("new_v1_formatted", vec![pieces, args_slice, fmt])
+ let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
+ let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());
+ let unsafe_expr = self.ecx.expr_block(P(ast::Block {
+ stmts: vec![self.ecx.stmt_expr(unsafe_arg)],
+ id: ast::DUMMY_NODE_ID,
+ rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
+ span: self.macsp,
+ tokens: None,
+ could_be_bare_literal: false,
+ }));
+
+ ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr])
};
let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
- let arguments = self.ecx.expr_call_global(self.macsp, path, fn_args);
- let body = self.ecx.expr_block(P(ast::Block {
- stmts: vec![self.ecx.stmt_expr(arguments)],
- id: ast::DUMMY_NODE_ID,
- rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
- span: self.macsp,
- tokens: None,
- could_be_bare_literal: false,
- }));
-
- let ident = Ident::from_str_and_span("args", self.macsp);
- let binding_mode = ast::BindingMode::ByRef(ast::Mutability::Not);
- let pat = self.ecx.pat_ident_binding_mode(self.macsp, ident, binding_mode);
- let arm = self.ecx.arm(self.macsp, pat, body);
- self.ecx.expr_match(self.macsp, args_match, vec![arm])
+ self.ecx.expr_call_global(self.macsp, path, fn_args)
}
fn format_arg(
}
Ok(fmt) => fmt,
Err(err) => {
- if let Some(mut err) = err {
+ if let Some((mut err, suggested)) = err {
let sugg_fmt = match args.len() {
0 => "{}".to_string(),
_ => format!("{}{{}}", "{} ".repeat(args.len())),
};
- err.span_suggestion(
- fmt_sp.shrink_to_lo(),
- "you might be missing a string literal to format with",
- format!("\"{}\", ", sugg_fmt),
- Applicability::MaybeIncorrect,
- );
+ if !suggested {
+ err.span_suggestion(
+ fmt_sp.shrink_to_lo(),
+ "you might be missing a string literal to format with",
+ format!("\"{}\", ", sugg_fmt),
+ Applicability::MaybeIncorrect,
+ );
+ }
err.emit();
}
return DummyResult::raw_expr(sp, true);
// account for `"` and account for raw strings `r#`
let padding = str_style.map(|i| i + 2).unwrap_or(1);
for sub in foreign::$kind::iter_subs(fmt_str, padding) {
- let trn = match sub.translate() {
- Some(trn) => trn,
+ let (trn, success) = match sub.translate() {
+ Ok(trn) => (trn, true),
+ Err(Some(msg)) => (msg, false),
// If it has no translation, don't call it out specifically.
- None => continue,
+ _ => continue,
};
let pos = sub.position();
if let Some(inner_sp) = pos {
let sp = fmt_sp.from_inner(inner_sp);
- suggestions.push((sp, trn));
+
+ if success {
+ suggestions.push((sp, trn));
+ } else {
+ diag.span_note(
+ sp,
+ &format!("format specifiers use curly braces, and {}", trn),
+ );
+ }
} else {
- diag.help(&format!("`{}` should be written as `{}`", sub, trn));
+ if success {
+ diag.help(&format!("`{}` should be written as `{}`", sub, trn));
+ } else {
+ diag.note(&format!(
+ "`{}` should use curly braces, and {}",
+ sub, trn
+ ));
+ }
}
}