#NoReturn

#NoReturn() declares that a function never returns to its caller: it ends the program, loops forever, or transfers control somewhere else for good. The compiler uses that to check control flow — code after a call is unreachable, and a call can end a path that would otherwise need a return.

noreturn-attribute = "#NoReturn" "(" ")"

It applies to a function and to an extern func, and takes no arguments. A function that never returns has no result to declare:

error: '#NoReturn' function cannot declare a return type
error: '#NoReturn' can only be applied to a function
error: '#NoReturn' does not accept arguments

Ending a path

A function with a result must return a value on every path. A call to a #NoReturn function counts as the end of its path:

import Core::Panic;
import Io::PrintLine;

#NoReturn()
func Fail(message: char8[..]) {
    PrintLine("fatal: {}", message);
    Panic(message);
}

func Digit(c: char8) -> int {
    if c >= c8'0' && c <= c8'9' {
        return (c - c8'0') as int;
    }
    Fail("not a digit");   // no return needed after this
}

Without the attribute on Fail, Digit fails with function 'Digit' must return a value of type 'int' on every control-flow path.

Panic itself is declared in Core as an intrinsic that never returns, and an extern binding of a C function such as abort or exit takes the attribute the same way:

#NoReturn()
#Link(CRuntime)
extern func abort();

An extern { } block cannot carry #NoReturn for its members; declare such a function on its own.

The body must not return

A return in a #NoReturn function is an error:

error: return is not allowed in a '#NoReturn' function

The body has to end by calling something that does not return either — Panic, another #NoReturn function, or an endless loop. A body that can reach its closing brace, such as one that stops after a PrintLine, is an error too, since a call that came back would continue into code the compiler marked unreachable:

error: '#NoReturn' function 'Stop' can reach the end of its body
  note: a call to it would come back to code that assumes it does not
  help: end every path with 'Panic', a call to another '#NoReturn' function, or an endless 'loop'

See also