Skip to content

Commit 6045e67

Browse files
committed
Auto merge of rust-lang#121625 - Urgau:non-local-defs_recover_perf, r=<try>
Recover most of the perf loss of rust-lang#120393 [rust-lang#120393](rust-lang#120393 (comment)) draft for perf
2 parents d377991 + 5d477fb commit 6045e67

File tree

3 files changed

+152
-96
lines changed

3 files changed

+152
-96
lines changed

compiler/rustc_lint/src/non_local_def.rs

+101-45
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind};
2-
use rustc_span::def_id::{DefId, LOCAL_CRATE};
3-
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
4-
5-
use smallvec::{smallvec, SmallVec};
1+
use rustc_hir::def_id::LocalDefId;
2+
use rustc_hir::{Body, Item, ItemKind, OwnerId, OwnerNode, Path, QPath, TyKind};
3+
use rustc_span::def_id::LOCAL_CRATE;
4+
use rustc_span::{sym, symbol::kw, symbol::Ident, ExpnKind, MacroKind};
65

76
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
87
use crate::{LateContext, LateLintPass, LintContext};
@@ -67,17 +66,16 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
6766
return;
6867
}
6968

70-
let parent = cx.tcx.parent(item.owner_id.def_id.into());
71-
let parent_def_kind = cx.tcx.def_kind(parent);
72-
let parent_opt_item_name = cx.tcx.opt_item_name(parent);
73-
74-
// Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
75-
if self.body_depth == 1
76-
&& parent_def_kind == DefKind::Const
77-
&& parent_opt_item_name == Some(kw::Underscore)
78-
{
79-
return;
80-
}
69+
let mut parent_owner = {
70+
let mut parent_owner_cache = None;
71+
move || {
72+
*parent_owner_cache.get_or_insert_with(|| {
73+
// Unwrap safety: can only panic when reaching the crate root
74+
// but we made sure above that we are not at crate root.
75+
cx.tcx.hir().parent_owner_iter(item.hir_id()).next().unwrap()
76+
})
77+
}
78+
};
8179

8280
let cargo_update = || {
8381
let oexpn = item.span.ctxt().outer_expn_data();
@@ -112,26 +110,52 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
112110
// If that's the case this means that this impl block declaration
113111
// is using local items and so we don't lint on it.
114112

115-
// We also ignore anon-const in item by including the anon-const
116-
// parent as well; and since it's quite uncommon, we use smallvec
117-
// to avoid unnecessary heap allocations.
118-
let local_parents: SmallVec<[DefId; 1]> = if parent_def_kind == DefKind::Const
119-
&& parent_opt_item_name == Some(kw::Underscore)
120-
{
121-
smallvec![parent, cx.tcx.parent(parent)]
122-
} else {
123-
smallvec![parent]
113+
let mut parent_owner_is_anon_const = {
114+
let mut parent_owner_is_anon_const = None;
115+
move || {
116+
*parent_owner_is_anon_const.get_or_insert_with(|| {
117+
matches!(
118+
parent_owner().1,
119+
OwnerNode::Item(Item {
120+
ident: Ident { name: kw::Underscore, .. },
121+
kind: ItemKind::Const(..),
122+
..
123+
})
124+
)
125+
})
126+
}
127+
};
128+
let mut extra_local_parent = {
129+
let mut extra_parent_cache = None;
130+
move || {
131+
*extra_parent_cache.get_or_insert_with(|| {
132+
parent_owner_is_anon_const()
133+
.then(|| {
134+
cx.tcx
135+
.hir()
136+
.parent_owner_iter(item.hir_id())
137+
.skip(1)
138+
.next()
139+
.map(|(owner_id, _owner_node)| owner_id.def_id)
140+
})
141+
.flatten()
142+
})
143+
}
124144
};
125145

126146
let self_ty_has_local_parent = match impl_.self_ty.kind {
127-
TyKind::Path(QPath::Resolved(_, ty_path)) => {
128-
path_has_local_parent(ty_path, cx, &*local_parents)
129-
}
147+
TyKind::Path(QPath::Resolved(_, ty_path)) => path_has_local_parent(
148+
ty_path,
149+
cx,
150+
&mut parent_owner,
151+
&mut extra_local_parent,
152+
),
130153
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
131154
path_has_local_parent(
132155
principle_poly_trait_ref.trait_ref.path,
133156
cx,
134-
&*local_parents,
157+
&mut parent_owner,
158+
&mut extra_local_parent,
135159
)
136160
}
137161
TyKind::TraitObject([], _, _)
@@ -151,19 +175,29 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
151175
| TyKind::Err(_) => false,
152176
};
153177

154-
let of_trait_has_local_parent = impl_
155-
.of_trait
156-
.map(|of_trait| path_has_local_parent(of_trait.path, cx, &*local_parents))
157-
.unwrap_or(false);
178+
let of_trait_has_local_parent = self_ty_has_local_parent
179+
|| impl_
180+
.of_trait
181+
.map(|of_trait| {
182+
path_has_local_parent(
183+
of_trait.path,
184+
cx,
185+
&mut parent_owner,
186+
&mut extra_local_parent,
187+
)
188+
})
189+
.unwrap_or(false);
158190

159191
// If none of them have a local parent (LOGICAL NOR) this means that
160192
// this impl definition is a non-local definition and so we lint on it.
161193
if !(self_ty_has_local_parent || of_trait_has_local_parent) {
194+
// Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
195+
if parent_owner_is_anon_const() && self.body_depth == 1 {
196+
return;
197+
}
198+
162199
let const_anon = if self.body_depth == 1
163-
&& parent_def_kind == DefKind::Const
164-
&& parent_opt_item_name != Some(kw::Underscore)
165-
&& let Some(parent) = parent.as_local()
166-
&& let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent)
200+
&& let OwnerNode::Item(item) = parent_owner().1
167201
&& let ItemKind::Const(ty, _, _) = item.kind
168202
&& let TyKind::Tup(&[]) = ty.kind
169203
{
@@ -172,14 +206,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
172206
None
173207
};
174208

209+
let parent_owner = parent_owner().1;
210+
175211
cx.emit_span_lint(
176212
NON_LOCAL_DEFINITIONS,
177213
item.span,
178214
NonLocalDefinitionsDiag::Impl {
179215
depth: self.body_depth,
180-
body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent),
181-
body_name: parent_opt_item_name
182-
.map(|s| s.to_ident_string())
216+
body_kind_descr: "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */,
217+
body_name: parent_owner
218+
.ident()
219+
.map(|s| s.name.to_ident_string())
183220
.unwrap_or_else(|| "<unnameable>".to_string()),
184221
cargo_update: cargo_update(),
185222
const_anon,
@@ -190,14 +227,17 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
190227
ItemKind::Macro(_macro, MacroKind::Bang)
191228
if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
192229
{
230+
let parent_owner = parent_owner().1;
231+
193232
cx.emit_span_lint(
194233
NON_LOCAL_DEFINITIONS,
195234
item.span,
196235
NonLocalDefinitionsDiag::MacroRules {
197236
depth: self.body_depth,
198-
body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent),
199-
body_name: parent_opt_item_name
200-
.map(|s| s.to_ident_string())
237+
body_kind_descr: "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */,
238+
body_name: parent_owner
239+
.ident()
240+
.map(|s| s.name.to_ident_string())
201241
.unwrap_or_else(|| "<unnameable>".to_string()),
202242
cargo_update: cargo_update(),
203243
},
@@ -217,6 +257,22 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
217257
/// std::convert::PartialEq<Foo<Bar>>
218258
/// ^^^^^^^^^^^^^^^^^^^^^^^
219259
/// ```
220-
fn path_has_local_parent(path: &Path<'_>, cx: &LateContext<'_>, local_parents: &[DefId]) -> bool {
221-
path.res.opt_def_id().is_some_and(|did| local_parents.contains(&cx.tcx.parent(did)))
260+
fn path_has_local_parent<'tcx>(
261+
path: &Path<'_>,
262+
cx: &LateContext<'tcx>,
263+
local_parent: &mut impl FnMut() -> (OwnerId, OwnerNode<'tcx>),
264+
extra_local_parent: &mut impl FnMut() -> Option<LocalDefId>,
265+
) -> bool {
266+
let Some(res_did) = path.res.opt_def_id() else {
267+
return true;
268+
};
269+
let Some(did) = res_did.as_local() else {
270+
return false;
271+
};
272+
let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(did) else {
273+
return true;
274+
};
275+
let owner_id = cx.tcx.hir().get_parent_item(hir_id);
276+
let res_parent = owner_id.def_id;
277+
res_parent == local_parent().0.def_id || Some(res_parent) == extra_local_parent()
222278
}

0 commit comments

Comments
 (0)