Decorators
A decorator is a codegen directive attached to a declaration. It controls how the compiler emits a symbol - its linker name, alignment, section placement, inlining, or PE import routing - and nothing else.
Decorators are codegen-only. Visibility (pub / ext) is a separate concern and is never controlled by a decorator.
Surface
A decorator is written as an attribute clause. A bare flag takes no arguments; a directive takes comptime-expression arguments.
#[name] # bare flag (e.g. inline)
#[name(args)] # directive with comptime-expr arguments
A line comment that begins #[ with no space opens an attribute. Write such a comment with a separating space: # [...].
Placement
Decorators appear before the declaration they target, one per line or space-separated on the same line. They attach to the immediately following declaration only and do not bleed across declarations.
#[inline]
#[symbol("big")]
fun big(a: i64, b: i64) i64 { ... }
#[align(64)] #[symbol("g_lit64")]
pub var g_lit64: u8 = 7;
Directives
The directive set is closed; new directives require a compiler change.
symbol(str) - linker name
Overrides the emitted or imported symbol name. Applies to functions and globals. Without it, the compiler mangles the mach name; symbol gives the linker the exact name.
#[symbol("main")]
fun entry(argc: i64, argv: **u8) i64 { ... }
#[symbol("write")]
ext fun libc_write(fd: i64, buf: *u8, n: i64) i64;
library(str) - PE import routing
Pins an ext import to a specific DLL in the link's dependency set. Applies to ext functions only, and composes with symbol - the import is emitted under the renamed symbol within the named DLL.
#[library("ws2_32.dll")] #[symbol("WSAStartup")]
ext fun wsa_startup(ver: u16, data: *u8) i32;
- The named DLL must appear in the manifest's
[os.*].libsfor the target OS. Pinning to an absent library is a link error, never a silent fallback. - Without
library, an unattributed PE import binds to the first declared dependency. Every import that belongs to a different DLL needs its ownlibrarypin. - On ELF (Linux) the loader resolves imports by global search, so
libraryhas no effect on the emitted binary; the value is still validated against the link's dependency set.
inline - force inlining
Marks a function for inlining at every call site, overriding the compiler's size- and use-count heuristics. Applies to functions only and takes no arguments.
#[inline]
fun fast_path(x: i64) i64 { ret x * 2; }
align(expr) - alignment override
Sets the alignment of a global variable or a record/union type. expr must be a comptime integer - a literal, or a comptime expression such as $size_of(T) or $align_of(T).
#[align(64)]
pub var cache_line: u8 = 0;
#[align($size_of(Pair))]
pub var g_cmp: u8 = 0;
#[align(32)]
rec Over { a: u8; }
- On a
var/val, it sets the global's section and address alignment. - On a
recoruni, it sets the type's own alignment, inherited by any global of that type. - It does not apply to
defaliases, which are transparent and have no layout of their own.
section(str) - object section placement
Places a function or global variable in a named section instead of the default .text / .data. The section is created if absent; cross-section calls and accesses use ordinary relocations.
#[section(".hottext")] #[symbol("f_hot")]
fun f_hot(x: i64) i64 { ret x + 1; }
#[section(".machsec")] #[symbol("g_sec")]
pub var g_sec: u64 = 100;
Applicability
Each directive targets a fixed set of declaration kinds. The full matrix:
| Directive | fun | ext fun | val / var | rec / uni |
|---|---|---|---|---|
symbol | yes | yes | yes | no |
library | no | yes | no | no |
inline | yes | no | no | no |
align | no | no | yes | yes |
section | yes | yes | yes | no |
See also
- Visibility -
pub/ext, the separate concern decorators never touch - Intrinsics -
$size_ofand$align_ofasalignarguments - Manifest - the
[os.*].libsset alibrarypin resolves against