@@ -15,7 +15,7 @@ use rustc_hir::{
1515use rustc_lint:: { LateContext , LateLintPass } ;
1616use rustc_middle:: ty:: Ty as MiddleTy ;
1717use rustc_session:: impl_lint_pass;
18- use rustc_span:: Span ;
18+ use rustc_span:: { sym , Span } ;
1919
2020declare_clippy_lint ! {
2121 /// ### What it does
@@ -87,6 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
8787 // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>`
8888 return ;
8989 }
90+
9091 // We push the self types of `impl`s on a stack here. Only the top type on the stack is
9192 // relevant for linting, since this is the self type of the `impl` we're currently in. To
9293 // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
@@ -134,14 +135,17 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
134135 }
135136
136137 fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , impl_item : & hir:: ImplItem < ' _ > ) {
138+ let Some ( & mut StackItem :: Check {
139+ impl_id,
140+ ref mut types_to_skip,
141+ ..
142+ } ) = self . stack . last_mut ( )
143+ else {
144+ return ;
145+ } ;
137146 // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
138147 // declaration. The collection of those types is all this method implementation does.
139148 if let ImplItemKind :: Fn ( FnSig { decl, .. } , ..) = impl_item. kind
140- && let Some ( & mut StackItem :: Check {
141- impl_id,
142- ref mut types_to_skip,
143- ..
144- } ) = self . stack . last_mut ( )
145149 && let Some ( impl_trait_ref) = cx. tcx . impl_trait_ref ( impl_id)
146150 {
147151 // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
@@ -187,8 +191,25 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
187191 }
188192 }
189193 }
194+ // Checking const items of `impl Self` blocks in which `std::thread_local!` expands into.
195+ // HACK: `std::thread_local_inner` sometimes clears `macro_backtrace` of types in `check_ty`.
196+ // To work around this problem, and assume that `LateLintPass` walks recursively from
197+ // `check_impl_item` into `check_ty`, `check_expr`,etc. We encode the state when we enter
198+ // this const item of `thread_local!` macro. Just remember to remove this state again in
199+ // `check_impl_item_post`.
200+ else if let ImplItemKind :: Const ( ..) = impl_item. kind
201+ && cx. tcx . impl_trait_ref ( impl_id) . is_none ( )
202+ && is_inside_thread_local_macro ( cx, impl_item. span )
203+ {
204+ self . stack . push ( StackItem :: NoCheck ) ;
205+ }
190206 }
191207
208+ fn check_impl_item_post ( & mut self , _: & LateContext < ' _ > , _: & hir:: ImplItem < ' _ > ) {
209+ if let Some ( StackItem :: NoCheck ) = self . stack . last ( ) {
210+ self . stack . pop ( ) ;
211+ }
212+ }
192213
193214 fn check_ty ( & mut self , cx : & LateContext < ' tcx > , hir_ty : & Ty < ' tcx > ) {
194215 if !hir_ty. span . from_expansion ( )
@@ -335,3 +356,11 @@ fn has_no_lifetime(ty: MiddleTy<'_>) -> bool {
335356 _ => true ,
336357 }
337358}
359+
360+ fn is_inside_thread_local_macro ( cx : & LateContext < ' _ > , span : Span ) -> bool {
361+ if let Some ( macro_def_id) = span. source_callee ( ) . and_then ( |expn| expn. macro_def_id ) {
362+ cx. tcx . is_diagnostic_item ( sym:: thread_local_macro, macro_def_id)
363+ } else {
364+ false
365+ }
366+ }
0 commit comments