summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/mir/terminator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/mir/terminator.rs')
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs132
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 },
+ }
+ }
+}