pub enum TerminatorKind<'tcx> {
Show 14 variants Goto { target: BasicBlock, }, SwitchInt { discr: Operand<'tcx>, targets: SwitchTargets, }, UnwindResume, UnwindTerminate, Return, Unreachable, Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool, }, Call { func: Operand<'tcx>, args: Vec<Operand<'tcx>, Global>, destination: Place<'tcx>, target: Option<BasicBlock>, unwind: UnwindAction, call_source: CallSource, fn_span: Span, }, Assert { cond: Operand<'tcx>, expected: bool, msg: Box<AssertKind<Operand<'tcx>>, Global>, target: BasicBlock, unwind: UnwindAction, }, 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: UnwindAction, }, InlineAsm { template: &'tcx [InlineAsmTemplatePiece], operands: Vec<InlineAsmOperand<'tcx>, Global>, options: InlineAsmOptions, line_spans: &'tcx [Span], destination: Option<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:

  1. All unwind fields in them must be UnwindAction::Terminate or UnwindAction::Unreachable.

  2. Return terminators are not allowed in them. Terminate and Resume 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.

  4. 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. Modify G as follows: for any two cleanup vertices u and v such that u dominates v, contract u and v into a single vertex, deleting self edges and duplicate edges in the process. Now remove all vertices from G 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

Fields

§target: BasicBlock

Block has one successor; we continue execution there.

§

SwitchInt

Fields

§discr: Operand<'tcx>

The discriminant value being tested.

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

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 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
§replace: bool

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

Fields

§func: Operand<'tcx>

The function that’s being called.

§args: Vec<Operand<'tcx>, Global>

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.

§unwind: UnwindAction

Action to be taken if the call unwinds.

§call_source: CallSource

Where this call came from in HIR/THIR.

§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
§target: 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.

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

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

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>, Global>

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).

§unwind: UnwindAction

Action to be taken 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.

Auto Trait Implementations§

§

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> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> CallHasher for Twhere T: Hash + ?Sized,

§

default fn get_hash<H, B>(value: &H, build_hasher: &B) -> u64where H: Hash + ?Sized, B: BuildHasher,

source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

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

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.