1+ use clippy_config:: msrvs:: Msrv ;
2+ use clippy_config:: Conf ;
13use clippy_utils:: diagnostics:: span_lint_and_sugg;
24use clippy_utils:: is_from_proc_macro;
5+ use rustc_attr:: { StabilityLevel , StableSince } ;
36use rustc_errors:: Applicability ;
47use rustc_hir:: def:: Res ;
58use rustc_hir:: def_id:: DefId ;
69use rustc_hir:: { HirId , Path , PathSegment } ;
710use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
811use rustc_middle:: lint:: in_external_macro;
12+ use rustc_semver:: RustcVersion ;
913use rustc_session:: impl_lint_pass;
1014use rustc_span:: symbol:: kw;
1115use rustc_span:: { sym, Span } ;
@@ -66,6 +70,10 @@ declare_clippy_lint! {
6670 /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
6771 /// is also useful for crates migrating to become `no_std` compatible.
6872 ///
73+ /// ### Known problems
74+ /// The lint is only partially aware of the required MSRV for items that were originally in `std` but moved
75+ /// to `core`.
76+ ///
6977 /// ### Example
7078 /// ```no_run
7179 /// # extern crate alloc;
@@ -81,20 +89,30 @@ declare_clippy_lint! {
8189 "type is imported from alloc when available in core"
8290}
8391
84- #[ derive( Default ) ]
8592pub struct StdReexports {
8693 // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
8794 // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
8895 // when the path could be also be used to access the module.
8996 prev_span : Span ,
97+ msrv : Msrv ,
98+ }
99+
100+ impl StdReexports {
101+ pub fn new ( conf : & ' static Conf ) -> Self {
102+ Self {
103+ prev_span : Span :: default ( ) ,
104+ msrv : conf. msrv . clone ( ) ,
105+ }
106+ }
90107}
108+
91109impl_lint_pass ! ( StdReexports => [ STD_INSTEAD_OF_CORE , STD_INSTEAD_OF_ALLOC , ALLOC_INSTEAD_OF_CORE ] ) ;
92110
93111impl < ' tcx > LateLintPass < ' tcx > for StdReexports {
94112 fn check_path ( & mut self , cx : & LateContext < ' tcx > , path : & Path < ' tcx > , _: HirId ) {
95113 if let Res :: Def ( _, def_id) = path. res
96114 && let Some ( first_segment) = get_first_segment ( path)
97- && is_stable ( cx, def_id)
115+ && is_stable ( cx, def_id, & self . msrv )
98116 && !in_external_macro ( cx. sess ( ) , path. span )
99117 && !is_from_proc_macro ( cx, & first_segment. ident )
100118 {
@@ -131,6 +149,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
131149 }
132150 }
133151 }
152+
153+ extract_msrv_attr ! ( LateContext ) ;
134154}
135155
136156/// Returns the first named segment of a [`Path`].
@@ -146,16 +166,29 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>>
146166 }
147167}
148168
149- /// Checks if all ancestors of `def_id` are stable, to avoid linting
150- /// [unstable moves](https://github.com/rust-lang/rust/pull/95956)
151- fn is_stable ( cx : & LateContext < ' _ > , mut def_id : DefId ) -> bool {
169+ /// Checks if all ancestors of `def_id` meet `msrv` to avoid linting [unstable moves](https://github.com/rust-lang/rust/pull/95956)
170+ /// or now stable moves that were once unstable.
171+ ///
172+ /// Does not catch individually moved items
173+ fn is_stable ( cx : & LateContext < ' _ > , mut def_id : DefId , msrv : & Msrv ) -> bool {
152174 loop {
153- if cx
154- . tcx
155- . lookup_stability ( def_id)
156- . map_or ( false , |stability| stability. is_unstable ( ) )
175+ if let Some ( stability) = cx. tcx . lookup_stability ( def_id)
176+ && let StabilityLevel :: Stable {
177+ since,
178+ allowed_through_unstable_modules : false ,
179+ } = stability. level
157180 {
158- return false ;
181+ let stable = match since {
182+ StableSince :: Version ( v) => {
183+ msrv. meets ( RustcVersion :: new ( v. major . into ( ) , v. minor . into ( ) , v. patch . into ( ) ) )
184+ } ,
185+ StableSince :: Current => msrv. current ( ) . is_none ( ) ,
186+ StableSince :: Err => false ,
187+ } ;
188+
189+ if !stable {
190+ return false ;
191+ }
159192 }
160193
161194 match cx. tcx . opt_parent ( def_id) {
0 commit comments