diff options
| author | Samuel Tardieu <sam@rfc1149.net> | 2025-03-18 19:21:30 +0100 |
|---|---|---|
| committer | Samuel Tardieu <sam@rfc1149.net> | 2025-05-21 17:17:30 +0200 |
| commit | 205e313ae4904468d8d2ee6f2cb785bb91271512 (patch) | |
| tree | 5b9c0939ab721c476f2b567f1164b6614f48bdab /clippy_lints/src | |
| parent | f2d49731575198637ee3bb2d83c7060c3581a512 (diff) | |
Do not warn about feature-enabled items
If an item has been enabled through a feature, it will not be linted even though the MSRV is not compatible. This use case may happen when stable compilers are allowed to enable unstable features, e.g. in the Rust for Linux toolchain.
Diffstat (limited to 'clippy_lints/src')
| -rw-r--r-- | clippy_lints/src/incompatible_msrv.rs | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 9d98777c632..1fd8ecd179a 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; use clippy_utils::msrvs::Msrv; -use rustc_attr_data_structures::{RustcVersion, StabilityLevel, StableSince}; +use rustc_attr_data_structures::{RustcVersion, Stability, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -72,9 +72,15 @@ declare_clippy_lint! { "ensures that all items used in the crate are available for the current MSRV" } +#[derive(Clone, Copy)] +enum Availability { + FeatureEnabled, + Since(RustcVersion), +} + pub struct IncompatibleMsrv { msrv: Msrv, - is_above_msrv: FxHashMap<DefId, RustcVersion>, + availability_cache: FxHashMap<DefId, Availability>, check_in_tests: bool, } @@ -84,35 +90,32 @@ impl IncompatibleMsrv { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv, - is_above_msrv: FxHashMap::default(), + availability_cache: FxHashMap::default(), check_in_tests: conf.check_incompatible_msrv_in_tests, } } - fn get_def_id_version(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> RustcVersion { - if let Some(version) = self.is_above_msrv.get(&def_id) { - return *version; + /// Returns the availability of `def_id`, whether it is enabled through a feature or + /// available since a given version (the default being Rust 1.0.0). + fn get_def_id_availability(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> Availability { + if let Some(availability) = self.availability_cache.get(&def_id) { + return *availability; } - let version = if let Some(version) = tcx - .lookup_stability(def_id) - .and_then(|stability| match stability.level { - StabilityLevel::Stable { - since: StableSince::Version(version), - .. - } => Some(version), - _ => None, - }) { - version + let stability = tcx.lookup_stability(def_id); + let version = if stability.is_some_and(|stability| tcx.features().enabled(stability.feature)) { + Availability::FeatureEnabled + } else if let Some(StableSince::Version(version)) = stability.as_ref().and_then(Stability::stable_since) { + Availability::Since(version) } else if let Some(parent_def_id) = tcx.opt_parent(def_id) { - self.get_def_id_version(tcx, parent_def_id) + self.get_def_id_availability(tcx, parent_def_id) } else { - RustcVersion { + Availability::Since(RustcVersion { major: 1, minor: 0, patch: 0, - } + }) }; - self.is_above_msrv.insert(def_id, version); + self.availability_cache.insert(def_id, version); version } @@ -143,7 +146,7 @@ impl IncompatibleMsrv { 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) + && let Availability::Since(version) = self.get_def_id_availability(cx.tcx, def_id) && version > current { span_lint_and_then( |
