Skip to content

Commit d5a7424

Browse files
committed
Auto merge of rust-lang#112882 - DrMeepster:new_un_derefer, r=oli-obk
Rewrite `UnDerefer` Currently, `UnDerefer` is used by drop elaboration to undo the effects of the `Derefer` pass. However, it just recreates the original places with derefs in the middle of the projection. Because `ProjectionElem::Deref` is intended to be removed completely in the future, this will not work forever. This PR introduces a `deref_chain` method that returns the places behind `DerefTemp` locals in a place and rewrites the move path code to use this. In the process, `UnDerefer` was merged into `MovePathLookup`. Now that move paths use the same places as in the MIR, the other uses of `UnDerefer` no longer require it. See rust-lang#98145 cc `@ouz-a` r? `@oli-obk`
2 parents 571c9fc + 4fbd6d5 commit d5a7424

File tree

8 files changed

+137
-136
lines changed

8 files changed

+137
-136
lines changed

compiler/rustc_borrowck/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ fn do_mir_borrowck<'tcx>(
222222

223223
let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
224224
match MoveData::gather_moves(&body, tcx, param_env) {
225-
Ok((_, move_data)) => (move_data, Vec::new()),
225+
Ok(move_data) => (move_data, Vec::new()),
226226
Err((move_data, move_errors)) => (move_data, move_errors),
227227
};
228228
let promoted_errors = promoted

compiler/rustc_mir_dataflow/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ pub mod impls;
4343
pub mod move_paths;
4444
pub mod rustc_peek;
4545
pub mod storage;
46-
pub mod un_derefer;
4746
pub mod value_analysis;
4847

4948
fluent_messages! { "../messages.ftl" }

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+66-79
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use crate::move_paths::FxHashMap;
2-
use crate::un_derefer::UnDerefer;
31
use rustc_index::IndexVec;
42
use rustc_middle::mir::tcx::RvalueInitializationState;
53
use rustc_middle::mir::*;
64
use rustc_middle::ty::{self, TyCtxt};
75
use smallvec::{smallvec, SmallVec};
86

7+
use std::iter;
98
use std::mem;
109

1110
use super::abs_domain::Lift;
@@ -21,7 +20,6 @@ struct MoveDataBuilder<'a, 'tcx> {
2120
param_env: ty::ParamEnv<'tcx>,
2221
data: MoveData<'tcx>,
2322
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
24-
un_derefer: UnDerefer<'tcx>,
2523
}
2624

2725
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -35,25 +33,29 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
3533
tcx,
3634
param_env,
3735
errors: Vec::new(),
38-
un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() },
3936
data: MoveData {
4037
moves: IndexVec::new(),
4138
loc_map: LocationMap::new(body),
4239
rev_lookup: MovePathLookup {
4340
locals: body
4441
.local_decls
45-
.indices()
46-
.map(|i| {
47-
Self::new_move_path(
48-
&mut move_paths,
49-
&mut path_map,
50-
&mut init_path_map,
51-
None,
52-
Place::from(i),
42+
.iter_enumerated()
43+
.filter(|(_, l)| !l.is_deref_temp())
44+
.map(|(i, _)| {
45+
(
46+
i,
47+
Self::new_move_path(
48+
&mut move_paths,
49+
&mut path_map,
50+
&mut init_path_map,
51+
None,
52+
Place::from(i),
53+
),
5354
)
5455
})
5556
.collect(),
5657
projections: Default::default(),
58+
derefer_sidetable: Default::default(),
5759
},
5860
move_paths,
5961
path_map,
@@ -98,13 +100,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
98100
///
99101
/// Maybe we should have separate "borrowck" and "moveck" modes.
100102
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
101-
if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body)
102-
{
103-
return self.move_path_for(new_place);
104-
}
103+
let deref_chain = self.builder.data.rev_lookup.deref_chain(place.as_ref());
105104

106105
debug!("lookup({:?})", place);
107-
let mut base = self.builder.data.rev_lookup.locals[place.local];
106+
let mut base =
107+
self.builder.data.rev_lookup.find_local(deref_chain.first().unwrap_or(&place).local);
108108

109109
// The move path index of the first union that we find. Once this is
110110
// some we stop creating child move paths, since moves from unions
@@ -113,51 +113,55 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
113113
// from `*(u.f: &_)` isn't allowed.
114114
let mut union_path = None;
115115

116-
for (place_ref, elem) in place.as_ref().iter_projections() {
117-
let body = self.builder.body;
118-
let tcx = self.builder.tcx;
119-
let place_ty = place_ref.ty(body, tcx).ty;
120-
121-
match place_ty.kind() {
122-
ty::Ref(..) | ty::RawPtr(..) => {
123-
return Err(MoveError::cannot_move_out_of(
124-
self.loc,
125-
BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) },
126-
));
127-
}
128-
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
129-
return Err(MoveError::cannot_move_out_of(
130-
self.loc,
131-
InteriorOfTypeWithDestructor { container_ty: place_ty },
132-
));
133-
}
134-
ty::Adt(adt, _) if adt.is_union() => {
135-
union_path.get_or_insert(base);
136-
}
137-
ty::Slice(_) => {
138-
return Err(MoveError::cannot_move_out_of(
139-
self.loc,
140-
InteriorOfSliceOrArray {
141-
ty: place_ty,
142-
is_index: matches!(elem, ProjectionElem::Index(..)),
143-
},
144-
));
145-
}
146-
147-
ty::Array(..) => {
148-
if let ProjectionElem::Index(..) = elem {
116+
for place in deref_chain.into_iter().chain(iter::once(place)) {
117+
for (place_ref, elem) in place.as_ref().iter_projections() {
118+
let body = self.builder.body;
119+
let tcx = self.builder.tcx;
120+
let place_ty = place_ref.ty(body, tcx).ty;
121+
match place_ty.kind() {
122+
ty::Ref(..) | ty::RawPtr(..) => {
149123
return Err(MoveError::cannot_move_out_of(
150124
self.loc,
151-
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
125+
BorrowedContent {
126+
target_place: place_ref.project_deeper(&[elem], tcx),
127+
},
128+
));
129+
}
130+
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
131+
return Err(MoveError::cannot_move_out_of(
132+
self.loc,
133+
InteriorOfTypeWithDestructor { container_ty: place_ty },
134+
));
135+
}
136+
ty::Adt(adt, _) if adt.is_union() => {
137+
union_path.get_or_insert(base);
138+
}
139+
ty::Slice(_) => {
140+
return Err(MoveError::cannot_move_out_of(
141+
self.loc,
142+
InteriorOfSliceOrArray {
143+
ty: place_ty,
144+
is_index: matches!(elem, ProjectionElem::Index(..)),
145+
},
152146
));
153147
}
154-
}
155148

156-
_ => {}
157-
};
149+
ty::Array(..) => {
150+
if let ProjectionElem::Index(..) = elem {
151+
return Err(MoveError::cannot_move_out_of(
152+
self.loc,
153+
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
154+
));
155+
}
156+
}
157+
158+
_ => {}
159+
};
158160

159-
if union_path.is_none() {
160-
base = self.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
161+
if union_path.is_none() {
162+
base = self
163+
.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
164+
}
161165
}
162166
}
163167

@@ -198,10 +202,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
198202
}
199203
}
200204

201-
pub type MoveDat<'tcx> = Result<
202-
(FxHashMap<Local, Place<'tcx>>, MoveData<'tcx>),
203-
(MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>),
204-
>;
205+
pub type MoveDat<'tcx> =
206+
Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)>;
205207

206208
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
207209
fn finalize(self) -> MoveDat<'tcx> {
@@ -217,11 +219,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
217219
"done dumping moves"
218220
});
219221

220-
if self.errors.is_empty() {
221-
Ok((self.un_derefer.derefer_sidetable, self.data))
222-
} else {
223-
Err((self.data, self.errors))
224-
}
222+
if self.errors.is_empty() { Ok(self.data) } else { Err((self.data, self.errors)) }
225223
}
226224
}
227225

@@ -250,7 +248,7 @@ pub(super) fn gather_moves<'tcx>(
250248
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
251249
fn gather_args(&mut self) {
252250
for arg in self.body.args_iter() {
253-
let path = self.data.rev_lookup.locals[arg];
251+
let path = self.data.rev_lookup.find_local(arg);
254252

255253
let init = self.data.inits.push(Init {
256254
path,
@@ -286,7 +284,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
286284
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
287285
assert!(place.projection.is_empty());
288286
if self.builder.body.local_decls[place.local].is_deref_temp() {
289-
self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed);
287+
self.builder.data.rev_lookup.derefer_sidetable.insert(place.local, *reffed);
290288
}
291289
}
292290
StatementKind::Assign(box (place, rval)) => {
@@ -308,7 +306,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
308306
StatementKind::StorageLive(_) => {}
309307
StatementKind::StorageDead(local) => {
310308
// DerefTemp locals (results of CopyForDeref) don't actually move anything.
311-
if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) {
309+
if !self.builder.data.rev_lookup.derefer_sidetable.contains_key(&local) {
312310
self.gather_move(Place::from(*local));
313311
}
314312
}
@@ -450,12 +448,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
450448

451449
fn gather_move(&mut self, place: Place<'tcx>) {
452450
debug!("gather_move({:?}, {:?})", self.loc, place);
453-
if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body)
454-
{
455-
self.gather_move(new_place);
456-
return;
457-
}
458-
459451
if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
460452
**place.projection
461453
{
@@ -512,11 +504,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
512504
fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) {
513505
debug!("gather_init({:?}, {:?})", self.loc, place);
514506

515-
if let Some(new_place) = self.builder.un_derefer.derefer(place, self.builder.body) {
516-
self.gather_init(new_place.as_ref(), kind);
517-
return;
518-
}
519-
520507
let mut place = place;
521508

522509
// Check if we are assigning into a field of a union, if so, lookup the place

compiler/rustc_mir_dataflow/src/move_paths/mod.rs

+62-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::move_paths::builder::MoveDat;
2-
use rustc_data_structures::fx::FxHashMap;
2+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
33
use rustc_index::{IndexSlice, IndexVec};
44
use rustc_middle::mir::*;
55
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
@@ -175,7 +175,7 @@ pub struct MoveData<'tcx> {
175175
/// particular path being moved.)
176176
pub loc_map: LocationMap<SmallVec<[MoveOutIndex; 4]>>,
177177
pub path_map: IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
178-
pub rev_lookup: MovePathLookup,
178+
pub rev_lookup: MovePathLookup<'tcx>,
179179
pub inits: IndexVec<InitIndex, Init>,
180180
/// Each Location `l` is mapped to the Inits that are effects
181181
/// of executing the code at `l`.
@@ -289,8 +289,8 @@ impl Init {
289289

290290
/// Tables mapping from a place to its MovePathIndex.
291291
#[derive(Debug)]
292-
pub struct MovePathLookup {
293-
locals: IndexVec<Local, MovePathIndex>,
292+
pub struct MovePathLookup<'tcx> {
293+
locals: FxIndexMap<Local, MovePathIndex>,
294294

295295
/// projections are made from a base-place and a projection
296296
/// elem. The base-place will have a unique MovePathIndex; we use
@@ -299,6 +299,9 @@ pub struct MovePathLookup {
299299
/// base-place). For the remaining lookup, we map the projection
300300
/// elem to the associated MovePathIndex.
301301
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
302+
303+
/// Maps `DerefTemp` locals to the `Place`s assigned to them.
304+
derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
302305
}
303306

304307
mod builder;
@@ -309,35 +312,82 @@ pub enum LookupResult {
309312
Parent(Option<MovePathIndex>),
310313
}
311314

312-
impl MovePathLookup {
315+
impl<'tcx> MovePathLookup<'tcx> {
313316
// Unlike the builder `fn move_path_for` below, this lookup
314317
// alternative will *not* create a MovePath on the fly for an
315318
// unknown place, but will rather return the nearest available
316319
// parent.
317320
pub fn find(&self, place: PlaceRef<'_>) -> LookupResult {
318-
let mut result = self.locals[place.local];
321+
let deref_chain = self.deref_chain(place);
319322

320-
for elem in place.projection.iter() {
321-
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
322-
result = subpath;
323-
} else {
323+
let local = match deref_chain.first() {
324+
Some(place) => place.local,
325+
None => place.local,
326+
};
327+
328+
let mut result = *self.locals.get(&local).unwrap_or_else(|| {
329+
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
330+
});
331+
332+
// this needs to be a closure because `place` has a different lifetime than `prefix`'s places
333+
let mut subpaths_for_place = |place: PlaceRef<'_>| {
334+
for elem in place.projection.iter() {
335+
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
336+
result = subpath;
337+
} else {
338+
return Some(result);
339+
}
340+
}
341+
None
342+
};
343+
344+
for place in deref_chain {
345+
if let Some(result) = subpaths_for_place(place.as_ref()) {
324346
return LookupResult::Parent(Some(result));
325347
}
326348
}
327349

350+
if let Some(result) = subpaths_for_place(place) {
351+
return LookupResult::Parent(Some(result));
352+
}
353+
328354
LookupResult::Exact(result)
329355
}
330356

331357
pub fn find_local(&self, local: Local) -> MovePathIndex {
332-
self.locals[local]
358+
let deref_chain = self.deref_chain(Place::from(local).as_ref());
359+
360+
let local = match deref_chain.last() {
361+
Some(place) => place.local,
362+
None => local,
363+
};
364+
365+
*self.locals.get(&local).unwrap_or_else(|| {
366+
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
367+
})
333368
}
334369

335370
/// An enumerated iterator of `local`s and their associated
336371
/// `MovePathIndex`es.
337372
pub fn iter_locals_enumerated(
338373
&self,
339374
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
340-
self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
375+
self.locals.iter().map(|(&l, &idx)| (l, idx))
376+
}
377+
378+
/// Returns the chain of places behind `DerefTemp` locals in `place`
379+
pub fn deref_chain(&self, place: PlaceRef<'_>) -> Vec<Place<'tcx>> {
380+
let mut prefix = Vec::new();
381+
let mut local = place.local;
382+
383+
while let Some(&reffed) = self.derefer_sidetable.get(&local) {
384+
prefix.insert(0, reffed);
385+
local = reffed.local;
386+
}
387+
388+
debug!("deref_chain({place:?}) = {prefix:?}");
389+
390+
prefix
341391
}
342392
}
343393

0 commit comments

Comments
 (0)