]> git.lizzy.rs Git - rust.git/commitdiff
introduce DropAndReplace for translating assignments
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Mon, 16 May 2016 22:06:52 +0000 (01:06 +0300)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Fri, 3 Jun 2016 13:11:18 +0000 (16:11 +0300)
this introduces a DropAndReplace terminator as a fix to #30380. That terminator
is suppsoed to be translated by desugaring during drop elaboration, which is
not implemented in this commit, so this breaks `-Z orbit` temporarily.

13 files changed:
src/librustc/mir/repr.rs
src/librustc/mir/visit.rs
src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
src/librustc_borrowck/borrowck/mir/gather_moves.rs
src/librustc_borrowck/borrowck/mir/mod.rs
src/librustc_mir/build/expr/stmt.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/transform/break_cleanup_edges.rs
src/librustc_mir/transform/no_landing_pads.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_trans/mir/block.rs

index f9a671435ffdb3327506c4b5286088517035efe6..db4c0c1e9eb77a108dac91ce41c74666eed02cf0 100644 (file)
@@ -330,11 +330,19 @@ pub enum TerminatorKind<'tcx> {
 
     /// Drop the Lvalue
     Drop {
-        value: Lvalue<'tcx>,
+        location: Lvalue<'tcx>,
         target: BasicBlock,
         unwind: Option<BasicBlock>
     },
 
+    /// Drop the Lvalue and assign the new value over it
+    DropAndReplace {
+        location: Lvalue<'tcx>,
+        value: Operand<'tcx>,
+        target: BasicBlock,
+        unwind: Option<BasicBlock>,
+    },
+
     /// Block ends with a call of a converging function
     Call {
         /// The function that’s being called
@@ -373,8 +381,14 @@ pub fn successors(&self) -> Cow<[BasicBlock]> {
                 slice::ref_slice(t).into_cow(),
             Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(),
             Call { destination: None, cleanup: None, .. } => (&[]).into_cow(),
-            Drop { target, unwind: Some(unwind), .. } => vec![target, unwind].into_cow(),
-            Drop { ref target, .. } => slice::ref_slice(target).into_cow(),
+            DropAndReplace { target, unwind: Some(unwind), .. } |
+            Drop { target, unwind: Some(unwind), .. } => {
+                vec![target, unwind].into_cow()
+            }
+            DropAndReplace { ref target, unwind: None, .. } |
+            Drop { ref target, unwind: None, .. } => {
+                slice::ref_slice(target).into_cow()
+            }
         }
     }
 
@@ -393,8 +407,12 @@ pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
             Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t],
             Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c],
             Call { destination: None, cleanup: None, .. } => vec![],
+            DropAndReplace { ref mut target, unwind: Some(ref mut unwind), .. } |
             Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind],
-            Drop { ref mut target, .. } => vec![target]
+            DropAndReplace { ref mut target, unwind: None, .. } |
+            Drop { ref mut target, unwind: None, .. } => {
+                vec![target]
+            }
         }
     }
 }
@@ -461,7 +479,9 @@ pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
             SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
             Return => write!(fmt, "return"),
             Resume => write!(fmt, "resume"),
-            Drop { ref value, .. } => write!(fmt, "drop({:?})", value),
+            Drop { ref location, .. } => write!(fmt, "drop({:?})", location),
+            DropAndReplace { ref location, ref value, .. } =>
+                write!(fmt, "replace({:?} <- {:?})", location, value),
             Call { ref func, ref args, ref destination, .. } => {
                 if let Some((ref destination, _)) = *destination {
                     write!(fmt, "{:?} = ", destination)?;
@@ -506,8 +526,12 @@ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
             Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()],
             Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()],
             Call { destination: None, cleanup: None, .. } => vec![],
+            DropAndReplace { unwind: None, .. } |
             Drop { unwind: None, .. } => vec!["return".into_cow()],
-            Drop { .. } => vec!["return".into_cow(), "unwind".into_cow()],
+            DropAndReplace { unwind: Some(_), .. } |
+            Drop { unwind: Some(_), .. } => {
+                vec!["return".into_cow(), "unwind".into_cow()]
+            }
         }
     }
 }
index 88460651352537357a6b7e0183110aa8a1e76681..17a8d040ab4787fa69b9ac08c2df10e8247e9d19 100644 (file)
@@ -394,10 +394,20 @@ fn super_terminator_kind(&mut self,
                     TerminatorKind::Return => {
                     }
 
-                    TerminatorKind::Drop { ref $($mutability)* value,
+                    TerminatorKind::Drop { ref $($mutability)* location,
                                            target,
                                            unwind } => {
-                        self.visit_lvalue(value, LvalueContext::Drop);
+                        self.visit_lvalue(location, LvalueContext::Drop);
+                        self.visit_branch(block, target);
+                        unwind.map(|t| self.visit_branch(block, t));
+                    }
+
+                    TerminatorKind::DropAndReplace { ref $($mutability)* location,
+                                                     ref $($mutability)* value,
+                                                     target,
+                                                     unwind } => {
+                        self.visit_lvalue(location, LvalueContext::Drop);
+                        self.visit_operand(value);
                         self.visit_branch(block, target);
                         unwind.map(|t| self.visit_branch(block, t));
                     }
index b46b6c368a05338ae0e7b0a47e94dbb663ebf94e..99592e5d60fe59897bb201a089182df23ae9827c 100644 (file)
@@ -444,10 +444,17 @@ fn propagate_bits_into_graph_successors_of(
             repr::TerminatorKind::Return |
             repr::TerminatorKind::Resume => {}
             repr::TerminatorKind::Goto { ref target } |
-            repr::TerminatorKind::Drop { ref target, value: _, unwind: None } => {
+            repr::TerminatorKind::Drop { ref target, location: _, unwind: None } |
+
+            repr::TerminatorKind::DropAndReplace {
+                ref target, value: _, location: _, unwind: None
+            } => {
                 self.propagate_bits_into_entry_set_for(in_out, changed, target);
             }
-            repr::TerminatorKind::Drop { ref target, value: _, unwind: Some(ref unwind) } => {
+            repr::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } |
+            repr::TerminatorKind::DropAndReplace {
+                ref target, value: _, location: _, unwind: Some(ref unwind)
+            } => {
                 self.propagate_bits_into_entry_set_for(in_out, changed, target);
                 self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
             }
index 48511cd5ebc912a04620cd22390c9122540a3cf1..fcaa655f749d53421c466b2c496dccdb6fc9287d 100644 (file)
@@ -671,10 +671,18 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
                 let _ = discr;
             }
 
-            TerminatorKind::Drop { value: ref lval, target: _, unwind: _ } => {
+            TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
                 let source = Location { block: bb,
                                         index: bb_data.statements.len() };
-                bb_ctxt.on_move_out_lval(SK::Drop, lval, source);
+                bb_ctxt.on_move_out_lval(SK::Drop, location, source);
+            }
+            TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
+                let assigned_path = bb_ctxt.builder.move_path_for(location);
+                bb_ctxt.path_map.fill_to(assigned_path.idx());
+
+                let source = Location { block: bb,
+                                        index: bb_data.statements.len() };
+                bb_ctxt.on_operand(SK::Use, value, source);
             }
             TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
                 let source = Location { block: bb,
index 1b9d08bade7c4a798652627ceccf0db9ba977061..38ebecf248ff798f9e89e9bc6152f9be3554da11 100644 (file)
@@ -309,15 +309,23 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
         Some(stmt) => match stmt.kind {
             repr::StatementKind::Assign(ref lvalue, _) => {
                 debug!("drop_flag_effects: assignment {:?}", stmt);
-                on_all_children_bits(tcx, mir, move_data,
+                 on_all_children_bits(tcx, mir, move_data,
                                      move_data.rev_lookup.find(lvalue),
                                      |moi| callback(moi, DropFlagState::Present))
             }
         },
         None => {
-            // terminator - no move-ins except for function return edge
-            let term = bb.terminator();
-            debug!("drop_flag_effects: terminator {:?}", term);
+            debug!("drop_flag_effects: replace {:?}", bb.terminator());
+            match bb.terminator().kind {
+                repr::TerminatorKind::DropAndReplace { ref location, .. } => {
+                    on_all_children_bits(tcx, mir, move_data,
+                                         move_data.rev_lookup.find(location),
+                                         |moi| callback(moi, DropFlagState::Present))
+                }
+                _ => {
+                    // other terminators do not contain move-ins
+                }
+            }
         }
     }
 }
index 9629396f48b50f1274b364e7021ade9a835d20af..3324467e70d1d868278071ce88f8eb3d4f45b472 100644 (file)
@@ -34,29 +34,25 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
                 let scope_id = this.innermost_scope_id();
                 let lhs_span = lhs.span;
 
-                let lhs_ty = lhs.ty;
-                let rhs_ty = rhs.ty;
-
-                let lhs_needs_drop = this.hir.needs_drop(lhs_ty);
-                let rhs_needs_drop = this.hir.needs_drop(rhs_ty);
-
                 // Note: we evaluate assignments right-to-left. This
                 // is better for borrowck interaction with overloaded
                 // operators like x[j] = x[i].
 
                 // Generate better code for things that don't need to be
                 // dropped.
-                let rhs = if lhs_needs_drop || rhs_needs_drop {
-                    let op = unpack!(block = this.as_operand(block, rhs));
-                    Rvalue::Use(op)
+                if this.hir.needs_drop(lhs.ty) {
+                    let rhs = unpack!(block = this.as_operand(block, rhs));
+                    let lhs = unpack!(block = this.as_lvalue(block, lhs));
+                    unpack!(block = this.build_drop_and_replace(
+                        block, lhs_span, lhs, rhs
+                    ));
+                    block.unit()
                 } else {
-                    unpack!(block = this.as_rvalue(block, rhs))
-                };
-
-                let lhs = unpack!(block = this.as_lvalue(block, lhs));
-                unpack!(block = this.build_drop(block, lhs_span, lhs.clone(), lhs_ty));
-                this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs);
-                block.unit()
+                    let rhs = unpack!(block = this.as_rvalue(block, rhs));
+                    let lhs = unpack!(block = this.as_lvalue(block, lhs));
+                    this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs);
+                    block.unit()
+                }
             }
             ExprKind::AssignOp { op, lhs, rhs } => {
                 // FIXME(#28160) there is an interesting semantics
index 071c8d618c845faaccd32bf643ab5da874ac3285..cd81fc764f4aff13804e6d41a0e39349174a87cf 100644 (file)
@@ -139,7 +139,7 @@ struct DropData<'tcx> {
     span: Span,
 
     /// lvalue to drop
-    value: Lvalue<'tcx>,
+    location: Lvalue<'tcx>,
 
     /// The cached block for the cleanups-on-diverge path. This block
     /// contains code to run the current drop and all the preceding
@@ -402,7 +402,7 @@ pub fn schedule_drop(&mut self,
                 // the drop that comes before it in the vector.
                 scope.drops.push(DropData {
                     span: span,
-                    value: lvalue.clone(),
+                    location: lvalue.clone(),
                     cached_block: None
                 });
                 return;
@@ -497,7 +497,7 @@ pub fn diverge_cleanup(&mut self) -> Option<BasicBlock> {
     pub fn build_drop(&mut self,
                       block: BasicBlock,
                       span: Span,
-                      value: Lvalue<'tcx>,
+                      location: Lvalue<'tcx>,
                       ty: Ty<'tcx>) -> BlockAnd<()> {
         if !self.hir.needs_drop(ty) {
             return block.unit();
@@ -509,7 +509,7 @@ pub fn build_drop(&mut self,
                            scope_id,
                            span,
                            TerminatorKind::Drop {
-                               value: value,
+                               location: location,
                                target: next_target,
                                unwind: diverge_target,
                            });
@@ -517,6 +517,27 @@ pub fn build_drop(&mut self,
     }
 
 
+
+    pub fn build_drop_and_replace(&mut self,
+                                  block: BasicBlock,
+                                  span: Span,
+                                  location: Lvalue<'tcx>,
+                                  value: Operand<'tcx>) -> BlockAnd<()> {
+        let scope_id = self.innermost_scope_id();
+        let next_target = self.cfg.start_new_block();
+        let diverge_target = self.diverge_cleanup();
+        self.cfg.terminate(block,
+                           scope_id,
+                           span,
+                           TerminatorKind::DropAndReplace {
+                               location: location,
+                               value: value,
+                               target: next_target,
+                               unwind: diverge_target,
+                           });
+        next_target.unit()
+    }
+
     // Panicking
     // =========
     // FIXME: should be moved into their own module
@@ -653,7 +674,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
         });
         let next = cfg.start_new_block();
         cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop {
-            value: drop_data.value.clone(),
+            location: drop_data.location.clone(),
             target: next,
             unwind: on_diverge
         });
@@ -709,7 +730,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                           scope.id,
                           drop_data.span,
                           TerminatorKind::Drop {
-                              value: drop_data.value.clone(),
+                              location: drop_data.location.clone(),
                               target: target,
                               unwind: None
                           });
index 0eb6223a71e54af5d64aed9cf8b11fc7e1ffda1e..4902d31cf4d7a9724fda1416746a30dade710395 100644 (file)
@@ -105,7 +105,9 @@ impl Pass for BreakCleanupEdges {}
 fn term_is_invoke(term: &Terminator) -> bool {
     match term.kind {
         TerminatorKind::Call { cleanup: Some(_), .. } |
-        TerminatorKind::Drop { unwind: Some(_), .. } => true,
+        // FIXME: not sure whether we need this one
+        TerminatorKind::Drop { unwind: Some(_), .. } |
+        TerminatorKind::DropAndReplace { .. } => true,
         _ => false
     }
 }
index de05032fa558624e90f40206504bd942a1ca6db3..67710c4328569bf82783362d15f0e0088056a41f 100644 (file)
@@ -29,12 +29,11 @@ fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>
             TerminatorKind::SwitchInt { .. } => {
                 /* nothing to do */
             },
+            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
+            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
             TerminatorKind::Drop { ref mut unwind, .. } => {
                 unwind.take();
             },
-            TerminatorKind::Call { ref mut cleanup, .. } => {
-                cleanup.take();
-            },
         }
         self.super_terminator(bb, terminator);
     }
index 431568b004d3ddbda6ec75e2680e9c5efa18c8d2..d81c4e2dfb68ee9d72e8202feb1d615a981f082a 100644 (file)
@@ -399,7 +399,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         });
         let terminator = block.terminator_mut();
         match terminator.kind {
-            TerminatorKind::Drop { value: Lvalue::Temp(index), target, .. } => {
+            TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => {
                 if promoted(index) {
                     terminator.kind = TerminatorKind::Goto {
                         target: target
index 2e4400c834f2325a1ce689eddc842a44af107efc..18a1f1595f3c3ef758f49f807552a227e7594dce 100644 (file)
@@ -422,6 +422,7 @@ fn qualify_const(&mut self) -> Qualif {
 
                 TerminatorKind::Switch {..} |
                 TerminatorKind::SwitchInt {..} |
+                TerminatorKind::DropAndReplace { .. } |
                 TerminatorKind::Resume => None,
 
                 TerminatorKind::Return => {
index 80c56a5dc08f15a0407f4d0d97bf5d352e731102..7a41211381cb91a6e0a87fb3efe0bd39702b9b06 100644 (file)
@@ -363,6 +363,20 @@ fn check_terminator(&mut self,
                 // no checks needed for these
             }
 
+
+            TerminatorKind::DropAndReplace {
+                ref location,
+                ref value,
+                ..
+            } => {
+                let lv_ty = mir.lvalue_ty(tcx, location).to_ty(tcx);
+                let rv_ty = mir.operand_ty(tcx, value);
+                if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
+                    span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
+                                 lv_ty, rv_ty, terr);
+                }
+            }
+
             TerminatorKind::If { ref cond, .. } => {
                 let cond_ty = mir.operand_ty(tcx, cond);
                 match cond_ty.sty {
index 4e3386bc736775440d22bb3f1fd6d015dbe9c392..fb93e487f3bb252e41cb33e8c34821edfb9a398b 100644 (file)
@@ -143,8 +143,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 })
             }
 
-            mir::TerminatorKind::Drop { ref value, target, unwind } => {
-                let lvalue = self.trans_lvalue(&bcx, value);
+            mir::TerminatorKind::Drop { ref location, target, unwind } => {
+                let lvalue = self.trans_lvalue(&bcx, location);
                 let ty = lvalue.ty.to_ty(bcx.tcx());
                 // Double check for necessity to drop
                 if !glue::type_needs_drop(bcx.tcx(), ty) {
@@ -177,6 +177,10 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 }
             }
 
+            mir::TerminatorKind::DropAndReplace { .. } => {
+                bug!("undesugared DropAndReplace in trans: {:?}", data);
+            }
+
             mir::TerminatorKind::Call { ref func, ref args, ref destination, ref cleanup } => {
                 // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
                 let callee = self.trans_operand(&bcx, func);