Enum TerminatorKind
pub enum TerminatorKind<'db> {
Show 14 variants
Goto {
target: Idx<BasicBlock<'db>>,
},
SwitchInt {
discr: Operand<'db>,
targets: SwitchTargets<'db>,
},
UnwindResume,
Abort,
Return,
Unreachable,
Drop {
place: Place<'db>,
target: Idx<BasicBlock<'db>>,
unwind: Option<Idx<BasicBlock<'db>>>,
},
DropAndReplace {
place: Place<'db>,
value: Operand<'db>,
target: Idx<BasicBlock<'db>>,
unwind: Option<Idx<BasicBlock<'db>>>,
},
Call {
func: Operand<'db>,
args: Box<[Operand<'db>]>,
destination: Place<'db>,
target: Option<Idx<BasicBlock<'db>>>,
cleanup: Option<Idx<BasicBlock<'db>>>,
from_hir_call: bool,
},
Assert {
cond: Operand<'db>,
expected: bool,
target: Idx<BasicBlock<'db>>,
cleanup: Option<Idx<BasicBlock<'db>>>,
},
Yield {
value: Operand<'db>,
resume: Idx<BasicBlock<'db>>,
resume_arg: Place<'db>,
drop: Option<Idx<BasicBlock<'db>>>,
},
CoroutineDrop,
FalseEdge {
real_target: Idx<BasicBlock<'db>>,
imaginary_target: Idx<BasicBlock<'db>>,
},
FalseUnwind {
real_target: Idx<BasicBlock<'db>>,
unwind: Option<Idx<BasicBlock<'db>>>,
},
}Variants§
Goto
Block has one successor; we continue execution there.
Fields
target: Idx<BasicBlock<'db>>SwitchInt
Switches based on the computed value.
First, evaluates the discr operand. The type of the operand must be a signed or unsigned
integer, char, or bool, and must match the given type. Then, if the list of switch targets
contains the computed value, continues execution at the associated basic block. Otherwise,
continues execution at the “otherwise” basic block.
Target values may not appear more than once.
UnwindResume
Indicates that the landing pad is finished and that the process should continue unwinding.
Like a return, this marks the end of this invocation of the function.
Only permitted in cleanup blocks. Resume is not permitted with -C unwind=abort after
deaggregation runs.
Abort
Indicates that the landing pad is finished and that the process should abort.
Used to prevent unwinding for foreign items or with -C unwind=abort. Only permitted in
cleanup blocks.
Return
Returns from the function.
Like function calls, the exact semantics of returns in Rust are unclear. Returning very
likely at least assigns the value currently in the return place (_0) to the place
specified in the associated Call terminator in the calling function, as if assigned via
dest = move _0. It might additionally do other things, like have side-effects in the
aliasing model.
If the body is a coroutine body, this has slightly different semantics; it instead causes a
CoroutineState::Returned(_0) to be created (as if by an Aggregate rvalue) and assigned
to the return place.
Unreachable
Indicates a terminator that can never be reached.
Executing this terminator is UB.
Drop
The behavior of this statement differs significantly before and after drop elaboration.
After drop elaboration, Drop executes the drop glue for the specified place, after which
it continues execution/unwinds at the given basic blocks. It is possible that executing drop
glue is special - this would be part of Rust’s memory model. (FIXME: due we have an
issue tracking if drop glue has any interesting semantics in addition to those of a function
call?)
Drop before drop elaboration is a conditional execution of the drop glue. Specifically, the
Drop will be executed if…
Needs clarification: End of that sentence. This in effect should document the exact behavior of drop elaboration. The following sounds vaguely right, but I’m not quite sure:
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.
DropAndReplace
Drops the place and assigns a new value to it.
This first performs the exact same operation as the pre drop-elaboration Drop terminator;
it then additionally assigns the value to the place as if by an assignment statement.
This assignment occurs both in the unwind and the regular code paths. The semantics are best
explained by the elaboration:
BB0 {
DropAndReplace(P <- V, goto BB1, unwind BB2)
}becomes
BB0 {
Drop(P, goto BB1, unwind BB2)
}
BB1 {
// P is now uninitialized
P <- V
}
BB2 {
// P is now uninitialized -- its dtor panicked
P <- V
}Disallowed after drop elaboration.
Call
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.
The return place type must match the return type. The type of the func operand must be
callable, meaning either a function pointer, a function type, or a closure type.
Needs clarification: The exact semantics of this. Current backends rely on move
operands not aliasing the return place. It is unclear how this is justified in MIR, see
#71117.
Fields
args: Box<[Operand<'db>]>Arguments the function is called with. These are owned by the callee, which is free to modify them. This allows the memory occupied by “by-value” arguments to be reused across function calls without duplicating the contents.
target: Option<Idx<BasicBlock<'db>>>Where to go after this call returns. If none, the call necessarily diverges.
cleanup: Option<Idx<BasicBlock<'db>>>Cleanups to be done if the call unwinds.
Assert
Evaluates the operand, which must have type bool. If it is not equal to expected,
initiates a panic. Initiating a panic corresponds to a Call terminator with some
unspecified constant as the function to call, all the operands stored in the AssertMessage
as parameters, and None for the destination. Keep in mind that the cleanup path is not
necessarily executed even in the case of a panic, for example in -C panic=abort. If the
assertion does not fail, execution continues at the specified basic block.
Yield
Marks a suspend point.
Like Return terminators in coroutine bodies, this computes value and then a
CoroutineState::Yielded(value) as if by Aggregate rvalue. That value is then assigned to
the return place of the function calling this one, and execution continues in the calling
function. When next invoked with the same first argument, execution of this function
continues at the resume basic block, with the second argument written to the resume_arg
place. If the coroutine is dropped before then, the drop basic block is invoked.
Not permitted in bodies that are not coroutine bodies, or after coroutine lowering.
Needs clarification: What about the evaluation order of the resume_arg and value?
Fields
resume: Idx<BasicBlock<'db>>Where to resume to.
drop: Option<Idx<BasicBlock<'db>>>Cleanup to be done if the coroutine is dropped at this suspend point.
CoroutineDrop
Indicates the end of dropping a coroutine.
Semantically just a return (from the coroutines drop glue). Only permitted in the same situations
as yield.
Needs clarification: Is that even correct? The coroutine drop code is always confusing to me, because it’s not even really in the current body.
Needs clarification: Are there type system constraints on these terminators? Should
there be a “block type” like cleanup blocks for them?
FalseEdge
A block where control flow only ever takes one real path, but borrowck needs to be more conservative.
At runtime this is semantically just a goto.
Disallowed after drop elaboration.
Fields
real_target: Idx<BasicBlock<'db>>The target normal control flow will take.
imaginary_target: Idx<BasicBlock<'db>>A block control flow could conceptually jump to, but won’t in practice.
FalseUnwind
A terminator for blocks that only take one path in reality, but where we reserve the right to unwind in borrowck, even if it won’t happen in practice. This can arise in infinite loops with no function calls for example.
At runtime this is semantically just a goto.
Disallowed after drop elaboration.
Fields
real_target: Idx<BasicBlock<'db>>The target normal control flow will take.
unwind: Option<Idx<BasicBlock<'db>>>The imaginary cleanup block link. This particular path will never be taken
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
of the remove_noop_landing_pads and abort_unwinding_calls passes.
Trait Implementations§
§impl<'db> Clone for TerminatorKind<'db>
impl<'db> Clone for TerminatorKind<'db>
§fn clone(&self) -> TerminatorKind<'db>
fn clone(&self) -> TerminatorKind<'db>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more§impl<'db> Debug for TerminatorKind<'db>
impl<'db> Debug for TerminatorKind<'db>
§impl<'db> PartialEq for TerminatorKind<'db>
impl<'db> PartialEq for TerminatorKind<'db>
impl<'db> Eq for TerminatorKind<'db>
impl<'db> StructuralPartialEq for TerminatorKind<'db>
Auto Trait Implementations§
impl<'db> Freeze for TerminatorKind<'db>
impl<'db> RefUnwindSafe for TerminatorKind<'db>
impl<'db> Send for TerminatorKind<'db>
impl<'db> Sync for TerminatorKind<'db>
impl<'db> Unpin for TerminatorKind<'db>
impl<'db> UnwindSafe for TerminatorKind<'db>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T, R> CollectAndApply<T, R> for T
impl<T, R> CollectAndApply<T, R> for T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more