about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMara Bos <m-ou.se@m-ou.se>2021-08-16 23:37:28 +0200
committerGitHub <noreply@github.com>2021-08-16 23:37:28 +0200
commitbeeff0440ff977228be9ea4f38b76daaccfbe4ea (patch)
treee3fc8ad0880f9bc929e3d3ab13f3cc905a552e79
parentd7df1b13da463011a843383a20c0fd4f111d3564 (diff)
parent079bf755a3449a61e61714a17d00f21337f2471e (diff)
downloadrust-beeff0440ff977228be9ea4f38b76daaccfbe4ea.tar.gz
rust-beeff0440ff977228be9ea4f38b76daaccfbe4ea.zip
Rollup merge of #87967 - m-ou-se:non-fmt-panic-detect-fake-spans, r=cjgillot
Detect fake spans in non_fmt_panic lint.

This addresses https://github.com/rust-lang/rust/issues/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 #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.
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs14
1 files changed, 11 insertions, 3 deletions
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 3349063e5dc..ee66a948dd9 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -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;
@@ -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)),
@@ -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",
@@ -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)
+}