From ff12d786bb5b8665c0842b52b285fb6271293bd2 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 28 Mar 2017 08:09:05 -0600 Subject: [PATCH] Switch TerminatorKind::Call to StatementKind. --- src/librustc/mir/mod.rs | 126 +++++------ src/librustc/mir/visit.rs | 26 +-- .../borrowck/mir/dataflow/impls.rs | 5 +- .../borrowck/mir/dataflow/mod.rs | 25 ++- .../borrowck/mir/dataflow/sanity_check.rs | 51 +++-- .../borrowck/mir/elaborate_drops.rs | 61 ++--- .../borrowck/mir/gather_moves.rs | 16 +- src/librustc_borrowck/borrowck/mir/mod.rs | 1 + src/librustc_mir/build/expr/into.rs | 26 ++- src/librustc_mir/build/matches/test.rs | 30 +-- src/librustc_mir/build/scope.rs | 23 +- src/librustc_mir/callgraph.rs | 8 +- src/librustc_mir/shim.rs | 27 ++- src/librustc_mir/transform/inline.rs | 196 +++++++++-------- src/librustc_mir/transform/no_landing_pads.rs | 6 +- src/librustc_mir/transform/promote_consts.rs | 165 +++++++------- src/librustc_mir/transform/qualify_consts.rs | 208 ++++++++---------- src/librustc_mir/transform/type_check.rs | 115 +++++----- src/librustc_mir/util/elaborate_drops.rs | 30 ++- src/librustc_passes/mir_stats.rs | 2 +- src/librustc_trans/collector.rs | 32 ++- src/librustc_trans/mir/analyze.rs | 18 +- src/librustc_trans/mir/block.rs | 10 - src/librustc_trans/mir/constant.rs | 49 ++--- src/librustc_trans/mir/statement.rs | 19 +- 25 files changed, 655 insertions(+), 620 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index eadc876dd945a..5814cd309cdc3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -515,18 +515,6 @@ pub enum TerminatorKind<'tcx> { target: Block, unwind: Option, }, - - /// Block ends with a call of a converging function - Call { - /// The function that’s being called - func: Operand<'tcx>, - /// Arguments the function is called with - args: Vec>, - /// Destination for the return value. If some, the call is converging. - destination: Option<(Lvalue<'tcx>, Block)>, - /// Cleanups to be done if the call unwinds. - cleanup: Option - }, } impl<'tcx> Terminator<'tcx> { @@ -559,11 +547,6 @@ impl<'tcx> TerminatorKind<'tcx> { Resume => (&[]).into_cow(), Return => (&[]).into_cow(), Unreachable => (&[]).into_cow(), - Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(), - Call { destination: Some((_, ref t)), cleanup: None, .. } => - 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(), DropAndReplace { target, unwind: Some(unwind), .. } | Drop { target, unwind: Some(unwind), .. } => { vec![target, unwind].into_cow() @@ -585,10 +568,6 @@ impl<'tcx> TerminatorKind<'tcx> { Resume => Vec::new(), Return => Vec::new(), Unreachable => Vec::new(), - Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c], - 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], DropAndReplace { ref mut target, unwind: None, .. } | @@ -663,19 +642,6 @@ impl<'tcx> TerminatorKind<'tcx> { 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)?; - } - write!(fmt, "{:?}(", func)?; - for (index, arg) in args.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{:?}", arg)?; - } - write!(fmt, ")") - } } } @@ -695,11 +661,6 @@ impl<'tcx> TerminatorKind<'tcx> { .chain(iter::once(String::from("otherwise").into())) .collect() } - Call { destination: Some(_), cleanup: Some(_), .. } => - vec!["return".into_cow(), "unwind".into_cow()], - 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()], DropAndReplace { unwind: Some(_), .. } | @@ -737,19 +698,39 @@ impl<'tcx> Statement<'tcx> { pub fn cleanup_target(&self) -> Option { match self.kind { - StatementKind::Assert { cleanup: Some(unwind), .. } => { - Some(unwind) + StatementKind::Assign(..) | + StatementKind::SetDiscriminant { .. } | + StatementKind::StorageLive(..) | + StatementKind::StorageDead(..) | + StatementKind::InlineAsm { .. } | + StatementKind::Nop => None, + StatementKind::Assert { cleanup: unwind, .. } | + StatementKind::Call { cleanup: unwind, .. } => { + if let Some(unwind) = unwind { + Some(unwind) + } else { + None + } } - _ => None } } pub fn cleanup_target_mut(&mut self) -> Option<&mut Block> { match self.kind { - StatementKind::Assert { cleanup: Some(ref mut unwind), .. } => { - Some(unwind) + StatementKind::Assign(..) | + StatementKind::SetDiscriminant { .. } | + StatementKind::StorageLive(..) | + StatementKind::StorageDead(..) | + StatementKind::InlineAsm { .. } | + StatementKind::Nop => None, + StatementKind::Assert { cleanup: ref mut unwind, .. } | + StatementKind::Call { cleanup: ref mut unwind, .. } => { + if let Some(ref mut unwind) = *unwind { + Some(unwind) + } else { + None + } } - _ => None } } } @@ -783,6 +764,18 @@ pub enum StatementKind<'tcx> { cleanup: Option }, + /// Block ends with a call of a converging function + Call { + /// The function that’s being called + func: Operand<'tcx>, + /// Arguments the function is called with + args: Vec>, + /// Destination for the return value. + destination: Lvalue<'tcx>, + /// Cleanups to be done if the call unwinds. + cleanup: Option + }, + /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } @@ -820,6 +813,17 @@ impl<'tcx> Debug for Statement<'tcx> { write!(fmt, ")") }, + Call { ref func, ref args, ref destination, .. } => { + write!(fmt, "{:?} = ", destination)?; + write!(fmt, "{:?}(", func)?; + for (index, arg) in args.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{:?}", arg)?; + } + write!(fmt, ")") + }, Nop => write!(fmt, "nop"), } } @@ -1459,6 +1463,16 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { cleanup: cleanup } }, + Call { ref func, ref args, ref destination, cleanup } => { + let dest = destination.fold_with(folder); + + Call { + func: func.fold_with(folder), + args: args.fold_with(folder), + destination: dest, + cleanup: cleanup + } + }, Nop => Nop, }; Statement { @@ -1488,6 +1502,10 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { false } }, + Call { ref func, ref args, ref destination, .. } => { + destination.visit_with(visitor) || func.visit_with(visitor) || + args.visit_with(visitor) + }, Nop => false, } } @@ -1516,18 +1534,6 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { target: target, unwind: unwind }, - Call { ref func, ref args, ref destination, cleanup } => { - let dest = destination.as_ref().map(|&(ref loc, dest)| { - (loc.fold_with(folder), dest) - }); - - Call { - func: func.fold_with(folder), - args: args.fold_with(folder), - destination: dest, - cleanup: cleanup - } - }, Resume => Resume, Return => Return, Unreachable => Unreachable, @@ -1547,12 +1553,6 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Drop { ref location, ..} => location.visit_with(visitor), DropAndReplace { ref location, ref value, ..} => location.visit_with(visitor) || value.visit_with(visitor), - Call { ref func, ref args, ref destination, .. } => { - let dest = if let Some((ref loc, _)) = *destination { - loc.visit_with(visitor) - } else { false }; - dest || func.visit_with(visitor) || args.visit_with(visitor) - }, Goto { .. } | Resume | Return | diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 6f158ffcd78fc..4710042969425 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -352,6 +352,17 @@ macro_rules! make_mir_visitor { self.visit_assert_message(msg, location); cleanup.map(|t| self.visit_branch(block, t)); } + StatementKind::Call { ref $($mutability)* func, + ref $($mutability)* args, + ref $($mutability)* destination, + cleanup } => { + self.visit_operand(func, location); + for arg in args { + self.visit_operand(arg, location); + } + self.visit_lvalue(destination, LvalueContext::Call, location); + cleanup.map(|t| self.visit_branch(block, t)); + } StatementKind::Nop => {} } } @@ -423,21 +434,6 @@ macro_rules! make_mir_visitor { self.visit_branch(block, target); unwind.map(|t| self.visit_branch(block, t)); } - - TerminatorKind::Call { ref $($mutability)* func, - ref $($mutability)* args, - ref $($mutability)* destination, - cleanup } => { - self.visit_operand(func, source_location); - for arg in args { - self.visit_operand(arg, source_location); - } - if let Some((ref $($mutability)* destination, target)) = *destination { - self.visit_lvalue(destination, LvalueContext::Call, source_location); - self.visit_branch(block, target); - } - cleanup.map(|t| self.visit_branch(block, t)); - } } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index aad9f0ccb0d3c..353718256bb07 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -300,7 +300,6 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, in_out: &mut IdxSet, _call_bb: mir::Block, - _dest_bb: mir::Block, dest_lval: &mir::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). @@ -357,7 +356,6 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, in_out: &mut IdxSet, _call_bb: mir::Block, - _dest_bb: mir::Block, dest_lval: &mir::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 0 (initialized). @@ -413,7 +411,6 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, in_out: &mut IdxSet, _call_bb: mir::Block, - _dest_bb: mir::Block, dest_lval: &mir::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). @@ -475,6 +472,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | mir::StatementKind::Assert { .. } | + mir::StatementKind::Call { .. } | mir::StatementKind::Nop => {} } } @@ -500,7 +498,6 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { fn propagate_call_return(&self, in_out: &mut IdxSet, _call_bb: mir::Block, - _dest_bb: mir::Block, dest_lval: &mir::Lvalue) { let move_data = self.move_data(); let bits_per_block = self.bits_per_block(); diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 05c41274bafb6..5000ac002169a 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -368,7 +368,6 @@ pub trait BitDenotation { fn propagate_call_return(&self, in_out: &mut IdxSet, call_bb: mir::Block, - dest_bb: mir::Block, dest_lval: &mir::Lvalue); } @@ -457,16 +456,24 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> self.propagate_bits_into_entry_set_for(in_out, changed, target); } } - mir::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { - if let Some(ref unwind) = *cleanup { - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); - } - if let Some((ref dest_lval, ref dest_bb)) = *destination { + } + + for stmt in bb_data.statements.iter() { + match stmt.kind { + mir::StatementKind::Assign(..) | + mir::StatementKind::SetDiscriminant { .. } | + mir::StatementKind::StorageLive(..) | + mir::StatementKind::StorageDead(..) | + mir::StatementKind::InlineAsm { .. } | + mir::StatementKind::Assert { .. } | + mir::StatementKind::Nop => {}, + mir::StatementKind::Call { ref cleanup, ref destination, func: _, args: _ } => { + if let Some(ref unwind) = *cleanup { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } // N.B.: This must be done *last*, after all other // propagation, as documented in comment above. - self.flow_state.operator.propagate_call_return( - in_out, bb, *dest_bb, dest_lval); - self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb); + self.flow_state.operator.propagate_call_return(in_out, bb, destination); } } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 189f8fd5121c9..cfff84ebec79a 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -10,7 +10,6 @@ use syntax::abi::{Abi}; use syntax::ast; -use syntax_pos::Span; use rustc::ty::{self, TyCtxt}; use rustc::mir::{self, Mir}; @@ -61,12 +60,24 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, O: BitDenotation + HasMoveData<'tcx> { let move_data = results.0.operator.move_data(); - let mir::BlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb]; - - let (args, span) = match is_rustc_peek(tcx, terminator) { - Some(args_and_span) => args_and_span, - None => return, - }; + let mir::BlockData { ref statements, terminator: _, is_cleanup: _ } = mir[bb]; + + let mut args: Option<&[mir::Operand]> = None; + let mut span = None; + // FIXME: Don't loop through statements twice, here, and below + for stmt in statements { + // FIXME: Can there potentially be multiple Call rustc_peek statements? If so, + // do we need to handle all of them? That is possible, of course, but will require slight + // refactoring.. + if let Some(a) = is_rustc_peek(tcx, stmt) { + args = Some(a); + span = Some(stmt.source_info.span); + } else { + return; + } + } + let args = args.unwrap(); + let span = span.unwrap(); assert!(args.len() == 1); let peek_arg_lval = match args[0] { mir::Operand::Consume(ref lval @ mir::Lvalue::Local(_)) => Some(lval), @@ -106,6 +117,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | mir::StatementKind::Assert { .. } | + mir::StatementKind::Call { .. } | mir::StatementKind::Nop => continue, mir::StatementKind::SetDiscriminant{ .. } => span_bug!(stmt.source_info.span, @@ -158,21 +170,16 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - terminator: &'a Option>) - -> Option<(&'a [mir::Operand<'tcx>], Span)> { - if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator { - if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind - { - if let mir::Operand::Constant(ref func) = *oper - { - if let ty::TyFnDef(def_id, _, sig) = func.ty.sty - { - let abi = sig.abi(); - let name = tcx.item_name(def_id); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - if name == "rustc_peek" { - return Some((args, source_info.span)); - } + statement: &'a mir::Statement<'tcx>) + -> Option<&'a [mir::Operand<'tcx>]> { + if let mir::StatementKind::Call { func: ref oper, ref args, .. } = statement.kind { + if let mir::Operand::Constant(ref func) = *oper { + if let ty::TyFnDef(def_id, _, sig) = func.ty.sty { + let abi = sig.abi(); + let name = tcx.item_name(def_id); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + if name == "rustc_peek" { + return Some(args); } } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index c6b479e648eca..8efff001b1c1c 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -494,17 +494,19 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn drop_flags_for_fn_rets(&mut self) { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { - if let TerminatorKind::Call { - destination: Some((ref lv, tgt)), cleanup: Some(_), .. - } = data.terminator().kind { - assert!(!self.patch.is_patched(bb)); - - let loc = Location { block: tgt, statement_index: 0 }; - let path = self.move_data().rev_lookup.find(lv); - on_lookup_result_bits( - self.tcx, self.mir, self.move_data(), path, - |child| self.set_drop_flag(loc, child, DropFlagState::Present) - ); + for (i, stmt) in data.statements.iter().enumerate() { + if let StatementKind::Call { + destination: ref lv, cleanup: Some(_), .. + } = stmt.kind { + // XXX: assert!(!self.patch.is_patched(bb)); + + let loc = Location { block: bb, statement_index: i }; + let path = self.move_data().rev_lookup.find(lv); + on_lookup_result_bits( + self.tcx, self.mir, self.move_data(), path, + |child| self.set_drop_flag(loc, child, DropFlagState::Present) + ); + } } } } @@ -546,10 +548,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { allow_initializations = false; } _ => { - assert!(!self.patch.is_patched(bb)); + assert!(!self.patch.is_patched(bb), "kind: {:?}", + data.terminator().kind); } } } + + // There may be a critical edge after this call, + // so mark the return as initialized *before* the + // call. + // XXX: + //if i < data.statements.len() { + // if let StatementKind::Call { + // destination: ref lv, cleanup: None, .. + // } = data.statements[i].kind { + // let loc = Location { block: bb, statement_index: i }; + // let path = self.move_data().rev_lookup.find(lv); + // on_lookup_result_bits( + // self.tcx, self.mir, self.move_data(), path, + // |child| self.set_drop_flag(loc, child, DropFlagState::Present) + // ); + // } + //} + let loc = Location { block: bb, statement_index: i }; super::drop_flag_effects_for_location( self.tcx, self.mir, self.env, loc, |path, ds| { @@ -557,22 +578,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.set_drop_flag(loc, path, ds) } } - ) - } - - // There may be a critical edge after this call, - // so mark the return as initialized *before* the - // call. - if let TerminatorKind::Call { - destination: Some((ref lv, _)), cleanup: None, .. - } = data.terminator().kind { - assert!(!self.patch.is_patched(bb)); - - let loc = Location { block: bb, statement_index: data.statements.len() }; - let path = self.move_data().rev_lookup.find(lv); - on_lookup_result_bits( - self.tcx, self.mir, self.move_data(), path, - |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index f87a191dc06ab..1b2704c7b80b7 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -412,6 +412,13 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } + StatementKind::Call { ref func, ref args, ref destination, .. } => { + self.gather_operand(loc, func); + for arg in args { + self.gather_operand(loc, arg); + } + self.create_move_path(destination); + } StatementKind::InlineAsm { .. } | StatementKind::Assert { .. } | StatementKind::Nop => {} @@ -476,15 +483,6 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { self.create_move_path(location); self.gather_operand(loc, value); } - TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { - self.gather_operand(loc, func); - for arg in args { - self.gather_operand(loc, arg); - } - if let Some((ref destination, _bb)) = *destination { - self.create_move_path(destination); - } - } } } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 6eadfcc2729fa..87597b7d111d7 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -365,6 +365,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | mir::StatementKind::Assert { .. } | + mir::StatementKind::Call { .. } | mir::StatementKind::Nop => {} }, None => { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index af085f0888823..4ba9a61129a46 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -212,14 +212,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args } => { + let fun = unpack!(block = this.as_local_operand(block, fun)); let diverges = match ty.sty { ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { // FIXME(canndrew): This is_never should probably be an is_uninhabited f.output().skip_binder().is_never() } - _ => false + _ => false, }; - let fun = unpack!(block = this.as_local_operand(block, fun)); let args: Vec<_> = args.into_iter() .map(|arg| unpack!(block = this.as_local_operand(block, arg))) @@ -227,16 +227,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let success = this.cfg.start_new_block(); let cleanup = this.diverge_cleanup(); - this.cfg.terminate(block, source_info, TerminatorKind::Call { - func: fun, - args: args, - cleanup: cleanup, - destination: if diverges { - None - } else { - Some ((destination.clone(), success)) + this.cfg.push(block, Statement { + source_info: source_info, + kind: StatementKind::Call { + func: fun, + args: args, + cleanup: cleanup, + destination: destination.clone(), } }); + if diverges { + this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + } else { + this.cfg.terminate(block, source_info, TerminatorKind::Goto { + target: success + }); + } success.unit() } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index fe92801ca5e0e..7ceb3f192e4f7 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -306,26 +306,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty); - let eq_block = self.cfg.start_new_block(); let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, source_info, TerminatorKind::Call { - func: Operand::Constant(Constant { - span: test.span, - ty: mty, - literal: method - }), - args: vec![val, expect], - destination: Some((eq_result.clone(), eq_block)), - cleanup: cleanup, + self.cfg.push(block, Statement { + source_info: source_info, + kind: StatementKind::Call { + func: Operand::Constant(Constant { + span: test.span, + ty: mty, + literal: method + }), + args: vec![val, expect], + destination: eq_result.clone(), + cleanup: cleanup, + }, }); // check the result - let block = self.cfg.start_new_block(); - self.cfg.terminate(eq_block, source_info, + let succ = self.cfg.start_new_block(); + self.cfg.terminate(block, source_info, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(eq_result), - block, fail)); - vec![block, fail] + succ, fail)); + vec![succ, fail] } else { let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val); vec![block, fail] diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 3d4f52270c934..94bb23555600f 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -358,10 +358,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, self.arg_count)); if let Some(ref free_data) = scope.free { - let next = self.cfg.start_new_block(); - let free = build_free(self.hir.tcx(), &tmp, free_data, next); - self.cfg.terminate(block, scope.source_info(span), free); - block = next; + self.cfg.push(block, Statement { + source_info: scope.source_info(span), + kind: build_free(self.hir.tcx(), &tmp, free_data) + }); } } } @@ -713,8 +713,12 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cached_block } else { let into = cfg.start_new_cleanup_block(); + cfg.push(into, Statement { + source_info: source_info(free_data.span), + kind: build_free(tcx, unit_temp, free_data) + }); cfg.terminate(into, source_info(free_data.span), - build_free(tcx, unit_temp, free_data, target)); + TerminatorKind::Goto { target: target }); free_data.cached_block = Some(into); into }; @@ -750,12 +754,11 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, unit_temp: &Lvalue<'tcx>, - data: &FreeData<'tcx>, - target: Block) - -> TerminatorKind<'tcx> { + data: &FreeData<'tcx>) + -> StatementKind<'tcx> { let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]); - TerminatorKind::Call { + StatementKind::Call { func: Operand::Constant(Constant { span: data.span, ty: tcx.item_type(free_func).subst(tcx, substs), @@ -764,7 +767,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, } }), args: vec![Operand::Consume(data.value.clone())], - destination: Some((unit_temp.clone(), target)), + destination: unit_temp.clone(), cleanup: None } } diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs index 0c5d37efd86d0..1c56217c5dfd3 100644 --- a/src/librustc_mir/callgraph.rs +++ b/src/librustc_mir/callgraph.rs @@ -79,11 +79,11 @@ struct CallVisitor<'a> { } impl<'a, 'tcx> Visitor<'tcx> for CallVisitor<'a> { - fn visit_terminator_kind(&mut self, _block: Block, - kind: &TerminatorKind<'tcx>, _loc: Location) { - if let TerminatorKind::Call { + fn visit_statement(&mut self, _block: Block, + statement: &Statement<'tcx>, _loc: Location) { + if let StatementKind::Call { func: Operand::Constant(ref f) - , .. } = *kind { + , .. } = statement.kind { if let ty::TyFnDef(def_id, _, _) = f.ty.sty { let callee = self.graph.add_node(def_id); self.graph.graph.add_edge(self.caller, callee, ()); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 314cac5ba2aa1..5aa1ac9172b60 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -366,17 +366,24 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, }) }; + statements.push(Statement { + source_info: source_info, + kind: StatementKind::Call { + func: callee, + args: args, + destination: Lvalue::Local(RETURN_POINTER), + cleanup: if let Adjustment::RefMut = rcvr_adjustment { + Some(Block::new(3)) + } else { + None + } + }, + }); + // BB #0 - block(&mut blocks, statements, TerminatorKind::Call { - func: callee, - args: args, - destination: Some((Lvalue::Local(RETURN_POINTER), - Block::new(1))), - cleanup: if let Adjustment::RefMut = rcvr_adjustment { - Some(Block::new(3)) - } else { - None - } + // FIXME: This block shouldn't be necessary. + block(&mut blocks, statements, TerminatorKind::Goto { + target: Block::new(1) }, false); if let Adjustment::RefMut = rcvr_adjustment { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index c53c13d2d5d42..e577182992e18 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -112,8 +112,8 @@ struct CallSite<'tcx> { caller: DefId, callee: DefId, substs: &'tcx Substs<'tcx>, - bb: Block, - location: SourceInfo, + source_info: SourceInfo, + location: Location, } impl<'a, 'tcx> Inliner<'a, 'tcx> { @@ -140,17 +140,18 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if bb_data.is_cleanup { continue; } // Only consider direct calls to functions - let terminator = bb_data.terminator(); - if let TerminatorKind::Call { - func: Operand::Constant(ref f), .. } = terminator.kind { - if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { - callsites.push(CallSite { - caller: def_id, - callee: callee_def_id, - substs: substs, - bb: bb, - location: terminator.source_info - }); + for (i, statement) in bb_data.statements.iter().enumerate().rev() { + if let StatementKind::Call { + func: Operand::Constant(ref f), .. } = statement.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + callsites.push(CallSite { + caller: def_id, + callee: callee_def_id, + substs: substs, + source_info: statement.source_info, + location: Location { block: bb, statement_index: i } + }); + } } } } @@ -218,19 +219,20 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Add callsites from inlined function for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) { // Only consider direct calls to functions - let terminator = bb_data.terminator(); - if let TerminatorKind::Call { - func: Operand::Constant(ref f), .. } = terminator.kind { - if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { - // Don't inline the same function multiple times. - if callsite.callee != callee_def_id { - callsites.push(CallSite { - caller: callsite.caller, - callee: callee_def_id, - substs: substs, - bb: bb, - location: terminator.source_info - }); + for (i, statement) in bb_data.statements.iter().enumerate().rev() { + if let StatementKind::Call { + func: Operand::Constant(ref f), .. } = statement.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + // Don't inline the same function multiple times. + if callsite.callee != callee_def_id { + callsites.push(CallSite { + caller: callsite.caller, + callee: callee_def_id, + substs: substs, + source_info: statement.source_info, + location: Location { block: bb, statement_index: i } + }); + } } } } @@ -345,6 +347,24 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { StatementKind::StorageDead(_) | StatementKind::Nop => {}, StatementKind::Assert { .. } => cost += CALL_PENALTY - INSTR_COST, + StatementKind::Call { ref func, .. } => { + if first_block && + func.ty(&callee_mir, tcx).fn_ret().skip_binder().is_never() { + threshold = 0; + } + + if let Operand::Constant(ref f) = *func { + if let ty::TyFnDef(.., f) = f.ty.sty { + // Don't give intrinsics the extra penalty for calls + if f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic { + cost += INSTR_COST; + } else { + cost += CALL_PENALTY; + } + } + } + } _ => cost += INSTR_COST } } @@ -369,23 +389,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - TerminatorKind::Unreachable | - TerminatorKind::Call { destination: None, .. } if first_block => { + TerminatorKind::Unreachable if first_block => { // If the function always diverges, don't inline // unless the cost is zero threshold = 0; } - TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { - if let ty::TyFnDef(.., f) = f.ty.sty { - // Don't give intrinsics the extra penalty for calls - if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - cost += INSTR_COST; - } else { - cost += CALL_PENALTY; - } - } - } _ => cost += INSTR_COST } @@ -426,19 +435,30 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn inline_call(&self, callsite: CallSite<'tcx>, - caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool { + caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool { // Don't inline a function into itself if callsite.caller == callsite.callee { return false; } let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + match caller_mir[callsite.location.block] + .statements[callsite.location.statement_index].kind { + StatementKind::Call { .. } => {}, + _ => return false, + } - let terminator = caller_mir[callsite.bb].terminator.take().unwrap(); - match terminator.kind { - // FIXME: Handle inlining of diverging calls - TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { + let statements_after = caller_mir[callsite.location.block].statements.split_off( + callsite.location.statement_index + 1 + ); + let mut after_block = BlockData::new(caller_mir[callsite.location.block].terminator.take()); + after_block.statements = statements_after; + let new_block_idx = caller_mir.basic_blocks_mut().push(after_block); + let statement = caller_mir[callsite.location.block].statements.pop().unwrap(); + match statement.kind { + // FIXME: Handle inlining of diverging calls + StatementKind::Call { args, destination, cleanup, .. } => { debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller); let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn(); @@ -449,11 +469,11 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { for mut scope in callee_mir.visibility_scopes.iter().cloned() { if scope.parent_scope.is_none() { - scope.parent_scope = Some(callsite.location.scope); + scope.parent_scope = Some(callsite.source_info.scope); scope.span = callee_mir.span; } - scope.span = callsite.location.span; + scope.span = callsite.source_info.span; let idx = caller_mir.visibility_scopes.push(scope); scope_map.push(idx); @@ -464,8 +484,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if let Some(ref mut source_info) = local.source_info { source_info.scope = scope_map[source_info.scope]; - - source_info.span = callsite.location.span; + source_info.span = callsite.source_info.span; } let idx = caller_mir.local_decls.push(local); @@ -498,12 +517,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - let dest = if dest_needs_borrow(&destination.0) { + let dest = if dest_needs_borrow(&destination) { debug!("Creating temp for return destination"); let dest = Rvalue::Ref( self.tcx.mk_region(ty::ReErased), BorrowKind::Mut, - destination.0); + destination); let ty = dest.ty(caller_mir, self.tcx); @@ -513,18 +532,15 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let tmp = Lvalue::Local(tmp); let stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(tmp.clone(), dest) + source_info: callsite.source_info, + kind: StatementKind::Assign(tmp.clone(), dest), }; - caller_mir[callsite.bb] - .statements.push(stmt); - tmp.deref() + caller_mir[callsite.location.block].statements.push(stmt); + tmp } else { - destination.0 + destination }; - let return_block = destination.1; - let args : Vec<_> = if is_box_free { assert!(args.len() == 1); // box_free takes a Box, but is defined with a *mut T, inlining @@ -553,33 +569,24 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { promoted_map: promoted_map, _callsite: callsite, destination: dest, - return_block: return_block, + return_block: new_block_idx, cleanup_block: cleanup, in_cleanup_block: false }; - for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) { integrator.visit_basic_block_data(bb, &mut block); caller_mir.basic_blocks_mut().push(block); } - let terminator = Terminator { - source_info: callsite.location, + caller_mir[callsite.location.block].terminator = Some(Terminator { + source_info: callsite.source_info, kind: TerminatorKind::Goto { target: Block::new(bb_len) } - }; - - caller_mir[callsite.bb].terminator = Some(terminator); + }); true } - kind => { - caller_mir[callsite.bb].terminator = Some(Terminator { - source_info: terminator.source_info, - kind: kind - }); - false - } + _ => bug!() } } @@ -596,11 +603,11 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ref_tmp = Lvalue::Local(ref_tmp); let ref_stmt = Statement { - source_info: callsite.location, + source_info: callsite.source_info, kind: StatementKind::Assign(ref_tmp.clone(), arg) }; - caller_mir[callsite.bb] + caller_mir[callsite.location.block] .statements.push(ref_stmt); let pointee_ty = match ptr_ty.sty { @@ -617,11 +624,11 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let cast_tmp = Lvalue::Local(cast_tmp); let cast_stmt = Statement { - source_info: callsite.location, + source_info: callsite.source_info, kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr) }; - caller_mir[callsite.bb] + caller_mir[callsite.location.block] .statements.push(cast_stmt); Operand::Consume(cast_tmp) @@ -651,10 +658,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let arg_tmp = Lvalue::Local(arg_tmp); let stmt = Statement { - source_info: callsite.location, + source_info: callsite.source_info, kind: StatementKind::Assign(arg_tmp.clone(), arg) }; - caller_mir[callsite.bb].statements.push(stmt); + caller_mir[callsite.location.block].statements.push(stmt); Operand::Consume(arg_tmp) }).collect() } @@ -787,18 +794,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { *unwind = self.cleanup_block; } } - TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { - if let Some((_, ref mut tgt)) = *destination { - *tgt = self.update_target(*tgt); - } - if let Some(tgt) = *cleanup { - *cleanup = Some(self.update_target(tgt)); - } else if !self.in_cleanup_block { - // Unless this call is in a cleanup block, add an unwind edge to - // the orignal call's cleanup block - *cleanup = self.cleanup_block; - } - } TerminatorKind::Return => { *kind = TerminatorKind::Goto { target: self.return_block }; } @@ -819,13 +814,22 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { ) { self.super_statement(block, statement, location); - if let StatementKind::Assert { ref mut cleanup, .. } = statement.kind { - if let Some(tgt) = *cleanup { - *cleanup = Some(self.update_target(tgt)); - } else if !self.in_cleanup_block { - // Unless this assert is in a cleanup block, add an unwind edge to - // the orignal call's cleanup block - *cleanup = self.cleanup_block; + match statement.kind { + StatementKind::Assign(..) | + StatementKind::SetDiscriminant { .. } | + StatementKind::StorageLive(..) | + StatementKind::StorageDead(..) | + StatementKind::InlineAsm { .. } | + StatementKind::Nop => {}, + StatementKind::Assert { ref mut cleanup, .. } | + StatementKind::Call { ref mut cleanup, .. } => { + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this assert is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } } } } diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 91ef6c43022a9..5ef2c7968006f 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -31,7 +31,6 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::SwitchInt { .. } => { /* nothing to do */ }, - TerminatorKind::Call { cleanup: ref mut unwind, .. } | TerminatorKind::DropAndReplace { ref mut unwind, .. } | TerminatorKind::Drop { ref mut unwind, .. } => { unwind.take(); @@ -54,8 +53,9 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { StatementKind::Nop => { /* nothing to do */ }, - StatementKind::Assert { cleanup: ref mut unwind, .. } => { - unwind.take(); + StatementKind::Call { ref mut cleanup, .. } | + StatementKind::Assert { ref mut cleanup, .. } => { + cleanup.take(); } } self.super_statement(bb, statement, location); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 869750256d604..5ceca0c8de548 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -73,7 +73,7 @@ pub enum Candidate { /// Array of indices found in the third argument of /// a call to one of the simd_shuffleN intrinsics. - ShuffleIndices(Block) + ShuffleIndices(Location) } struct TempCollector<'tcx> { @@ -174,18 +174,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }) } - fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { - let last = self.promoted.basic_blocks().last().unwrap(); - let data = &mut self.promoted[last]; - data.statements.push(Statement { - source_info: SourceInfo { - span: span, - scope: ARGUMENT_VISIBILITY_SCOPE - }, - kind: StatementKind::Assign(Lvalue::Local(dest), rvalue) - }); - } - /// Copy the initialization of this temp to the /// promoted MIR, recursing through temps. fn promote_temp(&mut self, temp: Local) -> Local { @@ -215,72 +203,77 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // First, take the Rvalue or Call out of the source MIR, // or duplicate it, depending on keep_original. - if loc.statement_index < no_stmts { - let (mut rvalue, source_info) = { - let statement = &mut self.source[loc.block].statements[loc.statement_index]; - let rhs = match statement.kind { - StatementKind::Assign(_, ref mut rhs) => rhs, - _ => { - span_bug!(statement.source_info.span, "{:?} is not an assignment", - statement); - } - }; + #[derive(Debug)] + enum StmtKind { + Assign, + Call, + } - (if self.keep_original { - rhs.clone() - } else { - let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]); - mem::replace(rhs, unit) - }, statement.source_info) - }; + let stmt_kind = match self.source[loc.block].statements[loc.statement_index].kind { + StatementKind::Call { .. } => StmtKind::Call, + StatementKind::Assign(..) => StmtKind::Assign, + _ => { + let statement = &self.source[loc.block].statements[loc.statement_index]; + span_bug!(statement.source_info.span, "{:?} not promotable", statement.kind); + } + }; - self.visit_rvalue(&mut rvalue, loc); - self.assign(new_temp, rvalue, source_info.span); - } else { - let terminator = if self.keep_original { - self.source[loc.block].terminator().clone() - } else { - let terminator = self.source[loc.block].terminator_mut(); - let target = match terminator.kind { - TerminatorKind::Call { destination: Some((_, target)), .. } => target, - ref kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + let kind = match stmt_kind { + StmtKind::Assign => { + let mut rvalue = { + let statement = &mut self.source[loc.block].statements[loc.statement_index]; + let rhs = if let StatementKind::Assign(_, ref mut rhs) = statement.kind { + rhs + } else { + bug!() + }; + + if self.keep_original { + rhs.clone() + } else { + let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]); + mem::replace(rhs, unit) } }; - Terminator { - source_info: terminator.source_info, - kind: mem::replace(&mut terminator.kind, TerminatorKind::Goto { - target: target - }) - } - }; + self.visit_rvalue(&mut rvalue, loc); + StatementKind::Assign(Lvalue::Local(new_temp), rvalue) + } + StmtKind::Call => { + let kind = if self.keep_original { + self.source[loc.block].statements[loc.statement_index].kind.clone() + } else { + mem::replace(&mut self.source[loc.block].statements[loc.statement_index].kind, + StatementKind::Nop) + }; - match terminator.kind { - TerminatorKind::Call { mut func, mut args, .. } => { + if let StatementKind::Call { mut func, mut args, .. } = kind { self.visit_operand(&mut func, loc); for arg in &mut args { self.visit_operand(arg, loc); } - let last = self.promoted.basic_blocks().last().unwrap(); - let new_target = self.new_block(); - - *self.promoted[last].terminator_mut() = Terminator { - kind: TerminatorKind::Call { - func: func, - args: args, - cleanup: None, - destination: Some((Lvalue::Local(new_temp), new_target)) - }, - ..terminator - }; - } - ref kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + StatementKind::Call { + func: func, + args: args, + cleanup: None, + destination: Lvalue::Local(new_temp), + } + } else { + bug!() } - }; + }, }; + let last = self.promoted.basic_blocks().last().unwrap(); + let data = &mut self.promoted[last]; + data.statements.push(Statement { + source_info: SourceInfo { + span: self.source[loc.block].statements[loc.statement_index].source_info.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }, + kind: kind + }); + self.keep_original = old_keep_original; new_temp } @@ -304,12 +297,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { _ => bug!() } } - Candidate::ShuffleIndices(bb) => { - match self.source[bb].terminator_mut().kind { - TerminatorKind::Call { ref mut args, .. } => { - Rvalue::Use(mem::replace(&mut args[2], new_operand)) - } - _ => bug!() + Candidate::ShuffleIndices(Location { block: bb, statement_index: stmt_idx }) => { + let statement = &mut self.source[bb].statements[stmt_idx]; + if let StatementKind::Call { ref mut args, .. } = statement.kind { + Rvalue::Use(mem::replace(&mut args[2], new_operand)) + } else { + bug!() } } }; @@ -318,7 +311,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { statement_index: usize::MAX }); - self.assign(RETURN_POINTER, rvalue, span); + let last = self.promoted.basic_blocks().last().unwrap(); + self.promoted[last].statements.push(Statement { + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, + kind: StatementKind::Assign(Lvalue::Local(RETURN_POINTER), rvalue) + }); self.source.promoted.push(self.promoted); } } @@ -363,18 +363,15 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } (statement.source_info.span, dest.ty(mir, tcx).to_ty(tcx)) } - Candidate::ShuffleIndices(bb) => { - let terminator = mir[bb].terminator(); - let ty = match terminator.kind { - TerminatorKind::Call { ref args, .. } => { - args[2].ty(mir, tcx) - } - _ => { - span_bug!(terminator.source_info.span, - "expected simd_shuffleN call to promote"); - } + Candidate::ShuffleIndices(Location { block: bb, statement_index: stmt_idx }) => { + let statement = &mir[bb].statements[stmt_idx]; + let ty = if let StatementKind::Call { ref args, .. } = statement.kind { + args[2].ty(mir, tcx) + } else { + span_bug!(statement.source_info.span, + "expected simd_shuffleN call to promote"); }; - (terminator.source_info.span, ty) + (statement.source_info.span, ty) } }; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 73962fac89389..ff6dd3be3d606 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -376,16 +376,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let target = match mir[bb].terminator().kind { TerminatorKind::Goto { target } | // Drops are considered noops. - TerminatorKind::Drop { target, .. } | - TerminatorKind::Call { destination: Some((_, target)), .. } => { + TerminatorKind::Drop { target, .. } => { Some(target) } - // Non-terminating calls cannot produce any value. - TerminatorKind::Call { destination: None, .. } => { - return Qualif::empty(); - } - TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Resume | @@ -760,111 +754,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - fn visit_terminator_kind(&mut self, - bb: Block, - kind: &TerminatorKind<'tcx>, - location: Location) { - if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind { - self.visit_operand(func, location); - - let fn_ty = func.ty(self.mir, self.tcx); - let (is_shuffle, is_const_fn) = match fn_ty.sty { - ty::TyFnDef(def_id, _, f) => { - (f.abi() == Abi::PlatformIntrinsic && - self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"), - is_const_fn(self.tcx, def_id)) - } - _ => (false, false) - }; - - for (i, arg) in args.iter().enumerate() { - self.nest(|this| { - this.visit_operand(arg, location); - if is_shuffle && i == 2 && this.mode == Mode::Fn { - let candidate = Candidate::ShuffleIndices(bb); - if !this.qualif.intersects(Qualif::NEVER_PROMOTE) { - this.promotion_candidates.push(candidate); - } else { - span_err!(this.tcx.sess, this.span, E0526, - "shuffle indices are not constant"); - } - } - }); - } - - // Const fn calls. - if is_const_fn { - // We are in a const or static initializer, - if self.mode != Mode::Fn && - - // feature-gate is not enabled, - !self.tcx.sess.features.borrow().const_fn && - - // this doesn't come from a crate with the feature-gate enabled, - self.def_id.is_local() && - - // this doesn't come from a macro that has #[allow_internal_unstable] - !self.tcx.sess.codemap().span_allows_unstable(self.span) - { - let mut err = self.tcx.sess.struct_span_err(self.span, - "const fns are an unstable feature"); - help!(&mut err, - "in Nightly builds, add `#![feature(const_fn)]` \ - to the crate attributes to enable"); - err.emit(); - } - } else { - self.qualif = Qualif::NOT_CONST; - if self.mode != Mode::Fn { - // FIXME(#24111) Remove this check when const fn stabilizes - let (msg, note) = if let UnstableFeatures::Disallow = - self.tcx.sess.opts.unstable_features { - (format!("calls in {}s are limited to \ - struct and enum constructors", - self.mode), - Some("a limited form of compile-time function \ - evaluation is available on a nightly \ - compiler via `const fn`")) - } else { - (format!("calls in {}s are limited \ - to constant functions, \ - struct and enum constructors", - self.mode), - None) - }; - let mut err = struct_span_err!(self.tcx.sess, self.span, E0015, "{}", msg); - if let Some(note) = note { - err.span_note(self.span, note); - } - err.emit(); - } - } - - if let Some((ref dest, _)) = *destination { - // Avoid propagating irrelevant callee/argument qualifications. - if self.qualif.intersects(Qualif::CONST_ERROR) { - self.qualif = Qualif::NOT_CONST; - } else { - // Be conservative about the returned value of a const fn. - let tcx = self.tcx; - let ty = dest.ty(self.mir, tcx).to_ty(tcx); - self.qualif = Qualif::empty(); - self.add_type(ty); - - // Let `const fn` transitively have destructors, - // but they do get stopped in `const` or `static`. - if self.mode != Mode::ConstFn { - self.deny_drop(); - } - } - self.assign(dest, location); - } - } else { - // Qualify any operands inside other terminators. - self.super_terminator_kind(bb, kind, location); - } - } - fn visit_assign(&mut self, _: Block, dest: &Lvalue<'tcx>, @@ -909,6 +798,101 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { StatementKind::Assign(ref lvalue, ref rvalue) => { this.visit_assign(bb, lvalue, rvalue, location); } + StatementKind::Call { ref func, ref args, ref destination, .. } => { + this.visit_operand(func, location); + + let fn_ty = func.ty(this.mir, this.tcx); + let (is_shuffle, is_const_fn) = match fn_ty.sty { + ty::TyFnDef(def_id, _, f) => { + (f.abi() == Abi::PlatformIntrinsic && + this.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"), + is_const_fn(this.tcx, def_id)) + } + _ => (false, false) + }; + + for (i, arg) in args.iter().enumerate() { + this.nest(|this| { + this.visit_operand(arg, location); + if is_shuffle && i == 2 && this.mode == Mode::Fn { + let candidate = Candidate::ShuffleIndices(location); + if !this.qualif.intersects(Qualif::NEVER_PROMOTE) { + this.promotion_candidates.push(candidate); + } else { + span_err!(this.tcx.sess, this.span, E0526, + "shuffle indices are not constant"); + } + } + }); + } + + // Const fn calls. + if is_const_fn { + // We are in a const or static initializer, + if this.mode != Mode::Fn && + + // feature-gate is not enabled, + !this.tcx.sess.features.borrow().const_fn && + + // this doesn't come from a crate with the feature-gate enabled, + this.def_id.is_local() && + + // this doesn't come from a macro that has #[allow_internal_unstable] + !this.tcx.sess.codemap().span_allows_unstable(this.span) + { + let mut err = this.tcx.sess.struct_span_err(this.span, + "const fns are an unstable feature"); + help!(&mut err, + "in Nightly builds, add `#![feature(const_fn)]` \ + to the crate attributes to enable"); + err.emit(); + } + } else { + this.qualif = Qualif::NOT_CONST; + if this.mode != Mode::Fn { + // FIXME(#24111) Remove this check when const fn stabilizes + let (msg, note) = if let UnstableFeatures::Disallow = + this.tcx.sess.opts.unstable_features { + (format!("calls in {}s are limited to \ + struct and enum constructors", + this.mode), + Some("a limited form of compile-time function \ + evaluation is available on a nightly \ + compiler via `const fn`")) + } else { + (format!("calls in {}s are limited \ + to constant functions, \ + struct and enum constructors", + this.mode), + None) + }; + let mut err = struct_span_err!(this.tcx.sess, this.span, E0015, "{}", + msg); + if let Some(note) = note { + err.span_note(this.span, note); + } + err.emit(); + } + } + + // Avoid propagating irrelevant callee/argument qualifications. + if this.qualif.intersects(Qualif::CONST_ERROR) { + this.qualif = Qualif::NOT_CONST; + } else { + // Be conservative about the returned value of a const fn. + let tcx = this.tcx; + let ty = destination.ty(this.mir, tcx).to_ty(tcx); + this.qualif = Qualif::empty(); + this.add_type(ty); + + // Let `const fn` transitively have destructors, + // but they do get stopped in `const` or `static`. + if this.mode != Mode::ConstFn { + this.deny_drop(); + } + } + this.assign(destination, location); + } StatementKind::SetDiscriminant { .. } | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 35be1527ac750..23bac443703b1 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -366,6 +366,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let lv_ty = lv.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Err(terr) = self.sub_types(rv_ty, lv_ty) { + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + for stmt2 in &bb_data.statements { + if stmt2.source_info == stmt.source_info { + println!("for {:?} / {:#?}", bb, bb_data); + } + } + } span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } @@ -412,6 +419,26 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } + StatementKind::Call { ref func, ref args, ref destination, .. } => { + let func_ty = func.ty(mir, tcx); + debug!("check_stmt: call, func_ty={:?}", func_ty); + let sig = match func_ty.sty { + ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig, + _ => { + span_mirbug!(self, stmt, "call to non-function {:?}", func_ty); + return; + } + }; + let sig = tcx.erase_late_bound_regions(&sig); + let sig = self.normalize(&sig); + self.check_call_dest(mir, stmt, &sig, destination); + + if self.is_box_free(func) { + self.check_box_free_inputs(mir, stmt, &sig, args); + } else { + self.check_call_inputs(mir, stmt, &sig, args); + } + } StatementKind::InlineAsm { .. } | StatementKind::Nop => {} } @@ -457,68 +484,38 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } // FIXME: check the values } - TerminatorKind::Call { ref func, ref args, ref destination, .. } => { - let func_ty = func.ty(mir, tcx); - debug!("check_terminator: call, func_ty={:?}", func_ty); - let sig = match func_ty.sty { - ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig, - _ => { - span_mirbug!(self, term, "call to non-function {:?}", func_ty); - return; - } - }; - let sig = tcx.erase_late_bound_regions(&sig); - let sig = self.normalize(&sig); - self.check_call_dest(mir, term, &sig, destination); - - if self.is_box_free(func) { - self.check_box_free_inputs(mir, term, &sig, args); - } else { - self.check_call_inputs(mir, term, &sig, args); - } - } } } fn check_call_dest(&mut self, mir: &Mir<'tcx>, - term: &Terminator<'tcx>, + stmt: &Statement<'tcx>, sig: &ty::FnSig<'tcx>, - destination: &Option<(Lvalue<'tcx>, Block)>) { + destination: &Lvalue<'tcx>) { let tcx = self.tcx(); - match *destination { - Some((ref dest, _)) => { - let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(sig.output(), dest_ty) { - span_mirbug!(self, term, - "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, sig.output(), terr); - } - }, - None => { - // FIXME(canndrew): This is_never should probably be an is_uninhabited - if !sig.output().is_never() { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } - }, + let dest_ty = destination.ty(mir, tcx).to_ty(tcx); + if let Err(terr) = self.sub_types(sig.output(), dest_ty) { + span_mirbug!(self, stmt, + "call dest mismatch ({:?} <- {:?}): {:?}", + dest_ty, sig.output(), terr); } } fn check_call_inputs(&mut self, mir: &Mir<'tcx>, - term: &Terminator<'tcx>, + stmt: &Statement<'tcx>, sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>]) { debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) { - span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); + span_mirbug!(self, stmt, "call to {:?} with wrong # of args", sig); } for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) { - span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}", + span_mirbug!(self, stmt, "bad arg #{:?} ({:?} <- {:?}): {:?}", n, fn_arg, op_arg_ty, terr); } } @@ -539,7 +536,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_box_free_inputs(&mut self, mir: &Mir<'tcx>, - term: &Terminator<'tcx>, + stmt: &Statement<'tcx>, sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>]) { @@ -548,20 +545,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // box_free takes a Box as a pointer. Allow for that. if sig.inputs().len() != 1 { - span_mirbug!(self, term, "box_free should take 1 argument"); + span_mirbug!(self, stmt, "box_free should take 1 argument"); return; } let pointee_ty = match sig.inputs()[0].sty { ty::TyRawPtr(mt) => mt.ty, _ => { - span_mirbug!(self, term, "box_free should take a raw ptr"); + span_mirbug!(self, stmt, "box_free should take a raw ptr"); return; } }; if args.len() != 1 { - span_mirbug!(self, term, "box_free called with wrong # of args"); + span_mirbug!(self, stmt, "box_free called with wrong # of args"); return; } @@ -570,13 +567,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ty::TyRawPtr(mt) => mt.ty, ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), _ => { - span_mirbug!(self, term, "box_free called with bad arg ty"); + span_mirbug!(self, stmt, "box_free called with bad arg ty"); return; } }; if let Err(terr) = self.sub_types(arg_ty, pointee_ty) { - span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}", + span_mirbug!(self, stmt, "bad box_free arg ({:?} <- {:?}): {:?}", pointee_ty, arg_ty, terr); } } @@ -584,6 +581,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BlockData<'tcx>) { let is_cleanup = block.is_cleanup; + + for stmt in &block.statements { + match stmt.kind { + StatementKind::Call { cleanup, .. } => { + if let Some(cleanup) = cleanup { + if is_cleanup { + span_mirbug!(self, block, "cleanup on cleanup block") + } + self.assert_iscleanup(mir, block, cleanup, true); + } + } + _ => {} + } + } + self.last_span = block.terminator().source_info.span; match block.terminator().kind { TerminatorKind::Goto { target } => @@ -614,17 +626,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.assert_iscleanup(mir, block, unwind, true); } } - TerminatorKind::Call { ref destination, cleanup, .. } => { - if let &Some((_, target)) = destination { - self.assert_iscleanup(mir, block, target, is_cleanup); - } - if let Some(cleanup) = cleanup { - if is_cleanup { - span_mirbug!(self, block, "cleanup on cleanup block") - } - self.assert_iscleanup(mir, block, cleanup, true); - } - } } } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 3b3bf32d5abfa..c21cae263f811 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -522,15 +522,19 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> Lvalue::Local(ref_lvalue), Rvalue::Ref(re_erased, BorrowKind::Mut, self.lvalue.clone()) ) - }], - terminator: Some(Terminator { - kind: TerminatorKind::Call { + }, + Statement { + source_info: self.source_info, + kind: StatementKind::Call { func: Operand::function_handle(tcx, drop_fn.def_id, substs, self.source_info.span), args: vec![Operand::Consume(Lvalue::Local(ref_lvalue))], - destination: Some((unit_temp, succ)), + destination: unit_temp, cleanup: unwind, - }, + } + }], + terminator: Some(Terminator { + kind: TerminatorKind::Goto { target: succ }, source_info: self.source_info }), is_cleanup: self.is_cleanup, @@ -628,13 +632,23 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let call = TerminatorKind::Call { + let call = StatementKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), args: vec![Operand::Consume(self.lvalue.clone())], - destination: Some((unit_temp, target)), + destination: unit_temp, cleanup: None }; // FIXME(#6393) - let free_block = self.new_block(is_cleanup, call); + let free_block = self.elaborator.patch().new_block(BlockData { + statements: vec![Statement { + kind: call, + source_info: self.source_info, + }], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Goto { target: target }, + }), + is_cleanup: is_cleanup + }); let block_start = Location { block: free_block, statement_index: 0 }; self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index ef3e04581461d..c1e7b00a338a9 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -130,6 +130,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { StatementKind::StorageDead(..) => "StatementKind::StorageDead", StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm", StatementKind::Assert { .. } => "StatementKind::Assert", + StatementKind::Call { .. } => "StatementKind::Call", StatementKind::Nop => "StatementKind::Nop", }, &statement.kind); self.super_statement(block, statement, location); @@ -156,7 +157,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { TerminatorKind::Unreachable => "TerminatorKind::Unreachable", TerminatorKind::Drop { .. } => "TerminatorKind::Drop", TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace", - TerminatorKind::Call { .. } => "TerminatorKind::Call", }, kind); self.super_terminator_kind(block, kind, location); } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2fb05d11e1f1d..6fceb9508ecfd 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -545,14 +545,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { block: mir::Block, kind: &mir::TerminatorKind<'tcx>, location: Location) { - let tcx = self.scx.tcx(); match *kind { - mir::TerminatorKind::Call { ref func, .. } => { - let callee_ty = func.ty(self.mir, tcx); - let callee_ty = monomorphize::apply_param_substs( - self.scx, self.param_substs, &callee_ty); - visit_fn_use(self.scx, callee_ty, true, &mut self.output); - } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { let ty = location.ty(self.mir, self.scx.tcx()) @@ -571,6 +564,31 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_terminator_kind(block, kind, location); } + + fn visit_statement( + &mut self, + _block: mir::Block, + statement: &mir::Statement<'tcx>, + _location: Location, + ) { + let tcx = self.scx.tcx(); + match statement.kind { + mir::StatementKind::Call { ref func, .. } => { + let callee_ty = func.ty(self.mir, tcx); + let callee_ty = monomorphize::apply_param_substs( + self.scx, self.param_substs, &callee_ty); + visit_fn_use(self.scx, callee_ty, true, &mut self.output); + } + mir::StatementKind::Assign(..) | + mir::StatementKind::SetDiscriminant { .. } | + mir::StatementKind::StorageLive(..) | + mir::StatementKind::StorageDead(..) | + mir::StatementKind::InlineAsm { .. } | + mir::StatementKind::Assert { .. } | + mir::StatementKind::Nop => {} + } + } + } fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 47b10bc397538..169d8fd6cadc5 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -103,12 +103,14 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { self.visit_rvalue(rvalue, location); } - fn visit_terminator_kind(&mut self, - block: mir::Block, - kind: &mir::TerminatorKind<'tcx>, - location: Location) { - match *kind { - mir::TerminatorKind::Call { + fn visit_statement( + &mut self, + block: mir::Block, + statement: &mir::Statement<'tcx>, + location: Location + ) { + match statement.kind { + mir::StatementKind::Call { func: mir::Operand::Constant(mir::Constant { literal: Literal::Value { value: ConstVal::Function(def_id, _), .. @@ -126,7 +128,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { _ => {} } - self.super_terminator_kind(block, kind, location); + self.super_statement(block, statement, location); } fn visit_lvalue(&mut self, @@ -212,6 +214,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { /* nothing to do */ }, + StatementKind::Call { cleanup: unwind, .. } | StatementKind::Assert { cleanup: unwind, .. } => { if let Some(unwind) = unwind { debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet", @@ -230,7 +233,6 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { /* nothing to do */ } - TerminatorKind::Call { cleanup: unwind, .. } | TerminatorKind::DropAndReplace { unwind, .. } | TerminatorKind::Drop { unwind, .. } => { if let Some(unwind) = unwind { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 1234fc677d435..afd64ccf4a656 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -202,16 +202,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bug!("undesugared DropAndReplace in trans: {:?}", data); } - mir::TerminatorKind::Call { ref func, ref args, ref destination, ref cleanup } => { - bcx = self.trans_call( - bcx, func, args, destination, cleanup, cleanup_bundle, terminator.source_info, - ); - if let Some((_, target)) = *destination { - funclet_br(self, bcx, target); - } else { - bcx.unreachable(); - } - } } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index d47ac91dc7e03..9dc729d4b0245 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -310,6 +310,29 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } + mir::StatementKind::Call { ref func, ref args, ref destination, .. } => { + let fn_ty = func.ty(self.mir, tcx); + let fn_ty = self.monomorphize(&fn_ty); + let (def_id, substs) = match fn_ty.sty { + ty::TyFnDef(def_id, substs, _) => (def_id, substs), + _ => span_bug!(span, "calling {:?} (of type {}) in constant", + func, fn_ty) + }; + + let mut const_args = IndexVec::with_capacity(args.len()); + for arg in args { + match self.const_operand(arg, span) { + Ok(arg) => { const_args.push(arg); }, + Err(err) => if failure.is_ok() { failure = Err(err); } + } + } + + match MirConstContext::trans_def(self.ccx, def_id, substs, const_args) { + Ok(value) => self.store(destination, value, span), + Err(err) => if failure.is_ok() { failure = Err(err); } + } + } + mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | mir::StatementKind::Nop => {} @@ -332,32 +355,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { })); } - mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => { - let fn_ty = func.ty(self.mir, tcx); - let fn_ty = self.monomorphize(&fn_ty); - let (def_id, substs) = match fn_ty.sty { - ty::TyFnDef(def_id, substs, _) => (def_id, substs), - _ => span_bug!(span, "calling {:?} (of type {}) in constant", - func, fn_ty) - }; - - let mut const_args = IndexVec::with_capacity(args.len()); - for arg in args { - match self.const_operand(arg, span) { - Ok(arg) => { const_args.push(arg); }, - Err(err) => if failure.is_ok() { failure = Err(err); } - } - } - if let Some((ref dest, target)) = *destination { - match MirConstContext::trans_def(self.ccx, def_id, substs, const_args) { - Ok(value) => self.store(dest, value, span), - Err(err) => if failure.is_ok() { failure = Err(err); } - } - target - } else { - span_bug!(span, "diverging {:?} in constant", terminator.kind); - } - } _ => span_bug!(span, "{:?} in constant", terminator.kind) }; } diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 3f32e77b7ef8e..921e87c4bffa9 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -112,6 +112,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx, cond, expected, msg, cleanup, cleanup_bundle, statement.source_info ) } + mir::StatementKind::Call { ref func, ref args, ref destination, ref cleanup } => { + self.trans_call( + bcx, func, args, destination, cleanup, cleanup_bundle, statement.source_info, + ) + } mir::StatementKind::Nop => bcx, } } @@ -337,7 +342,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mut bcx: Builder<'a, 'tcx>, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], - destination: &Option<(mir::Lvalue<'tcx>, mir::Block)>, + destination: &mir::Lvalue<'tcx>, cleanup: &Option, cleanup_bundle: Option<&OperandBundleDef>, source_info: mir::SourceInfo, @@ -379,8 +384,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } if intrinsic == Some("transmute") { - let &(ref dest, _) = destination.as_ref().unwrap(); - self.trans_transmute(&bcx, &args[0], dest); + self.trans_transmute(&bcx, &args[0], destination); return bcx; } @@ -406,13 +410,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let mut llargs = Vec::with_capacity(arg_count); // Prepare the return value destination - let ret_dest = if let Some((ref dest, _)) = *destination { - let is_intrinsic = intrinsic.is_some(); - self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, - is_intrinsic) - } else { - ReturnDest::Nothing - }; + let ret_dest = self.make_return_dest(&bcx, destination, &fn_ty.ret, &mut llargs, + intrinsic.is_some()); // Split the rust-call tupled arguments off. let (first_args, untuple) = if abi == Abi::RustCall && !args.is_empty() {