Attributes and directives

The @ annotations on declarations and parameters, and the compile-time directive surface.

Attributes are written @name or @name(args) and attach to a declaration.

Declaration attributes

Attribute Applies to Effect
@implements(...) Record, enum Lang traits (Drop, Clone, Copy) or a user-defined trait
@packed Record Removes padding between fields in the emitted C struct
@aligned(N) Record Sets a minimum alignment
@lang(try) Enum Marks the enum try-capable, for the ! operator
@cold Function Marks the function unlikely to run
@inline, @inline(always), @inline(never) Function Inlining hint, force, or refusal
@externName("...") Function Overrides the C symbol name
@extension(Type), @extension(Type, mut) Function Turns the function into a method on Type
@deprecated, @deprecated("...") Declaration Warns at every use
@allow(...), @warn(...), @deny(...) Declaration Changes a lint’s level for that item
@test Function Registers a native test case
@directive(...) Function Declares a compile-time directive

The inline modifier is written before function:

inline(always) function hotPath(x: i32): i32 {
    return x + 1;
}

Parameter attributes

Attribute Effect
@takes An extern parameter that consumes ownership
@noescape A closure parameter that will not outlive the call
extern rt {
    function release(@takes ptr: *mut void): void;
}

function forEach(@noescape f: (i32) -> void, data: *i32, len: i32): void {
    return;
}

@test

@test marks a top-level function as a case for ignis test. The contract is strict, and every part of it is checked: top level, not extern, not generic, no parameters, returns void.

import Test from "std::test";

@test
function smoke(): void {
    Test::assert(true);
    return;
}

Compile-time directives

@directive(...) declares a function that runs during compilation rather than at runtime. The metadata is given as named arguments — target, phase, effect, and optionally group and capabilities.

import Compile from "std::compile";

@directive(target: "record", phase: check, effect: diagnose)
function derive(context: Compile::Context, target: Compile::ItemReference): void {
    Compile::error(context, target, "records must satisfy this invariant");
    return;
}

The recognized phases are check, expand, collect, finalize and transform. std::compile is compile-time only and never links into a runtime binary.

This surface is the least settled part of the language. What works today: directive declarations and uses are validated and scheduled before lowering, capability checks run in a default-deny sandbox, and the diagnostic calls Compile::error, Compile::warning and Compile::note execute. What does not: generated item insertion and its semantic reintegration. The rest of the std::compile surface exists as opaque compile-time handles, and unsupported generation operations are hard errors rather than silent no-ops.