Enum rustc_middle::mir::TerminatorKind
source · pub enum TerminatorKind<'tcx> {
Show 15 variants
Goto {
target: BasicBlock,
},
SwitchInt {
discr: Operand<'tcx>,
targets: SwitchTargets,
},
UnwindResume,
UnwindTerminate(UnwindTerminateReason),
Return,
Unreachable,
Drop {
place: Place<'tcx>,
target: BasicBlock,
unwind: UnwindAction,
replace: bool,
},
Call {
func: Operand<'tcx>,
args: Box<[Spanned<Operand<'tcx>>]>,
destination: Place<'tcx>,
target: Option<BasicBlock>,
unwind: UnwindAction,
call_source: CallSource,
fn_span: Span,
},
TailCall {
func: Operand<'tcx>,
args: Box<[Spanned<Operand<'tcx>>]>,
fn_span: Span,
},
Assert {
cond: Operand<'tcx>,
expected: bool,
msg: Box<AssertMessage<'tcx>>,
target: BasicBlock,
unwind: UnwindAction,
},
Yield {
value: Operand<'tcx>,
resume: BasicBlock,
resume_arg: Place<'tcx>,
drop: Option<BasicBlock>,
},
CoroutineDrop,
FalseEdge {
real_target: BasicBlock,
imaginary_target: BasicBlock,
},
FalseUnwind {
real_target: BasicBlock,
unwind: UnwindAction,
},
InlineAsm {
template: &'tcx [InlineAsmTemplatePiece],
operands: Box<[InlineAsmOperand<'tcx>]>,
options: InlineAsmOptions,
line_spans: &'tcx [Span],
targets: Box<[BasicBlock]>,
unwind: UnwindAction,
},
}
Expand description
The various kinds of terminators, representing ways of exiting from a basic block.
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 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
unwind action must have its cleanup
flag set.
cleanup
basic blocks have a couple restrictions:
-
All
unwind
fields in them must beUnwindAction::Terminate
orUnwindAction::Unreachable
. -
Return
terminators are not allowed in them.Terminate
andResume
terminators are. -
All other basic blocks (in the current body) that are reachable from
cleanup
basic blocks must also becleanup
. This is a part of the type system and checked statically, so it is still an error to have such an edge in the CFG even if it’s known that it won’t be taken at runtime. -
The control flow between cleanup blocks must look like an upside down tree. Roughly speaking, this means that control flow that looks like a V is allowed, while control flow that looks like a W is not. This is necessary to ensure that landing pad information can be correctly codegened on MSVC. More precisely:
Begin with the standard control flow graph
G
. ModifyG
as follows: for any two cleanup verticesu
andv
such thatu
dominatesv
, contractu
andv
into a single vertex, deleting self edges and duplicate edges in the process. Now remove all vertices fromG
that are not cleanup vertices or are not reachable. The resulting graph must be an inverted tree, that is each vertex may have at most one successor and there may be no cycles.
Variants§
Goto
Block has one successor; we continue execution there.
Fields
target: BasicBlock
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.
UnwindTerminate(UnwindTerminateReason)
Indicates that the landing pad is finished and that the process should terminate.
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
terminators are a complete nop for types that have no drop
glue. For other types, Drop
terminators behave exactly like a call to
core::mem::drop_in_place
with a pointer to the given place.
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.
The replace
flag indicates whether this terminator was created as part of an assignment.
This should only be used for diagnostic purposes, and does not have any operational
meaning.
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<[Spanned<Operand<'tcx>>]>
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.
The span for each arg is also included
(e.g. a
and b
in x.foo(a, b)
).
target: Option<BasicBlock>
Where to go after this call returns. If none, the call necessarily diverges.
unwind: UnwindAction
Action to be taken if the call unwinds.
call_source: CallSource
Where this call came from in HIR/THIR.
TailCall
Tail call.
Roughly speaking this is a chimera of Call
and Return
, with some caveats.
Semantically tail calls consists of two actions:
- pop of the current stack frame
- a call to the
func
, with the return address of the current caller- so that a
return
insidefunc
returns to the caller of the caller of the function that is currently being executed
- so that a
Note that in difference with Call
this is missing
destination
(because it’s always the return place)target
(because it’s always taken from the current stack frame)unwind
(because it’s always taken from the current stack frame)
Fields
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.
When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR
that is used for CTFE), the following variants of this terminator behave as goto target
:
OverflowNeg(..)
,Overflow(op, ..)
if op is add, sub, mul, shl, shr, but NOT div or rem.
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: BasicBlock
Where to resume to.
drop: Option<BasicBlock>
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: BasicBlock
The target normal control flow will take.
imaginary_target: BasicBlock
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: BasicBlock
The target normal control flow will take.
unwind: UnwindAction
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.
InlineAsm
Block ends with an inline assembly block. This is a terminator since inline assembly is allowed to diverge.
Fields
template: &'tcx [InlineAsmTemplatePiece]
The template for the inline assembly, with placeholders.
operands: Box<[InlineAsmOperand<'tcx>]>
The operands for the inline assembly, as Operand
s or Place
s.
options: InlineAsmOptions
Miscellaneous options for the inline assembly.
line_spans: &'tcx [Span]
Source spans for each line of the inline assembly code. These are used to map assembler errors back to the line in the source code.
targets: Box<[BasicBlock]>
Valid targets for the inline assembly. The first element is the fallthrough destination, unless InlineAsmOptions::NORETURN is set.
unwind: UnwindAction
Action to be taken if the inline assembly unwinds. This is present if and only if InlineAsmOptions::MAY_UNWIND is set.
Implementations§
source§impl<'tcx> TerminatorKind<'tcx>
impl<'tcx> TerminatorKind<'tcx>
sourcepub fn fmt_head<W: Write>(&self, fmt: &mut W) -> Result
pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> Result
Writes the “head” part of the terminator; that is, its name and the data it uses to pick the successor basic block, if any. The only information not included is the list of possible successors, which may be rendered differently between the text and the graphviz format.
sourcepub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>>
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>>
Returns the list of labels for the edges to the successor basic blocks.
source§impl TerminatorKind<'_>
impl TerminatorKind<'_>
source§impl<'tcx> TerminatorKind<'tcx>
impl<'tcx> TerminatorKind<'tcx>
pub fn successors(&self) -> Successors<'_>
pub fn successors_mut(&mut self) -> SuccessorsMut<'_>
source§impl<'tcx> TerminatorKind<'tcx>
impl<'tcx> TerminatorKind<'tcx>
pub fn if_( cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock, ) -> TerminatorKind<'tcx>
source§impl<'tcx> TerminatorKind<'tcx>
impl<'tcx> TerminatorKind<'tcx>
pub fn unwind(&self) -> Option<&UnwindAction>
pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction>
pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)>
pub fn as_goto(&self) -> Option<BasicBlock>
source§impl<'tcx> TerminatorKind<'tcx>
impl<'tcx> TerminatorKind<'tcx>
pub fn edges(&self) -> TerminatorEdges<'_, 'tcx>
Trait Implementations§
source§impl<'tcx> Clone for TerminatorKind<'tcx>
impl<'tcx> Clone for TerminatorKind<'tcx>
source§fn clone(&self) -> TerminatorKind<'tcx>
fn clone(&self) -> TerminatorKind<'tcx>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl<'tcx> Debug for TerminatorKind<'tcx>
impl<'tcx> Debug for TerminatorKind<'tcx>
source§impl<'tcx> Hash for TerminatorKind<'tcx>
impl<'tcx> Hash for TerminatorKind<'tcx>
source§impl<'tcx, '__ctx> HashStable<StableHashingContext<'__ctx>> for TerminatorKind<'tcx>
impl<'tcx, '__ctx> HashStable<StableHashingContext<'__ctx>> for TerminatorKind<'tcx>
fn hash_stable( &self, __hcx: &mut StableHashingContext<'__ctx>, __hasher: &mut StableHasher, )
source§impl<'tcx> PartialEq for TerminatorKind<'tcx>
impl<'tcx> PartialEq for TerminatorKind<'tcx>
source§fn eq(&self, other: &TerminatorKind<'tcx>) -> bool
fn eq(&self, other: &TerminatorKind<'tcx>) -> bool
self
and other
values to be equal, and is used
by ==
.source§impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for TerminatorKind<'tcx>
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for TerminatorKind<'tcx>
source§fn try_fold_with<__F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
__folder: &mut __F,
) -> Result<Self, __F::Error>
fn try_fold_with<__F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, __folder: &mut __F, ) -> Result<Self, __F::Error>
source§fn fold_with<F>(self, folder: &mut F) -> Selfwhere
F: TypeFolder<I>,
fn fold_with<F>(self, folder: &mut F) -> Selfwhere
F: TypeFolder<I>,
try_fold_with
for use with infallible
folders. Do not override this method, to ensure coherence with
try_fold_with
.source§impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for TerminatorKind<'tcx>
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for TerminatorKind<'tcx>
source§fn visit_with<__V: TypeVisitor<TyCtxt<'tcx>>>(
&self,
__visitor: &mut __V,
) -> __V::Result
fn visit_with<__V: TypeVisitor<TyCtxt<'tcx>>>( &self, __visitor: &mut __V, ) -> __V::Result
impl<'tcx> StructuralPartialEq for TerminatorKind<'tcx>
Auto Trait Implementations§
impl<'tcx> DynSend for TerminatorKind<'tcx>
impl<'tcx> DynSync for TerminatorKind<'tcx>
impl<'tcx> Freeze for TerminatorKind<'tcx>
impl<'tcx> !RefUnwindSafe for TerminatorKind<'tcx>
impl<'tcx> Send for TerminatorKind<'tcx>
impl<'tcx> Sync for TerminatorKind<'tcx>
impl<'tcx> Unpin for TerminatorKind<'tcx>
impl<'tcx> !UnwindSafe for TerminatorKind<'tcx>
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§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<T, R> CollectAndApply<T, R> for T
impl<T, R> CollectAndApply<T, R> for T
source§impl<Tcx, T> DepNodeParams<Tcx> for T
impl<Tcx, T> DepNodeParams<Tcx> for T
default fn fingerprint_style() -> FingerprintStyle
source§default fn to_fingerprint(&self, tcx: Tcx) -> Fingerprint
default fn to_fingerprint(&self, tcx: Tcx) -> Fingerprint
default fn to_debug_str(&self, _: Tcx) -> String
source§default fn recover(_: Tcx, _: &DepNode) -> Option<T>
default fn recover(_: Tcx, _: &DepNode) -> Option<T>
DepNode
,
something which is needed when forcing DepNode
s during red-green
evaluation. The query system will only call this method if
fingerprint_style()
is not FingerprintStyle::Opaque
.
It is always valid to return None
here, in which case incremental
compilation will treat the query as having changed instead of forcing it.source§impl<T> Filterable for T
impl<T> Filterable for T
source§fn filterable(
self,
filter_name: &'static str,
) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§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 moresource§impl<P> IntoQueryParam<P> for P
impl<P> IntoQueryParam<P> for P
fn into_query_param(self) -> P
source§impl<'tcx, T> IsSuggestable<'tcx> for T
impl<'tcx, T> IsSuggestable<'tcx> for T
source§impl<T> MaybeResult<T> for T
impl<T> MaybeResult<T> for T
source§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<I, T> TypeVisitableExt<I> for Twhere
I: Interner,
T: TypeVisitable<I>,
impl<I, T> TypeVisitableExt<I> for Twhere
I: Interner,
T: TypeVisitable<I>,
fn has_type_flags(&self, flags: TypeFlags) -> bool
source§fn has_vars_bound_at_or_above(&self, binder: DebruijnIndex) -> bool
fn has_vars_bound_at_or_above(&self, binder: DebruijnIndex) -> bool
true
if self
has any late-bound regions that are either
bound by binder
or bound by some binder outside of binder
.
If binder
is ty::INNERMOST
, this indicates whether
there are any late-bound regions that appear free.fn error_reported(&self) -> Result<(), <I as Interner>::ErrorGuaranteed>
source§fn has_vars_bound_above(&self, binder: DebruijnIndex) -> bool
fn has_vars_bound_above(&self, binder: DebruijnIndex) -> bool
true
if this type has any regions that escape binder
(and
hence are not bound by it).source§fn has_escaping_bound_vars(&self) -> bool
fn has_escaping_bound_vars(&self) -> bool
true
if this type has regions that are not a part of the type.
For example, for<'a> fn(&'a i32)
return false
, while fn(&'a i32)
would return true
. The latter can occur when traversing through the
former. Read morefn has_aliases(&self) -> bool
fn has_inherent_projections(&self) -> bool
fn has_opaque_types(&self) -> bool
fn has_coroutines(&self) -> bool
fn references_error(&self) -> bool
fn has_non_region_param(&self) -> bool
fn has_infer_regions(&self) -> bool
fn has_infer_types(&self) -> bool
fn has_non_region_infer(&self) -> bool
fn has_infer(&self) -> bool
fn has_placeholders(&self) -> bool
fn has_non_region_placeholders(&self) -> bool
fn has_param(&self) -> bool
source§fn has_free_regions(&self) -> bool
fn has_free_regions(&self) -> bool
fn has_erased_regions(&self) -> bool
source§fn has_erasable_regions(&self) -> bool
fn has_erasable_regions(&self) -> bool
source§fn is_global(&self) -> bool
fn is_global(&self) -> bool
source§fn has_bound_regions(&self) -> bool
fn has_bound_regions(&self) -> bool
source§fn has_non_region_bound_vars(&self) -> bool
fn has_non_region_bound_vars(&self) -> bool
source§fn has_bound_vars(&self) -> bool
fn has_bound_vars(&self) -> bool
source§fn still_further_specializable(&self) -> bool
fn still_further_specializable(&self) -> bool
impl
specialization.source§impl<I, T, U> Upcast<I, U> for Twhere
U: UpcastFrom<I, T>,
impl<I, T, U> Upcast<I, U> for Twhere
U: UpcastFrom<I, T>,
source§impl<I, T> UpcastFrom<I, T> for T
impl<I, T> UpcastFrom<I, T> for T
fn upcast_from(from: T, _tcx: I) -> T
source§impl<Tcx, T> Value<Tcx> for Twhere
Tcx: DepContext,
impl<Tcx, T> Value<Tcx> for Twhere
Tcx: DepContext,
default fn from_cycle_error( tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed, ) -> T
source§impl<T> WithSubscriber for T
impl<T> WithSubscriber for T
source§fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
source§fn with_current_subscriber(self) -> WithDispatch<Self>
fn with_current_subscriber(self) -> WithDispatch<Self>
impl<'a, T> Captures<'a> for Twhere
T: ?Sized,
impl<T> ErasedDestructor for Twhere
T: 'static,
impl<T> MaybeSendSync for T
Layout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...)
attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 80 bytes
Size for each variant:
Goto
: 7 bytesSwitchInt
: 79 bytesUnwindResume
: 0 bytesUnwindTerminate
: 1 byteReturn
: 0 bytesUnreachable
: 0 bytesDrop
: 31 bytesCall
: 79 bytesTailCall
: 55 bytesAssert
: 47 bytesYield
: 55 bytesCoroutineDrop
: 0 bytesFalseEdge
: 11 bytesFalseUnwind
: 15 bytesInlineAsm
: 79 bytes