about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/incompatible_msrv.rs26
-rw-r--r--tests/ui/incompatible_msrv.rs39
-rw-r--r--tests/ui/incompatible_msrv.stderr37
3 files changed, 94 insertions, 8 deletions
diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs
index 12dfb14c454..e55edb1fcaa 100644
--- a/clippy_lints/src/incompatible_msrv.rs
+++ b/clippy_lints/src/incompatible_msrv.rs
@@ -4,12 +4,12 @@ use clippy_utils::is_in_test;
 use clippy_utils::msrvs::Msrv;
 use rustc_attr_parsing::{RustcVersion, StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{Expr, ExprKind, HirId};
+use rustc_hir::{Expr, ExprKind, HirId, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::DefId;
-use rustc_span::{ExpnKind, Span};
+use rustc_span::{ExpnKind, Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -93,6 +93,21 @@ impl IncompatibleMsrv {
             // Intentionally not using `.from_expansion()`, since we do still care about macro expansions
             return;
         }
+
+        // Functions coming from `core` while expanding a macro such as `assert*!()` get to cheat too: the
+        // macros may have existed prior to the checked MSRV, but their expansion with a recent compiler
+        // might use recent functions or methods. Compiling with an older compiler would not use those.
+        if span.from_expansion()
+            && cx.tcx.crate_name(def_id.krate) == sym::core
+            && span
+                .ctxt()
+                .outer_expn_data()
+                .macro_def_id
+                .is_some_and(|def_id| cx.tcx.crate_name(def_id.krate) == sym::core)
+        {
+            return;
+        }
+
         if (self.check_in_tests || !is_in_test(cx.tcx, node))
             && let Some(current) = self.msrv.current(cx)
             && let version = self.get_def_id_version(cx.tcx, def_id)
@@ -118,8 +133,11 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv {
                     self.emit_lint_if_under_msrv(cx, method_did, expr.hir_id, span);
                 }
             },
-            ExprKind::Call(call, [_]) => {
-                if let ExprKind::Path(qpath) = call.kind
+            ExprKind::Call(call, _) => {
+                // Desugaring into function calls by the compiler will use `QPath::LangItem` variants. Those should
+                // not be linted as they will not be generated in older compilers if the function is not available,
+                // and the compiler is allowed to call unstable functions.
+                if let ExprKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) = call.kind
                     && let Some(path_def_id) = cx.qpath_res(&qpath, call.hir_id).opt_def_id()
                 {
                     self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, call.span);
diff --git a/tests/ui/incompatible_msrv.rs b/tests/ui/incompatible_msrv.rs
index b4fea4cae5e..99101b2bb8f 100644
--- a/tests/ui/incompatible_msrv.rs
+++ b/tests/ui/incompatible_msrv.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::incompatible_msrv)]
 #![feature(custom_inner_attributes)]
+#![feature(panic_internals)]
 #![clippy::msrv = "1.3.0"]
 
 use std::collections::HashMap;
@@ -34,4 +35,42 @@ async fn issue12273(v: impl Future<Output = ()>) {
     v.await;
 }
 
+fn core_special_treatment(p: bool) {
+    // Do not lint code coming from `core` macros expanding into `core` function calls
+    if p {
+        panic!("foo"); // Do not lint
+    }
+
+    // But still lint code calling `core` functions directly
+    if p {
+        core::panicking::panic("foo");
+        //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0`
+    }
+
+    // Lint code calling `core` from non-`core` macros
+    macro_rules! my_panic {
+        ($msg:expr) => {
+            core::panicking::panic($msg)
+        }; //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0`
+    }
+    my_panic!("foo");
+
+    // Lint even when the macro comes from `core` and calls `core` functions
+    assert!(core::panicking::panic("out of luck"));
+    //~^ ERROR: is `1.3.0` but this item is stable since `1.6.0`
+}
+
+#[clippy::msrv = "1.26.0"]
+fn lang_items() {
+    // Do not lint lang items. `..=` will expand into `RangeInclusive::new()`, which was introduced
+    // in Rust 1.27.0.
+    let _ = 1..=3;
+}
+
+#[clippy::msrv = "1.80.0"]
+fn issue14212() {
+    let _ = std::iter::repeat_n((), 5);
+    //~^ ERROR: is `1.80.0` but this item is stable since `1.82.0`
+}
+
 fn main() {}
diff --git a/tests/ui/incompatible_msrv.stderr b/tests/ui/incompatible_msrv.stderr
index 56c9eae5aaf..5ea2bb9cc58 100644
--- a/tests/ui/incompatible_msrv.stderr
+++ b/tests/ui/incompatible_msrv.stderr
@@ -1,5 +1,5 @@
 error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.10.0`
-  --> tests/ui/incompatible_msrv.rs:13:39
+  --> tests/ui/incompatible_msrv.rs:14:39
    |
 LL |     assert_eq!(map.entry("poneyland").key(), &"poneyland");
    |                                       ^^^^^
@@ -8,16 +8,45 @@ LL |     assert_eq!(map.entry("poneyland").key(), &"poneyland");
    = help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]`
 
 error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.12.0`
-  --> tests/ui/incompatible_msrv.rs:17:11
+  --> tests/ui/incompatible_msrv.rs:18:11
    |
 LL |         v.into_key();
    |           ^^^^^^^^^^
 
 error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0`
-  --> tests/ui/incompatible_msrv.rs:21:5
+  --> tests/ui/incompatible_msrv.rs:22:5
    |
 LL |     sleep(Duration::new(1, 0));
    |     ^^^^^
 
-error: aborting due to 3 previous errors
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0`
+  --> tests/ui/incompatible_msrv.rs:46:9
+   |
+LL |         core::panicking::panic("foo");
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0`
+  --> tests/ui/incompatible_msrv.rs:53:13
+   |
+LL |             core::panicking::panic($msg)
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     my_panic!("foo");
+   |     ---------------- in this macro invocation
+   |
+   = note: this error originates in the macro `my_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.6.0`
+  --> tests/ui/incompatible_msrv.rs:59:13
+   |
+LL |     assert!(core::panicking::panic("out of luck"));
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.80.0` but this item is stable since `1.82.0`
+  --> tests/ui/incompatible_msrv.rs:72:13
+   |
+LL |     let _ = std::iter::repeat_n((), 5);
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors