Refactor unwind from Option to a new enum
This commit is contained in:
@@ -515,14 +515,14 @@ pub struct CopyNonOverlapping<'tcx> {
|
||||
///
|
||||
/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
|
||||
/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
|
||||
/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
|
||||
/// once the current function is reached, execution continues at the given basic block, if any. If
|
||||
/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
|
||||
/// equivalent to the execution of a `Resume` terminator.
|
||||
/// terminators have a `unwind: UnwindAction` field on them. If stack unwinding occurs, then
|
||||
/// once the current function is reached, an action will be taken based on the `unwind` field.
|
||||
/// If the action is `Cleanup`, then the execution continues at the given basic block. If the
|
||||
/// action is `Continue` then no cleanup is performed, and the stack continues unwinding.
|
||||
///
|
||||
/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
|
||||
/// basic blocks have a couple restrictions:
|
||||
/// 1. All `cleanup` fields in them must be `None`.
|
||||
/// The basic block pointed to by a `Cleanup` unwind action must have its `cleanup` flag set.
|
||||
/// `cleanup` basic blocks have a couple restrictions:
|
||||
/// 1. All `unwind` fields in them must be `UnwindAction::Continue`.
|
||||
/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
|
||||
/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
|
||||
/// must also be `cleanup`. This is a part of the type system and checked statically, so it is
|
||||
@@ -604,7 +604,7 @@ pub enum TerminatorKind<'tcx> {
|
||||
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
|
||||
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
|
||||
/// > consider indirect assignments.
|
||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
|
||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
|
||||
|
||||
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
|
||||
/// the referred to function. The operand types must match the argument types of the function.
|
||||
@@ -628,8 +628,8 @@ pub enum TerminatorKind<'tcx> {
|
||||
destination: Place<'tcx>,
|
||||
/// Where to go after this call returns. If none, the call necessarily diverges.
|
||||
target: Option<BasicBlock>,
|
||||
/// Cleanups to be done if the call unwinds.
|
||||
cleanup: Option<BasicBlock>,
|
||||
/// Action to be taken if the call unwinds.
|
||||
unwind: UnwindAction,
|
||||
/// `true` if this is from a call in HIR rather than from an overloaded
|
||||
/// operator. True for overloaded function call.
|
||||
from_hir_call: bool,
|
||||
@@ -654,7 +654,7 @@ pub enum TerminatorKind<'tcx> {
|
||||
expected: bool,
|
||||
msg: AssertMessage<'tcx>,
|
||||
target: BasicBlock,
|
||||
cleanup: Option<BasicBlock>,
|
||||
unwind: UnwindAction,
|
||||
},
|
||||
|
||||
/// Marks a suspend point.
|
||||
@@ -720,9 +720,10 @@ pub enum TerminatorKind<'tcx> {
|
||||
/// in practice, but in order to avoid fragility we want to always
|
||||
/// consider it in borrowck. We don't want to accept programs which
|
||||
/// pass borrowck only when `panic=abort` or some assertions are disabled
|
||||
/// due to release vs. debug mode builds. This needs to be an `Option` because
|
||||
/// due to release vs. debug mode builds.
|
||||
/// This field does not necessary have to be `UnwindAction::Cleanup` because
|
||||
/// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
|
||||
unwind: Option<BasicBlock>,
|
||||
unwind: UnwindAction,
|
||||
},
|
||||
|
||||
/// Block ends with an inline assembly block. This is a terminator since
|
||||
@@ -745,12 +746,22 @@ pub enum TerminatorKind<'tcx> {
|
||||
/// diverging (InlineAsmOptions::NORETURN).
|
||||
destination: Option<BasicBlock>,
|
||||
|
||||
/// Cleanup to be done if the inline assembly unwinds. This is present
|
||||
/// Action to be taken if the inline assembly unwinds. This is present
|
||||
/// if and only if InlineAsmOptions::MAY_UNWIND is set.
|
||||
cleanup: Option<BasicBlock>,
|
||||
unwind: UnwindAction,
|
||||
},
|
||||
}
|
||||
|
||||
/// Action to be taken when a stack unwind happens.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum UnwindAction {
|
||||
// No action is to be taken. Continue unwinding.
|
||||
Continue,
|
||||
// Cleanups to be done.
|
||||
Cleanup(BasicBlock),
|
||||
}
|
||||
|
||||
/// Information about an assertion failure.
|
||||
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
|
||||
pub enum AssertKind<O> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind};
|
||||
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction};
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
pub use rustc_ast::Mutability;
|
||||
use rustc_macros::HashStable;
|
||||
@@ -118,11 +118,11 @@ impl<'tcx> Terminator<'tcx> {
|
||||
self.kind.successors_mut()
|
||||
}
|
||||
|
||||
pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
|
||||
pub fn unwind(&self) -> Option<&UnwindAction> {
|
||||
self.kind.unwind()
|
||||
}
|
||||
|
||||
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
|
||||
pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
|
||||
self.kind.unwind_mut()
|
||||
}
|
||||
}
|
||||
@@ -135,34 +135,34 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
pub fn successors(&self) -> Successors<'_> {
|
||||
use self::TerminatorKind::*;
|
||||
match *self {
|
||||
Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. }
|
||||
| Yield { resume: t, drop: Some(ref u), .. }
|
||||
| Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
||||
| Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
||||
| FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) }
|
||||
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => {
|
||||
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
||||
}
|
||||
Goto { target: t }
|
||||
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||
| Call { target: Some(t), unwind: _, .. }
|
||||
| Yield { resume: t, drop: None, .. }
|
||||
| Drop { target: t, unwind: _, .. }
|
||||
| Assert { target: t, unwind: _, .. }
|
||||
| FalseUnwind { real_target: t, unwind: _ }
|
||||
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||
| InlineAsm { destination: Some(t), unwind: _, .. } => {
|
||||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
||||
}
|
||||
Resume
|
||||
| Abort
|
||||
| GeneratorDrop
|
||||
| Return
|
||||
| Unreachable
|
||||
| Call { target: None, cleanup: None, .. }
|
||||
| InlineAsm { destination: None, cleanup: None, .. } => {
|
||||
| Call { target: None, unwind: _, .. }
|
||||
| InlineAsm { destination: None, unwind: _, .. } => {
|
||||
None.into_iter().chain((&[]).into_iter().copied())
|
||||
}
|
||||
Goto { target: t }
|
||||
| Call { target: None, cleanup: Some(t), .. }
|
||||
| Call { target: Some(t), cleanup: None, .. }
|
||||
| Yield { resume: t, drop: None, .. }
|
||||
| Drop { target: t, unwind: None, .. }
|
||||
| Assert { target: t, cleanup: None, .. }
|
||||
| FalseUnwind { real_target: t, unwind: None }
|
||||
| InlineAsm { destination: Some(t), cleanup: None, .. }
|
||||
| InlineAsm { destination: None, cleanup: Some(t), .. } => {
|
||||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
||||
}
|
||||
Call { target: Some(t), cleanup: Some(ref u), .. }
|
||||
| Yield { resume: t, drop: Some(ref u), .. }
|
||||
| Drop { target: t, unwind: Some(ref u), .. }
|
||||
| Assert { target: t, cleanup: Some(ref u), .. }
|
||||
| FalseUnwind { real_target: t, unwind: Some(ref u) }
|
||||
| InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => {
|
||||
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
||||
}
|
||||
SwitchInt { ref targets, .. } => {
|
||||
None.into_iter().chain(targets.targets.iter().copied())
|
||||
}
|
||||
@@ -175,32 +175,34 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
|
||||
use self::TerminatorKind::*;
|
||||
match *self {
|
||||
Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
|
||||
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) }
|
||||
| InlineAsm {
|
||||
destination: Some(ref mut t),
|
||||
unwind: UnwindAction::Cleanup(ref mut u),
|
||||
..
|
||||
} => Some(t).into_iter().chain(slice::from_mut(u)),
|
||||
Goto { target: ref mut t }
|
||||
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
||||
| Call { target: Some(ref mut t), unwind: _, .. }
|
||||
| Yield { resume: ref mut t, drop: None, .. }
|
||||
| Drop { target: ref mut t, unwind: _, .. }
|
||||
| Assert { target: ref mut t, unwind: _, .. }
|
||||
| FalseUnwind { real_target: ref mut t, unwind: _ }
|
||||
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
||||
| InlineAsm { destination: Some(ref mut t), unwind: _, .. } => {
|
||||
Some(t).into_iter().chain(&mut [])
|
||||
}
|
||||
Resume
|
||||
| Abort
|
||||
| GeneratorDrop
|
||||
| Return
|
||||
| Unreachable
|
||||
| Call { target: None, cleanup: None, .. }
|
||||
| InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
|
||||
Goto { target: ref mut t }
|
||||
| Call { target: None, cleanup: Some(ref mut t), .. }
|
||||
| Call { target: Some(ref mut t), cleanup: None, .. }
|
||||
| Yield { resume: ref mut t, drop: None, .. }
|
||||
| Drop { target: ref mut t, unwind: None, .. }
|
||||
| Assert { target: ref mut t, cleanup: None, .. }
|
||||
| FalseUnwind { real_target: ref mut t, unwind: None }
|
||||
| InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
|
||||
| InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
|
||||
Some(t).into_iter().chain(&mut [])
|
||||
}
|
||||
Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
|
||||
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
|
||||
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
|
||||
| Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
|
||||
| FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
|
||||
| InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
|
||||
Some(t).into_iter().chain(slice::from_mut(u))
|
||||
}
|
||||
| Call { target: None, unwind: _, .. }
|
||||
| InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []),
|
||||
SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
|
||||
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||
Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
|
||||
@@ -208,7 +210,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
|
||||
pub fn unwind(&self) -> Option<&UnwindAction> {
|
||||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
@@ -219,15 +221,15 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::FalseEdge { .. } => None,
|
||||
TerminatorKind::Call { cleanup: ref unwind, .. }
|
||||
| TerminatorKind::Assert { cleanup: ref unwind, .. }
|
||||
TerminatorKind::Call { ref unwind, .. }
|
||||
| TerminatorKind::Assert { ref unwind, .. }
|
||||
| TerminatorKind::Drop { ref unwind, .. }
|
||||
| TerminatorKind::FalseUnwind { ref unwind, .. }
|
||||
| TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
|
||||
| TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
|
||||
pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
|
||||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
@@ -238,11 +240,11 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::FalseEdge { .. } => None,
|
||||
TerminatorKind::Call { cleanup: ref mut unwind, .. }
|
||||
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
|
||||
TerminatorKind::Call { ref mut unwind, .. }
|
||||
| TerminatorKind::Assert { ref mut unwind, .. }
|
||||
| TerminatorKind::Drop { ref mut unwind, .. }
|
||||
| TerminatorKind::FalseUnwind { ref mut unwind, .. }
|
||||
| TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
|
||||
| TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,31 +388,33 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
.map(|&u| Cow::Owned(u.to_string()))
|
||||
.chain(iter::once("otherwise".into()))
|
||||
.collect(),
|
||||
Call { target: Some(_), cleanup: Some(_), .. } => {
|
||||
Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
|
||||
vec!["return".into(), "unwind".into()]
|
||||
}
|
||||
Call { target: Some(_), cleanup: None, .. } => vec!["return".into()],
|
||||
Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()],
|
||||
Call { target: None, cleanup: None, .. } => vec![],
|
||||
Call { target: Some(_), unwind: UnwindAction::Continue, .. } => vec!["return".into()],
|
||||
Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()],
|
||||
Call { target: None, unwind: UnwindAction::Continue, .. } => vec![],
|
||||
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
|
||||
Yield { drop: None, .. } => vec!["resume".into()],
|
||||
Drop { unwind: None, .. } => {
|
||||
vec!["return".into()]
|
||||
}
|
||||
Drop { unwind: Some(_), .. } => {
|
||||
vec!["return".into(), "unwind".into()]
|
||||
}
|
||||
Assert { cleanup: None, .. } => vec!["".into()],
|
||||
Drop { unwind: UnwindAction::Continue, .. } => vec!["return".into()],
|
||||
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
|
||||
Assert { unwind: UnwindAction::Continue, .. } => vec!["".into()],
|
||||
Assert { .. } => vec!["success".into(), "unwind".into()],
|
||||
FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
|
||||
FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
|
||||
FalseUnwind { unwind: None, .. } => vec!["real".into()],
|
||||
InlineAsm { destination: Some(_), cleanup: Some(_), .. } => {
|
||||
FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => {
|
||||
vec!["real".into(), "cleanup".into()]
|
||||
}
|
||||
FalseUnwind { unwind: UnwindAction::Continue, .. } => vec!["real".into()],
|
||||
InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
|
||||
vec!["return".into(), "unwind".into()]
|
||||
}
|
||||
InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
|
||||
InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
|
||||
InlineAsm { destination: None, cleanup: None, .. } => vec![],
|
||||
InlineAsm { destination: Some(_), unwind: UnwindAction::Continue, .. } => {
|
||||
vec!["return".into()]
|
||||
}
|
||||
InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => {
|
||||
vec!["unwind".into()]
|
||||
}
|
||||
InlineAsm { destination: None, unwind: UnwindAction::Continue, .. } => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ macro_rules! make_mir_visitor {
|
||||
args,
|
||||
destination,
|
||||
target: _,
|
||||
cleanup: _,
|
||||
unwind: _,
|
||||
from_hir_call: _,
|
||||
fn_span: _
|
||||
} => {
|
||||
@@ -529,7 +529,7 @@ macro_rules! make_mir_visitor {
|
||||
expected: _,
|
||||
msg,
|
||||
target: _,
|
||||
cleanup: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
self.visit_operand(cond, location);
|
||||
self.visit_assert_message(msg, location);
|
||||
@@ -555,7 +555,7 @@ macro_rules! make_mir_visitor {
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _,
|
||||
cleanup: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
for op in operands {
|
||||
match op {
|
||||
|
||||
Reference in New Issue
Block a user