Ctrl K
ComunidadGuías…

doc/noalloc.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Allocation contracts

`@[noalloc]` checks a V function and every function body reachable through its direct calls.
The compiler reports allocation sites with the root function, call chain, and source location.
Checks run during ordinary compilation and `-check`, including instantiated generic functions.
Allocations in startup code or unrelated functions do not violate the contract.

```v
@[noalloc]
fn factorial(n int) int {
	if n < 2 {
		return 1
	}
	return n * factorial(n - 1)
}
```

Checks cover source operations and the compiler's lowered code. Dynamic array and map creation,
string construction, interface and sum-type boxing, escaping local storage, closures, and
allocations inside called functions are rejected. An annotation on a V callee does not hide its
body: the compiler still checks it. Cached imports are read from source when their bodies are
needed for allocation checks. Recursion is checked without revisiting the same body.

Boolean short-circuit operators, string header copies and returns, and zero-copy string views
such as `unsafe { tos(ptr, len) }` do not allocate. Constructing strings by concatenation,
interpolation, or cloning remains checked. Struct literals check only defaults for fields that
are not explicitly initialized; literal defaults, including signed numeric constants and
`unsafe { nil }`, are allowed.

This check is conservative. Operations whose allocation behavior cannot be proved are rejected,
even when a particular execution would allocate nothing. This includes indirect function calls,
interface dispatch, bound method values, unexpanded compile-time code, custom operators, and
copies or returns of owning aggregates. The standalone FastC backend rejects V allocation contracts;
use the C backend. Contracts on function aliases and interface declarations are unsupported and
produce an error. Annotate V or C function declarations instead.

Automatic ownership and cleanup (`-ownership`, `-d ownership`, `-autofree`), profiling
(`-prof`, `-profile`), call tracing (`-trace-calls`), and coverage (`-coverage`) are rejected
for annotated functions. These modes can introduce callbacks or instrumentation after the
allocation checks, so their generated behavior cannot establish this contract.

## Reusable output buffers

By default, appending to an existing mutable array parameter is allowed. Such a buffer can grow
until it reaches its high-water mark. The exception covers only that buffer's growth: constructing
an appended dynamic array, slicing a fixed array, or boxing an interface element still fails.
Bulk append is rejected because an aliasing source can require a separate temporary copy.

```v
@[noalloc]
fn write_byte(mut out []u8, value u8) {
	out << value
}
```

Use `@[noalloc: strict]` to forbid buffer growth as well. Other attribute arguments are invalid.

## Foreign functions and termination

C declarations are assumed to allocate unless explicitly annotated with `@[noalloc]`. The
annotation is a trusted foreign contract, so the declaration's author must verify it. Standard
memory copying, comparison, searching, freeing, and string-length primitives have these contracts.

Calls to the known `panic`, `exit`, `C.exit`, and `C.abort` functions are exempt, including their
arguments, because they terminate execution. Statements before a terminating call remain checked;
an earlier branch that returns successfully cannot bypass the contract.
Hoisted argument allocations are exempt only for a source-validated body consisting solely of
the terminating call. More complex terminating control flow can be rejected conservatively.

Cached V declarations without an available body cannot establish a nonallocation proof. The
compiler rejects such calls rather than trusting an annotation in a cached declaration header.