Skip to content

Commit 96dc03b

Browse files
committed
Remove uniform_array_move_out passes
These passes were buggy, MIR building is now responsible for canonicalizing `ConstantIndex` projections and `MoveData` is responsible for splitting `Subslice` projections.
1 parent bf278eb commit 96dc03b

File tree

10 files changed

+168
-489
lines changed

10 files changed

+168
-489
lines changed

Diff for: src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
7878
.collect();
7979

8080
if move_out_indices.is_empty() {
81-
let root_place = self
82-
.prefixes(used_place, PrefixSet::All)
83-
.last()
84-
.unwrap();
81+
let root_place = PlaceRef { projection: &[], ..used_place };
8582

8683
if !self.uninitialized_error_reported.insert(root_place) {
8784
debug!(

Diff for: src/librustc_mir/borrow_check/mod.rs

+65-2
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ fn do_mir_borrowck<'a, 'tcx>(
174174

175175
let mut errors_buffer = Vec::new();
176176
let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
177-
match MoveData::gather_moves(&body, tcx) {
177+
match MoveData::gather_moves(&body, tcx, param_env) {
178178
Ok(move_data) => (move_data, None),
179179
Err((move_data, move_errors)) => (move_data, Some(move_errors)),
180180
};
@@ -1600,7 +1600,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16001600
(prefix, place_span.0, place_span.1),
16011601
mpi,
16021602
);
1603-
return; // don't bother finding other problems.
16041603
}
16051604
}
16061605
Err(NoMovePathFound::ReachedStatic) => {
@@ -1614,6 +1613,46 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16141613
}
16151614
}
16161615

1616+
/// Subslices correspond to multiple move paths, so we iterate through the
1617+
/// elements of the base array. For each element we check
1618+
///
1619+
/// * Does this element overlap with our slice.
1620+
/// * Is any part of it uninitialized.
1621+
fn check_if_subslice_element_is_moved(
1622+
&mut self,
1623+
location: Location,
1624+
desired_action: InitializationRequiringAction,
1625+
place_span: (PlaceRef<'cx, 'tcx>, Span),
1626+
maybe_uninits: &FlowAtLocation<'tcx, MaybeUninitializedPlaces<'cx, 'tcx>>,
1627+
from: u32,
1628+
to: u32,
1629+
) {
1630+
if let Some(mpi) = self.move_path_for_place(place_span.0) {
1631+
let mut child = self.move_data.move_paths[mpi].first_child;
1632+
while let Some(child_mpi) = child {
1633+
let child_move_place = &self.move_data.move_paths[child_mpi];
1634+
let child_place = &child_move_place.place;
1635+
let last_proj = child_place.projection.last().unwrap();
1636+
if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
1637+
debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
1638+
1639+
if (from..to).contains(offset) {
1640+
if let Some(uninit_child) = maybe_uninits.has_any_child_of(child_mpi) {
1641+
self.report_use_of_moved_or_uninitialized(
1642+
location,
1643+
desired_action,
1644+
(place_span.0, place_span.0, place_span.1),
1645+
uninit_child,
1646+
);
1647+
return; // don't bother finding other problems.
1648+
}
1649+
}
1650+
}
1651+
child = child_move_place.next_sibling;
1652+
}
1653+
}
1654+
}
1655+
16171656
fn check_if_path_or_subpath_is_moved(
16181657
&mut self,
16191658
location: Location,
@@ -1640,6 +1679,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16401679

16411680
self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
16421681

1682+
if let [
1683+
base_proj @ ..,
1684+
ProjectionElem::Subslice { from, to, from_end: false },
1685+
] = place_span.0.projection {
1686+
let place_ty = Place::ty_from(
1687+
place_span.0.base,
1688+
base_proj,
1689+
self.body(),
1690+
self.infcx.tcx,
1691+
);
1692+
if let ty::Array(..) = place_ty.ty.kind {
1693+
let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
1694+
self.check_if_subslice_element_is_moved(
1695+
location,
1696+
desired_action,
1697+
(array_place, place_span.1),
1698+
maybe_uninits,
1699+
*from,
1700+
*to,
1701+
);
1702+
return;
1703+
}
1704+
}
1705+
16431706
// A move of any shallow suffix of `place` also interferes
16441707
// with an attempt to use `place`. This is scenario 3 above.
16451708
//

Diff for: src/librustc_mir/borrow_check/places_conflict.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,8 @@ fn place_projection_conflict<'tcx>(
533533
}
534534
}
535535
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
536-
ProjectionElem::Subslice { to, .. })
537-
| (ProjectionElem::Subslice { to, .. },
536+
ProjectionElem::Subslice { to, from_end: true, .. })
537+
| (ProjectionElem::Subslice { to, from_end: true, .. },
538538
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
539539
if offset > to {
540540
debug!("place_element_conflict: \

Diff for: src/librustc_mir/dataflow/move_paths/builder.rs

+93-38
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc::ty::{self, TyCtxt};
44
use rustc_index::vec::IndexVec;
55
use smallvec::{smallvec, SmallVec};
66

7-
use std::collections::hash_map::Entry;
7+
use std::convert::TryInto;
88
use std::mem;
99

1010
use super::abs_domain::Lift;
@@ -17,19 +17,21 @@ use super::{
1717
struct MoveDataBuilder<'a, 'tcx> {
1818
body: &'a Body<'tcx>,
1919
tcx: TyCtxt<'tcx>,
20+
param_env: ty::ParamEnv<'tcx>,
2021
data: MoveData<'tcx>,
2122
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
2223
}
2324

2425
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
25-
fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
26+
fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
2627
let mut move_paths = IndexVec::new();
2728
let mut path_map = IndexVec::new();
2829
let mut init_path_map = IndexVec::new();
2930

3031
MoveDataBuilder {
3132
body,
3233
tcx,
34+
param_env,
3335
errors: Vec::new(),
3436
data: MoveData {
3537
moves: IndexVec::new(),
@@ -148,42 +150,47 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
148150
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
149151
));
150152
}
151-
_ => {
152-
// FIXME: still badly broken
153-
}
153+
_ => {}
154154
},
155155
_ => {}
156156
};
157157

158-
let proj = &place.projection[..i+1];
159-
base = match self
160-
.builder
161-
.data
162-
.rev_lookup
163-
.projections
164-
.entry((base, elem.lift()))
165-
{
166-
Entry::Occupied(ent) => *ent.get(),
167-
Entry::Vacant(ent) => {
168-
let path = MoveDataBuilder::new_move_path(
169-
&mut self.builder.data.move_paths,
170-
&mut self.builder.data.path_map,
171-
&mut self.builder.data.init_path_map,
172-
Some(base),
173-
Place {
174-
base: place.base.clone(),
175-
projection: tcx.intern_place_elems(proj),
176-
},
177-
);
178-
ent.insert(path);
179-
path
180-
}
181-
};
158+
base = self.add_move_path(base, elem, |tcx| {
159+
Place {
160+
base: place.base.clone(),
161+
projection: tcx.intern_place_elems(&place.projection[..i+1]),
162+
}
163+
});
182164
}
183165

184166
Ok(base)
185167
}
186168

169+
fn add_move_path(
170+
&mut self,
171+
base: MovePathIndex,
172+
elem: &PlaceElem<'tcx>,
173+
mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>,
174+
) -> MovePathIndex {
175+
let MoveDataBuilder {
176+
data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. },
177+
tcx,
178+
..
179+
} = self.builder;
180+
*rev_lookup.projections
181+
.entry((base, elem.lift()))
182+
.or_insert_with(move || {
183+
let path = MoveDataBuilder::new_move_path(
184+
move_paths,
185+
path_map,
186+
init_path_map,
187+
Some(base),
188+
mk_place(*tcx),
189+
);
190+
path
191+
})
192+
}
193+
187194
fn create_move_path(&mut self, place: &Place<'tcx>) {
188195
// This is an non-moving access (such as an overwrite or
189196
// drop), so this not being a valid move path is OK.
@@ -214,8 +221,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
214221
pub(super) fn gather_moves<'tcx>(
215222
body: &Body<'tcx>,
216223
tcx: TyCtxt<'tcx>,
224+
param_env: ty::ParamEnv<'tcx>,
217225
) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
218-
let mut builder = MoveDataBuilder::new(body, tcx);
226+
let mut builder = MoveDataBuilder::new(body, tcx, param_env);
219227

220228
builder.gather_args();
221229

@@ -411,20 +419,67 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
411419
fn gather_move(&mut self, place: &Place<'tcx>) {
412420
debug!("gather_move({:?}, {:?})", self.loc, place);
413421

414-
let path = match self.move_path_for(place) {
415-
Ok(path) | Err(MoveError::UnionMove { path }) => path,
416-
Err(error @ MoveError::IllegalMove { .. }) => {
417-
self.builder.errors.push((place.clone(), error));
418-
return;
422+
if let [
423+
ref base @ ..,
424+
ProjectionElem::Subslice { from, to, from_end: false },
425+
] = **place.projection {
426+
// Split `Subslice` patterns into the corresponding list of
427+
// `ConstIndex` patterns. This is done to ensure that all move paths
428+
// are disjoint, which is expected by drop elaboration.
429+
let base_place = Place {
430+
base: place.base.clone(),
431+
projection: self.builder.tcx.intern_place_elems(base),
432+
};
433+
let base_path = match self.move_path_for(&base_place) {
434+
Ok(path) => path,
435+
Err(MoveError::UnionMove { path }) => {
436+
self.record_move(place, path);
437+
return;
438+
}
439+
Err(error @ MoveError::IllegalMove { .. }) => {
440+
self.builder.errors.push((base_place, error));
441+
return;
442+
}
443+
};
444+
let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
445+
let len: u32 = match base_ty.kind {
446+
ty::Array(_, size) => {
447+
let length = size.eval_usize(self.builder.tcx, self.builder.param_env);
448+
length.try_into().expect(
449+
"slice pattern of array with more than u32::MAX elements"
450+
)
451+
}
452+
_ => bug!("from_end: false slice pattern of non-array type"),
453+
};
454+
for offset in from..to {
455+
let elem = ProjectionElem::ConstantIndex {
456+
offset,
457+
min_length: len,
458+
from_end: false,
459+
};
460+
let path = self.add_move_path(
461+
base_path,
462+
&elem,
463+
|tcx| tcx.mk_place_elem(base_place.clone(), elem),
464+
);
465+
self.record_move(place, path);
419466
}
420-
};
421-
let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
467+
} else {
468+
match self.move_path_for(place) {
469+
Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path),
470+
Err(error @ MoveError::IllegalMove { .. }) => {
471+
self.builder.errors.push((place.clone(), error));
472+
}
473+
};
474+
}
475+
}
422476

477+
fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) {
478+
let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
423479
debug!(
424480
"gather_move({:?}, {:?}): adding move {:?} of {:?}",
425481
self.loc, place, move_out, path
426482
);
427-
428483
self.builder.data.path_map[path].push(move_out);
429484
self.builder.data.loc_map[self.loc].push(move_out);
430485
}

Diff for: src/librustc_mir/transform/elaborate_drops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
2626

2727
let def_id = src.def_id();
2828
let param_env = tcx.param_env(src.def_id()).with_reveal_all();
29-
let move_data = match MoveData::gather_moves(body, tcx) {
29+
let move_data = match MoveData::gather_moves(body, tcx, param_env) {
3030
Ok(move_data) => move_data,
3131
Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"),
3232
};

Diff for: src/librustc_mir/transform/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ pub mod copy_prop;
3535
pub mod const_prop;
3636
pub mod generator;
3737
pub mod inline;
38-
pub mod uniform_array_move_out;
3938
pub mod uninhabited_enum_branching;
4039

4140
pub(crate) fn provide(providers: &mut Providers<'_>) {
@@ -229,7 +228,6 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
229228
// What we need to do constant evaluation.
230229
&simplify::SimplifyCfg::new("initial"),
231230
&rustc_peek::SanityCheck,
232-
&uniform_array_move_out::UniformArrayMoveOut,
233231
]);
234232
body.ensure_predecessors();
235233
tcx.alloc_steal_mir(body)
@@ -294,7 +292,6 @@ fn run_optimization_passes<'tcx>(
294292
// Optimizations begin.
295293
&uninhabited_enum_branching::UninhabitedEnumBranching,
296294
&simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
297-
&uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
298295
&inline::Inline,
299296

300297
// Lowering generator control-flow and variables

Diff for: src/librustc_mir/transform/rustc_peek.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
3737

3838
let attributes = tcx.get_attrs(def_id);
3939
let param_env = tcx.param_env(def_id);
40-
let move_data = MoveData::gather_moves(body, tcx).unwrap();
40+
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
4141
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
4242
let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
4343
let flow_inits =

0 commit comments

Comments
 (0)