Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Structured vs Unstructured Control-Flow

Charon can represent a function body in two ways. Both describe the same computation; they differ in how they connect one operation to the next.

Structured control-flow is the default. In this mode, control-flow is represented by having Statements be able to contain Blocks (statement lists), e.g. a match will contain one block for each possible branch, and a function call will contain a block for its unwind path. The only “indirect” control-flow affordances are break/continue within a loop.

Unstructured control-flow instead represents the function body as a set of blocks that can jump to one another. Each Block contains a series of control-flow-free Statements, followed by a single Terminator, which describes which other blocks computation may jump to. For example, a match will contain one block id for each possible branch. Loops are not explicitly represented: they are simply cases where the graph of blocks is cyclic.

Pass --ullbc to get unstructured bodies in the output.

The unstructured bodies are actually what rustc gives us; we reconstruct the structured bodies ourselves.

Code Duplication

In structured mode, by default we aim for the output code to be legible, and for that we may duplicate input code. For example:

#![allow(unused)]
fn main() {
if foo() && bar() {
    do_something();
} else {
    do_something_else();
}
}

is today reconstructed as:

#![allow(unused)]
fn main() {
if foo() {
    if bar() {
        do_something();
    } else {
        do_something_else();
    }
} else {
    do_something_else();
}
}

This specific case may be improved (see charon#803), but in the general case we will still have duplication.

If this is undesirable for your use case, use --no-code-duplication. Instead of duplicating code this will introduce loops and break from them. Our example becomes more or less:

#![allow(unused)]
fn main() {
'a: loop {
    if foo() {
        if bar() {
            do_something();
            break 'a
        }
    }
    do_something_else();
}
}