Unchecked Code Syntax
This section describes the syntax for unchecked code constructs.
Unchecked Functions
A function MAY be marked with the unchecked modifier to indicate that calling it requires a checked block.
function = [ "pub" ] [ "unchecked" ] "fn" IDENT "(" [ params ] ")" [ "->" type ] "{" block "}" ;
unchecked fn dangerous_operation() -> i32 {
42
}
pub unchecked fn public_dangerous() -> i32 {
0
}
Checked Blocks
A checked block is an expression that enables unchecked operations within its body.
checked_expr = "checked" [ STRING ] "{" block "}" ;
The optional string literal is the block's reason (9.1:14).
A checked block evaluates its body block using the ordinary block-expression rules (4.5). Its value is the body block's value: the tail expression's value when present, or () when the body has no tail expression. The type of a checked block is the type of that body block.
fn main() -> i32 {
let x = checked {
let a = 10;
let b = 32;
a + b
};
x
}
--preview checked_reasons to use. See ADR-0095 for the design. A checked block MAY state the invariant it relies on as a string literal between checked and the block: its reason. The reason is part of the syntax tree and is carried through the compiler's emitted views of the program; it has no effect on the block's value, type, or evaluation (9.1:6). Checked block reasons are a preview feature: a checked block that states a reason MUST be compiled with --preview checked_reasons (8.4:1). Under that preview every checked block MUST state a reason, and the reason MUST NOT be empty; a block that omits its reason, or states an empty one, is rejected with E1301 at the block. There is no allow-list or per-site opt-out: the point of the rule is that every site where the programmer takes over an obligation from the compiler has been thought about and says so.
fn first(base: ptr const i32, len: u64) -> i32 {
if len == 0 { return 0; }
checked "len > 0 was established by the guard above, so index 0 is in bounds" {
@ptr_read(base)
}
}
Raw Pointer Types
Rue provides two raw pointer types for low-level memory access:
ptr const T- a pointer to immutable data of typeTptr mut T- a pointer to mutable data of typeT
ptr_type = "ptr" ( "const" | "mut" ) type ;
Raw pointer types are fully type-checked: they may appear as the type of a local, a parameter, a struct field, or a function return type. A ptr const T and a ptr mut T are distinct types, and two pointer types are equal only when their pointee types T are equal — a ptr const i32 is neither a ptr mut i32 nor a ptr const i64.
fn takes_ptr(p: ptr const i32) -> i32 { 0 }
fn takes_mut_ptr(p: ptr mut i32) -> i32 { 0 }
fn identity_ptr(p: ptr const i32) -> ptr const i32 { p }
struct Node { next: ptr const Node, value: i32 }
A raw-pointer intrinsic — @raw, @raw_mut, @field_ptr, @ptr_read, @ptr_write, @ptr_read_unaligned, @ptr_write_unaligned, @ptr_offset, @ptr_to_int, or @int_to_ptr — is an unchecked operation and MUST appear within a checked block. Using one outside a checked block is a compile error. (Defining a ptr const T / ptr mut T value's type is always legal; only the pointer operations require a checked block.) The same requirement applies to the allocation family (9.2:13), the raw-byte intrinsics (9.2:14h, 9.2:14l), and @syscall (9.2:3a). Byte-granular access has no intrinsic of its own: it is @ptr_read/@ptr_write over a ptr u8 (9.2:6d), already listed above.
fn main() -> i32 {
let x: i32 = 42;
// The pointer operations are wrapped in `checked`; the pointer types
// themselves need no `checked`.
let p: ptr const i32 = checked { @raw(x) };
checked { @ptr_read(p) }
}