|
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