Rollup merge of #87441 - ibraheemdev:i-86865, r=cjgillot
Emit suggestion when passing byte literal to format macro Closes #86865
This commit is contained in:
commit
358a018292
5 changed files with 61 additions and 15 deletions
|
@ -510,7 +510,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||||
match expr_to_spanned_string(ecx, template_expr, msg) {
|
match expr_to_spanned_string(ecx, template_expr, msg) {
|
||||||
Ok(template_part) => template_part,
|
Ok(template_part) => template_part,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Some(mut err) = err {
|
if let Some((mut err, _)) = err {
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -964,17 +964,19 @@ pub fn expand_preparsed_format_args(
|
||||||
}
|
}
|
||||||
Ok(fmt) => fmt,
|
Ok(fmt) => fmt,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Some(mut err) = err {
|
if let Some((mut err, suggested)) = err {
|
||||||
let sugg_fmt = match args.len() {
|
let sugg_fmt = match args.len() {
|
||||||
0 => "{}".to_string(),
|
0 => "{}".to_string(),
|
||||||
_ => format!("{}{{}}", "{} ".repeat(args.len())),
|
_ => format!("{}{{}}", "{} ".repeat(args.len())),
|
||||||
};
|
};
|
||||||
err.span_suggestion(
|
if !suggested {
|
||||||
fmt_sp.shrink_to_lo(),
|
err.span_suggestion(
|
||||||
"you might be missing a string literal to format with",
|
fmt_sp.shrink_to_lo(),
|
||||||
format!("\"{}\", ", sugg_fmt),
|
"you might be missing a string literal to format with",
|
||||||
Applicability::MaybeIncorrect,
|
format!("\"{}\", ", sugg_fmt),
|
||||||
);
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
return DummyResult::raw_expr(sp, true);
|
return DummyResult::raw_expr(sp, true);
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
|
||||||
use rustc_attr::{self as attr, Deprecation, Stability};
|
use rustc_attr::{self as attr, Deprecation, Stability};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::{self, Lrc};
|
use rustc_data_structures::sync::{self, Lrc};
|
||||||
use rustc_errors::{DiagnosticBuilder, ErrorReported};
|
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
|
||||||
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
||||||
use rustc_lint_defs::BuiltinLintDiagnostics;
|
use rustc_lint_defs::BuiltinLintDiagnostics;
|
||||||
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
|
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
|
||||||
|
@ -1136,13 +1136,15 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a string literal from the macro expanded version of `expr`,
|
/// Extracts a string literal from the macro expanded version of `expr`,
|
||||||
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
|
/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
|
||||||
/// compilation on error, merely emits a non-fatal error and returns `None`.
|
/// The returned bool indicates whether an applicable suggestion has already been
|
||||||
|
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
|
||||||
|
/// indicates that an ast error was encountered.
|
||||||
pub fn expr_to_spanned_string<'a>(
|
pub fn expr_to_spanned_string<'a>(
|
||||||
cx: &'a mut ExtCtxt<'_>,
|
cx: &'a mut ExtCtxt<'_>,
|
||||||
expr: P<ast::Expr>,
|
expr: P<ast::Expr>,
|
||||||
err_msg: &str,
|
err_msg: &str,
|
||||||
) -> Result<(Symbol, ast::StrStyle, Span), Option<DiagnosticBuilder<'a>>> {
|
) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> {
|
||||||
// Perform eager expansion on the expression.
|
// Perform eager expansion on the expression.
|
||||||
// We want to be able to handle e.g., `concat!("foo", "bar")`.
|
// We want to be able to handle e.g., `concat!("foo", "bar")`.
|
||||||
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
|
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
|
||||||
|
@ -1150,14 +1152,27 @@ pub fn expr_to_spanned_string<'a>(
|
||||||
Err(match expr.kind {
|
Err(match expr.kind {
|
||||||
ast::ExprKind::Lit(ref l) => match l.kind {
|
ast::ExprKind::Lit(ref l) => match l.kind {
|
||||||
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
|
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
|
||||||
|
ast::LitKind::ByteStr(_) => {
|
||||||
|
let mut err = cx.struct_span_err(l.span, err_msg);
|
||||||
|
err.span_suggestion(
|
||||||
|
expr.span.shrink_to_lo(),
|
||||||
|
"consider removing the leading `b`",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
Some((err, true))
|
||||||
|
}
|
||||||
ast::LitKind::Err(_) => None,
|
ast::LitKind::Err(_) => None,
|
||||||
_ => Some(cx.struct_span_err(l.span, err_msg)),
|
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
|
||||||
},
|
},
|
||||||
ast::ExprKind::Err => None,
|
ast::ExprKind::Err => None,
|
||||||
_ => Some(cx.struct_span_err(expr.span, err_msg)),
|
_ => Some((cx.struct_span_err(expr.span, err_msg), false)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts a string literal from the macro expanded version of `expr`,
|
||||||
|
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
|
||||||
|
/// compilation on error, merely emits a non-fatal error and returns `None`.
|
||||||
pub fn expr_to_string(
|
pub fn expr_to_string(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
expr: P<ast::Expr>,
|
expr: P<ast::Expr>,
|
||||||
|
@ -1165,7 +1180,7 @@ pub fn expr_to_string(
|
||||||
) -> Option<(Symbol, ast::StrStyle)> {
|
) -> Option<(Symbol, ast::StrStyle)> {
|
||||||
expr_to_spanned_string(cx, expr, err_msg)
|
expr_to_spanned_string(cx, expr, err_msg)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
err.map(|mut err| {
|
err.map(|(mut err, _)| {
|
||||||
err.emit();
|
err.emit();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
11
src/test/ui/issues/issue-86865.rs
Normal file
11
src/test/ui/issues/issue-86865.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!(b"foo");
|
||||||
|
//~^ ERROR format argument must be a string literal
|
||||||
|
//~| HELP consider removing the leading `b`
|
||||||
|
let mut s = String::new();
|
||||||
|
write!(s, b"foo{}", "bar");
|
||||||
|
//~^ ERROR format argument must be a string literal
|
||||||
|
//~| HELP consider removing the leading `b`
|
||||||
|
}
|
18
src/test/ui/issues/issue-86865.stderr
Normal file
18
src/test/ui/issues/issue-86865.stderr
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
error: format argument must be a string literal
|
||||||
|
--> $DIR/issue-86865.rs:4:14
|
||||||
|
|
|
||||||
|
LL | println!(b"foo");
|
||||||
|
| -^^^^^
|
||||||
|
| |
|
||||||
|
| help: consider removing the leading `b`
|
||||||
|
|
||||||
|
error: format argument must be a string literal
|
||||||
|
--> $DIR/issue-86865.rs:8:15
|
||||||
|
|
|
||||||
|
LL | write!(s, b"foo{}", "bar");
|
||||||
|
| -^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: consider removing the leading `b`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue