Skip to content

Commit 358a018

Browse files
authored
Rollup merge of #87441 - ibraheemdev:i-86865, r=cjgillot
Emit suggestion when passing byte literal to format macro Closes #86865
2 parents e422612 + f56034e commit 358a018

File tree

5 files changed

+61
-15
lines changed

5 files changed

+61
-15
lines changed

compiler/rustc_builtin_macros/src/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
510510
match expr_to_spanned_string(ecx, template_expr, msg) {
511511
Ok(template_part) => template_part,
512512
Err(err) => {
513-
if let Some(mut err) = err {
513+
if let Some((mut err, _)) = err {
514514
err.emit();
515515
}
516516
return None;

compiler/rustc_builtin_macros/src/format.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -964,17 +964,19 @@ pub fn expand_preparsed_format_args(
964964
}
965965
Ok(fmt) => fmt,
966966
Err(err) => {
967-
if let Some(mut err) = err {
967+
if let Some((mut err, suggested)) = err {
968968
let sugg_fmt = match args.len() {
969969
0 => "{}".to_string(),
970970
_ => format!("{}{{}}", "{} ".repeat(args.len())),
971971
};
972-
err.span_suggestion(
973-
fmt_sp.shrink_to_lo(),
974-
"you might be missing a string literal to format with",
975-
format!("\"{}\", ", sugg_fmt),
976-
Applicability::MaybeIncorrect,
977-
);
972+
if !suggested {
973+
err.span_suggestion(
974+
fmt_sp.shrink_to_lo(),
975+
"you might be missing a string literal to format with",
976+
format!("\"{}\", ", sugg_fmt),
977+
Applicability::MaybeIncorrect,
978+
);
979+
}
978980
err.emit();
979981
}
980982
return DummyResult::raw_expr(sp, true);

compiler/rustc_expand/src/base.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
1010
use rustc_attr::{self as attr, Deprecation, Stability};
1111
use rustc_data_structures::fx::FxHashMap;
1212
use rustc_data_structures::sync::{self, Lrc};
13-
use rustc_errors::{DiagnosticBuilder, ErrorReported};
13+
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
1414
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
1515
use rustc_lint_defs::BuiltinLintDiagnostics;
1616
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
@@ -1136,36 +1136,51 @@ impl<'a> ExtCtxt<'a> {
11361136
}
11371137

11381138
/// Extracts a string literal from the macro expanded version of `expr`,
1139-
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
1140-
/// compilation on error, merely emits a non-fatal error and returns `None`.
1139+
/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
1140+
/// The returned bool indicates whether an applicable suggestion has already been
1141+
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
1142+
/// indicates that an ast error was encountered.
11411143
pub fn expr_to_spanned_string<'a>(
11421144
cx: &'a mut ExtCtxt<'_>,
11431145
expr: P<ast::Expr>,
11441146
err_msg: &str,
1145-
) -> Result<(Symbol, ast::StrStyle, Span), Option<DiagnosticBuilder<'a>>> {
1147+
) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> {
11461148
// Perform eager expansion on the expression.
11471149
// We want to be able to handle e.g., `concat!("foo", "bar")`.
11481150
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
11491151

11501152
Err(match expr.kind {
11511153
ast::ExprKind::Lit(ref l) => match l.kind {
11521154
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
1155+
ast::LitKind::ByteStr(_) => {
1156+
let mut err = cx.struct_span_err(l.span, err_msg);
1157+
err.span_suggestion(
1158+
expr.span.shrink_to_lo(),
1159+
"consider removing the leading `b`",
1160+
String::new(),
1161+
Applicability::MaybeIncorrect,
1162+
);
1163+
Some((err, true))
1164+
}
11531165
ast::LitKind::Err(_) => None,
1154-
_ => Some(cx.struct_span_err(l.span, err_msg)),
1166+
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
11551167
},
11561168
ast::ExprKind::Err => None,
1157-
_ => Some(cx.struct_span_err(expr.span, err_msg)),
1169+
_ => Some((cx.struct_span_err(expr.span, err_msg), false)),
11581170
})
11591171
}
11601172

1173+
/// Extracts a string literal from the macro expanded version of `expr`,
1174+
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
1175+
/// compilation on error, merely emits a non-fatal error and returns `None`.
11611176
pub fn expr_to_string(
11621177
cx: &mut ExtCtxt<'_>,
11631178
expr: P<ast::Expr>,
11641179
err_msg: &str,
11651180
) -> Option<(Symbol, ast::StrStyle)> {
11661181
expr_to_spanned_string(cx, expr, err_msg)
11671182
.map_err(|err| {
1168-
err.map(|mut err| {
1183+
err.map(|(mut err, _)| {
11691184
err.emit();
11701185
})
11711186
})

src/test/ui/issues/issue-86865.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use std::fmt::Write;
2+
3+
fn main() {
4+
println!(b"foo");
5+
//~^ ERROR format argument must be a string literal
6+
//~| HELP consider removing the leading `b`
7+
let mut s = String::new();
8+
write!(s, b"foo{}", "bar");
9+
//~^ ERROR format argument must be a string literal
10+
//~| HELP consider removing the leading `b`
11+
}

src/test/ui/issues/issue-86865.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: format argument must be a string literal
2+
--> $DIR/issue-86865.rs:4:14
3+
|
4+
LL | println!(b"foo");
5+
| -^^^^^
6+
| |
7+
| help: consider removing the leading `b`
8+
9+
error: format argument must be a string literal
10+
--> $DIR/issue-86865.rs:8:15
11+
|
12+
LL | write!(s, b"foo{}", "bar");
13+
| -^^^^^^^
14+
| |
15+
| help: consider removing the leading `b`
16+
17+
error: aborting due to 2 previous errors
18+

0 commit comments

Comments
 (0)