]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
1 | // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | ||
9e0c209e | 12 | use rustc::ty::{self, TyCtxt, ParameterEnvironment}; |
54a0048b SL |
13 | use rustc::mir::repr::*; |
14 | use rustc::util::nodemap::FnvHashMap; | |
9e0c209e SL |
15 | use rustc_data_structures::indexed_vec::{IndexVec}; |
16 | ||
17 | use syntax::codemap::DUMMY_SP; | |
54a0048b | 18 | |
54a0048b SL |
19 | use std::collections::hash_map::Entry; |
20 | use std::fmt; | |
9e0c209e SL |
21 | use std::mem; |
22 | use std::ops::{Index, IndexMut}; | |
54a0048b | 23 | |
54a0048b SL |
24 | use super::abs_domain::{AbstractElem, Lift}; |
25 | ||
26 | // This submodule holds some newtype'd Index wrappers that are using | |
27 | // NonZero to ensure that Option<Index> occupies only a single word. | |
28 | // They are in a submodule to impose privacy restrictions; namely, to | |
29 | // ensure that other code does not accidentally access `index.0` | |
30 | // (which is likely to yield a subtle off-by-one error). | |
31 | mod indexes { | |
9e0c209e | 32 | use std::fmt; |
54a0048b | 33 | use core::nonzero::NonZero; |
3157f602 | 34 | use rustc_data_structures::indexed_vec::Idx; |
54a0048b SL |
35 | |
36 | macro_rules! new_index { | |
9e0c209e SL |
37 | ($Index:ident, $debug_name:expr) => { |
38 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | |
54a0048b SL |
39 | pub struct $Index(NonZero<usize>); |
40 | ||
3157f602 XL |
41 | impl Idx for $Index { |
42 | fn new(idx: usize) -> Self { | |
54a0048b SL |
43 | unsafe { $Index(NonZero::new(idx + 1)) } |
44 | } | |
3157f602 | 45 | fn index(self) -> usize { |
54a0048b SL |
46 | *self.0 - 1 |
47 | } | |
48 | } | |
9e0c209e SL |
49 | |
50 | impl fmt::Debug for $Index { | |
51 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
52 | write!(fmt, "{}{}", $debug_name, self.index()) | |
53 | } | |
54 | } | |
54a0048b SL |
55 | } |
56 | } | |
57 | ||
58 | /// Index into MovePathData.move_paths | |
9e0c209e | 59 | new_index!(MovePathIndex, "mp"); |
54a0048b SL |
60 | |
61 | /// Index into MoveData.moves. | |
9e0c209e | 62 | new_index!(MoveOutIndex, "mo"); |
54a0048b SL |
63 | } |
64 | ||
65 | pub use self::indexes::MovePathIndex; | |
66 | pub use self::indexes::MoveOutIndex; | |
67 | ||
3157f602 XL |
68 | impl self::indexes::MoveOutIndex { |
69 | pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { | |
9e0c209e | 70 | move_data.moves[*self].path |
3157f602 XL |
71 | } |
72 | } | |
73 | ||
54a0048b SL |
74 | /// `MovePath` is a canonicalized representation of a path that is |
75 | /// moved or assigned to. | |
76 | /// | |
77 | /// It follows a tree structure. | |
78 | /// | |
79 | /// Given `struct X { m: M, n: N }` and `x: X`, moves like `drop x.m;` | |
80 | /// move *out* of the l-value `x.m`. | |
81 | /// | |
82 | /// The MovePaths representing `x.m` and `x.n` are siblings (that is, | |
83 | /// one of them will link to the other via the `next_sibling` field, | |
84 | /// and the other will have no entry in its `next_sibling` field), and | |
85 | /// they both have the MovePath representing `x` as their parent. | |
86 | #[derive(Clone)] | |
87 | pub struct MovePath<'tcx> { | |
88 | pub next_sibling: Option<MovePathIndex>, | |
89 | pub first_child: Option<MovePathIndex>, | |
90 | pub parent: Option<MovePathIndex>, | |
9e0c209e | 91 | pub lvalue: Lvalue<'tcx>, |
54a0048b SL |
92 | } |
93 | ||
94 | impl<'tcx> fmt::Debug for MovePath<'tcx> { | |
95 | fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { | |
96 | write!(w, "MovePath {{")?; | |
97 | if let Some(parent) = self.parent { | |
98 | write!(w, " parent: {:?},", parent)?; | |
99 | } | |
100 | if let Some(first_child) = self.first_child { | |
101 | write!(w, " first_child: {:?},", first_child)?; | |
102 | } | |
103 | if let Some(next_sibling) = self.next_sibling { | |
104 | write!(w, " next_sibling: {:?}", next_sibling)?; | |
105 | } | |
9e0c209e | 106 | write!(w, " lvalue: {:?} }}", self.lvalue) |
54a0048b SL |
107 | } |
108 | } | |
109 | ||
3157f602 | 110 | #[derive(Debug)] |
54a0048b | 111 | pub struct MoveData<'tcx> { |
9e0c209e SL |
112 | pub move_paths: IndexVec<MovePathIndex, MovePath<'tcx>>, |
113 | pub moves: IndexVec<MoveOutIndex, MoveOut>, | |
114 | /// Each Location `l` is mapped to the MoveOut's that are effects | |
115 | /// of executing the code at `l`. (There can be multiple MoveOut's | |
116 | /// for a given `l` because each MoveOut is associated with one | |
117 | /// particular path being moved.) | |
118 | pub loc_map: LocationMap<Vec<MoveOutIndex>>, | |
119 | pub path_map: IndexVec<MovePathIndex, Vec<MoveOutIndex>>, | |
54a0048b SL |
120 | pub rev_lookup: MovePathLookup<'tcx>, |
121 | } | |
122 | ||
3157f602 | 123 | #[derive(Debug)] |
9e0c209e | 124 | pub struct LocationMap<T> { |
54a0048b | 125 | /// Location-indexed (BasicBlock for outer index, index within BB |
9e0c209e SL |
126 | /// for inner index) map. |
127 | map: IndexVec<BasicBlock, Vec<T>>, | |
54a0048b SL |
128 | } |
129 | ||
9e0c209e SL |
130 | impl<T> Index<Location> for LocationMap<T> { |
131 | type Output = T; | |
54a0048b | 132 | fn index(&self, index: Location) -> &Self::Output { |
9e0c209e | 133 | &self.map[index.block][index.statement_index] |
54a0048b SL |
134 | } |
135 | } | |
136 | ||
9e0c209e SL |
137 | impl<T> IndexMut<Location> for LocationMap<T> { |
138 | fn index_mut(&mut self, index: Location) -> &mut Self::Output { | |
139 | &mut self.map[index.block][index.statement_index] | |
140 | } | |
54a0048b SL |
141 | } |
142 | ||
9e0c209e SL |
143 | impl<T> LocationMap<T> where T: Default + Clone { |
144 | fn new(mir: &Mir) -> Self { | |
145 | LocationMap { | |
146 | map: mir.basic_blocks().iter().map(|block| { | |
147 | vec![T::default(); block.statements.len()+1] | |
148 | }).collect() | |
149 | } | |
54a0048b SL |
150 | } |
151 | } | |
152 | ||
153 | /// `MoveOut` represents a point in a program that moves out of some | |
154 | /// L-value; i.e., "creates" uninitialized memory. | |
155 | /// | |
156 | /// With respect to dataflow analysis: | |
157 | /// - Generated by moves and declaration of uninitialized variables. | |
158 | /// - Killed by assignments to the memory. | |
159 | #[derive(Copy, Clone)] | |
160 | pub struct MoveOut { | |
161 | /// path being moved | |
162 | pub path: MovePathIndex, | |
163 | /// location of move | |
164 | pub source: Location, | |
165 | } | |
166 | ||
167 | impl fmt::Debug for MoveOut { | |
168 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
9e0c209e | 169 | write!(fmt, "{:?}@{:?}", self.path, self.source) |
54a0048b SL |
170 | } |
171 | } | |
172 | ||
54a0048b | 173 | /// Tables mapping from an l-value to its MovePathIndex. |
3157f602 | 174 | #[derive(Debug)] |
54a0048b | 175 | pub struct MovePathLookup<'tcx> { |
9e0c209e SL |
176 | vars: IndexVec<Var, MovePathIndex>, |
177 | temps: IndexVec<Temp, MovePathIndex>, | |
178 | args: IndexVec<Arg, MovePathIndex>, | |
54a0048b SL |
179 | |
180 | /// The move path representing the return value is constructed | |
181 | /// lazily when we first encounter it in the input MIR. | |
182 | return_ptr: Option<MovePathIndex>, | |
183 | ||
54a0048b SL |
184 | /// projections are made from a base-lvalue and a projection |
185 | /// elem. The base-lvalue will have a unique MovePathIndex; we use | |
186 | /// the latter as the index into the outer vector (narrowing | |
187 | /// subsequent search so that it is solely relative to that | |
188 | /// base-lvalue). For the remaining lookup, we map the projection | |
189 | /// elem to the associated MovePathIndex. | |
9e0c209e SL |
190 | projections: FnvHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> |
191 | } | |
192 | ||
193 | struct MoveDataBuilder<'a, 'tcx: 'a> { | |
194 | mir: &'a Mir<'tcx>, | |
195 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
196 | param_env: &'a ParameterEnvironment<'tcx>, | |
197 | data: MoveData<'tcx>, | |
198 | } | |
199 | ||
200 | pub enum MovePathError { | |
201 | IllegalMove, | |
202 | UnionMove { path: MovePathIndex }, | |
203 | } | |
204 | ||
205 | impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { | |
206 | fn new(mir: &'a Mir<'tcx>, | |
207 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
208 | param_env: &'a ParameterEnvironment<'tcx>) | |
209 | -> Self { | |
210 | let mut move_paths = IndexVec::new(); | |
211 | let mut path_map = IndexVec::new(); | |
212 | ||
213 | MoveDataBuilder { | |
214 | mir: mir, | |
215 | tcx: tcx, | |
216 | param_env: param_env, | |
217 | data: MoveData { | |
218 | moves: IndexVec::new(), | |
219 | loc_map: LocationMap::new(mir), | |
220 | rev_lookup: MovePathLookup { | |
221 | vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| { | |
222 | Self::new_move_path(&mut move_paths, &mut path_map, None, v) | |
223 | }).collect(), | |
224 | temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| { | |
225 | Self::new_move_path(&mut move_paths, &mut path_map, None, t) | |
226 | }).collect(), | |
227 | args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| { | |
228 | Self::new_move_path(&mut move_paths, &mut path_map, None, a) | |
229 | }).collect(), | |
230 | return_ptr: None, | |
231 | projections: FnvHashMap(), | |
232 | }, | |
233 | move_paths: move_paths, | |
234 | path_map: path_map, | |
235 | } | |
54a0048b | 236 | } |
54a0048b | 237 | } |
54a0048b | 238 | |
9e0c209e SL |
239 | fn new_move_path(move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>, |
240 | path_map: &mut IndexVec<MovePathIndex, Vec<MoveOutIndex>>, | |
241 | parent: Option<MovePathIndex>, | |
242 | lvalue: Lvalue<'tcx>) | |
243 | -> MovePathIndex | |
244 | { | |
245 | let move_path = move_paths.push(MovePath { | |
246 | next_sibling: None, | |
247 | first_child: None, | |
248 | parent: parent, | |
249 | lvalue: lvalue | |
250 | }); | |
251 | ||
252 | if let Some(parent) = parent { | |
253 | let next_sibling = | |
254 | mem::replace(&mut move_paths[parent].first_child, Some(move_path)); | |
255 | move_paths[move_path].next_sibling = next_sibling; | |
54a0048b | 256 | } |
54a0048b | 257 | |
9e0c209e SL |
258 | let path_map_ent = path_map.push(vec![]); |
259 | assert_eq!(path_map_ent, move_path); | |
260 | move_path | |
54a0048b SL |
261 | } |
262 | ||
9e0c209e SL |
263 | /// This creates a MovePath for a given lvalue, returning an `MovePathError` |
264 | /// if that lvalue can't be moved from. | |
265 | /// | |
266 | /// NOTE: lvalues behind references *do not* get a move path, which is | |
267 | /// problematic for borrowck. | |
268 | /// | |
269 | /// Maybe we should have seperate "borrowck" and "moveck" modes. | |
270 | fn move_path_for(&mut self, lval: &Lvalue<'tcx>) | |
271 | -> Result<MovePathIndex, MovePathError> | |
272 | { | |
273 | debug!("lookup({:?})", lval); | |
274 | match *lval { | |
275 | Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]), | |
276 | Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), | |
277 | Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), | |
278 | // error: can't move out of a static | |
279 | Lvalue::Static(..) => Err(MovePathError::IllegalMove), | |
280 | Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { | |
281 | Some(ptr) => Ok(ptr), | |
282 | ref mut ptr @ None => { | |
283 | let path = Self::new_move_path( | |
284 | &mut self.data.move_paths, | |
285 | &mut self.data.path_map, | |
286 | None, | |
287 | lval.clone()); | |
288 | *ptr = Some(path); | |
289 | Ok(path) | |
290 | } | |
291 | }, | |
292 | Lvalue::Projection(ref proj) => { | |
293 | self.move_path_for_projection(lval, proj) | |
54a0048b SL |
294 | } |
295 | } | |
296 | } | |
297 | ||
9e0c209e SL |
298 | fn create_move_path(&mut self, lval: &Lvalue<'tcx>) { |
299 | // This is an assignment, not a move, so this not being a valid | |
300 | // move path is OK. | |
301 | let _ = self.move_path_for(lval); | |
302 | } | |
303 | ||
304 | fn move_path_for_projection(&mut self, | |
305 | lval: &Lvalue<'tcx>, | |
306 | proj: &LvalueProjection<'tcx>) | |
307 | -> Result<MovePathIndex, MovePathError> | |
308 | { | |
309 | let base = try!(self.move_path_for(&proj.base)); | |
310 | let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); | |
311 | match lv_ty.sty { | |
312 | // error: can't move out of borrowed content | |
313 | ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), | |
314 | // error: can't move out of struct with destructor | |
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 { | |
324 | // error: can't move out of an array | |
325 | ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove), | |
326 | _ => { | |
327 | // FIXME: still badly broken | |
328 | } | |
329 | }, | |
330 | _ => {} | |
331 | }; | |
332 | match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) { | |
333 | Entry::Occupied(ent) => Ok(*ent.get()), | |
334 | Entry::Vacant(ent) => { | |
335 | let path = Self::new_move_path( | |
336 | &mut self.data.move_paths, | |
337 | &mut self.data.path_map, | |
338 | Some(base), | |
339 | lval.clone() | |
340 | ); | |
341 | ent.insert(path); | |
342 | Ok(path) | |
54a0048b SL |
343 | } |
344 | } | |
345 | } | |
346 | ||
9e0c209e SL |
347 | fn finalize(self) -> MoveData<'tcx> { |
348 | debug!("{}", { | |
349 | debug!("moves for {:?}:", self.mir.span); | |
350 | for (j, mo) in self.data.moves.iter_enumerated() { | |
351 | debug!(" {:?} = {:?}", j, mo); | |
54a0048b | 352 | } |
9e0c209e SL |
353 | debug!("move paths for {:?}:", self.mir.span); |
354 | for (j, path) in self.data.move_paths.iter_enumerated() { | |
355 | debug!(" {:?} = {:?}", j, path); | |
54a0048b | 356 | } |
9e0c209e SL |
357 | "done dumping moves" |
358 | }); | |
359 | self.data | |
54a0048b | 360 | } |
9e0c209e | 361 | } |
54a0048b | 362 | |
9e0c209e SL |
363 | #[derive(Copy, Clone, Debug)] |
364 | pub enum LookupResult { | |
365 | Exact(MovePathIndex), | |
366 | Parent(Option<MovePathIndex>) | |
54a0048b SL |
367 | } |
368 | ||
369 | impl<'tcx> MovePathLookup<'tcx> { | |
370 | // Unlike the builder `fn move_path_for` below, this lookup | |
371 | // alternative will *not* create a MovePath on the fly for an | |
9e0c209e SL |
372 | // unknown l-value, but will rather return the nearest available |
373 | // parent. | |
374 | pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult { | |
54a0048b | 375 | match *lval { |
9e0c209e SL |
376 | Lvalue::Var(var) => LookupResult::Exact(self.vars[var]), |
377 | Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]), | |
378 | Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]), | |
379 | Lvalue::Static(..) => LookupResult::Parent(None), | |
380 | Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()), | |
54a0048b | 381 | Lvalue::Projection(ref proj) => { |
9e0c209e SL |
382 | match self.find(&proj.base) { |
383 | LookupResult::Exact(base_path) => { | |
384 | match self.projections.get(&(base_path, proj.elem.lift())) { | |
385 | Some(&subpath) => LookupResult::Exact(subpath), | |
386 | None => LookupResult::Parent(Some(base_path)) | |
387 | } | |
388 | } | |
389 | inexact => inexact | |
390 | } | |
54a0048b SL |
391 | } |
392 | } | |
393 | } | |
394 | } | |
395 | ||
9e0c209e SL |
396 | impl<'a, 'tcx> MoveData<'tcx> { |
397 | pub fn gather_moves(mir: &Mir<'tcx>, | |
398 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
399 | param_env: &ParameterEnvironment<'tcx>) | |
400 | -> Self { | |
401 | gather_moves(mir, tcx, param_env) | |
3157f602 | 402 | } |
9e0c209e | 403 | } |
3157f602 | 404 | |
9e0c209e SL |
405 | fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, |
406 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
407 | param_env: &ParameterEnvironment<'tcx>) | |
408 | -> MoveData<'tcx> { | |
409 | let mut builder = MoveDataBuilder::new(mir, tcx, param_env); | |
54a0048b | 410 | |
9e0c209e SL |
411 | for (bb, block) in mir.basic_blocks().iter_enumerated() { |
412 | for (i, stmt) in block.statements.iter().enumerate() { | |
413 | let source = Location { block: bb, statement_index: i }; | |
414 | builder.gather_statement(source, stmt); | |
54a0048b SL |
415 | } |
416 | ||
9e0c209e SL |
417 | let terminator_loc = Location { |
418 | block: bb, | |
419 | statement_index: block.statements.len() | |
420 | }; | |
421 | builder.gather_terminator(terminator_loc, block.terminator()); | |
54a0048b | 422 | } |
54a0048b | 423 | |
9e0c209e | 424 | builder.finalize() |
54a0048b SL |
425 | } |
426 | ||
9e0c209e SL |
427 | impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { |
428 | fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { | |
429 | debug!("gather_statement({:?}, {:?})", loc, stmt); | |
430 | match stmt.kind { | |
431 | StatementKind::Assign(ref lval, ref rval) => { | |
432 | self.create_move_path(lval); | |
433 | self.gather_rvalue(loc, rval); | |
434 | } | |
435 | StatementKind::StorageLive(_) | | |
436 | StatementKind::StorageDead(_) => {} | |
437 | StatementKind::SetDiscriminant{ .. } => { | |
438 | span_bug!(stmt.source_info.span, | |
439 | "SetDiscriminant should not exist during borrowck"); | |
440 | } | |
441 | StatementKind::Nop => {} | |
442 | } | |
3157f602 XL |
443 | } |
444 | ||
9e0c209e SL |
445 | fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) { |
446 | match *rvalue { | |
447 | Rvalue::Use(ref operand) | | |
448 | Rvalue::Repeat(ref operand, _) | | |
449 | Rvalue::Cast(_, ref operand, _) | | |
450 | Rvalue::UnaryOp(_, ref operand) => { | |
451 | self.gather_operand(loc, operand) | |
452 | } | |
453 | Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) | | |
454 | Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => { | |
455 | self.gather_operand(loc, lhs); | |
456 | self.gather_operand(loc, rhs); | |
457 | } | |
458 | Rvalue::Aggregate(ref _kind, ref operands) => { | |
459 | for operand in operands { | |
460 | self.gather_operand(loc, operand); | |
5bcae85e | 461 | } |
54a0048b | 462 | } |
9e0c209e SL |
463 | Rvalue::Ref(..) | |
464 | Rvalue::Len(..) | | |
465 | Rvalue::InlineAsm { .. } => {} | |
466 | Rvalue::Box(..) => { | |
467 | // This returns an rvalue with uninitialized contents. We can't | |
468 | // move out of it here because it is an rvalue - assignments always | |
469 | // completely initialize their lvalue. | |
470 | // | |
471 | // However, this does not matter - MIR building is careful to | |
472 | // only emit a shallow free for the partially-initialized | |
473 | // temporary. | |
474 | // | |
475 | // In any case, if we want to fix this, we have to register a | |
476 | // special move and change the `statement_effect` functions. | |
477 | } | |
54a0048b | 478 | } |
9e0c209e | 479 | } |
54a0048b | 480 | |
9e0c209e SL |
481 | fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { |
482 | debug!("gather_terminator({:?}, {:?})", loc, term); | |
483 | match term.kind { | |
3157f602 XL |
484 | TerminatorKind::Goto { target: _ } | |
485 | TerminatorKind::Resume | | |
486 | TerminatorKind::Unreachable => { } | |
54a0048b SL |
487 | |
488 | TerminatorKind::Return => { | |
9e0c209e | 489 | self.gather_move(loc, &Lvalue::ReturnPointer); |
54a0048b SL |
490 | } |
491 | ||
9e0c209e SL |
492 | TerminatorKind::If { .. } | |
493 | TerminatorKind::Assert { .. } | | |
494 | TerminatorKind::SwitchInt { .. } | | |
495 | TerminatorKind::Switch { .. } => { | |
496 | // branching terminators - these don't move anything | |
54a0048b SL |
497 | } |
498 | ||
3157f602 | 499 | TerminatorKind::Drop { ref location, target: _, unwind: _ } => { |
9e0c209e | 500 | self.gather_move(loc, location); |
54a0048b | 501 | } |
3157f602 | 502 | TerminatorKind::DropAndReplace { ref location, ref value, .. } => { |
9e0c209e SL |
503 | self.create_move_path(location); |
504 | self.gather_operand(loc, value); | |
3157f602 | 505 | } |
54a0048b | 506 | TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { |
9e0c209e | 507 | self.gather_operand(loc, func); |
54a0048b | 508 | for arg in args { |
9e0c209e | 509 | self.gather_operand(loc, arg); |
54a0048b SL |
510 | } |
511 | if let Some((ref destination, _bb)) = *destination { | |
9e0c209e | 512 | self.create_move_path(destination); |
54a0048b SL |
513 | } |
514 | } | |
515 | } | |
54a0048b SL |
516 | } |
517 | ||
9e0c209e SL |
518 | fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) { |
519 | match *operand { | |
520 | Operand::Constant(..) => {} // not-a-move | |
521 | Operand::Consume(ref lval) => { // a move | |
522 | self.gather_move(loc, lval); | |
54a0048b SL |
523 | } |
524 | } | |
54a0048b | 525 | } |
54a0048b | 526 | |
9e0c209e SL |
527 | fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) { |
528 | debug!("gather_move({:?}, {:?})", loc, lval); | |
54a0048b | 529 | |
9e0c209e SL |
530 | let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx); |
531 | if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) { | |
532 | debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty); | |
533 | return | |
534 | } | |
54a0048b | 535 | |
9e0c209e SL |
536 | let path = match self.move_path_for(lval) { |
537 | Ok(path) | Err(MovePathError::UnionMove { path }) => path, | |
538 | Err(MovePathError::IllegalMove) => { | |
539 | // Moving out of a bad path. Eventually, this should be a MIR | |
540 | // borrowck error instead of a bug. | |
541 | span_bug!(self.mir.span, | |
542 | "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", | |
543 | lval, lv_ty, loc); | |
54a0048b | 544 | } |
9e0c209e SL |
545 | }; |
546 | let move_out = self.data.moves.push(MoveOut { path: path, source: loc }); | |
547 | ||
548 | debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", | |
549 | loc, lval, move_out, path); | |
550 | ||
551 | self.data.path_map[path].push(move_out); | |
552 | self.data.loc_map[loc].push(move_out); | |
54a0048b SL |
553 | } |
554 | } |