Build Diagnostics

#Error("…") and #Warn("…") are messages from the source to whoever builds it. Written as a directive, #Error stops the build where the compiler reaches it and #Warn prints a warning and lets the build go on. Neither produces any code.

directive = ( "#Error" | "#Warn" ) "(" string-literal ")"
import Core::{ #target, #Error };

func Main() -> int {
    when #target.pointerBits < 64 {
        #Error("this program needs a 64-bit target");
    }
    return 0;
}

On a build that reaches it, the error points at the directive itself:

Src/Main.rux:5:9: error: this program needs a 64-bit target

The same names written above a declaration are attributes, which fire at every call of that declaration instead — see #Error and #Warn.

They run after when

Directives are evaluated after conditional compilation has chosen its branches, and a branch that is not taken is never looked at — so a directive in it never fires. That is how they are meant to be used: #Error in the branch a build should never take, #Warn in the branch that deserves a remark. A directive outside any when is always reached, so a bare #Error("…"); in a body stops every build on every target.

Where they may be written

PositionFormImport from Core
a statement in a function body#Error("…");yes
a bare-expression arm of a when match in a body.AArch64 => #Warn("…"),yes
an arm of a when match between declarationselse => #Error("…")no

Between declarations, the match arm is the only place a directive can stand. Inside the braces of a declaration-level when chain, #Error("…") is read as the start of an attribute, and the compiler then wants a declaration after it:

error: expected a declaration after the attributes before '}'

Write the declaration-level check as a match with an else arm:

import Core::{ #target };

when #target.os {
    .FreeBSD, .Linux, .macOS => const Separator: char8[..] = "/";
    .Windows => const Separator: char8[..] = "\\";
    else => #Error("this package does not know the path separator of this system")
}

As a statement, a directive is a call to the intrinsic functions Core declares (pub intrinsic func #Error(message: char8[..]);), so it must be imported; without the import the build fails with error: name '#Warn' is not defined in this scope.

The message

The message must be a string literal written in place — it is printed while compiling, before any constant or variable has a value at run time. A constant is refused:

error: '#Warn' message must be a string literal
A non-literal message in a declaration-level arm.
rux 0.4.0 does not report a non-literal message in a declaration-level when arm such as .Windows => #Error(Message); the compiler stops responding instead. Keep the message a literal.

Escapes in the literal work as in any string (\n, \", …). Write the message for the person building: say what is unsupported and, where it helps, what to do instead.

See also