Enum hir_ty::mir::TerminatorKind
source · pub enum TerminatorKind {
Show 14 variants
Goto {
target: BasicBlockId,
},
SwitchInt {
discr: Operand,
targets: SwitchTargets,
},
UnwindResume,
Abort,
Return,
Unreachable,
Drop {
place: Place,
target: BasicBlockId,
unwind: Option<BasicBlockId>,
},
DropAndReplace {
place: Place,
value: Operand,
target: BasicBlockId,
unwind: Option<BasicBlockId>,
},
Call {
func: Operand,
args: Box<[Operand]>,
destination: Place,
target: Option<BasicBlockId>,
cleanup: Option<BasicBlockId>,
from_hir_call: bool,
},
Assert {
cond: Operand,
expected: bool,
target: BasicBlockId,
cleanup: Option<BasicBlockId>,
},
Yield {
value: Operand,
resume: BasicBlockId,
resume_arg: Place,
drop: Option<BasicBlockId>,
},
CoroutineDrop,
FalseEdge {
real_target: BasicBlockId,
imaginary_target: BasicBlockId,
},
FalseUnwind {
real_target: BasicBlockId,
unwind: Option<BasicBlockId>,
},
}
Variants§
Goto
Block has one successor; we continue execution there.
Fields
target: BasicBlockId
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]>
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<BasicBlockId>
Where to go after this call returns. If none, the call necessarily diverges.
cleanup: Option<BasicBlockId>
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: BasicBlockId
Where to resume to.
drop: Option<BasicBlockId>
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: BasicBlockId
The target normal control flow will take.
imaginary_target: BasicBlockId
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: BasicBlockId
The target normal control flow will take.
unwind: Option<BasicBlockId>
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§
source§impl Clone for TerminatorKind
impl Clone for TerminatorKind
source§fn clone(&self) -> TerminatorKind
fn clone(&self) -> TerminatorKind
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for TerminatorKind
impl Debug for TerminatorKind
source§impl PartialEq for TerminatorKind
impl PartialEq for TerminatorKind
impl Eq for TerminatorKind
impl StructuralPartialEq for TerminatorKind
Auto Trait Implementations§
impl Freeze for TerminatorKind
impl RefUnwindSafe for TerminatorKind
impl Send for TerminatorKind
impl Sync for TerminatorKind
impl Unpin for TerminatorKind
impl UnwindSafe for TerminatorKind
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,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)§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<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