|
12 | 12 | use rustc::ty::{self, TyCtxt, ParameterEnvironment};
|
13 | 13 | use rustc::mir::repr::*;
|
14 | 14 | use rustc::util::nodemap::FnvHashMap;
|
15 |
| -use rustc::util::common::ErrorReported; |
16 | 15 | use rustc_data_structures::indexed_vec::{IndexVec};
|
17 | 16 |
|
18 | 17 | use syntax::codemap::DUMMY_SP;
|
@@ -198,6 +197,11 @@ struct MoveDataBuilder<'a, 'tcx: 'a> {
|
198 | 197 | data: MoveData<'tcx>,
|
199 | 198 | }
|
200 | 199 |
|
| 200 | +pub enum MovePathError { |
| 201 | + IllegalMove, |
| 202 | + UnionMove { path: MovePathIndex }, |
| 203 | +} |
| 204 | + |
201 | 205 | impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
202 | 206 | fn new(mir: &'a Mir<'tcx>,
|
203 | 207 | tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
@@ -256,23 +260,23 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
256 | 260 | move_path
|
257 | 261 | }
|
258 | 262 |
|
259 |
| - /// This creates a MovePath for a given lvalue, returning an `ErrorReported` |
| 263 | + /// This creates a MovePath for a given lvalue, returning an `MovePathError` |
260 | 264 | /// if that lvalue can't be moved from.
|
261 | 265 | ///
|
262 | 266 | /// NOTE: lvalues behind references *do not* get a move path, which is
|
263 | 267 | /// problematic for borrowck.
|
264 | 268 | ///
|
265 | 269 | /// Maybe we should have seperate "borrowck" and "moveck" modes.
|
266 | 270 | fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
|
267 |
| - -> Result<MovePathIndex, ErrorReported> |
| 271 | + -> Result<MovePathIndex, MovePathError> |
268 | 272 | {
|
269 | 273 | debug!("lookup({:?})", lval);
|
270 | 274 | match *lval {
|
271 | 275 | Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]),
|
272 | 276 | Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]),
|
273 | 277 | Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]),
|
274 | 278 | // error: can't move out of a static
|
275 |
| - Lvalue::Static(..) => Err(ErrorReported), |
| 279 | + Lvalue::Static(..) => Err(MovePathError::IllegalMove), |
276 | 280 | Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr {
|
277 | 281 | Some(ptr) => Ok(ptr),
|
278 | 282 | ref mut ptr @ None => {
|
@@ -300,21 +304,28 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
300 | 304 | fn move_path_for_projection(&mut self,
|
301 | 305 | lval: &Lvalue<'tcx>,
|
302 | 306 | proj: &LvalueProjection<'tcx>)
|
303 |
| - -> Result<MovePathIndex, ErrorReported> |
| 307 | + -> Result<MovePathIndex, MovePathError> |
304 | 308 | {
|
305 | 309 | let base = try!(self.move_path_for(&proj.base));
|
306 | 310 | let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
|
307 | 311 | match lv_ty.sty {
|
308 | 312 | // error: can't move out of borrowed content
|
309 |
| - ty::TyRef(..) | ty::TyRawPtr(..) => return Err(ErrorReported), |
| 313 | + ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), |
310 | 314 | // error: can't move out of struct with destructor
|
311 |
| - ty::TyStruct(adt, _) | ty::TyEnum(adt, _) if adt.has_dtor() => |
312 |
| - return Err(ErrorReported), |
313 |
| - |
314 |
| - ty::TyArray(..) | ty::TySlice(..) => match proj.elem { |
| 315 | + ty::TyAdt(adt, _) if adt.has_dtor() => |
| 316 | + return Err(MovePathError::IllegalMove), |
| 317 | + // move out of union - always move the entire union |
| 318 | + ty::TyAdt(adt, _) if adt.is_union() => |
| 319 | + return Err(MovePathError::UnionMove { path: base }), |
| 320 | + // error: can't move out of a slice |
| 321 | + ty::TySlice(..) => |
| 322 | + return Err(MovePathError::IllegalMove), |
| 323 | + ty::TyArray(..) => match proj.elem { |
315 | 324 | // error: can't move out of an array
|
316 |
| - ProjectionElem::Index(..) => return Err(ErrorReported), |
317 |
| - _ => {} |
| 325 | + ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove), |
| 326 | + _ => { |
| 327 | + // FIXME: still badly broken |
| 328 | + } |
318 | 329 | },
|
319 | 330 | _ => {}
|
320 | 331 | };
|
@@ -521,13 +532,16 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
521 | 532 | return
|
522 | 533 | }
|
523 | 534 |
|
524 |
| - let path = self.move_path_for(lval).unwrap_or_else(|_| { |
525 |
| - // Moving out of a bad path. Eventually, this should be a MIR |
526 |
| - // borrowck error instead of a bug. |
527 |
| - span_bug!(self.mir.span, |
528 |
| - "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", |
529 |
| - lval, lv_ty, loc); |
530 |
| - }); |
| 535 | + let path = match self.move_path_for(lval) { |
| 536 | + Ok(path) | Err(MovePathError::UnionMove { path }) => path, |
| 537 | + Err(MovePathError::IllegalMove) => { |
| 538 | + // Moving out of a bad path. Eventually, this should be a MIR |
| 539 | + // borrowck error instead of a bug. |
| 540 | + span_bug!(self.mir.span, |
| 541 | + "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", |
| 542 | + lval, lv_ty, loc); |
| 543 | + } |
| 544 | + }; |
531 | 545 | let move_out = self.data.moves.push(MoveOut { path: path, source: loc });
|
532 | 546 |
|
533 | 547 | debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
|
|
0 commit comments