Skip to content

Commit 5d81633

Browse files
committed
Skip use_self inside thread_local! of a impl Self block
1 parent c938b1a commit 5d81633

File tree

3 files changed

+37
-22
lines changed

3 files changed

+37
-22
lines changed

clippy_lints/src/use_self.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_hir::{
1515
use rustc_lint::{LateContext, LateLintPass};
1616
use rustc_middle::ty::Ty as MiddleTy;
1717
use rustc_session::impl_lint_pass;
18-
use rustc_span::Span;
18+
use rustc_span::{sym, Span};
1919

2020
declare_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+
}

tests/ui/use_self.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ mod issue_13092 {
675675

676676
impl MyStruct {
677677
thread_local! {
678-
static SPECIAL: RefCell<Self> = RefCell::default();
678+
static SPECIAL: RefCell<MyStruct> = RefCell::default();
679679
}
680680
}
681681
}

tests/ui/use_self.stderr

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -259,19 +259,5 @@ error: unnecessary structure name repetition
259259
LL | E::A => {},
260260
| ^ help: use the applicable keyword: `Self`
261261

262-
error: unnecessary structure name repetition
263-
--> tests/ui/use_self.rs:678:37
264-
|
265-
LL | static SPECIAL: RefCell<MyStruct> = RefCell::default();
266-
| ^^^^^^^^ help: use the applicable keyword: `Self`
267-
268-
error: unnecessary structure name repetition
269-
--> tests/ui/use_self.rs:678:37
270-
|
271-
LL | static SPECIAL: RefCell<MyStruct> = RefCell::default();
272-
| ^^^^^^^^ help: use the applicable keyword: `Self`
273-
|
274-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
275-
276-
error: aborting due to 45 previous errors
262+
error: aborting due to 43 previous errors
277263

0 commit comments

Comments
 (0)