Skip to content

Commit 20b2461

Browse files
authored
Skip use_self inside macro expansions of a impl Self block (rust-lang#13128)
changelog: [`use_self`] Skip if inside macro expansions of a `impl Self` block Fixes rust-lang#13092. r? Alexendoo
2 parents 3e3715c + 9ea2b65 commit 20b2461

File tree

6 files changed

+120
-39
lines changed

6 files changed

+120
-39
lines changed

clippy_lints/src/use_self.rs

+13-24
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::is_from_proc_macro;
44
use clippy_utils::msrvs::{self, Msrv};
5-
use clippy_utils::ty::same_type_and_consts;
5+
use clippy_utils::ty::{same_type_and_consts, ty_from_hir_ty};
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_errors::Applicability;
88
use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -12,7 +12,6 @@ use rustc_hir::{
1212
self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
1313
HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
1414
};
15-
use rustc_hir_analysis::lower_ty;
1615
use rustc_lint::{LateContext, LateLintPass};
1716
use rustc_middle::ty::Ty as MiddleTy;
1817
use rustc_session::impl_lint_pass;
@@ -73,7 +72,6 @@ impl UseSelf {
7372
enum StackItem {
7473
Check {
7574
impl_id: LocalDefId,
76-
in_body: u32,
7775
types_to_skip: FxHashSet<HirId>,
7876
},
7977
NoCheck,
@@ -96,8 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
9694
.as_ref()
9795
.is_none_or(|params| params.parenthesized == GenericArgsParentheses::No)
9896
&& !item.span.from_expansion()
97+
// expensive, should be last check
9998
&& !is_from_proc_macro(cx, item)
100-
// expensive, should be last check
10199
{
102100
// Self cannot be used inside const generic parameters
103101
let types_to_skip = generics
@@ -117,7 +115,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
117115
.collect();
118116
StackItem::Check {
119117
impl_id: item.owner_id.def_id,
120-
in_body: 0,
121118
types_to_skip,
122119
}
123120
} else {
@@ -131,6 +128,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
131128
}
132129

133130
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
131+
// Checking items of `impl Self` blocks in which macro expands into.
132+
if impl_item.span.from_expansion() {
133+
self.stack.push(StackItem::NoCheck);
134+
return;
135+
}
134136
// We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
135137
// declaration. The collection of those types is all this method implementation does.
136138
if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind
@@ -186,18 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
186188
}
187189
}
188190

189-
fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
190-
// `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
191-
// we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
192-
// However the `node_type()` method can *only* be called in bodies.
193-
if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
194-
*in_body = in_body.saturating_add(1);
195-
}
196-
}
197-
198-
fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
199-
if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
200-
*in_body = in_body.saturating_sub(1);
191+
fn check_impl_item_post(&mut self, _: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
192+
if impl_item.span.from_expansion()
193+
&& let Some(StackItem::NoCheck) = self.stack.last()
194+
{
195+
self.stack.pop();
201196
}
202197
}
203198

@@ -206,7 +201,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
206201
&& self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
207202
&& let Some(&StackItem::Check {
208203
impl_id,
209-
in_body,
210204
ref types_to_skip,
211205
}) = self.stack.last()
212206
&& let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind
@@ -215,12 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
215209
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
216210
)
217211
&& !types_to_skip.contains(&hir_ty.hir_id)
218-
&& let ty = if in_body > 0 {
219-
cx.typeck_results().node_type(hir_ty.hir_id)
220-
} else {
221-
// We don't care about ignoring infer vars here
222-
lower_ty(cx.tcx, hir_ty.as_unambig_ty())
223-
}
212+
&& let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
224213
&& let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
225214
&& same_type_and_consts(ty, impl_ty)
226215
// Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that

clippy_lints/src/zero_sized_map_values.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
2-
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
2+
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, ty_from_hir_ty};
33
use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
4-
use rustc_hir_analysis::lower_ty;
54
use rustc_lint::{LateContext, LateLintPass};
65
use rustc_middle::ty::layout::LayoutOf as _;
7-
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
6+
use rustc_middle::ty::{self, TypeVisitableExt};
87
use rustc_session::declare_lint_pass;
98
use rustc_span::sym;
109

@@ -82,15 +81,3 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
8281
}
8382
false
8483
}
85-
86-
fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
87-
cx.maybe_typeck_results()
88-
.and_then(|results| {
89-
if results.hir_owner == hir_ty.hir_id.owner {
90-
results.node_type_opt(hir_ty.hir_id)
91-
} else {
92-
None
93-
}
94-
})
95-
.unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
96-
}

clippy_utils/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern crate rustc_data_structures;
3939
extern crate rustc_driver;
4040
extern crate rustc_errors;
4141
extern crate rustc_hir;
42+
extern crate rustc_hir_analysis;
4243
extern crate rustc_hir_typeck;
4344
extern crate rustc_index;
4445
extern crate rustc_infer;

clippy_utils/src/ty/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_hir as hir;
1010
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
1111
use rustc_hir::def_id::DefId;
1212
use rustc_hir::{Expr, FnDecl, LangItem, TyKind};
13+
use rustc_hir_analysis::lower_ty;
1314
use rustc_infer::infer::TyCtxtInferExt;
1415
use rustc_lint::LateContext;
1516
use rustc_middle::mir::ConstValue;
@@ -36,6 +37,19 @@ use crate::{def_path_def_ids, match_def_path, path_res};
3637
mod type_certainty;
3738
pub use type_certainty::expr_type_is_certain;
3839

40+
/// Lower a [`hir::Ty`] to a [`rustc_middle::Ty`].
41+
pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
42+
cx.maybe_typeck_results()
43+
.and_then(|results| {
44+
if results.hir_owner == hir_ty.hir_id.owner {
45+
results.node_type_opt(hir_ty.hir_id)
46+
} else {
47+
None
48+
}
49+
})
50+
.unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
51+
}
52+
3953
/// Checks if the given type implements copy.
4054
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
4155
cx.type_is_copy_modulo_regions(ty)

tests/ui/use_self.fixed

+45
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,48 @@ mod issue_10371 {
667667
}
668668
}
669669
}
670+
671+
mod issue_13092 {
672+
use std::cell::RefCell;
673+
macro_rules! macro_inner_item {
674+
($ty:ty) => {
675+
fn foo(_: $ty) {
676+
fn inner(_: $ty) {}
677+
}
678+
};
679+
}
680+
681+
#[derive(Default)]
682+
struct MyStruct;
683+
684+
impl MyStruct {
685+
macro_inner_item!(MyStruct);
686+
}
687+
688+
impl MyStruct {
689+
thread_local! {
690+
static SPECIAL: RefCell<MyStruct> = RefCell::default();
691+
}
692+
}
693+
}
694+
695+
mod crash_check_13128 {
696+
struct A;
697+
698+
impl A {
699+
fn a() {
700+
struct B;
701+
702+
// pushes a NoCheck
703+
impl Iterator for &B {
704+
// Pops the NoCheck
705+
type Item = A;
706+
707+
// Lints A -> Self
708+
fn next(&mut self) -> Option<A> {
709+
Some(A)
710+
}
711+
}
712+
}
713+
}
714+
}

tests/ui/use_self.rs

+45
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,48 @@ mod issue_10371 {
667667
}
668668
}
669669
}
670+
671+
mod issue_13092 {
672+
use std::cell::RefCell;
673+
macro_rules! macro_inner_item {
674+
($ty:ty) => {
675+
fn foo(_: $ty) {
676+
fn inner(_: $ty) {}
677+
}
678+
};
679+
}
680+
681+
#[derive(Default)]
682+
struct MyStruct;
683+
684+
impl MyStruct {
685+
macro_inner_item!(MyStruct);
686+
}
687+
688+
impl MyStruct {
689+
thread_local! {
690+
static SPECIAL: RefCell<MyStruct> = RefCell::default();
691+
}
692+
}
693+
}
694+
695+
mod crash_check_13128 {
696+
struct A;
697+
698+
impl A {
699+
fn a() {
700+
struct B;
701+
702+
// pushes a NoCheck
703+
impl Iterator for &B {
704+
// Pops the NoCheck
705+
type Item = A;
706+
707+
// Lints A -> Self
708+
fn next(&mut self) -> Option<A> {
709+
Some(A)
710+
}
711+
}
712+
}
713+
}
714+
}

0 commit comments

Comments
 (0)