mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
langref: embrace the term "illegal behavior"
Also standardise the terms "safety-checked" and "unchecked".
This commit is contained in:
parent
def7e2f20a
commit
f0b331e95a
3 changed files with 66 additions and 50 deletions
|
|
@ -1049,12 +1049,12 @@
|
|||
{#header_close#}
|
||||
{#header_open|Runtime Integer Values#}
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
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#}.
|
||||
</p>
|
||||
{#code|runtime_vs_comptime.zig#}
|
||||
|
||||
|
|
@ -1064,7 +1064,7 @@
|
|||
{#link|Division by Zero#}.
|
||||
</p>
|
||||
<p>
|
||||
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
|
|||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
{#code|test_slice_bounds.zig#}
|
||||
|
|
@ -2048,7 +2048,7 @@ or
|
|||
|
||||
<p>
|
||||
{#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
|
|||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
{#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#}:
|
||||
</p>
|
||||
{#code|test_wrong_union_access.zig#}
|
||||
|
||||
|
|
@ -3023,11 +3023,11 @@ or
|
|||
{#syntax#}const number = parseU64("1234", 10) catch unreachable;{#endsyntax#}
|
||||
<p>
|
||||
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 <em>was</em> 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 <em>was</em> a surprise error here, the application
|
||||
would crash appropriately.
|
||||
</p>
|
||||
<p>
|
||||
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 {
|
|||
</p>
|
||||
<p>
|
||||
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?
|
||||
</p>
|
||||
{#code|fibonacci_comptime_infinite_recursion.zig#}
|
||||
|
|
@ -4239,7 +4239,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
|
|||
</p>
|
||||
<p>
|
||||
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#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
|
@ -4805,7 +4805,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
Attempting 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.
|
||||
|
|
@ -4824,7 +4824,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
Attempting to convert an integer that does not correspond to any error results in
|
||||
safety-protected {#link|Undefined Behavior#}.
|
||||
safety-checked {#link|Illegal Behavior#}.
|
||||
</p>
|
||||
{#see_also|@intFromError#}
|
||||
{#header_close#}
|
||||
|
|
@ -4856,7 +4856,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
<p>
|
||||
Converts 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#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
|
@ -4912,7 +4912,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
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#}.
|
||||
the result type, and the result type has ill-defined layout, invokes unchecked {#link|Illegal Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
|
@ -5029,7 +5029,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#}.
|
||||
</p>
|
||||
{#code|test_intCast_builtin.zig#}
|
||||
|
||||
|
|
@ -5090,7 +5090,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
If 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#}.
|
||||
</p>
|
||||
{#see_also|@floatFromInt#}
|
||||
{#header_close#}
|
||||
|
|
@ -5250,7 +5250,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
<p>
|
||||
The {#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.
|
||||
</p>
|
||||
<p>{#syntax#}PrefetchOptions{#endsyntax#} can be found with {#syntax#}@import("std").builtin.PrefetchOptions{#endsyntax#}.</p>
|
||||
{#header_close#}
|
||||
|
|
@ -5262,7 +5262,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
{#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#}.
|
||||
</p>
|
||||
<p>
|
||||
{#syntax#}@ptrCast{#endsyntax#} cannot be used for:
|
||||
|
|
@ -5286,7 +5286,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
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#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
|
@ -5361,8 +5361,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
<li>
|
||||
{#syntax#}Optimized{#endsyntax#} - Floating point operations may do all of the following:
|
||||
<ul>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<li>Treat the sign of a zero argument or result as insignificant.</li>
|
||||
<li>Use the reciprocal of an argument rather than perform division.</li>
|
||||
<li>Perform floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-add).</li>
|
||||
|
|
@ -5401,7 +5401,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
The 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#}.
|
||||
</p>
|
||||
<p>
|
||||
{#syntax#}comptime_int{#endsyntax#} is modeled as an integer with an infinite number of bits,
|
||||
|
|
@ -5418,7 +5418,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
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#}.
|
||||
</p>
|
||||
{#see_also|@shlExact|@shrExact#}
|
||||
{#header_close#}
|
||||
|
|
@ -5431,7 +5431,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</p>
|
||||
<p>
|
||||
The 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#}.
|
||||
</p>
|
||||
{#see_also|@shlExact|@shlWithOverflow#}
|
||||
{#header_close#}
|
||||
|
|
@ -5706,7 +5706,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
{#header_open|@tagName#}
|
||||
<pre>{#syntax#}@tagName(value: anytype) [:0]const u8{#endsyntax#}</pre>
|
||||
<p>
|
||||
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#}.
|
||||
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#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
|
@ -5943,7 +5943,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
<li>Reproducible build</li>
|
||||
</ul>
|
||||
{#header_close#}
|
||||
{#see_also|Compile Variables|Zig Build System|Undefined Behavior#}
|
||||
{#see_also|Compile Variables|Zig Build System|Illegal Behavior#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Single Threaded Builds#}
|
||||
|
|
@ -5958,20 +5958,36 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
</ul>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Undefined Behavior#}
|
||||
{#header_open|Illegal Behavior#}
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
When a safety check fails, Zig crashes with a stack trace, like this:
|
||||
Some Illegal Behavior is <em>safety-checked</em>: 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.
|
||||
</p>
|
||||
{#code|test_undefined_behavior.zig#}
|
||||
<p>
|
||||
All other Illegal Behavior is <em>unchecked</em>, 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.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
When a safety check fails, Zig's default panic handler crashes with a stack trace, like this:
|
||||
</p>
|
||||
{#code|test_illegal_behavior.zig#}
|
||||
|
||||
{#header_open|Reaching Unreachable Code#}
|
||||
<p>At compile-time:</p>
|
||||
|
|
@ -6337,7 +6353,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||
<p>
|
||||
{#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#}.
|
||||
</p>
|
||||
<p>
|
||||
{#syntax#}var{#endsyntax#} declarations at the top level or in {#link|struct#} declarations are stored in the global
|
||||
|
|
@ -6445,7 +6461,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).
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
|
@ -6733,10 +6749,10 @@ int foo(void) {
|
|||
<li>Supports all the syntax of the other two pointer types ({#syntax#}*T{#endsyntax#}) and ({#syntax#}[*]T{#endsyntax#}).</li>
|
||||
<li>Coerces to other pointer types, as well as {#link|Optional Pointers#}.
|
||||
When a C pointer is coerced to a non-optional pointer, safety-checked
|
||||
{#link|Undefined Behavior#} occurs if the address is 0.
|
||||
{#link|Illegal Behavior#} occurs if the address is 0.
|
||||
</li>
|
||||
<li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
|
||||
{#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
|
||||
{#link|Illegal Behavior#}. Optional C pointers introduce another bit to keep track of
|
||||
null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
|
||||
is unnecessary as one can use normal {#link|Optional Pointers#}.
|
||||
</li>
|
||||
|
|
@ -7051,8 +7067,8 @@ fn readU32Be() u32 {}
|
|||
<ul>
|
||||
<li>Omit any information that is redundant based on the name of the thing being documented.</li>
|
||||
<li>Duplicating information onto multiple similar functions is encouraged because it helps IDEs and other tools provide better help text.</li>
|
||||
<li>Use the word <strong>assume</strong> to indicate invariants that cause {#link|Undefined Behavior#} when violated.</li>
|
||||
<li>Use the word <strong>assert</strong> to indicate invariants that cause <em>safety-checked</em> {#link|Undefined Behavior#} when violated.</li>
|
||||
<li>Use the word <strong>assume</strong> to indicate invariants that cause <em>unchecked</em> {#link|Illegal Behavior#} when violated.</li>
|
||||
<li>Use the word <strong>assert</strong> to indicate invariants that cause <em>safety-checked</em> {#link|Illegal Behavior#} when violated.</li>
|
||||
</ul>
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
|
|
@ -7448,8 +7464,8 @@ fn readU32Be() u32 {}
|
|||
In particular, inside a {#syntax#}nosuspend{#endsyntax#} scope:
|
||||
<ul>
|
||||
<li>Using the {#syntax#}suspend{#endsyntax#} keyword results in a compile error.</li>
|
||||
<li>Using {#syntax#}await{#endsyntax#} on a function frame which hasn't completed yet results in safety-checked {#link|Undefined Behavior#}.</li>
|
||||
<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>
|
||||
<li>Using {#syntax#}await{#endsyntax#} on a function frame which hasn't completed yet results in safety-checked {#link|Illegal Behavior#}.</li>
|
||||
<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>
|
||||
</ul>
|
||||
Code inside a {#syntax#}nosuspend{#endsyntax#} scope does not cause the enclosing function to become an {#link|async function|Async Functions#}.
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ test "@setRuntimeSafety" {
|
|||
// The builtin applies to the scope that it is called in. So here, integer overflow
|
||||
// will not be caught in ReleaseFast and ReleaseSmall modes:
|
||||
// var x: u8 = 255;
|
||||
// x += 1; // undefined behavior in ReleaseFast/ReleaseSmall modes.
|
||||
// x += 1; // Unchecked Illegal Behavior in ReleaseFast/ReleaseSmall modes.
|
||||
{
|
||||
// However this block has safety enabled, so safety checks happen here,
|
||||
// even in ReleaseFast and ReleaseSmall modes.
|
||||
|
|
@ -15,7 +15,7 @@ test "@setRuntimeSafety" {
|
|||
// would not be caught in any build mode.
|
||||
@setRuntimeSafety(false);
|
||||
// var x: u8 = 255;
|
||||
// x += 1; // undefined behavior in all build modes.
|
||||
// x += 1; // Unchecked Illegal Behavior in all build modes.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue