Skip to content

Commit 748a202

Browse files
committed
Auto merge of #61968 - eddyb:hir-noclone, r=<try>
rustc: disallow cloning HIR nodes. Besides being inefficient, cloning also risks creating broken HIR (without properly recreating all the IDs and whatnot, in which case you might as well reconstruct the entire node without ever `Clone`-ing anything). We detect *some* detrimental situations (based on the occurrence of `HirId`s, I believe?), but it's better to statically disallow it, IMO. One of the examples that is fixed by this PR is `tcx.hir().fn_decl{,_by_hir_id}`, which was cloning an entire `hir::FnDecl` *every single time it was called*. r? @petrochenkov cc @rust-lang/compiler
2 parents e79b2a1 + 673c3fc commit 748a202

File tree

14 files changed

+567
-576
lines changed

14 files changed

+567
-576
lines changed

src/librustc/hir/lowering.rs

+48-55
Original file line numberDiff line numberDiff line change
@@ -608,15 +608,7 @@ impl<'a> LoweringContext<'a> {
608608
});
609609

610610
if let Some(hir_id) = item_hir_id {
611-
let item_generics = match self.lctx.items.get(&hir_id).unwrap().node {
612-
hir::ItemKind::Impl(_, _, _, ref generics, ..)
613-
| hir::ItemKind::Trait(_, _, ref generics, ..) => {
614-
generics.params.clone()
615-
}
616-
_ => HirVec::new(),
617-
};
618-
619-
self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| {
611+
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
620612
let this = &mut ItemLowerer { lctx: this };
621613
if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.node {
622614
this.with_trait_impl_ref(opt_trait_ref, |this| {
@@ -1054,14 +1046,22 @@ impl<'a> LoweringContext<'a> {
10541046
// This should only be used with generics that have already had their
10551047
// in-band lifetimes added. In practice, this means that this function is
10561048
// only used when lowering a child item of a trait or impl.
1057-
fn with_parent_impl_lifetime_defs<T, F>(&mut self,
1058-
params: &HirVec<hir::GenericParam>,
1049+
fn with_parent_item_lifetime_defs<T, F>(&mut self,
1050+
parent_hir_id: hir::HirId,
10591051
f: F
10601052
) -> T where
10611053
F: FnOnce(&mut LoweringContext<'_>) -> T,
10621054
{
10631055
let old_len = self.in_scope_lifetimes.len();
1064-
let lt_def_names = params.iter().filter_map(|param| match param.kind {
1056+
1057+
let parent_generics = match self.items.get(&parent_hir_id).unwrap().node {
1058+
hir::ItemKind::Impl(_, _, _, ref generics, ..)
1059+
| hir::ItemKind::Trait(_, _, ref generics, ..) => {
1060+
&generics.params[..]
1061+
}
1062+
_ => &[],
1063+
};
1064+
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
10651065
hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()),
10661066
_ => None,
10671067
});
@@ -1113,8 +1113,7 @@ impl<'a> LoweringContext<'a> {
11131113

11141114
lowered_generics.params = lowered_generics
11151115
.params
1116-
.iter()
1117-
.cloned()
1116+
.into_iter()
11181117
.chain(in_band_defs)
11191118
.collect();
11201119

@@ -3114,8 +3113,8 @@ impl<'a> LoweringContext<'a> {
31143113
&NodeMap::default(),
31153114
itctx.reborrow(),
31163115
);
3117-
let trait_ref = self.with_parent_impl_lifetime_defs(
3118-
&bound_generic_params,
3116+
let trait_ref = self.with_in_scope_lifetime_defs(
3117+
&p.bound_generic_params,
31193118
|this| this.lower_trait_ref(&p.trait_ref, itctx),
31203119
);
31213120

@@ -3602,8 +3601,7 @@ impl<'a> LoweringContext<'a> {
36023601
// Essentially a single `use` which imports two names is desugared into
36033602
// two imports.
36043603
for (res, &new_node_id) in resolutions.zip([id1, id2].iter()) {
3605-
let vis = vis.clone();
3606-
let ident = ident.clone();
3604+
let ident = *ident;
36073605
let mut path = path.clone();
36083606
for seg in &mut path.segments {
36093607
seg.id = self.sess.next_node_id();
@@ -3616,19 +3614,7 @@ impl<'a> LoweringContext<'a> {
36163614
let path =
36173615
this.lower_path_extra(res, &path, ParamMode::Explicit, None);
36183616
let item = hir::ItemKind::Use(P(path), hir::UseKind::Single);
3619-
let vis_kind = match vis.node {
3620-
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
3621-
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
3622-
hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
3623-
hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
3624-
let path = this.renumber_segment_ids(path);
3625-
hir::VisibilityKind::Restricted {
3626-
path,
3627-
hir_id: this.next_id(),
3628-
}
3629-
}
3630-
};
3631-
let vis = respan(vis.span, vis_kind);
3617+
let vis = this.rebuild_vis(&vis);
36323618

36333619
this.insert_item(
36343620
hir::Item {
@@ -3692,8 +3678,6 @@ impl<'a> LoweringContext<'a> {
36923678
for &(ref use_tree, id) in trees {
36933679
let new_hir_id = self.lower_node_id(id);
36943680

3695-
let mut vis = vis.clone();
3696-
let mut ident = ident.clone();
36973681
let mut prefix = prefix.clone();
36983682

36993683
// Give the segments new node-ids since they are being cloned.
@@ -3707,27 +3691,16 @@ impl<'a> LoweringContext<'a> {
37073691
// own its own names, we have to adjust the owner before
37083692
// lowering the rest of the import.
37093693
self.with_hir_id_owner(id, |this| {
3694+
let mut vis = this.rebuild_vis(&vis);
3695+
let mut ident = *ident;
3696+
37103697
let item = this.lower_use_tree(use_tree,
37113698
&prefix,
37123699
id,
37133700
&mut vis,
37143701
&mut ident,
37153702
attrs);
37163703

3717-
let vis_kind = match vis.node {
3718-
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
3719-
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
3720-
hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
3721-
hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
3722-
let path = this.renumber_segment_ids(path);
3723-
hir::VisibilityKind::Restricted {
3724-
path: path,
3725-
hir_id: this.next_id(),
3726-
}
3727-
}
3728-
};
3729-
let vis = respan(vis.span, vis_kind);
3730-
37313704
this.insert_item(
37323705
hir::Item {
37333706
hir_id: new_hir_id,
@@ -3773,15 +3746,35 @@ impl<'a> LoweringContext<'a> {
37733746
/// Paths like the visibility path in `pub(super) use foo::{bar, baz}` are repeated
37743747
/// many times in the HIR tree; for each occurrence, we need to assign distinct
37753748
/// `NodeId`s. (See, e.g., #56128.)
3776-
fn renumber_segment_ids(&mut self, path: &P<hir::Path>) -> P<hir::Path> {
3777-
debug!("renumber_segment_ids(path = {:?})", path);
3778-
let mut path = path.clone();
3779-
for seg in path.segments.iter_mut() {
3780-
if seg.hir_id.is_some() {
3781-
seg.hir_id = Some(self.next_id());
3782-
}
3749+
fn rebuild_use_path(&mut self, path: &hir::Path) -> hir::Path {
3750+
debug!("rebuild_use_path(path = {:?})", path);
3751+
let segments = path.segments.iter().map(|seg| hir::PathSegment {
3752+
ident: seg.ident,
3753+
hir_id: seg.hir_id.map(|_| self.next_id()),
3754+
res: seg.res,
3755+
args: None,
3756+
infer_args: seg.infer_args,
3757+
}).collect();
3758+
hir::Path {
3759+
span: path.span,
3760+
res: path.res,
3761+
segments,
37833762
}
3784-
path
3763+
}
3764+
3765+
fn rebuild_vis(&mut self, vis: &hir::Visibility) -> hir::Visibility {
3766+
let vis_kind = match vis.node {
3767+
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
3768+
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
3769+
hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
3770+
hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
3771+
hir::VisibilityKind::Restricted {
3772+
path: P(self.rebuild_use_path(path)),
3773+
hir_id: self.next_id(),
3774+
}
3775+
}
3776+
};
3777+
respan(vis.span, vis_kind)
37853778
}
37863779

37873780
fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {

src/librustc/hir/map/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ impl<'hir> Entry<'hir> {
5151
}
5252
}
5353

54-
fn fn_decl(&self) -> Option<&FnDecl> {
54+
fn fn_decl(&self) -> Option<&'hir FnDecl> {
5555
match self.node {
5656
Node::Item(ref item) => {
5757
match item.node {
58-
ItemKind::Fn(ref fn_decl, _, _, _) => Some(&fn_decl),
58+
ItemKind::Fn(ref fn_decl, _, _, _) => Some(fn_decl),
5959
_ => None,
6060
}
6161
}
@@ -76,7 +76,7 @@ impl<'hir> Entry<'hir> {
7676

7777
Node::Expr(ref expr) => {
7878
match expr.node {
79-
ExprKind::Closure(_, ref fn_decl, ..) => Some(&fn_decl),
79+
ExprKind::Closure(_, ref fn_decl, ..) => Some(fn_decl),
8080
_ => None,
8181
}
8282
}
@@ -412,9 +412,9 @@ impl<'hir> Map<'hir> {
412412
self.forest.krate.body(id)
413413
}
414414

415-
pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<FnDecl> {
415+
pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl> {
416416
if let Some(entry) = self.find_entry(hir_id) {
417-
entry.fn_decl().cloned()
417+
entry.fn_decl()
418418
} else {
419419
bug!("no entry for hir_id `{}`", hir_id)
420420
}

0 commit comments

Comments
 (0)