From 13eca5ad7cee8432e376a402cca4bda9df3b8c8e Mon Sep 17 00:00:00 2001
From: mlugg
- Given a pointer to a field, returns the base pointer of a struct.
+ Given a pointer to a struct field, returns a pointer to the struct containing that field.
+ The return type (and struct in question) is the inferred result type.
+
+ If {#syntax#}field_ptr{#endsyntax#} does not point to the {#syntax#}field_name{#endsyntax#} field of an instance of
+ the result type, and the result type has ill-defined layout, invokes unchecked {#link|Undefined Behavior#}.
- Integer literals have no size limitation, and if any undefined behavior occurs,
+ Integer literals have no size limitation, and if any Illegal Behavior occurs,
the compiler catches it.
However, once an integer value is no longer known at compile-time, it must have a
- known size, and is vulnerable to undefined behavior.
+ known size, and is vulnerable to safety-checked {#link|Illegal Behavior#}.
{#syntax#}@fieldParentPtr(comptime field_name: []const u8, field_ptr: *T) anytype{#endsyntax#}
- Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on + Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause {#link|Illegal Behavior#} on integer overflow. Alternative operators are provided for wrapping and saturating arithmetic on all targets. {#syntax#}+%{#endsyntax#} and {#syntax#}-%{#endsyntax#} perform wrapping arithmetic while {#syntax#}+|{#endsyntax#} and {#syntax#}-|{#endsyntax#} perform saturating arithmetic. @@ -2029,7 +2029,7 @@ or
Slices have bounds checking and are therefore protected - against this kind of undefined behavior. This is one reason + against this kind of Illegal Behavior. This is one reason we prefer slices to pointers.
{#code|test_slice_bounds.zig#} @@ -2048,7 +2048,7 @@ or{#link|@ptrCast#} converts a pointer's element type to another. This - creates a new pointer that can cause undetectable illegal behavior + creates a new pointer that can cause undetectable Illegal Behavior depending on the loads and stores that pass through it. Generally, other kinds of type conversions are preferable to {#syntax#}@ptrCast{#endsyntax#} if possible. @@ -2164,7 +2164,7 @@ or
Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is - actually the sentinel value. If this is not the case, safety-protected {#link|Undefined Behavior#} results. + actually the sentinel value. If this is not the case, safety-checked {#link|Illegal Behavior#} results.
{#code|test_sentinel_mismatch.zig#} @@ -2425,7 +2425,7 @@ or or use an {#link|extern union#} or a {#link|packed union#} which have guaranteed in-memory layout. {#link|Accessing the non-active field|Wrong Union Field Access#} is - safety-checked {#link|Undefined Behavior#}: + safety-checked {#link|Illegal Behavior#}: {#code|test_wrong_union_access.zig#} @@ -3024,11 +3024,11 @@ or {#syntax#}const number = parseU64("1234", 10) catch unreachable;{#endsyntax#}Here we know for sure that "1234" will parse successfully. So we put the - {#syntax#}unreachable{#endsyntax#} value on the right hand side. {#syntax#}unreachable{#endsyntax#} generates - a panic in {#link|Debug#} and {#link|ReleaseSafe#} modes and undefined behavior in - {#link|ReleaseFast#} and {#link|ReleaseSmall#} modes. So, while we're debugging the - application, if there was a surprise error here, the application would crash - appropriately. + {#syntax#}unreachable{#endsyntax#} value on the right hand side. + {#syntax#}unreachable{#endsyntax#} invokes safety-checked {#link|Illegal Behavior#}, so + in {#link|Debug#} and {#link|ReleaseSafe#}, triggers a safety panic by default. So, while + we're debugging the application, if there was a surprise error here, the application + would crash appropriately.
You may want to take a different action for every situation. For that, we combine @@ -4035,7 +4035,7 @@ fn performFn(start_value: i32) i32 {
Luckily, we used an unsigned integer, and so when we tried to subtract 1 from 0, it triggered - undefined behavior, which is always a compile error if the compiler knows it happened. + {#link|Illegal Behavior#}, which is always a compile error if the compiler knows it happened. But what would have happened if we used a signed integer?
{#code|fibonacci_comptime_infinite_recursion.zig#} @@ -4240,7 +4240,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {Failure to declare the full set of clobbers for a given inline assembly - expression is unchecked {#link|Undefined Behavior#}. + expression is unchecked {#link|Illegal Behavior#}.
{#header_close#} @@ -4806,7 +4806,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valAttempting to convert an integer with no corresponding value in the enum invokes - safety-checked {#link|Undefined Behavior#}. + safety-checked {#link|Illegal Behavior#}. Note that a {#link|non-exhaustive enum|Non-exhaustive enum#} has corresponding values for all integers in the enum's integer tag type: the {#syntax#}_{#endsyntax#} value represents all the remaining unnamed integers in the enum's tag type. @@ -4825,7 +4825,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
Attempting to convert an integer that does not correspond to any error results in - safety-protected {#link|Undefined Behavior#}. + safety-checked {#link|Illegal Behavior#}.
{#see_also|@intFromError#} {#header_close#} @@ -4857,7 +4857,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valConverts an error set or error union value from one error set to another error set. The return type is the inferred result type. Attempting to convert an error which is not in the destination error - set results in safety-protected {#link|Undefined Behavior#}. + set results in safety-checked {#link|Illegal Behavior#}.
{#header_close#} @@ -4913,7 +4913,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valIf {#syntax#}field_ptr{#endsyntax#} does not point to the {#syntax#}field_name{#endsyntax#} field of an instance of - the result type, and the result type has ill-defined layout, invokes unchecked {#link|Undefined Behavior#}. + the result type, and the result type has ill-defined layout, invokes unchecked {#link|Illegal Behavior#}.
{#header_close#} @@ -5030,7 +5030,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val Converts an integer to another integer while keeping the same numerical value. The return type is the inferred result type. Attempting to convert a number which is out of range of the destination type results in - safety-protected {#link|Undefined Behavior#}. + safety-checked {#link|Illegal Behavior#}. {#code|test_intCast_builtin.zig#} @@ -5091,7 +5091,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valIf the integer part of the floating point number cannot fit in the destination type, - it invokes safety-checked {#link|Undefined Behavior#}. + it invokes safety-checked {#link|Illegal Behavior#}.
{#see_also|@floatFromInt#} {#header_close#} @@ -5251,7 +5251,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valThe {#syntax#}ptr{#endsyntax#} argument may be any pointer type and determines the memory address to prefetch. This function does not dereference the pointer, it is perfectly legal - to pass a pointer to invalid memory to this function and no illegal behavior will result. + to pass a pointer to invalid memory to this function and no Illegal Behavior will result.
{#syntax#}PrefetchOptions{#endsyntax#} can be found with {#syntax#}@import("std").builtin.PrefetchOptions{#endsyntax#}.
{#header_close#} @@ -5263,7 +5263,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val{#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#} - to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}. + to a non-optional pointer invokes safety-checked {#link|Illegal Behavior#}.
{#syntax#}@ptrCast{#endsyntax#} cannot be used for: @@ -5287,7 +5287,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#} - is zero, this invokes safety-checked {#link|Undefined Behavior#}. + is zero, this invokes safety-checked {#link|Illegal Behavior#}.
{#header_close#} @@ -5362,8 +5362,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valThe type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits. - This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} is undefined behavior. + This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
{#syntax#}comptime_int{#endsyntax#} is modeled as an integer with an infinite number of bits, @@ -5419,7 +5419,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).int.bits){#endsyntax#} bits. - This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).int.bits{#endsyntax#} is undefined behavior. + This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
{#see_also|@shlExact|@shrExact#} {#header_close#} @@ -5432,7 +5432,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_valThe type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits. - This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} is undefined behavior. + This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
{#see_also|@shlExact|@shlWithOverflow#} {#header_close#} @@ -5707,7 +5707,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#header_open|@tagName#}{#syntax#}@tagName(value: anytype) [:0]const u8{#endsyntax#}
- Converts an enum value or union value to a string literal representing the name.
If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Undefined Behavior#}. + Converts an enum value or union value to a string literal representing the name.
If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Illegal Behavior#}.
{#header_close#} @@ -5944,7 +5944,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val- Zig has many instances of undefined behavior. If undefined behavior is - detected at compile-time, Zig emits a compile error and refuses to continue. - Most undefined behavior that cannot be detected at compile-time can be detected - at runtime. In these cases, Zig has safety checks. Safety checks can be disabled - on a per-block basis with {#link|@setRuntimeSafety#}. The {#link|ReleaseFast#} - and {#link|ReleaseSmall#} build modes disable all safety checks (except where overridden - by {#link|@setRuntimeSafety#}) in order to facilitate optimizations. + Many operations in Zig trigger what is known as "Illegal Behavior" (IB). If Illegal Behavior is detected at + compile-time, Zig emits a compile error and refuses to continue. Otherwise, when Illegal Behavior is not caught + at compile-time, it falls into one of two categories.
- When a safety check fails, Zig crashes with a stack trace, like this: + Some Illegal Behavior is safety-checked: this means that the compiler will insert "safety checks" + anywhere that the Illegal Behavior may occur at runtime, to determine whether it is about to happen. If it + is, the safety check "fails", which triggers a panic.
- {#code|test_undefined_behavior.zig#} ++ All other Illegal Behavior is unchecked, meaning the compiler is unable to insert safety checks for + it. If Unchecked Illegal Behavior is invoked at runtime, anything can happen: usually that will be some kind of + crash, but the optimizer is free to make Unchecked Illegal Behavior do anything, such as calling arbitrary functions + or clobbering arbitrary data. This is similar to the concept of "undefined behavior" in some other languages. Note that + Unchecked Illegal Behavior still always results in a compile error if evaluated at {#link|comptime#}, because the Zig + compiler is able to perform more sophisticated checks at compile-time than at runtime. +
++ Most Illegal Behavior is safety-checked. However, to facilitate optimizations, safety checks are disabled by default + in the {#link|ReleaseFast#} and {#link|ReleaseSmall#} optimization modes. Safety checks can also be enabled or disabled + on a per-block basis, overriding the default for the current optimization mode, using {#link|@setRuntimeSafety#}. When + safety checks are disabled, Safety-Checked Illegal Behavior behaves like Unchecked Illegal Behavior; that is, any behavior + may result from invoking it. +
++ When a safety check fails, Zig's default panic handler crashes with a stack trace, like this: +
+ {#code|test_illegal_behavior.zig#} {#header_open|Reaching Unreachable Code#}At compile-time:
@@ -6338,7 +6354,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val{#syntax#}var{#endsyntax#} declarations inside functions are stored in the function's stack frame. Once a function returns, any {#link|Pointers#} to variables in the function's stack frame become invalid references, and - dereferencing them becomes unchecked {#link|Undefined Behavior#}. + dereferencing them becomes unchecked {#link|Illegal Behavior#}.
{#syntax#}var{#endsyntax#} declarations at the top level or in {#link|struct#} declarations are stored in the global @@ -6446,7 +6462,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val The API documentation for functions and data structures should take great care to explain the ownership and lifetime semantics of pointers. Ownership determines whose responsibility it is to free the memory referenced by the pointer, and lifetime determines the point at which - the memory becomes inaccessible (lest {#link|Undefined Behavior#} occur). + the memory becomes inaccessible (lest {#link|Illegal Behavior#} occur).
{#header_close#} @@ -6734,10 +6750,10 @@ int foo(void) {await async some_async_fn()
, which contains an {#syntax#}await{#endsyntax#}.await async some_async_fn()
, which contains an {#syntax#}await{#endsyntax#}.main
because no errors are returned from the function.
- {#see_also|Values|Tuples|@import|Errors|Root Source File|Source Encoding|try#}
+ {#see_also|Values|Tuples|@import|Errors|Entry Point|Source Encoding|try#}
{#header_close#}
{#header_open|Comments#}
@@ -823,7 +823,7 @@ zig test is a tool that creates and runs a test build. By default, it builds and runs an executable program using the default test runner provided by the {#link|Zig Standard Library#} as its main entry point. During the build, {#syntax#}test{#endsyntax#} declarations found while - {#link|resolving|Root Source File#} the given Zig source file are included for the default test runner + {#link|resolving|File and Declaration Discovery#} the given Zig source file are included for the default test runner to run and report on.
TODO: explain how root source file finds other files
-TODO: pub fn main
-TODO: pub fn panic
-TODO: if linking with libc you can use export fn main
-TODO: order independent top level declarations
-TODO: lazy analysis
-TODO: using comptime { _ = @import() }
+ {#header_open|Compilation Model#} ++ A Zig compilation is separated into modules. Each module is a collection of Zig source files, + one of which is the module's root source file. Each module can depend on any number of + other modules, forming a directed graph (dependency loops between modules are allowed). If module A + depends on module B, then any Zig source file in module A can import the root source file of + module B using {#syntax#}@import{#endsyntax#} with the module's name. In essence, a module acts as an + alias to import a Zig source file (which might exist in a completely separate part of the filesystem). +
+
+ A simple Zig program compiled with zig build-exe
has two key modules: the one containing your
+ code, known as the "main" or "root" module, and the standard library. Your module depends on
+ the standard library module under the name "std", which is what allows you to write
+ {#syntax#}@import("std"){#endsyntax#}! In fact, every single module in a Zig compilation — including
+ the standard library itself — implicitly depends on the standard library module under the name "std".
+
+ The "root module" (the one provided by you in the zig build-exe
example) has a special
+ property. Like the standard library, it is implicitly made available to all modules (including itself),
+ this time under the name "root". So, {#syntax#}@import("root"){#endsyntax#} will always be equivalent to
+ {#syntax#}@import{#endsyntax#} of your "main" source file (often, but not necessarily, named
+ main.zig
).
+
+ Every Zig source file is implicitly a {#syntax#}struct{#endsyntax#} declaration; you can imagine that + the file's contents are literally surrounded by {#syntax#}struct { ... }{#endsyntax#}. This means that + as well as declarations, the top level of a file is permitted to contain fields: +
+ {#code|TopLevelFields.zig#} ++ Such files can be instantiated just like any other {#syntax#}struct{#endsyntax#} type. A file's "root + struct type" can be referred to within that file using {#link|@This#}. +
+ {#header_close#} + {#header_open|File and Declaration Discovery#} ++ Zig places importance on the concept of whether any piece of code is semantically analyzed; in + eseence, whether the compiler "looks at" it. What code is analyzed is based on what files and + declarations are "discovered" from a certain point. This process of "discovery" is based on a simple set + of recursive rules: +
++ That's it! Those rules define how Zig files and declarations are discovered. All that remains is to + understand where this process starts. +
+
+ The answer to that is the root of the standard library: every Zig compilation begins by analyzing the
+ file lib/std/std.zig
. This file contains a {#syntax#}comptime{#endsyntax#} declaration
+ which imports {#syntax#}lib/std/start.zig{#endsyntax#}, and that file in turn uses
+ {#syntax#}@import("root"){#endsyntax#} to reference the "root module"; so, the file you provide as your
+ main module's root source file is effectively also a root, because the standard library will always
+ reference it.
+
+ It is often desirable to make sure that certain declarations — particularly {#syntax#}test{#endsyntax#} + or {#syntax#}export{#endsyntax#} declarations — are discovered. Based on the above rules, a common + strategy for this is to use {#syntax#}@import{#endsyntax#} within a {#syntax#}comptime{#endsyntax#} or + {#syntax#}test{#endsyntax#} block: +
+ {#syntax_block|zig|force_file_discovery.zig#} +comptime { + // This will ensure that the file 'api.zig' is always discovered (as long as this file is discovered). + // It is useful if 'api.zig' contains important exported declarations. + _ = @import("api.zig"); + + // We could also have a file which contains declarations we only want to export depending on a comptime + // condition. In that case, we can use an `if` statement here: + if (builtin.os.tag == .windows) { + _ = @import("windows_api.zig"); + } +} + +test { + // This will ensure that the file 'tests.zig' is always discovered (as long as this file is discovered), + // if this compilation is a test. It is useful if 'tests.zig' contains tests we want to ensure are run. + _ = @import("tests.zig"); + + // We could also have a file which contains tests we only want to run depending on a comptime condition. + // In that case, we can use an `if` statement here: + if (builtin.os.tag == .windows) { + _ = @import("windows_tests.zig"); + } +} + +const builtin = @import("builtin"); + {#end_syntax_block#} + {#header_close#} + {#header_open|Special Root Declarations#} ++ Because the root module's root source file is always accessible using + {#syntax#}@import("root"){#endsyntax#}, is is sometimes used by libraries — including the Zig Standard + Library — as a place for the program to expose some "global" information to that library. The Zig + Standard Library will look for several declarations in this file. +
+ {#header_open|Entry Point#} ++ When building an executable, the most important thing to be looked up in this file is the program's + entry point. Most commonly, this is a function named {#syntax#}main{#endsyntax#}, which + {#syntax#}std.start{#endsyntax#} will call just after performing important initialization work. +
++ Alternatively, the presence of a declaration named {#syntax#}_start{#endsyntax#} (for instance, + {#syntax#}pub const _start = {};{#endsyntax#}) will disable the default {#syntax#}std.start{#endsyntax#} + logic, allowing your root source file to export a low-level entry point as needed. +
+ {#code|entry_point.zig#} +
+ If the Zig compilation links libc, the {#syntax#}main{#endsyntax#} function can optionally be an
+ {#syntax#}export fn{#endsyntax#} which matches the signature of the C main
function:
+
+ {#syntax#}std.start{#endsyntax#} may also use other entry point declarations in certain situations, such + as {#syntax#}wWinMain{#endsyntax#} or {#syntax#}EfiMain{#endsyntax#}. Refer to the + {#syntax#}lib/std/start.zig{#endsyntax#} logic for details of these declarations. +
+ {#header_close#} + {#header_open|Standard Library Options#} ++ The standard library also looks for a declaration in the root module's root source file named + {#syntax#}std_options{#endsyntax#}. If present, this declaration is expected to be a struct of type + {#syntax#}std.Options{#endsyntax#}, and allows the program to customize some standard library + functionality, such as the {#syntax#}std.log{#endsyntax#} implementation. +
+ {#code|std_options.zig#} + {#header_close#} + {#header_open|Panic Handler#} ++ The Zig Standard Library looks for a declaration named {#syntax#}panic{#endsyntax#} in the root module's + root source file. If present, it is expected to be a namespace (container type) with declarations + providing different panic handlers. +
++ See {#syntax#}std.debug.simple_panic{#endsyntax#} for a basic implementation of this namespace. +
++ Overriding how the panic handler actually outputs messages, but keeping the formatted safety panics + which are enabled by default, can be easily achieved with {#syntax#}std.debug.FullPanic{#endsyntax#}: +
+ {#code|panic_handler.zig#} + {#header_close#} + {#header_close#} {#header_close#} {#header_open|Zig Build System#}diff --git a/doc/langref/TopLevelFields.zig b/doc/langref/TopLevelFields.zig new file mode 100644 index 000000000000..7fb460a7ca21 --- /dev/null +++ b/doc/langref/TopLevelFields.zig @@ -0,0 +1,18 @@ +//! Because this file contains fields, it is a type which is intended to be instantiated, and so +//! is named in TitleCase instead of snake_case by convention. + +foo: u32, +bar: u64, + +/// `@This()` can be used to refer to this struct type. In files with fields, is quite common to name the type +/// here, so it can be easily referenced by other declarations. +const TopLevelFields = @This(); + +pub fn init(val: u32) TopLevelFields { + return .{ + .foo = val, + .bar = val * 10, + }; +} + +// syntax diff --git a/doc/langref/entry_point.zig b/doc/langref/entry_point.zig new file mode 100644 index 000000000000..0927daf17ed4 --- /dev/null +++ b/doc/langref/entry_point.zig @@ -0,0 +1,20 @@ +/// `std.start` imports this file using `@import("root")`, and uses this declaration as the program's +/// user-provided entry point. It can return any of the following types: +/// * `void` +/// * `E!void`, for any error set `E` +/// * `u8` +/// * `E!u8`, for any error set `E` +/// Returning a `void` value from this function will exit with code 0. +/// Returning a `u8` value from this function with exit with the given status code. +/// Returning an error value from this function will print an Error Return Trace and exit with code 1. +pub fn main() void { + std.debug.print("Hello, World!\n", .{}); +} + +// If uncommented, this declaration would suppress the usual std.start logic, causing +// the `main` declaration above to be ignored. +//pub const _start = {}; + +const std = @import("std"); + +// exe=succeed diff --git a/doc/langref/libc_export_entry_point.zig b/doc/langref/libc_export_entry_point.zig new file mode 100644 index 000000000000..bec791a295be --- /dev/null +++ b/doc/langref/libc_export_entry_point.zig @@ -0,0 +1,10 @@ +pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int { + const args = argv[0..@intCast(argc)]; + std.debug.print("Hello! argv[0] is '{s}'\n", .{args[0]}); + return 0; +} + +const std = @import("std"); + +// exe=succeed +// link_libc diff --git a/doc/langref/panic_handler.zig b/doc/langref/panic_handler.zig new file mode 100644 index 000000000000..7eb3a67f16b0 --- /dev/null +++ b/doc/langref/panic_handler.zig @@ -0,0 +1,18 @@ +pub fn main() void { + @setRuntimeSafety(true); + var x: u8 = 255; + // Let's overflow this integer! + x += 1; +} + +pub const panic = std.debug.FullPanic(myPanic); + +fn myPanic(msg: []const u8, first_trace_addr: ?usize) noreturn { + _ = first_trace_addr; + std.debug.print("Panic! {s}\n", .{msg}); + std.process.exit(1); +} + +const std = @import("std"); + +// exe=fail diff --git a/doc/langref/std_options.zig b/doc/langref/std_options.zig new file mode 100644 index 000000000000..b37d407fc86a --- /dev/null +++ b/doc/langref/std_options.zig @@ -0,0 +1,25 @@ +/// The presence of this declaration allows the program to override certain behaviors of the standard library. +/// For a full list of available options, see the documentation for `std.Options`. +pub const std_options: std.Options = .{ + // By default, in safe build modes, the standard library will attach a segfault handler to the program to + // print a helpful stack trace if a segmentation fault occurs. Here, we can disable this, or even enable + // it in unsafe build modes. + .enable_segfault_handler = true, + // This is the logging function used by `std.log`. + .logFn = myLogFn, +}; + +fn myLogFn( + comptime level: std.log.Level, + comptime scope: @Type(.enum_literal), + comptime format: []const u8, + args: anytype, +) void { + // We could do anything we want here! + // ...but actually, let's just call the default implementation. + std.log.defaultLog(level, scope, format, args); +} + +const std = @import("std"); + +// syntax