authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-22 18:41:35-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-22 18:41:35-05:00
log813312f0e871d436581c5d0be8700ee04aa2fb97
tree040e0fc53bfc7dd5b3fb3f5e2646c2ddc7e24781
parentb25d93e7d95418ea92b388ff8b58a04673c04539
parentcc64295a6313f8697ed02143390caa8fe3a63626
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22714 from mlugg/langref

langref improvements

9 files changed, 319 insertions(+), 66 deletions(-)

doc/langref.html.in+221-59
......@@ -381,7 +381,7 @@
381381 In this case, the {#syntax#}!{#endsyntax#} may be omitted from the return
382382 type of <code>main</code> because no errors are returned from the function.
383383 </p>
384 {#see_also|Values|Tuples|@import|Errors|Root Source File|Source Encoding|try#}
384 {#see_also|Values|Tuples|@import|Errors|Entry Point|Source Encoding|try#}
385385 {#header_close#}
386386 {#header_open|Comments#}
387387 <p>
......@@ -823,7 +823,7 @@
823823 <kbd>zig test</kbd> is a tool that creates and runs a test build. By default, it builds and runs an
824824 executable program using the <em>default test runner</em> provided by the {#link|Zig Standard Library#}
825825 as its main entry point. During the build, {#syntax#}test{#endsyntax#} declarations found while
826 {#link|resolving|Root Source File#} the given Zig source file are included for the default test runner
826 {#link|resolving|File and Declaration Discovery#} the given Zig source file are included for the default test runner
827827 to run and report on.
828828 </p>
829829 <aside>
......@@ -1049,12 +1049,12 @@
10491049 {#header_close#}
10501050 {#header_open|Runtime Integer Values#}
10511051 <p>
1052 Integer literals have no size limitation, and if any undefined behavior occurs,
1052 Integer literals have no size limitation, and if any Illegal Behavior occurs,
10531053 the compiler catches it.
10541054 </p>
10551055 <p>
10561056 However, once an integer value is no longer known at compile-time, it must have a
1057 known size, and is vulnerable to undefined behavior.
1057 known size, and is vulnerable to safety-checked {#link|Illegal Behavior#}.
10581058 </p>
10591059 {#code|runtime_vs_comptime.zig#}
10601060
......@@ -1064,7 +1064,7 @@
10641064 {#link|Division by Zero#}.
10651065 </p>
10661066 <p>
1067 Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on
1067 Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause {#link|Illegal Behavior#} on
10681068 integer overflow. Alternative operators are provided for wrapping and saturating arithmetic on all targets.
10691069 {#syntax#}+%{#endsyntax#} and {#syntax#}-%{#endsyntax#} perform wrapping arithmetic
10701070 while {#syntax#}+|{#endsyntax#} and {#syntax#}-|{#endsyntax#} perform saturating arithmetic.
......@@ -2029,7 +2029,7 @@ or
20292029 </p>
20302030 <p>
20312031 Slices have bounds checking and are therefore protected
2032 against this kind of undefined behavior. This is one reason
2032 against this kind of Illegal Behavior. This is one reason
20332033 we prefer slices to pointers.
20342034 </p>
20352035 {#code|test_slice_bounds.zig#}
......@@ -2048,7 +2048,7 @@ or
20482048
20492049 <p>
20502050 {#link|@ptrCast#} converts a pointer's element type to another. This
2051 creates a new pointer that can cause undetectable illegal behavior
2051 creates a new pointer that can cause undetectable Illegal Behavior
20522052 depending on the loads and stores that pass through it. Generally, other
20532053 kinds of type conversions are preferable to
20542054 {#syntax#}@ptrCast{#endsyntax#} if possible.
......@@ -2164,7 +2164,7 @@ or
21642164
21652165 <p>
21662166 Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is
2167 actually the sentinel value. If this is not the case, safety-protected {#link|Undefined Behavior#} results.
2167 actually the sentinel value. If this is not the case, safety-checked {#link|Illegal Behavior#} results.
21682168 </p>
21692169 {#code|test_sentinel_mismatch.zig#}
21702170
......@@ -2425,7 +2425,7 @@ or
24252425 or use an {#link|extern union#} or a {#link|packed union#} which have
24262426 guaranteed in-memory layout.
24272427 {#link|Accessing the non-active field|Wrong Union Field Access#} is
2428 safety-checked {#link|Undefined Behavior#}:
2428 safety-checked {#link|Illegal Behavior#}:
24292429 </p>
24302430 {#code|test_wrong_union_access.zig#}
24312431
......@@ -3023,11 +3023,11 @@ or
30233023 {#syntax#}const number = parseU64("1234", 10) catch unreachable;{#endsyntax#}
30243024 <p>
30253025 Here we know for sure that "1234" will parse successfully. So we put the
3026 {#syntax#}unreachable{#endsyntax#} value on the right hand side. {#syntax#}unreachable{#endsyntax#} generates
3027 a panic in {#link|Debug#} and {#link|ReleaseSafe#} modes and undefined behavior in
3028 {#link|ReleaseFast#} and {#link|ReleaseSmall#} modes. So, while we're debugging the
3029 application, if there <em>was</em> a surprise error here, the application would crash
3030 appropriately.
3026 {#syntax#}unreachable{#endsyntax#} value on the right hand side.
3027 {#syntax#}unreachable{#endsyntax#} invokes safety-checked {#link|Illegal Behavior#}, so
3028 in {#link|Debug#} and {#link|ReleaseSafe#}, triggers a safety panic by default. So, while
3029 we're debugging the application, if there <em>was</em> a surprise error here, the application
3030 would crash appropriately.
30313031 </p>
30323032 <p>
30333033 You may want to take a different action for every situation. For that, we combine
......@@ -4034,7 +4034,7 @@ fn performFn(start_value: i32) i32 {
40344034 </p>
40354035 <p>
40364036 Luckily, we used an unsigned integer, and so when we tried to subtract 1 from 0, it triggered
4037 undefined behavior, which is always a compile error if the compiler knows it happened.
4037 {#link|Illegal Behavior#}, which is always a compile error if the compiler knows it happened.
40384038 But what would have happened if we used a signed integer?
40394039 </p>
40404040 {#code|fibonacci_comptime_infinite_recursion.zig#}
......@@ -4239,7 +4239,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
42394239 </p>
42404240 <p>
42414241 Failure to declare the full set of clobbers for a given inline assembly
4242 expression is unchecked {#link|Undefined Behavior#}.
4242 expression is unchecked {#link|Illegal Behavior#}.
42434243 </p>
42444244 {#header_close#}
42454245
......@@ -4805,7 +4805,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
48054805 </p>
48064806 <p>
48074807 Attempting to convert an integer with no corresponding value in the enum invokes
4808 safety-checked {#link|Undefined Behavior#}.
4808 safety-checked {#link|Illegal Behavior#}.
48094809 Note that a {#link|non-exhaustive enum|Non-exhaustive enum#} has corresponding values for all
48104810 integers in the enum's integer tag type: the {#syntax#}_{#endsyntax#} value represents all
48114811 the remaining unnamed integers in the enum's tag type.
......@@ -4824,7 +4824,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
48244824 </p>
48254825 <p>
48264826 Attempting to convert an integer that does not correspond to any error results in
4827 safety-protected {#link|Undefined Behavior#}.
4827 safety-checked {#link|Illegal Behavior#}.
48284828 </p>
48294829 {#see_also|@intFromError#}
48304830 {#header_close#}
......@@ -4856,7 +4856,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
48564856 <p>
48574857 Converts an error set or error union value from one error set to another error set. The return type is the
48584858 inferred result type. Attempting to convert an error which is not in the destination error
4859 set results in safety-protected {#link|Undefined Behavior#}.
4859 set results in safety-checked {#link|Illegal Behavior#}.
48604860 </p>
48614861 {#header_close#}
48624862
......@@ -4907,7 +4907,12 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
49074907 {#header_open|@fieldParentPtr#}
49084908 <pre>{#syntax#}@fieldParentPtr(comptime field_name: []const u8, field_ptr: *T) anytype{#endsyntax#}</pre>
49094909 <p>
4910 Given a pointer to a field, returns the base pointer of a struct.
4910 Given a pointer to a struct field, returns a pointer to the struct containing that field.
4911 The return type (and struct in question) is the inferred result type.
4912 </p>
4913 <p>
4914 If {#syntax#}field_ptr{#endsyntax#} does not point to the {#syntax#}field_name{#endsyntax#} field of an instance of
4915 the result type, and the result type has ill-defined layout, invokes unchecked {#link|Illegal Behavior#}.
49114916 </p>
49124917 {#header_close#}
49134918
......@@ -5024,7 +5029,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
50245029 Converts an integer to another integer while keeping the same numerical value.
50255030 The return type is the inferred result type.
50265031 Attempting to convert a number which is out of range of the destination type results in
5027 safety-protected {#link|Undefined Behavior#}.
5032 safety-checked {#link|Illegal Behavior#}.
50285033 </p>
50295034 {#code|test_intCast_builtin.zig#}
50305035
......@@ -5085,7 +5090,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
50855090 </p>
50865091 <p>
50875092 If the integer part of the floating point number cannot fit in the destination type,
5088 it invokes safety-checked {#link|Undefined Behavior#}.
5093 it invokes safety-checked {#link|Illegal Behavior#}.
50895094 </p>
50905095 {#see_also|@floatFromInt#}
50915096 {#header_close#}
......@@ -5217,7 +5222,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
52175222 <li>From library code, calling the programmer's panic function if they exposed one in the root source file.</li>
52185223 <li>When mixing C and Zig code, calling the canonical panic implementation across multiple .o files.</li>
52195224 </ul>
5220 {#see_also|Root Source File#}
5225 {#see_also|Panic Handler#}
52215226 {#header_close#}
52225227
52235228 {#header_open|@popCount#}
......@@ -5245,7 +5250,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
52455250 <p>
52465251 The {#syntax#}ptr{#endsyntax#} argument may be any pointer type and determines the memory
52475252 address to prefetch. This function does not dereference the pointer, it is perfectly legal
5248 to pass a pointer to invalid memory to this function and no illegal behavior will result.
5253 to pass a pointer to invalid memory to this function and no Illegal Behavior will result.
52495254 </p>
52505255 <p>{#syntax#}PrefetchOptions{#endsyntax#} can be found with {#syntax#}@import("std").builtin.PrefetchOptions{#endsyntax#}.</p>
52515256 {#header_close#}
......@@ -5257,7 +5262,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
52575262 </p>
52585263 <p>
52595264 {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}
5260 to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.
5265 to a non-optional pointer invokes safety-checked {#link|Illegal Behavior#}.
52615266 </p>
52625267 <p>
52635268 {#syntax#}@ptrCast{#endsyntax#} cannot be used for:
......@@ -5281,7 +5286,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
52815286 </p>
52825287 <p>
52835288 If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#}
5284 is zero, this invokes safety-checked {#link|Undefined Behavior#}.
5289 is zero, this invokes safety-checked {#link|Illegal Behavior#}.
52855290 </p>
52865291 {#header_close#}
52875292
......@@ -5356,8 +5361,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
53565361 <li>
53575362 {#syntax#}Optimized{#endsyntax#} - Floating point operations may do all of the following:
53585363 <ul>
5359 <li>Assume the arguments and result are not NaN. Optimizations are required to retain defined behavior over NaNs, but the value of the result is undefined.</li>
5360 <li>Assume the arguments and result are not +/-Inf. Optimizations are required to retain defined behavior over +/-Inf, but the value of the result is undefined.</li>
5364 <li>Assume the arguments and result are not NaN. Optimizations are required to retain legal behavior over NaNs, but the value of the result is undefined.</li>
5365 <li>Assume the arguments and result are not +/-Inf. Optimizations are required to retain legal behavior over +/-Inf, but the value of the result is undefined.</li>
53615366 <li>Treat the sign of a zero argument or result as insignificant.</li>
53625367 <li>Use the reciprocal of an argument rather than perform division.</li>
53635368 <li>Perform floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-add).</li>
......@@ -5396,7 +5401,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
53965401 </p>
53975402 <p>
53985403 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits.
5399 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} is undefined behavior.
5404 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
54005405 </p>
54015406 <p>
54025407 {#syntax#}comptime_int{#endsyntax#} is modeled as an integer with an infinite number of bits,
......@@ -5413,7 +5418,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
54135418 </p>
54145419 <p>
54155420 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).int.bits){#endsyntax#} bits.
5416 This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).int.bits{#endsyntax#} is undefined behavior.
5421 This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
54175422 </p>
54185423 {#see_also|@shlExact|@shrExact#}
54195424 {#header_close#}
......@@ -5426,7 +5431,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
54265431 </p>
54275432 <p>
54285433 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits.
5429 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} is undefined behavior.
5434 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
54305435 </p>
54315436 {#see_also|@shlExact|@shlWithOverflow#}
54325437 {#header_close#}
......@@ -5701,7 +5706,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
57015706 {#header_open|@tagName#}
57025707 <pre>{#syntax#}@tagName(value: anytype) [:0]const u8{#endsyntax#}</pre>
57035708 <p>
5704 Converts an enum value or union value to a string literal representing the name.</p><p>If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Undefined Behavior#}.
5709 Converts an enum value or union value to a string literal representing the name.</p><p>If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Illegal Behavior#}.
57055710 </p>
57065711 {#header_close#}
57075712
......@@ -5938,7 +5943,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
59385943 <li>Reproducible build</li>
59395944 </ul>
59405945 {#header_close#}
5941 {#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
5946 {#see_also|Compile Variables|Zig Build System|Illegal Behavior#}
59425947 {#header_close#}
59435948
59445949 {#header_open|Single Threaded Builds#}
......@@ -5953,20 +5958,36 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
59535958 </ul>
59545959 {#header_close#}
59555960
5956 {#header_open|Undefined Behavior#}
5961 {#header_open|Illegal Behavior#}
5962 <p>
5963 Many operations in Zig trigger what is known as "Illegal Behavior" (IB). If Illegal Behavior is detected at
5964 compile-time, Zig emits a compile error and refuses to continue. Otherwise, when Illegal Behavior is not caught
5965 at compile-time, it falls into one of two categories.
5966 </p>
5967 <p>
5968 Some Illegal Behavior is <em>safety-checked</em>: this means that the compiler will insert "safety checks"
5969 anywhere that the Illegal Behavior may occur at runtime, to determine whether it is about to happen. If it
5970 is, the safety check "fails", which triggers a panic.
5971 </p>
5972 <p>
5973 All other Illegal Behavior is <em>unchecked</em>, meaning the compiler is unable to insert safety checks for
5974 it. If Unchecked Illegal Behavior is invoked at runtime, anything can happen: usually that will be some kind of
5975 crash, but the optimizer is free to make Unchecked Illegal Behavior do anything, such as calling arbitrary functions
5976 or clobbering arbitrary data. This is similar to the concept of "undefined behavior" in some other languages. Note that
5977 Unchecked Illegal Behavior still always results in a compile error if evaluated at {#link|comptime#}, because the Zig
5978 compiler is able to perform more sophisticated checks at compile-time than at runtime.
5979 </p>
59575980 <p>
5958 Zig has many instances of undefined behavior. If undefined behavior is
5959 detected at compile-time, Zig emits a compile error and refuses to continue.
5960 Most undefined behavior that cannot be detected at compile-time can be detected
5961 at runtime. In these cases, Zig has safety checks. Safety checks can be disabled
5962 on a per-block basis with {#link|@setRuntimeSafety#}. The {#link|ReleaseFast#}
5963 and {#link|ReleaseSmall#} build modes disable all safety checks (except where overridden
5964 by {#link|@setRuntimeSafety#}) in order to facilitate optimizations.
5981 Most Illegal Behavior is safety-checked. However, to facilitate optimizations, safety checks are disabled by default
5982 in the {#link|ReleaseFast#} and {#link|ReleaseSmall#} optimization modes. Safety checks can also be enabled or disabled
5983 on a per-block basis, overriding the default for the current optimization mode, using {#link|@setRuntimeSafety#}. When
5984 safety checks are disabled, Safety-Checked Illegal Behavior behaves like Unchecked Illegal Behavior; that is, any behavior
5985 may result from invoking it.
59655986 </p>
59665987 <p>
5967 When a safety check fails, Zig crashes with a stack trace, like this:
5988 When a safety check fails, Zig's default panic handler crashes with a stack trace, like this:
59685989 </p>
5969 {#code|test_undefined_behavior.zig#}
5990 {#code|test_illegal_behavior.zig#}
59705991
59715992 {#header_open|Reaching Unreachable Code#}
59725993 <p>At compile-time:</p>
......@@ -6332,7 +6353,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
63326353 <p>
63336354 {#syntax#}var{#endsyntax#} declarations inside functions are stored in the function's stack frame. Once a function returns,
63346355 any {#link|Pointers#} to variables in the function's stack frame become invalid references, and
6335 dereferencing them becomes unchecked {#link|Undefined Behavior#}.
6356 dereferencing them becomes unchecked {#link|Illegal Behavior#}.
63366357 </p>
63376358 <p>
63386359 {#syntax#}var{#endsyntax#} declarations at the top level or in {#link|struct#} declarations are stored in the global
......@@ -6440,7 +6461,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
64406461 The API documentation for functions and data structures should take great care to explain
64416462 the ownership and lifetime semantics of pointers. Ownership determines whose responsibility it
64426463 is to free the memory referenced by the pointer, and lifetime determines the point at which
6443 the memory becomes inaccessible (lest {#link|Undefined Behavior#} occur).
6464 the memory becomes inaccessible (lest {#link|Illegal Behavior#} occur).
64446465 </p>
64456466 {#header_close#}
64466467
......@@ -6459,14 +6480,155 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
64596480 {#builtin#}
64606481 {#see_also|Build Mode#}
64616482 {#header_close#}
6462 {#header_open|Root Source File#}
6463 <p>TODO: explain how root source file finds other files</p>
6464 <p>TODO: pub fn main</p>
6465 <p>TODO: pub fn panic</p>
6466 <p>TODO: if linking with libc you can use export fn main</p>
6467 <p>TODO: order independent top level declarations</p>
6468 <p>TODO: lazy analysis</p>
6469 <p>TODO: using comptime { _ = @import() }</p>
6483 {#header_open|Compilation Model#}
6484 <p>
6485 A Zig compilation is separated into <em>modules</em>. Each module is a collection of Zig source files,
6486 one of which is the module's <em>root source file</em>. Each module can <em>depend</em> on any number of
6487 other modules, forming a directed graph (dependency loops between modules are allowed). If module A
6488 depends on module B, then any Zig source file in module A can import the <em>root source file</em> of
6489 module B using {#syntax#}@import{#endsyntax#} with the module's name. In essence, a module acts as an
6490 alias to import a Zig source file (which might exist in a completely separate part of the filesystem).
6491 </p>
6492 <p>
6493 A simple Zig program compiled with <code>zig build-exe</code> has two key modules: the one containing your
6494 code, known as the "main" or "root" module, and the standard library. Your module <em>depends on</em>
6495 the standard library module under the name "std", which is what allows you to write
6496 {#syntax#}@import("std"){#endsyntax#}! In fact, every single module in a Zig compilation &mdash; including
6497 the standard library itself &mdash; implicitly depends on the standard library module under the name "std".
6498 </p>
6499 <p>
6500 The "root module" (the one provided by you in the <code>zig build-exe</code> example) has a special
6501 property. Like the standard library, it is implicitly made available to all modules (including itself),
6502 this time under the name "root". So, {#syntax#}@import("root"){#endsyntax#} will always be equivalent to
6503 {#syntax#}@import{#endsyntax#} of your "main" source file (often, but not necessarily, named
6504 <code>main.zig</code>).
6505 </p>
6506 {#header_open|Source File Structs#}
6507 <p>
6508 Every Zig source file is implicitly a {#syntax#}struct{#endsyntax#} declaration; you can imagine that
6509 the file's contents are literally surrounded by {#syntax#}struct { ... }{#endsyntax#}. This means that
6510 as well as declarations, the top level of a file is permitted to contain fields:
6511 </p>
6512 {#code|TopLevelFields.zig#}
6513 <p>
6514 Such files can be instantiated just like any other {#syntax#}struct{#endsyntax#} type. A file's "root
6515 struct type" can be referred to within that file using {#link|@This#}.
6516 </p>
6517 {#header_close#}
6518 {#header_open|File and Declaration Discovery#}
6519 <p>
6520 Zig places importance on the concept of whether any piece of code is <em>semantically analyzed</em>; in
6521 essence, whether the compiler "looks at" it. What code is analyzed is based on what files and
6522 declarations are "discovered" from a certain point. This process of "discovery" is based on a simple set
6523 of recursive rules:
6524 </p>
6525 <ul>
6526 <li>If a call to {#syntax#}@import{#endsyntax#} is analyzed, the file being imported is analyzed.</li>
6527 <li>If a type (including a file) is analyzed, all {#syntax#}comptime{#endsyntax#}, {#syntax#}usingnamespace{#endsyntax#}, and {#syntax#}export{#endsyntax#} declarations within it are analyzed.</li>
6528 <li>If a type (including a file) is analyzed, and the compilation is for a {#link|test|Zig Test#}, and the module the type is within is the root module of the compilation, then all {#syntax#}test{#endsyntax#} declarations within it are also analyzed.</li>
6529 <li>If a reference to a named declaration (i.e. a usage of it) is analyzed, the declaration being referenced is analyzed. Declarations are order-independent, so this reference may be above or below the declaration being referenced, or even in another file entirely.</li>
6530 </ul>
6531 <p>
6532 That's it! Those rules define how Zig files and declarations are discovered. All that remains is to
6533 understand where this process <em>starts</em>.
6534 </p>
6535 <p>
6536 The answer to that is the root of the standard library: every Zig compilation begins by analyzing the
6537 file <code>lib/std/std.zig</code>. This file contains a {#syntax#}comptime{#endsyntax#} declaration
6538 which imports {#syntax#}lib/std/start.zig{#endsyntax#}, and that file in turn uses
6539 {#syntax#}@import("root"){#endsyntax#} to reference the "root module"; so, the file you provide as your
6540 main module's root source file is effectively also a root, because the standard library will always
6541 reference it.
6542 </p>
6543 <p>
6544 It is often desirable to make sure that certain declarations &mdash; particularly {#syntax#}test{#endsyntax#}
6545 or {#syntax#}export{#endsyntax#} declarations &mdash; are discovered. Based on the above rules, a common
6546 strategy for this is to use {#syntax#}@import{#endsyntax#} within a {#syntax#}comptime{#endsyntax#} or
6547 {#syntax#}test{#endsyntax#} block:
6548 </p>
6549 {#syntax_block|zig|force_file_discovery.zig#}
6550comptime {
6551 // This will ensure that the file 'api.zig' is always discovered (as long as this file is discovered).
6552 // It is useful if 'api.zig' contains important exported declarations.
6553 _ = @import("api.zig");
6554
6555 // We could also have a file which contains declarations we only want to export depending on a comptime
6556 // condition. In that case, we can use an `if` statement here:
6557 if (builtin.os.tag == .windows) {
6558 _ = @import("windows_api.zig");
6559 }
6560}
6561
6562test {
6563 // This will ensure that the file 'tests.zig' is always discovered (as long as this file is discovered),
6564 // if this compilation is a test. It is useful if 'tests.zig' contains tests we want to ensure are run.
6565 _ = @import("tests.zig");
6566
6567 // We could also have a file which contains tests we only want to run depending on a comptime condition.
6568 // In that case, we can use an `if` statement here:
6569 if (builtin.os.tag == .windows) {
6570 _ = @import("windows_tests.zig");
6571 }
6572}
6573
6574const builtin = @import("builtin");
6575 {#end_syntax_block#}
6576 {#header_close#}
6577 {#header_open|Special Root Declarations#}
6578 <p>
6579 Because the root module's root source file is always accessible using
6580 {#syntax#}@import("root"){#endsyntax#}, is is sometimes used by libraries &mdash; including the Zig Standard
6581 Library &mdash; as a place for the program to expose some "global" information to that library. The Zig
6582 Standard Library will look for several declarations in this file.
6583 </p>
6584 {#header_open|Entry Point#}
6585 <p>
6586 When building an executable, the most important thing to be looked up in this file is the program's
6587 <em>entry point</em>. Most commonly, this is a function named {#syntax#}main{#endsyntax#}, which
6588 {#syntax#}std.start{#endsyntax#} will call just after performing important initialization work.
6589 </p>
6590 <p>
6591 Alternatively, the presence of a declaration named {#syntax#}_start{#endsyntax#} (for instance,
6592 {#syntax#}pub const _start = {};{#endsyntax#}) will disable the default {#syntax#}std.start{#endsyntax#}
6593 logic, allowing your root source file to export a low-level entry point as needed.
6594 </p>
6595 {#code|entry_point.zig#}
6596 <p>
6597 If the Zig compilation links libc, the {#syntax#}main{#endsyntax#} function can optionally be an
6598 {#syntax#}export fn{#endsyntax#} which matches the signature of the C <code>main</code> function:
6599 </p>
6600 {#code|libc_export_entry_point.zig#}
6601 <p>
6602 {#syntax#}std.start{#endsyntax#} may also use other entry point declarations in certain situations, such
6603 as {#syntax#}wWinMain{#endsyntax#} or {#syntax#}EfiMain{#endsyntax#}. Refer to the
6604 {#syntax#}lib/std/start.zig{#endsyntax#} logic for details of these declarations.
6605 </p>
6606 {#header_close#}
6607 {#header_open|Standard Library Options#}
6608 <p>
6609 The standard library also looks for a declaration in the root module's root source file named
6610 {#syntax#}std_options{#endsyntax#}. If present, this declaration is expected to be a struct of type
6611 {#syntax#}std.Options{#endsyntax#}, and allows the program to customize some standard library
6612 functionality, such as the {#syntax#}std.log{#endsyntax#} implementation.
6613 </p>
6614 {#code|std_options.zig#}
6615 {#header_close#}
6616 {#header_open|Panic Handler#}
6617 <p>
6618 The Zig Standard Library looks for a declaration named {#syntax#}panic{#endsyntax#} in the root module's
6619 root source file. If present, it is expected to be a namespace (container type) with declarations
6620 providing different panic handlers.
6621 </p>
6622 <p>
6623 See {#syntax#}std.debug.simple_panic{#endsyntax#} for a basic implementation of this namespace.
6624 </p>
6625 <p>
6626 Overriding how the panic handler actually outputs messages, but keeping the formatted safety panics
6627 which are enabled by default, can be easily achieved with {#syntax#}std.debug.FullPanic{#endsyntax#}:
6628 </p>
6629 {#code|panic_handler.zig#}
6630 {#header_close#}
6631 {#header_close#}
64706632 {#header_close#}
64716633 {#header_open|Zig Build System#}
64726634 <p>
......@@ -6728,10 +6890,10 @@ int foo(void) {
67286890 <li>Supports all the syntax of the other two pointer types ({#syntax#}*T{#endsyntax#}) and ({#syntax#}[*]T{#endsyntax#}).</li>
67296891 <li>Coerces to other pointer types, as well as {#link|Optional Pointers#}.
67306892 When a C pointer is coerced to a non-optional pointer, safety-checked
6731 {#link|Undefined Behavior#} occurs if the address is 0.
6893 {#link|Illegal Behavior#} occurs if the address is 0.
67326894 </li>
67336895 <li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
6734 {#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
6896 {#link|Illegal Behavior#}. Optional C pointers introduce another bit to keep track of
67356897 null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
67366898 is unnecessary as one can use normal {#link|Optional Pointers#}.
67376899 </li>
......@@ -7046,8 +7208,8 @@ fn readU32Be() u32 {}
70467208 <ul>
70477209 <li>Omit any information that is redundant based on the name of the thing being documented.</li>
70487210 <li>Duplicating information onto multiple similar functions is encouraged because it helps IDEs and other tools provide better help text.</li>
7049 <li>Use the word <strong>assume</strong> to indicate invariants that cause {#link|Undefined Behavior#} when violated.</li>
7050 <li>Use the word <strong>assert</strong> to indicate invariants that cause <em>safety-checked</em> {#link|Undefined Behavior#} when violated.</li>
7211 <li>Use the word <strong>assume</strong> to indicate invariants that cause <em>unchecked</em> {#link|Illegal Behavior#} when violated.</li>
7212 <li>Use the word <strong>assert</strong> to indicate invariants that cause <em>safety-checked</em> {#link|Illegal Behavior#} when violated.</li>
70517213 </ul>
70527214 {#header_close#}
70537215 {#header_close#}
......@@ -7443,8 +7605,8 @@ fn readU32Be() u32 {}
74437605 In particular, inside a {#syntax#}nosuspend{#endsyntax#} scope:
74447606 <ul>
74457607 <li>Using the {#syntax#}suspend{#endsyntax#} keyword results in a compile error.</li>
7446 <li>Using {#syntax#}await{#endsyntax#} on a function frame which hasn't completed yet results in safety-checked {#link|Undefined Behavior#}.</li>
7447 <li>Calling an async function may result in safety-checked {#link|Undefined Behavior#}, because it's equivalent to <code>await async some_async_fn()</code>, which contains an {#syntax#}await{#endsyntax#}.</li>
7608 <li>Using {#syntax#}await{#endsyntax#} on a function frame which hasn't completed yet results in safety-checked {#link|Illegal Behavior#}.</li>
7609 <li>Calling an async function may result in safety-checked {#link|Illegal Behavior#}, because it's equivalent to <code>await async some_async_fn()</code>, which contains an {#syntax#}await{#endsyntax#}.</li>
74487610 </ul>
74497611 Code inside a {#syntax#}nosuspend{#endsyntax#} scope does not cause the enclosing function to become an {#link|async function|Async Functions#}.
74507612 <ul>
doc/langref/TopLevelFields.zig created+18
......@@ -0,0 +1,18 @@
1//! Because this file contains fields, it is a type which is intended to be instantiated, and so
2//! is named in TitleCase instead of snake_case by convention.
3
4foo: u32,
5bar: u64,
6
7/// `@This()` can be used to refer to this struct type. In files with fields, it is quite common to
8/// name the type here, so it can be easily referenced by other declarations in this file.
9const TopLevelFields = @This();
10
11pub fn init(val: u32) TopLevelFields {
12 return .{
13 .foo = val,
14 .bar = val * 10,
15 };
16}
17
18// syntax
doc/langref/entry_point.zig created+20
......@@ -0,0 +1,20 @@
1/// `std.start` imports this file using `@import("root")`, and uses this declaration as the program's
2/// user-provided entry point. It can return any of the following types:
3/// * `void`
4/// * `E!void`, for any error set `E`
5/// * `u8`
6/// * `E!u8`, for any error set `E`
7/// Returning a `void` value from this function will exit with code 0.
8/// Returning a `u8` value from this function will exit with the given status code.
9/// Returning an error value from this function will print an Error Return Trace and exit with code 1.
10pub fn main() void {
11 std.debug.print("Hello, World!\n", .{});
12}
13
14// If uncommented, this declaration would suppress the usual std.start logic, causing
15// the `main` declaration above to be ignored.
16//pub const _start = {};
17
18const std = @import("std");
19
20// exe=succeed
doc/langref/libc_export_entry_point.zig created+10
......@@ -0,0 +1,10 @@
1pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int {
2 const args = argv[0..@intCast(argc)];
3 std.debug.print("Hello! argv[0] is '{s}'\n", .{args[0]});
4 return 0;
5}
6
7const std = @import("std");
8
9// exe=succeed
10// link_libc
doc/langref/panic_handler.zig created+18
......@@ -0,0 +1,18 @@
1pub fn main() void {
2 @setRuntimeSafety(true);
3 var x: u8 = 255;
4 // Let's overflow this integer!
5 x += 1;
6}
7
8pub const panic = std.debug.FullPanic(myPanic);
9
10fn myPanic(msg: []const u8, first_trace_addr: ?usize) noreturn {
11 _ = first_trace_addr;
12 std.debug.print("Panic! {s}\n", .{msg});
13 std.process.exit(1);
14}
15
16const std = @import("std");
17
18// exe=fail
doc/langref/std_options.zig created+25
......@@ -0,0 +1,25 @@
1/// The presence of this declaration allows the program to override certain behaviors of the standard library.
2/// For a full list of available options, see the documentation for `std.Options`.
3pub const std_options: std.Options = .{
4 // By default, in safe build modes, the standard library will attach a segfault handler to the program to
5 // print a helpful stack trace if a segmentation fault occurs. Here, we can disable this, or even enable
6 // it in unsafe build modes.
7 .enable_segfault_handler = true,
8 // This is the logging function used by `std.log`.
9 .logFn = myLogFn,
10};
11
12fn myLogFn(
13 comptime level: std.log.Level,
14 comptime scope: @Type(.enum_literal),
15 comptime format: []const u8,
16 args: anytype,
17) void {
18 // We could do anything we want here!
19 // ...but actually, let's just call the default implementation.
20 std.log.defaultLog(level, scope, format, args);
21}
22
23const std = @import("std");
24
25// syntax
doc/langref/test_illegal_behavior.zig created+5
......@@ -0,0 +1,5 @@
1test "safety check" {
2 unreachable;
3}
4
5// test_error=reached unreachable code
doc/langref/test_setRuntimeSafety_builtin.zig+2-2
......@@ -2,7 +2,7 @@ test "@setRuntimeSafety" {
22 // The builtin applies to the scope that it is called in. So here, integer overflow
33 // will not be caught in ReleaseFast and ReleaseSmall modes:
44 // var x: u8 = 255;
5 // x += 1; // undefined behavior in ReleaseFast/ReleaseSmall modes.
5 // x += 1; // Unchecked Illegal Behavior in ReleaseFast/ReleaseSmall modes.
66 {
77 // However this block has safety enabled, so safety checks happen here,
88 // even in ReleaseFast and ReleaseSmall modes.
......@@ -15,7 +15,7 @@ test "@setRuntimeSafety" {
1515 // would not be caught in any build mode.
1616 @setRuntimeSafety(false);
1717 // var x: u8 = 255;
18 // x += 1; // undefined behavior in all build modes.
18 // x += 1; // Unchecked Illegal Behavior in all build modes.
1919 }
2020 }
2121}
doc/langref/test_undefined_behavior.zig deleted-5
......@@ -1,5 +0,0 @@
1test "safety check" {
2 unreachable;
3}
4
5// test_error=reached unreachable code