pub enum TerminatorKind<'tcx> {
Show 15 variants Goto { target: BasicBlock, }, SwitchInt { discr: Operand<'tcx>, switch_ty: Ty<'tcx>, targets: SwitchTargets, }, Resume, Abort, Return, Unreachable, Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock>, }, DropAndReplace { place: Place<'tcx>, value: Operand<'tcx>, target: BasicBlock, unwind: Option<BasicBlock>, }, Call { func: Operand<'tcx>, args: Vec<Operand<'tcx>>, destination: Place<'tcx>, target: Option<BasicBlock>, cleanup: Option<BasicBlock>, from_hir_call: bool, fn_span: Span, }, Assert { cond: Operand<'tcx>, expected: bool, msg: AssertMessage<'tcx>, target: BasicBlock, cleanup: Option<BasicBlock>, }, Yield { value: Operand<'tcx>, resume: BasicBlock, resume_arg: Place<'tcx>, drop: Option<BasicBlock>, }, GeneratorDrop, FalseEdge { real_target: BasicBlock, imaginary_target: BasicBlock, }, FalseUnwind { real_target: BasicBlock, unwind: Option<BasicBlock>, }, InlineAsm { template: &'tcx [InlineAsmTemplatePiece], operands: Vec<InlineAsmOperand<'tcx>>, options: InlineAsmOptions, line_spans: &'tcx [Span], destination: Option<BasicBlock>, cleanup: Option<BasicBlock>, },
}
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 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.

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.
  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 still an error to have such an edge in the CFG even if it’s known that it won’t be taken at runtime.

Variants

Goto

Fields

target: BasicBlock

Block has one successor; we continue execution there.

SwitchInt

Fields

discr: Operand<'tcx>

The discriminant value being tested.

switch_ty: Ty<'tcx>

The type of value being tested. This is always the same as the type of discr. FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.

targets: SwitchTargets

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.

Resume

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 generator body, this has slightly different semantics; it instead causes a GeneratorState::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

Fields

place: Place<'tcx>
target: BasicBlock
unwind: Option<BasicBlock>

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

Fields

place: Place<'tcx>
value: Operand<'tcx>
target: BasicBlock
unwind: Option<BasicBlock>

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

Fields

func: Operand<'tcx>

The function that’s being called.

args: Vec<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.

destination: Place<'tcx>

Where the returned value will be written

target: Option<BasicBlock>

Where to go after this call returns. If none, the call necessarily diverges.

cleanup: Option<BasicBlock>

Cleanups to be done if the call unwinds.

from_hir_call: bool

true if this is from a call in HIR rather than from an overloaded operator. True for overloaded function call.

fn_span: Span

This Span is the span of the function, without the dot and receiver (e.g. foo(a, b) in x.foo(a, b)

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.

Assert

Fields

cond: Operand<'tcx>
expected: bool
msg: AssertMessage<'tcx>
target: BasicBlock
cleanup: Option<BasicBlock>

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

Fields

value: Operand<'tcx>

The value to return.

resume: BasicBlock

Where to resume to.

resume_arg: Place<'tcx>

The place to store the resume argument in.

drop: Option<BasicBlock>

Cleanup to be done if the generator is dropped at this suspend point.

Marks a suspend point.

Like Return terminators in generator bodies, this computes value and then a GeneratorState::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 generator is dropped before then, the drop basic block is invoked.

Not permitted in bodies that are not generator bodies, or after generator lowering.

Needs clarification: What about the evaluation order of the resume_arg and value?

GeneratorDrop

Indicates the end of dropping a generator.

Semantically just a return (from the generators drop glue). Only permitted in the same situations as yield.

Needs clarification: Is that even correct? The generator 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

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.

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.

FalseUnwind

Fields

real_target: BasicBlock

The target normal control flow will take.

unwind: Option<BasicBlock>

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.

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.

InlineAsm

Fields

template: &'tcx [InlineAsmTemplatePiece]

The template for the inline assembly, with placeholders.

operands: Vec<InlineAsmOperand<'tcx>>

The operands for the inline assembly, as Operands or Places.

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.

destination: Option<BasicBlock>

Destination block after the inline assembly returns, unless it is diverging (InlineAsmOptions::NORETURN).

cleanup: Option<BasicBlock>

Cleanup to be done if the inline assembly unwinds. This is present if and only if InlineAsmOptions::MAY_UNWIND is set.

Block ends with an inline assembly block. This is a terminator since inline assembly is allowed to diverge.

Implementations

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.

Returns the list of labels for the edges to the successor basic blocks.

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used by ==. Read more
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason. Read more
The entry point for folding. To fold a value t with a folder f call: t.try_fold_with(f). Read more
A convenient alternative to try_fold_with for use with infallible folders. Do not override this method, to ensure coherence with try_fold_with. Read more
The entry point for visiting. To visit a value t with a visitor v call: t.visit_with(v). Read more
Returns 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. Read more
Returns true if this self has any regions that escape binder (and hence are not bound by it). Read more
“Free” regions in this context means that it has any region that is not (a) erased or (b) late-bound. Read more
True if there are any un-erased free regions.
Indicates whether this value references only ‘global’ generic parameters that are the same regardless of what fn we are in. This is used for caching. Read more
True if there are any late-bound regions
Indicates whether this value still has parameters/placeholders/inference variables which could be replaced later, in a way that would change the results of impl specialization. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
This method turns the parameters of a DepNodeConstructor into an opaque Fingerprint to be used in DepNode. Not all DepNodeParams support being turned into a Fingerprint (they don’t need to if the corresponding DepNode is anonymous). Read more
This method tries to recover the query key from the given DepNode, something which is needed when forcing DepNodes 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. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.

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: 96 bytes

Size for each variant:

  • Goto: 12 bytes
  • SwitchInt: 88 bytes
  • Resume: 0 bytes
  • Abort: 0 bytes
  • Return: 0 bytes
  • Unreachable: 0 bytes
  • Drop: 32 bytes
  • DropAndReplace: 56 bytes
  • Call: 96 bytes
  • Assert: 96 bytes
  • Yield: 56 bytes
  • GeneratorDrop: 0 bytes
  • FalseEdge: 16 bytes
  • FalseUnwind: 16 bytes
  • InlineAsm: 80 bytes