Skip to content

Commit 43fb82d

Browse files
committed
mir-borrowck: Gather move errors during MoveData construction and report them.
Currently is using DUMMY_SP as the associated span; a follow-up commit will pass in appropriate spans when constructing the errors.
1 parent fdd7d13 commit 43fb82d

File tree

5 files changed

+99
-35
lines changed

5 files changed

+99
-35
lines changed

src/librustc_mir/borrow_check.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use dataflow::{MoveDataParamEnv};
3030
use dataflow::{BitDenotation, BlockSets, DataflowResults, DataflowResultsConsumer};
3131
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
3232
use dataflow::{Borrows, BorrowData, BorrowIndex};
33+
use dataflow::move_paths::{MoveError, IllegalMoveOriginKind};
3334
use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult};
3435
use util::borrowck_errors::{BorrowckErrors, Origin};
3536

@@ -59,7 +60,33 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
5960
let param_env = tcx.param_env(def_id);
6061
tcx.infer_ctxt().enter(|_infcx| {
6162

62-
let move_data = MoveData::gather_moves(mir, tcx, param_env);
63+
let move_data = match MoveData::gather_moves(mir, tcx, param_env) {
64+
Ok(move_data) => move_data,
65+
Err((move_data, move_errors)) => {
66+
for move_error in move_errors {
67+
let (span, kind): (Span, IllegalMoveOriginKind) = match move_error {
68+
MoveError::UnionMove { .. } =>
69+
unimplemented!("dont know how to report union move errors yet."),
70+
MoveError::IllegalMove { cannot_move_out_of: o } => (o.span, o.kind),
71+
};
72+
let origin = Origin::Mir;
73+
let mut err = match kind {
74+
IllegalMoveOriginKind::Static =>
75+
tcx.cannot_move_out_of(span, "static item", origin),
76+
IllegalMoveOriginKind::BorrowedContent =>
77+
tcx.cannot_move_out_of(span, "borrowed_content", origin),
78+
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } =>
79+
tcx.cannot_move_out_of_interior_of_drop(span, ty, origin),
80+
IllegalMoveOriginKind::InteriorOfSlice { elem_ty: ty, is_index } =>
81+
tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin),
82+
IllegalMoveOriginKind::InteriorOfArray { elem_ty: ty, is_index } =>
83+
tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin),
84+
};
85+
err.emit();
86+
}
87+
move_data
88+
}
89+
};
6390
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
6491
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
6592
let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,

src/librustc_mir/dataflow/move_paths/builder.rs

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,15 @@ use std::mem;
2222
use super::abs_domain::Lift;
2323

2424
use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
25+
use super::{MoveError};
26+
use super::IllegalMoveOriginKind::*;
2527

26-
pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
28+
struct MoveDataBuilder<'a, 'tcx: 'a> {
2729
mir: &'a Mir<'tcx>,
2830
tcx: TyCtxt<'a, 'tcx, 'tcx>,
2931
param_env: ty::ParamEnv<'tcx>,
3032
data: MoveData<'tcx>,
31-
}
32-
33-
pub enum MovePathError {
34-
IllegalMove,
35-
UnionMove { path: MovePathIndex },
33+
errors: Vec<MoveError<'tcx>>,
3634
}
3735

3836
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -47,6 +45,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
4745
mir,
4846
tcx,
4947
param_env,
48+
errors: Vec::new(),
5049
data: MoveData {
5150
moves: IndexVec::new(),
5251
loc_map: LocationMap::new(mir),
@@ -94,13 +93,12 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
9493
///
9594
/// Maybe we should have separate "borrowck" and "moveck" modes.
9695
fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
97-
-> Result<MovePathIndex, MovePathError>
96+
-> Result<MovePathIndex, MoveError<'tcx>>
9897
{
9998
debug!("lookup({:?})", lval);
10099
match *lval {
101100
Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
102-
// error: can't move out of a static
103-
Lvalue::Static(..) => Err(MovePathError::IllegalMove),
101+
Lvalue::Static(..) => Err(MoveError::cannot_move_out_of(Static)),
104102
Lvalue::Projection(ref proj) => {
105103
self.move_path_for_projection(lval, proj)
106104
}
@@ -116,25 +114,32 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
116114
fn move_path_for_projection(&mut self,
117115
lval: &Lvalue<'tcx>,
118116
proj: &LvalueProjection<'tcx>)
119-
-> Result<MovePathIndex, MovePathError>
117+
-> Result<MovePathIndex, MoveError<'tcx>>
120118
{
121119
let base = try!(self.move_path_for(&proj.base));
122120
let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
123121
match lv_ty.sty {
124-
// error: can't move out of borrowed content
125-
ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
126-
// error: can't move out of struct with destructor
122+
ty::TyRef(..) | ty::TyRawPtr(..) =>
123+
return Err(MoveError::cannot_move_out_of(BorrowedContent)),
127124
ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
128-
return Err(MovePathError::IllegalMove),
125+
return Err(MoveError::cannot_move_out_of(InteriorOfTypeWithDestructor {
126+
container_ty: lv_ty
127+
})),
129128
// move out of union - always move the entire union
130129
ty::TyAdt(adt, _) if adt.is_union() =>
131-
return Err(MovePathError::UnionMove { path: base }),
132-
// error: can't move out of a slice
133-
ty::TySlice(..) =>
134-
return Err(MovePathError::IllegalMove),
135-
ty::TyArray(..) => match proj.elem {
136-
// error: can't move out of an array
137-
ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove),
130+
return Err(MoveError::UnionMove { path: base }),
131+
ty::TySlice(elem_ty) =>
132+
return Err(MoveError::cannot_move_out_of(InteriorOfSlice {
133+
elem_ty, is_index: match proj.elem {
134+
ProjectionElem::Index(..) => true,
135+
_ => false
136+
},
137+
})),
138+
ty::TyArray(elem_ty, _num_elems) => match proj.elem {
139+
ProjectionElem::Index(..) =>
140+
return Err(MoveError::cannot_move_out_of(InteriorOfArray {
141+
elem_ty, is_index: true
142+
})),
138143
_ => {
139144
// FIXME: still badly broken
140145
}
@@ -156,7 +161,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
156161
}
157162
}
158163

159-
fn finalize(self) -> MoveData<'tcx> {
164+
fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
160165
debug!("{}", {
161166
debug!("moves for {:?}:", self.mir.span);
162167
for (j, mo) in self.data.moves.iter_enumerated() {
@@ -168,14 +173,20 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
168173
}
169174
"done dumping moves"
170175
});
171-
self.data
176+
177+
if self.errors.len() > 0 {
178+
Err((self.data, self.errors))
179+
} else {
180+
Ok(self.data)
181+
}
172182
}
173183
}
174184

175185
pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
176186
tcx: TyCtxt<'a, 'tcx, 'tcx>,
177187
param_env: ty::ParamEnv<'tcx>)
178-
-> MoveData<'tcx> {
188+
-> Result<MoveData<'tcx>,
189+
(MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
179190
let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
180191

181192
for (bb, block) in mir.basic_blocks().iter_enumerated() {
@@ -317,13 +328,10 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
317328
}
318329

319330
let path = match self.move_path_for(lval) {
320-
Ok(path) | Err(MovePathError::UnionMove { path }) => path,
321-
Err(MovePathError::IllegalMove) => {
322-
// Moving out of a bad path. Eventually, this should be a MIR
323-
// borrowck error instead of a bug.
324-
span_bug!(self.mir.span,
325-
"Broken MIR: moving out of lvalue {:?}: {:?} at {:?}",
326-
lval, lv_ty, loc);
331+
Ok(path) | Err(MoveError::UnionMove { path }) => path,
332+
Err(error @ MoveError::IllegalMove { .. }) => {
333+
self.errors.push(error);
334+
return;
327335
}
328336
};
329337
let move_out = self.data.moves.push(MoveOut { path: path, source: loc });

src/librustc_mir/dataflow/move_paths/mod.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc::ty::{self, TyCtxt};
1313
use rustc::mir::*;
1414
use rustc::util::nodemap::FxHashMap;
1515
use rustc_data_structures::indexed_vec::{IndexVec};
16+
use syntax_pos::{DUMMY_SP, Span};
1617

1718
use std::fmt;
1819
use std::ops::{Index, IndexMut};
@@ -227,11 +228,39 @@ impl<'tcx> MovePathLookup<'tcx> {
227228
}
228229
}
229230

231+
#[derive(Debug)]
232+
pub struct IllegalMoveOrigin<'tcx> {
233+
pub(crate) span: Span,
234+
pub(crate) kind: IllegalMoveOriginKind<'tcx>,
235+
}
236+
237+
#[derive(Debug)]
238+
pub(crate) enum IllegalMoveOriginKind<'tcx> {
239+
Static,
240+
BorrowedContent,
241+
InteriorOfTypeWithDestructor { container_ty: ty::Ty<'tcx> },
242+
InteriorOfSlice { elem_ty: ty::Ty<'tcx>, is_index: bool, },
243+
InteriorOfArray { elem_ty: ty::Ty<'tcx>, is_index: bool, },
244+
}
245+
246+
#[derive(Debug)]
247+
pub enum MoveError<'tcx> {
248+
IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> },
249+
UnionMove { path: MovePathIndex },
250+
}
251+
252+
impl<'tcx> MoveError<'tcx> {
253+
fn cannot_move_out_of(kind: IllegalMoveOriginKind<'tcx>) -> Self {
254+
let origin = IllegalMoveOrigin { span: DUMMY_SP, kind: kind, };
255+
MoveError::IllegalMove { cannot_move_out_of: origin }
256+
}
257+
}
258+
230259
impl<'a, 'tcx> MoveData<'tcx> {
231260
pub fn gather_moves(mir: &Mir<'tcx>,
232261
tcx: TyCtxt<'a, 'tcx, 'tcx>,
233262
param_env: ty::ParamEnv<'tcx>)
234-
-> Self {
263+
-> Result<Self, (Self, Vec<MoveError<'tcx>>)> {
235264
builder::gather_moves(mir, tcx, param_env)
236265
}
237266
}

src/librustc_mir/transform/elaborate_drops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl MirPass for ElaborateDrops {
4545
}
4646
let id = src.item_id();
4747
let param_env = tcx.param_env(tcx.hir.local_def_id(id));
48-
let move_data = MoveData::gather_moves(mir, tcx, param_env);
48+
let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
4949
let elaborate_patch = {
5050
let mir = &*mir;
5151
let env = MoveDataParamEnv {

src/librustc_mir/transform/rustc_peek.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl MirPass for SanityCheck {
4545

4646
let attributes = tcx.get_attrs(def_id);
4747
let param_env = tcx.param_env(def_id);
48-
let move_data = MoveData::gather_moves(mir, tcx, param_env);
48+
let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
4949
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
5050
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
5151
let flow_inits =

0 commit comments

Comments
 (0)