1
+ use clippy_config:: msrvs:: Msrv ;
2
+ use clippy_config:: Conf ;
1
3
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
4
use clippy_utils:: is_from_proc_macro;
5
+ use rustc_attr:: { StabilityLevel , StableSince } ;
3
6
use rustc_errors:: Applicability ;
4
7
use rustc_hir:: def:: Res ;
5
8
use rustc_hir:: def_id:: DefId ;
6
9
use rustc_hir:: { HirId , Path , PathSegment } ;
7
10
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
8
11
use rustc_middle:: lint:: in_external_macro;
12
+ use rustc_semver:: RustcVersion ;
9
13
use rustc_session:: impl_lint_pass;
10
14
use rustc_span:: symbol:: kw;
11
15
use rustc_span:: { sym, Span } ;
@@ -66,6 +70,10 @@ declare_clippy_lint! {
66
70
/// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
67
71
/// is also useful for crates migrating to become `no_std` compatible.
68
72
///
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
+ ///
69
77
/// ### Example
70
78
/// ```no_run
71
79
/// # extern crate alloc;
@@ -81,20 +89,30 @@ declare_clippy_lint! {
81
89
"type is imported from alloc when available in core"
82
90
}
83
91
84
- #[ derive( Default ) ]
85
92
pub struct StdReexports {
86
93
// Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
87
94
// twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
88
95
// when the path could be also be used to access the module.
89
96
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
+ }
90
107
}
108
+
91
109
impl_lint_pass ! ( StdReexports => [ STD_INSTEAD_OF_CORE , STD_INSTEAD_OF_ALLOC , ALLOC_INSTEAD_OF_CORE ] ) ;
92
110
93
111
impl < ' tcx > LateLintPass < ' tcx > for StdReexports {
94
112
fn check_path ( & mut self , cx : & LateContext < ' tcx > , path : & Path < ' tcx > , _: HirId ) {
95
113
if let Res :: Def ( _, def_id) = path. res
96
114
&& let Some ( first_segment) = get_first_segment ( path)
97
- && is_stable ( cx, def_id)
115
+ && is_stable ( cx, def_id, & self . msrv )
98
116
&& !in_external_macro ( cx. sess ( ) , path. span )
99
117
&& !is_from_proc_macro ( cx, & first_segment. ident )
100
118
{
@@ -131,6 +149,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
131
149
}
132
150
}
133
151
}
152
+
153
+ extract_msrv_attr ! ( LateContext ) ;
134
154
}
135
155
136
156
/// Returns the first named segment of a [`Path`].
@@ -146,16 +166,29 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>>
146
166
}
147
167
}
148
168
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 {
152
174
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
157
180
{
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
+ }
159
192
}
160
193
161
194
match cx. tcx . opt_parent ( def_id) {
0 commit comments