Skip to content

Commit f56034e

Browse files
committed
emit suggestion byte literal is passed to format!
1 parent e1d49aa commit f56034e

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
@@ -412,7 +412,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast
412412
match expr_to_spanned_string(ecx, template_expr, msg) {
413413
Ok(template_part) => template_part,
414414
Err(err) => {
415-
if let Some(mut err) = err {
415+
if let Some((mut err, _)) = err {
416416
err.emit();
417417
}
418418
return DummyResult::raw_expr(sp, true);

compiler/rustc_builtin_macros/src/format.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -946,17 +946,19 @@ pub fn expand_preparsed_format_args(
946946
}
947947
Ok(fmt) => fmt,
948948
Err(err) => {
949-
if let Some(mut err) = err {
949+
if let Some((mut err, suggested)) = err {
950950
let sugg_fmt = match args.len() {
951951
0 => "{}".to_string(),
952952
_ => format!("{}{{}}", "{} ".repeat(args.len())),
953953
};
954-
err.span_suggestion(
955-
fmt_sp.shrink_to_lo(),
956-
"you might be missing a string literal to format with",
957-
format!("\"{}\", ", sugg_fmt),
958-
Applicability::MaybeIncorrect,
959-
);
954+
if !suggested {
955+
err.span_suggestion(
956+
fmt_sp.shrink_to_lo(),
957+
"you might be missing a string literal to format with",
958+
format!("\"{}\", ", sugg_fmt),
959+
Applicability::MaybeIncorrect,
960+
);
961+
}
960962
err.emit();
961963
}
962964
return DummyResult::raw_expr(sp, true);

compiler/rustc_expand/src/base.rs

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

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

11471149
Err(match expr.kind {
11481150
ast::ExprKind::Lit(ref l) => match l.kind {
11491151
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
1152+
ast::LitKind::ByteStr(_) => {
1153+
let mut err = cx.struct_span_err(l.span, err_msg);
1154+
err.span_suggestion(
1155+
expr.span.shrink_to_lo(),
1156+
"consider removing the leading `b`",
1157+
String::new(),
1158+
Applicability::MaybeIncorrect,
1159+
);
1160+
Some((err, true))
1161+
}
11501162
ast::LitKind::Err(_) => None,
1151-
_ => Some(cx.struct_span_err(l.span, err_msg)),
1163+
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
11521164
},
11531165
ast::ExprKind::Err => None,
1154-
_ => Some(cx.struct_span_err(expr.span, err_msg)),
1166+
_ => Some((cx.struct_span_err(expr.span, err_msg), false)),
11551167
})
11561168
}
11571169

1170+
/// Extracts a string literal from the macro expanded version of `expr`,
1171+
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
1172+
/// compilation on error, merely emits a non-fatal error and returns `None`.
11581173
pub fn expr_to_string(
11591174
cx: &mut ExtCtxt<'_>,
11601175
expr: P<ast::Expr>,
11611176
err_msg: &str,
11621177
) -> Option<(Symbol, ast::StrStyle)> {
11631178
expr_to_spanned_string(cx, expr, err_msg)
11641179
.map_err(|err| {
1165-
err.map(|mut err| {
1180+
err.map(|(mut err, _)| {
11661181
err.emit();
11671182
})
11681183
})

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)