diff options
Diffstat (limited to 'compiler/rustc_middle/src/mir/terminator.rs')
-rw-r--r-- | compiler/rustc_middle/src/mir/terminator.rs | 132 |
1 files changed, 119 insertions, 13 deletions
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 1b9c1438f..1f878d23b 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -10,6 +10,7 @@ use std::iter; use std::slice; pub use super::query::*; +use super::*; #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { @@ -280,7 +281,7 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { match (successor_count, unwind) { (0, None) => Ok(()), - (0, Some(unwind)) => write!(fmt, " -> {}", unwind), + (0, Some(unwind)) => write!(fmt, " -> {unwind}"), (1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()), _ => { write!(fmt, " -> [")?; @@ -307,22 +308,22 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match self { Goto { .. } => write!(fmt, "goto"), - SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr), + SwitchInt { discr, .. } => write!(fmt, "switchInt({discr:?})"), Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), Terminate => write!(fmt, "abort"), - Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), + Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"), Unreachable => write!(fmt, "unreachable"), - Drop { place, .. } => write!(fmt, "drop({:?})", place), + Drop { place, .. } => write!(fmt, "drop({place:?})"), Call { func, args, destination, .. } => { - write!(fmt, "{:?} = ", destination)?; - write!(fmt, "{:?}(", func)?; + write!(fmt, "{destination:?} = ")?; + write!(fmt, "{func:?}(")?; for (index, arg) in args.iter().enumerate() { if index > 0 { write!(fmt, ", ")?; } - write!(fmt, "{:?}", arg)?; + write!(fmt, "{arg:?}")?; } write!(fmt, ")") } @@ -331,7 +332,7 @@ impl<'tcx> TerminatorKind<'tcx> { if !expected { write!(fmt, "!")?; } - write!(fmt, "{:?}, ", cond)?; + write!(fmt, "{cond:?}, ")?; msg.fmt_assert_args(fmt)?; write!(fmt, ")") } @@ -344,7 +345,7 @@ impl<'tcx> TerminatorKind<'tcx> { let print_late = |&late| if late { "late" } else { "" }; match op { InlineAsmOperand::In { reg, value } => { - write!(fmt, "in({}) {:?}", reg, value)?; + write!(fmt, "in({reg}) {value:?}")?; } InlineAsmOperand::Out { reg, late, place: Some(place) } => { write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?; @@ -371,17 +372,17 @@ impl<'tcx> TerminatorKind<'tcx> { write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?; } InlineAsmOperand::Const { value } => { - write!(fmt, "const {:?}", value)?; + write!(fmt, "const {value:?}")?; } InlineAsmOperand::SymFn { value } => { - write!(fmt, "sym_fn {:?}", value)?; + write!(fmt, "sym_fn {value:?}")?; } InlineAsmOperand::SymStatic { def_id } => { - write!(fmt, "sym_static {:?}", def_id)?; + write!(fmt, "sym_static {def_id:?}")?; } } } - write!(fmt, ", options({:?}))", options) + write!(fmt, ", options({options:?}))") } } } @@ -430,3 +431,108 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + +#[derive(Copy, Clone, Debug)] +pub enum TerminatorEdges<'mir, 'tcx> { + /// For terminators that have no successor, like `return`. + None, + /// For terminators that a single successor, like `goto`, and `assert` without cleanup block. + Single(BasicBlock), + /// For terminators that two successors, `assert` with cleanup block and `falseEdge`. + Double(BasicBlock, BasicBlock), + /// Special action for `Yield`, `Call` and `InlineAsm` terminators. + AssignOnReturn { + return_: Option<BasicBlock>, + unwind: UnwindAction, + place: CallReturnPlaces<'mir, 'tcx>, + }, + /// Special edge for `SwitchInt`. + SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> }, +} + +/// List of places that are written to after a successful (non-unwind) return +/// from a `Call`, `Yield` or `InlineAsm`. +#[derive(Copy, Clone, Debug)] +pub enum CallReturnPlaces<'a, 'tcx> { + Call(Place<'tcx>), + Yield(Place<'tcx>), + InlineAsm(&'a [InlineAsmOperand<'tcx>]), +} + +impl<'tcx> CallReturnPlaces<'_, 'tcx> { + pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) { + match *self { + Self::Call(place) | Self::Yield(place) => f(place), + Self::InlineAsm(operands) => { + for op in operands { + match *op { + InlineAsmOperand::Out { place: Some(place), .. } + | InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place), + _ => {} + } + } + } + } + } +} + +impl<'tcx> Terminator<'tcx> { + pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> { + self.kind.edges() + } +} + +impl<'tcx> TerminatorKind<'tcx> { + pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> { + use TerminatorKind::*; + match *self { + Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdges::None, + + Goto { target } => TerminatorEdges::Single(target), + + Assert { target, unwind, expected: _, msg: _, cond: _ } + | Drop { target, unwind, place: _, replace: _ } + | FalseUnwind { real_target: target, unwind } => match unwind { + UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind), + UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => { + TerminatorEdges::Single(target) + } + }, + + FalseEdge { real_target, imaginary_target } => { + TerminatorEdges::Double(real_target, imaginary_target) + } + + Yield { resume: target, drop, resume_arg, value: _ } => { + TerminatorEdges::AssignOnReturn { + return_: Some(target), + unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup), + place: CallReturnPlaces::Yield(resume_arg), + } + } + + Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => { + TerminatorEdges::AssignOnReturn { + return_: target, + unwind, + place: CallReturnPlaces::Call(destination), + } + } + + InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination, + unwind, + } => TerminatorEdges::AssignOnReturn { + return_: destination, + unwind, + place: CallReturnPlaces::InlineAsm(operands), + }, + + SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr }, + } + } +} |