Skip to content

Commit

Permalink
Rollup merge of rust-lang#87967 - m-ou-se:non-fmt-panic-detect-fake-s…
Browse files Browse the repository at this point in the history
…pans, r=cjgillot

Detect fake spans in non_fmt_panic lint.

This addresses rust-lang#87621

Some proc_macros claim that the user wrote all of the tokens it outputs, by applying a span from the input to all of the produced tokens. That can result in confusing suggestions, as in rust-lang#87621. This is a simple patch that avoids suggesting anything for `panic!("{}")` if the span of `"{}"` and `panic!(..)` are identical, which is normally not possible.
  • Loading branch information
camsteffen committed Aug 15, 2021
2 parents dc22db6 + 079bf75 commit 8756a24
Showing 1 changed file with 11 additions and 3 deletions.
14 changes: 11 additions & 3 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
let mut l = lint.build("panic message is not a string literal");
l.note("this usage of panic!() is deprecated; it will be a hard error in Rust 2021");
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
if !span.contains(arg_span) {
if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from.
l.emit();
return;
Expand Down Expand Up @@ -204,7 +204,7 @@ fn check_panic_str<'tcx>(
_ => "panic message contains unused formatting placeholders",
});
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
if span.contains(arg.span) {
if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)),
Expand Down Expand Up @@ -235,7 +235,7 @@ fn check_panic_str<'tcx>(
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
let mut l = lint.build(msg);
l.note("this message is not used as a format string, but will be in Rust 2021");
if span.contains(arg.span) {
if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally",
Expand Down Expand Up @@ -283,3 +283,11 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
if let hygiene::ExpnKind::Macro(_, symbol) = expn.kind { symbol } else { sym::panic };
(expn.call_site, panic_macro, macro_symbol.as_str())
}

fn is_arg_inside_call(arg: Span, call: Span) -> bool {
// We only add suggestions if the argument we're looking at appears inside the
// panic call in the source file, to avoid invalid suggestions when macros are involved.
// We specifically check for the spans to not be identical, as that happens sometimes when
// proc_macros lie about spans and apply the same span to all the tokens they produce.
call.contains(arg) && !call.source_equal(&arg)
}

0 comments on commit 8756a24

Please sign in to comment.