@@ -1651,7 +1651,7 @@ fn foo(bytes: []u8) u32 {
16511651 <pre><code class="zig">@ptrCast(*u32, f32(12.34)).*</code></pre>
16521652 <p>Instead, use {#link|@bitCast#}:
16531653 <pre><code class="zig">@bitCast(u32, f32(12.34))</code></pre>
1654- <p>As an added benefit, the <code>@bitcast </code> version works at compile-time.</p>
1654+ <p>As an added benefit, the <code>@bitCast </code> version works at compile-time.</p>
16551655 {#see_also|Slices|Memory#}
16561656 {#header_close#}
16571657 {#header_close#}
@@ -3551,13 +3551,91 @@ const optional_value: ?i32 = null;
35513551 <p>TODO: ptrcast builtin</p>
35523552 <p>TODO: explain number literals vs concrete types</p>
35533553 {#header_close#}
3554+
35543555 {#header_open|void#}
3555- <p>TODO: assigning void has no codegen</p>
3556- <p>TODO: hashmap with void becomes a set</p>
3557- <p>TODO: difference between c_void and void</p>
3558- <p>TODO: void is the default return value of functions</p>
3559- <p>TODO: functions require assigning the return value</p>
3556+ <p>
3557+ <code>void</code> represents a type that has no value. Code that makes use of void values is
3558+ not included in the final generated code:
3559+ </p>
3560+ {#code_begin|syntax#}
3561+ export fn entry() void {
3562+ var x: void = {};
3563+ var y: void = {};
3564+ x = y;
3565+ }
3566+ {#code_end#}
3567+ <p>When this turns into LLVM IR, there is no code generated in the body of <code>entry</code>,
3568+ even in debug mode. For example, on x86_64:</p>
3569+ <pre><code>0000000000000010 <entry>:
3570+ 10: 55 push %rbp
3571+ 11: 48 89 e5 mov %rsp,%rbp
3572+ 14: 5d pop %rbp
3573+ 15: c3 retq </code></pre>
3574+ <p>These assembly instructions do not have any code associated with the void values -
3575+ they only perform the function call prologue and epilog.</p>
3576+ <p>
3577+ <code>void</code> can be useful for instantiating generic types. For example, given a
3578+ <code>Map(Key, Value)</code>, one can pass <code>void</code> for the <code>Value</code>
3579+ type to make it into a <code>Set</code>:
3580+ </p>
3581+ {#code_begin|test#}
3582+ const std = @import("std");
3583+ const assert = std.debug.assert;
3584+
3585+ test "turn HashMap into a set with void" {
3586+ var map = std.HashMap(i32, void, hash_i32, eql_i32).init(std.debug.global_allocator);
3587+ defer map.deinit();
3588+
3589+ _ = try map.put(1, {});
3590+ _ = try map.put(2, {});
3591+
3592+ assert(map.contains(2));
3593+ assert(!map.contains(3));
3594+
3595+ _ = map.remove(2);
3596+ assert(!map.contains(2));
3597+ }
3598+
3599+ fn hash_i32(x: i32) u32 {
3600+ return @bitCast(u32, x);
3601+ }
3602+
3603+ fn eql_i32(a: i32, b: i32) bool {
3604+ return a == b;
3605+ }
3606+ {#code_end#}
3607+ <p>Note that this is different than using a dummy value for the hash map value.
3608+ By using <code>void</code> as the type of the value, the hash map entry type has no value field, and
3609+ thus the hash map takes up less space. Further, all the code that deals with storing and loading the
3610+ value is deleted, as seen above.
3611+ </p>
3612+ <p>
3613+ <code>void</code> is distinct from <code>c_void</code>, which is defined like this:
3614+ <code>pub const c_void = @OpaqueType();</code>.
3615+ <code>void</code> has a known size of 0 bytes, and <code>c_void</code> has an unknown, but non-zero, size.
3616+ </p>
3617+ <p>
3618+ Expressions of type <code>void</code> are the only ones whose value can be ignored. For example:
3619+ </p>
3620+ {#code_begin|test_err|expression value is ignored#}
3621+ test "ignoring expression value" {
3622+ foo();
3623+ }
3624+
3625+ fn foo() i32 {
3626+ return 1234;
3627+ }
3628+ {#code_end#}
3629+ <p>However, if the expression has type <code>void</code>:</p>
3630+ {#code_begin|test#}
3631+ test "ignoring expression value" {
3632+ foo();
3633+ }
3634+
3635+ fn foo() void {}
3636+ {#code_end#}
35603637 {#header_close#}
3638+
35613639 {#header_open|this#}
35623640 <p>TODO: example of this referring to Self struct</p>
35633641 <p>TODO: example of this referring to recursion function</p>
0 commit comments