Skip to content

Commit

Permalink
emit suggestion byte literal is passed to format!
Browse files Browse the repository at this point in the history
  • Loading branch information
ibraheemdev committed Aug 31, 2021
1 parent e1d49aa commit f56034e
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 15 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast
match expr_to_spanned_string(ecx, template_expr, msg) {
Ok(template_part) => template_part,
Err(err) => {
if let Some(mut err) = err {
if let Some((mut err, _)) = err {
err.emit();
}
return DummyResult::raw_expr(sp, true);
Expand Down
16 changes: 9 additions & 7 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,17 +946,19 @@ pub fn expand_preparsed_format_args(
}
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);
Expand Down
29 changes: 22 additions & 7 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
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::BuiltinLintDiagnostics;
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
Expand Down Expand Up @@ -1133,36 +1133,51 @@ impl<'a> ExtCtxt<'a> {
}

/// 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`.
/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
/// 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>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
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.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();

Err(match expr.kind {
ast::ExprKind::Lit(ref l) => match l.kind {
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,
_ => Some(cx.struct_span_err(l.span, err_msg)),
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
},
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(
cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>,
err_msg: &str,
) -> Option<(Symbol, ast::StrStyle)> {
expr_to_spanned_string(cx, expr, err_msg)
.map_err(|err| {
err.map(|mut err| {
err.map(|(mut err, _)| {
err.emit();
})
})
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-86865.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions src/test/ui/issues/issue-86865.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit f56034e

Please sign in to comment.