authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-04 08:24:56-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-04 08:24:56-05:00
log0714e19598e91f457d3d0119856fd7a24dd4f150
tree07b65f462477aea604d6b76eb0ab930c03d5c92e
parent99b6429a89cda26305bde2c73eecc33eff022cb8
parent9c5852aa8674320d2912627708f32fea37d7cd08
signaturelock-open Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into llvm8


256 files changed, 16974 insertions(+), 16761 deletions(-)

.builds/freebsd.yml+8-8
...@@ -13,28 +13,28 @@ tasks:...@@ -13,28 +13,28 @@ tasks:
13 - test: |13 - test: |
14 cd zig/build14 cd zig/build
15 bin/zig test ../test/stage1/behavior.zig15 bin/zig test ../test/stage1/behavior.zig
16 bin/zig test ../std/special/compiler_rt/index.zig16 bin/zig test ../std/special/compiler_rt.zig
1717
18 bin/zig test ../test/stage1/behavior.zig --library c18 bin/zig test ../test/stage1/behavior.zig --library c
19 bin/zig test ../std/special/compiler_rt/index.zig --library c19 bin/zig test ../std/special/compiler_rt.zig --library c
2020
21 bin/zig test ../test/stage1/behavior.zig --release-fast21 bin/zig test ../test/stage1/behavior.zig --release-fast
22 bin/zig test ../std/special/compiler_rt/index.zig --release-fast22 bin/zig test ../std/special/compiler_rt.zig --release-fast
2323
24 bin/zig test ../test/stage1/behavior.zig --release-fast --library c24 bin/zig test ../test/stage1/behavior.zig --release-fast --library c
25 bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c25 bin/zig test ../std/special/compiler_rt.zig --release-fast --library c
2626
27 bin/zig test ../test/stage1/behavior.zig --release-small --library c27 bin/zig test ../test/stage1/behavior.zig --release-small --library c
28 bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c28 bin/zig test ../std/special/compiler_rt.zig --release-small --library c
2929
30 bin/zig test ../test/stage1/behavior.zig --release-small30 bin/zig test ../test/stage1/behavior.zig --release-small
31 bin/zig test ../std/special/compiler_rt/index.zig --release-small31 bin/zig test ../std/special/compiler_rt.zig --release-small
3232
33 bin/zig test ../test/stage1/behavior.zig --release-safe33 bin/zig test ../test/stage1/behavior.zig --release-safe
34 bin/zig test ../std/special/compiler_rt/index.zig --release-safe34 bin/zig test ../std/special/compiler_rt.zig --release-safe
3535
36 bin/zig test ../test/stage1/behavior.zig --release-safe --library c36 bin/zig test ../test/stage1/behavior.zig --release-safe --library c
37 bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c37 bin/zig test ../std/special/compiler_rt.zig --release-safe --library c
38 # TODO enable all tests38 # TODO enable all tests
39 #bin/zig build --build-file ../build.zig test39 #bin/zig build --build-file ../build.zig test
40 # TODO integrate with the download page updater and make a40 # TODO integrate with the download page updater and make a
CMakeLists.txt+21-21
...@@ -442,7 +442,7 @@ set(ZIG_CPP_SOURCES...@@ -442,7 +442,7 @@ set(ZIG_CPP_SOURCES
442442
443set(ZIG_STD_FILES443set(ZIG_STD_FILES
444 "array_list.zig"444 "array_list.zig"
445 "atomic/index.zig"445 "atomic.zig"
446 "atomic/int.zig"446 "atomic/int.zig"
447 "atomic/queue.zig"447 "atomic/queue.zig"
448 "atomic/stack.zig"448 "atomic/stack.zig"
...@@ -452,17 +452,17 @@ set(ZIG_STD_FILES...@@ -452,17 +452,17 @@ set(ZIG_STD_FILES
452 "buffer.zig"452 "buffer.zig"
453 "build.zig"453 "build.zig"
454 "build/fmt.zig"454 "build/fmt.zig"
455 "c.zig"
455 "c/darwin.zig"456 "c/darwin.zig"
456 "c/freebsd.zig"457 "c/freebsd.zig"
457 "c/index.zig"
458 "c/linux.zig"458 "c/linux.zig"
459 "c/netbsd.zig"459 "c/netbsd.zig"
460 "c/windows.zig"460 "c/windows.zig"
461 "coff.zig"461 "coff.zig"
462 "crypto.zig"
462 "crypto/blake2.zig"463 "crypto/blake2.zig"
463 "crypto/chacha20.zig"464 "crypto/chacha20.zig"
464 "crypto/hmac.zig"465 "crypto/hmac.zig"
465 "crypto/index.zig"
466 "crypto/md5.zig"466 "crypto/md5.zig"
467 "crypto/poly1305.zig"467 "crypto/poly1305.zig"
468 "crypto/sha1.zig"468 "crypto/sha1.zig"
...@@ -470,8 +470,8 @@ set(ZIG_STD_FILES...@@ -470,8 +470,8 @@ set(ZIG_STD_FILES
470 "crypto/sha3.zig"470 "crypto/sha3.zig"
471 "crypto/x25519.zig"471 "crypto/x25519.zig"
472 "cstr.zig"472 "cstr.zig"
473 "debug.zig"
473 "debug/failing_allocator.zig"474 "debug/failing_allocator.zig"
474 "debug/index.zig"
475 "dwarf.zig"475 "dwarf.zig"
476 "dynamic_library.zig"476 "dynamic_library.zig"
477 "elf.zig"477 "elf.zig"
...@@ -488,25 +488,25 @@ set(ZIG_STD_FILES...@@ -488,25 +488,25 @@ set(ZIG_STD_FILES
488 "event/net.zig"488 "event/net.zig"
489 "event/rwlock.zig"489 "event/rwlock.zig"
490 "event/rwlocked.zig"490 "event/rwlocked.zig"
491 "fmt.zig"
492 "fmt/errol.zig"
491 "fmt/errol/enum3.zig"493 "fmt/errol/enum3.zig"
492 "fmt/errol/index.zig"
493 "fmt/errol/lookup.zig"494 "fmt/errol/lookup.zig"
494 "fmt/index.zig"
495 "fmt/parse_float.zig"495 "fmt/parse_float.zig"
496 "hash.zig"
496 "hash/adler.zig"497 "hash/adler.zig"
497 "hash/crc.zig"498 "hash/crc.zig"
498 "hash/fnv.zig"499 "hash/fnv.zig"
499 "hash/index.zig"
500 "hash/siphash.zig"500 "hash/siphash.zig"
501 "hash_map.zig"501 "hash_map.zig"
502 "heap.zig"502 "heap.zig"
503 "index.zig"
504 "io.zig"503 "io.zig"
505 "io/seekable_stream.zig"504 "io/seekable_stream.zig"
506 "json.zig"505 "json.zig"
507 "lazy_init.zig"506 "lazy_init.zig"
508 "linked_list.zig"507 "linked_list.zig"
509 "macho.zig"508 "macho.zig"
509 "math.zig"
510 "math/acos.zig"510 "math/acos.zig"
511 "math/acosh.zig"511 "math/acosh.zig"
512 "math/asin.zig"512 "math/asin.zig"
...@@ -514,10 +514,11 @@ set(ZIG_STD_FILES...@@ -514,10 +514,11 @@ set(ZIG_STD_FILES
514 "math/atan.zig"514 "math/atan.zig"
515 "math/atan2.zig"515 "math/atan2.zig"
516 "math/atanh.zig"516 "math/atanh.zig"
517 "math/big/index.zig"517 "math/big.zig"
518 "math/big/int.zig"518 "math/big/int.zig"
519 "math/cbrt.zig"519 "math/cbrt.zig"
520 "math/ceil.zig"520 "math/ceil.zig"
521 "math/complex.zig"
521 "math/complex/abs.zig"522 "math/complex/abs.zig"
522 "math/complex/acos.zig"523 "math/complex/acos.zig"
523 "math/complex/acosh.zig"524 "math/complex/acosh.zig"
...@@ -530,7 +531,6 @@ set(ZIG_STD_FILES...@@ -530,7 +531,6 @@ set(ZIG_STD_FILES
530 "math/complex/cos.zig"531 "math/complex/cos.zig"
531 "math/complex/cosh.zig"532 "math/complex/cosh.zig"
532 "math/complex/exp.zig"533 "math/complex/exp.zig"
533 "math/complex/index.zig"
534 "math/complex/ldexp.zig"534 "math/complex/ldexp.zig"
535 "math/complex/log.zig"535 "math/complex/log.zig"
536 "math/complex/pow.zig"536 "math/complex/pow.zig"
...@@ -553,7 +553,6 @@ set(ZIG_STD_FILES...@@ -553,7 +553,6 @@ set(ZIG_STD_FILES
553 "math/frexp.zig"553 "math/frexp.zig"
554 "math/hypot.zig"554 "math/hypot.zig"
555 "math/ilogb.zig"555 "math/ilogb.zig"
556 "math/index.zig"
557 "math/inf.zig"556 "math/inf.zig"
558 "math/isfinite.zig"557 "math/isfinite.zig"
559 "math/isinf.zig"558 "math/isinf.zig"
...@@ -578,50 +577,51 @@ set(ZIG_STD_FILES...@@ -578,50 +577,51 @@ set(ZIG_STD_FILES
578 "math/tanh.zig"577 "math/tanh.zig"
579 "math/trunc.zig"578 "math/trunc.zig"
580 "mem.zig"579 "mem.zig"
581 "meta/index.zig"580 "meta.zig"
582 "meta/trait.zig"581 "meta/trait.zig"
583 "mutex.zig"582 "mutex.zig"
584 "net.zig"583 "net.zig"
584 "os.zig"
585 "os/child_process.zig"585 "os/child_process.zig"
586 "os/darwin.zig"586 "os/darwin.zig"
587 "os/darwin/errno.zig"587 "os/darwin/errno.zig"
588 "os/epoch.zig"588 "os/epoch.zig"
589 "os/file.zig"589 "os/file.zig"
590 "os/freebsd.zig"
590 "os/freebsd/errno.zig"591 "os/freebsd/errno.zig"
591 "os/freebsd/index.zig"
592 "os/get_app_data_dir.zig"592 "os/get_app_data_dir.zig"
593 "os/get_user_id.zig"593 "os/get_user_id.zig"
594 "os/index.zig"594 "os/linux.zig"
595 "os/linux/arm64.zig"595 "os/linux/arm64.zig"
596 "os/linux/errno.zig"596 "os/linux/errno.zig"
597 "os/linux/index.zig"
598 "os/linux/vdso.zig"597 "os/linux/vdso.zig"
599 "os/linux/x86_64.zig"598 "os/linux/x86_64.zig"
599 "os/netbsd.zig"
600 "os/netbsd/errno.zig"600 "os/netbsd/errno.zig"
601 "os/netbsd/index.zig"
602 "os/path.zig"601 "os/path.zig"
603 "os/time.zig"602 "os/time.zig"
604 "os/uefi.zig"603 "os/uefi.zig"
604 "os/windows.zig"
605 "os/windows/advapi32.zig"605 "os/windows/advapi32.zig"
606 "os/windows/error.zig"606 "os/windows/error.zig"
607 "os/windows/index.zig"
608 "os/windows/kernel32.zig"607 "os/windows/kernel32.zig"
609 "os/windows/ntdll.zig"608 "os/windows/ntdll.zig"
610 "os/windows/ole32.zig"609 "os/windows/ole32.zig"
611 "os/windows/shell32.zig"610 "os/windows/shell32.zig"
612 "os/windows/tls.zig"
613 "os/windows/util.zig"611 "os/windows/util.zig"
614 "os/zen.zig"612 "os/zen.zig"
615 "pdb.zig"613 "pdb.zig"
616 "priority_queue.zig"614 "priority_queue.zig"
617 "rand/index.zig"615 "rand.zig"
618 "rand/ziggurat.zig"616 "rand/ziggurat.zig"
619 "segmented_list.zig"617 "segmented_list.zig"
620 "sort.zig"618 "sort.zig"
621 "special/bootstrap.zig"619 "special/bootstrap.zig"
622 "special/bootstrap_lib.zig"620 "special/bootstrap_lib.zig"
621 "special/bootstrap_windows_tls.zig"
623 "special/build_runner.zig"622 "special/build_runner.zig"
624 "special/builtin.zig"623 "special/builtin.zig"
624 "special/compiler_rt.zig"
625 "special/compiler_rt/addXf3.zig"625 "special/compiler_rt/addXf3.zig"
626 "special/compiler_rt/aulldiv.zig"626 "special/compiler_rt/aulldiv.zig"
627 "special/compiler_rt/aullrem.zig"627 "special/compiler_rt/aullrem.zig"
...@@ -656,7 +656,6 @@ set(ZIG_STD_FILES...@@ -656,7 +656,6 @@ set(ZIG_STD_FILES
656 "special/compiler_rt/floatuntidf.zig"656 "special/compiler_rt/floatuntidf.zig"
657 "special/compiler_rt/floatuntisf.zig"657 "special/compiler_rt/floatuntisf.zig"
658 "special/compiler_rt/floatuntitf.zig"658 "special/compiler_rt/floatuntitf.zig"
659 "special/compiler_rt/index.zig"
660 "special/compiler_rt/muloti4.zig"659 "special/compiler_rt/muloti4.zig"
661 "special/compiler_rt/multi3.zig"660 "special/compiler_rt/multi3.zig"
662 "special/compiler_rt/truncXfYf2.zig"661 "special/compiler_rt/truncXfYf2.zig"
...@@ -674,10 +673,11 @@ set(ZIG_STD_FILES...@@ -674,10 +673,11 @@ set(ZIG_STD_FILES
674 "special/test_runner.zig"673 "special/test_runner.zig"
675 "spinlock.zig"674 "spinlock.zig"
676 "statically_initialized_mutex.zig"675 "statically_initialized_mutex.zig"
676 "std.zig"
677 "testing.zig"677 "testing.zig"
678 "unicode.zig"678 "unicode.zig"
679 "zig.zig"
679 "zig/ast.zig"680 "zig/ast.zig"
680 "zig/index.zig"
681 "zig/parse.zig"681 "zig/parse.zig"
682 "zig/parse_string_literal.zig"682 "zig/parse_string_literal.zig"
683 "zig/render.zig"683 "zig/render.zig"
build.zig+2-2
...@@ -115,9 +115,9 @@ pub fn build(b: *Builder) !void {...@@ -115,9 +115,9 @@ pub fn build(b: *Builder) !void {
115115
116 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));116 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
117117
118 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));118 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes));
119119
120 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", modes));120 test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes));
121121
122 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));122 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
123 test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes));123 test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes));
doc/langref.html.in+27-23
...@@ -6116,7 +6116,7 @@ test "main" {...@@ -6116,7 +6116,7 @@ test "main" {
6116 {#header_close#}6116 {#header_close#}
61176117
6118 {#header_open|@frameAddress#}6118 {#header_open|@frameAddress#}
6119 <pre>{#syntax#}@frameAddress(){#endsyntax#}</pre>6119 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>
6120 <p>6120 <p>
6121 This function returns the base pointer of the current stack frame.6121 This function returns the base pointer of the current stack frame.
6122 </p>6122 </p>
...@@ -6482,17 +6482,18 @@ test "call foo" {...@@ -6482,17 +6482,18 @@ test "call foo" {
6482 {#header_close#}6482 {#header_close#}
64836483
6484 {#header_open|@returnAddress#}6484 {#header_open|@returnAddress#}
6485 <pre>{#syntax#}@returnAddress(){#endsyntax#}</pre>6485 <pre>{#syntax#}@returnAddress() usize{#endsyntax#}</pre>
6486 <p>6486 <p>
6487 This function returns a pointer to the return address of the current stack6487 This function returns the address of the next machine code instruction that will be executed
6488 frame.6488 when the current function returns.
6489 </p>6489 </p>
6490 <p>6490 <p>
6491 The implications of this are target specific and not consistent across6491 The implications of this are target specific and not consistent across
6492 all platforms.6492 all platforms.
6493 </p>6493 </p>
6494 <p>6494 <p>
6495 This function is only valid within function scope.6495 This function is only valid within function scope. If the function gets inlined into
6496 a calling function, the returned address will apply to the calling function.
6496 </p>6497 </p>
6497 {#header_close#}6498 {#header_close#}
6498 {#header_open|@setAlignStack#}6499 {#header_open|@setAlignStack#}
...@@ -6785,7 +6786,6 @@ pub const TypeId = enum {...@@ -6785,7 +6786,6 @@ pub const TypeId = enum {
6785 Enum,6786 Enum,
6786 Union,6787 Union,
6787 Fn,6788 Fn,
6788 Namespace,
6789 Block,6789 Block,
6790 BoundFn,6790 BoundFn,
6791 ArgTuple,6791 ArgTuple,
...@@ -6820,7 +6820,6 @@ pub const TypeInfo = union(TypeId) {...@@ -6820,7 +6820,6 @@ pub const TypeInfo = union(TypeId) {
6820 Enum: Enum,6820 Enum: Enum,
6821 Union: Union,6821 Union: Union,
6822 Fn: Fn,6822 Fn: Fn,
6823 Namespace: void,
6824 BoundFn: Fn,6823 BoundFn: Fn,
6825 ArgTuple: void,6824 ArgTuple: void,
6826 Opaque: void,6825 Opaque: void,
...@@ -6829,18 +6828,18 @@ pub const TypeInfo = union(TypeId) {...@@ -6829,18 +6828,18 @@ pub const TypeInfo = union(TypeId) {
68296828
6830 pub const Int = struct {6829 pub const Int = struct {
6831 is_signed: bool,6830 is_signed: bool,
6832 bits: u8,6831 bits: comptime_int,
6833 };6832 };
68346833
6835 pub const Float = struct {6834 pub const Float = struct {
6836 bits: u8,6835 bits: comptime_int,
6837 };6836 };
68386837
6839 pub const Pointer = struct {6838 pub const Pointer = struct {
6840 size: Size,6839 size: Size,
6841 is_const: bool,6840 is_const: bool,
6842 is_volatile: bool,6841 is_volatile: bool,
6843 alignment: u32,6842 alignment: comptime_int,
6844 child: type,6843 child: type,
68456844
6846 pub const Size = enum {6845 pub const Size = enum {
...@@ -6851,7 +6850,7 @@ pub const TypeInfo = union(TypeId) {...@@ -6851,7 +6850,7 @@ pub const TypeInfo = union(TypeId) {
6851 };6850 };
68526851
6853 pub const Array = struct {6852 pub const Array = struct {
6854 len: usize,6853 len: comptime_int,
6855 child: type,6854 child: type,
6856 };6855 };
68576856
...@@ -6863,7 +6862,7 @@ pub const TypeInfo = union(TypeId) {...@@ -6863,7 +6862,7 @@ pub const TypeInfo = union(TypeId) {
68636862
6864 pub const StructField = struct {6863 pub const StructField = struct {
6865 name: []const u8,6864 name: []const u8,
6866 offset: ?usize,6865 offset: ?comptime_int,
6867 field_type: type,6866 field_type: type,
6868 };6867 };
68696868
...@@ -6884,7 +6883,7 @@ pub const TypeInfo = union(TypeId) {...@@ -6884,7 +6883,7 @@ pub const TypeInfo = union(TypeId) {
68846883
6885 pub const Error = struct {6884 pub const Error = struct {
6886 name: []const u8,6885 name: []const u8,
6887 value: usize,6886 value: comptime_int,
6888 };6887 };
68896888
6890 pub const ErrorSet = struct {6889 pub const ErrorSet = struct {
...@@ -6893,7 +6892,7 @@ pub const TypeInfo = union(TypeId) {...@@ -6893,7 +6892,7 @@ pub const TypeInfo = union(TypeId) {
68936892
6894 pub const EnumField = struct {6893 pub const EnumField = struct {
6895 name: []const u8,6894 name: []const u8,
6896 value: usize,6895 value: comptime_int,
6897 };6896 };
68986897
6899 pub const Enum = struct {6898 pub const Enum = struct {
...@@ -8167,17 +8166,18 @@ coding style....@@ -8167,17 +8166,18 @@ coding style.
8167 </p>8166 </p>
8168 <ul>8167 <ul>
8169 <li>8168 <li>
8170 If {#syntax#}x{#endsyntax#} is a {#syntax#}struct{#endsyntax#} (or an alias of a {#syntax#}struct{#endsyntax#}),8169 If {#syntax#}x{#endsyntax#} is a {#syntax#}type{#endsyntax#}
8171 then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.8170 then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}, unless it
8172 </li>8171 is a {#syntax#}struct{#endsyntax#} with 0 fields and is never meant to be instantiated,
8173 <li>8172 in which case it is considered to be a "namespace" and uses {#syntax#}snake_case{#endsyntax#}.
8174 If {#syntax#}x{#endsyntax#} otherwise identifies a type, {#syntax#}x{#endsyntax#} should have {#syntax#}snake_case{#endsyntax#}.
8175 </li>8173 </li>
8176 <li>8174 <li>
8177 If {#syntax#}x{#endsyntax#} is callable, and {#syntax#}x{#endsyntax#}'s return type is {#syntax#}type{#endsyntax#}, then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.8175 If {#syntax#}x{#endsyntax#} is callable, and {#syntax#}x{#endsyntax#}'s return type is
8176 {#syntax#}type{#endsyntax#}, then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.
8178 </li>8177 </li>
8179 <li>8178 <li>
8180 If {#syntax#}x{#endsyntax#} is otherwise callable, then {#syntax#}x{#endsyntax#} should be {#syntax#}camelCase{#endsyntax#}.8179 If {#syntax#}x{#endsyntax#} is otherwise callable, then {#syntax#}x{#endsyntax#} should
8180 be {#syntax#}camelCase{#endsyntax#}.
8181 </li>8181 </li>
8182 <li>8182 <li>
8183 Otherwise, {#syntax#}x{#endsyntax#} should be {#syntax#}snake_case{#endsyntax#}.8183 Otherwise, {#syntax#}x{#endsyntax#} should be {#syntax#}snake_case{#endsyntax#}.
...@@ -8203,7 +8203,9 @@ const const_name = 42;...@@ -8203,7 +8203,9 @@ const const_name = 42;
8203const primitive_type_alias = f32;8203const primitive_type_alias = f32;
8204const string_alias = []u8;8204const string_alias = []u8;
82058205
8206const StructName = struct {};8206const StructName = struct {
8207 field: i32,
8208};
8207const StructAlias = StructName;8209const StructAlias = StructName;
82088210
8209fn functionName(param_name: TypeName) void {8211fn functionName(param_name: TypeName) void {
...@@ -8231,7 +8233,9 @@ const xml_document =...@@ -8231,7 +8233,9 @@ const xml_document =
8231 \\<document>8233 \\<document>
8232 \\</document>8234 \\</document>
8233;8235;
8234const XmlParser = struct {};8236const XmlParser = struct {
8237 field: i32,
8238};
82358239
8236// The initials BE (Big Endian) are just another word in Zig identifier names.8240// The initials BE (Big Endian) are just another word in Zig identifier names.
8237fn readU32Be() u32 {}8241fn readU32Be() u32 {}
src-self-hosted/compilation.zig+2-2
...@@ -47,7 +47,7 @@ pub const ZigCompiler = struct {...@@ -47,7 +47,7 @@ pub const ZigCompiler = struct {
4747
48 var lazy_init_targets = std.lazyInit(void);48 var lazy_init_targets = std.lazyInit(void);
4949
50 fn init(loop: *event.Loop) !ZigCompiler {50 pub fn init(loop: *event.Loop) !ZigCompiler {
51 lazy_init_targets.get() orelse {51 lazy_init_targets.get() orelse {
52 Target.initializeAll();52 Target.initializeAll();
53 lazy_init_targets.resolve();53 lazy_init_targets.resolve();
...@@ -533,7 +533,7 @@ pub const Compilation = struct {...@@ -533,7 +533,7 @@ pub const Compilation = struct {
533 const basename = std.os.path.basename(root_src);533 const basename = std.os.path.basename(root_src);
534534
535 comp.root_package = try Package.create(comp.arena(), dirname, basename);535 comp.root_package = try Package.create(comp.arena(), dirname, basename);
536 comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "index.zig");536 comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "std.zig");
537 try comp.root_package.add("std", comp.std_package);537 try comp.root_package.add("std", comp.std_package);
538 } else {538 } else {
539 comp.root_package = try Package.create(comp.arena(), ".", "");539 comp.root_package = try Package.create(comp.arena(), ".", "");
src-self-hosted/introspect.zig+1-1
...@@ -11,7 +11,7 @@ pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![...@@ -11,7 +11,7 @@ pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![
11 const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });11 const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });
12 errdefer allocator.free(test_zig_dir);12 errdefer allocator.free(test_zig_dir);
1313
14 const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "index.zig" });14 const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "std.zig" });
15 defer allocator.free(test_index_file);15 defer allocator.free(test_index_file);
1616
17 var file = try os.File.openRead(test_index_file);17 var file = try os.File.openRead(test_index_file);
src-self-hosted/type.zig-12
...@@ -39,7 +39,6 @@ pub const Type = struct {...@@ -39,7 +39,6 @@ pub const Type = struct {
39 Id.ErrorSet => @fieldParentPtr(ErrorSet, "base", base).destroy(comp),39 Id.ErrorSet => @fieldParentPtr(ErrorSet, "base", base).destroy(comp),
40 Id.Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),40 Id.Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),
41 Id.Union => @fieldParentPtr(Union, "base", base).destroy(comp),41 Id.Union => @fieldParentPtr(Union, "base", base).destroy(comp),
42 Id.Namespace => @fieldParentPtr(Namespace, "base", base).destroy(comp),
43 Id.BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),42 Id.BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),
44 Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),43 Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
45 Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),44 Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
...@@ -73,7 +72,6 @@ pub const Type = struct {...@@ -73,7 +72,6 @@ pub const Type = struct {
73 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),72 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
74 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),73 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
75 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),74 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
76 Id.Namespace => unreachable,
77 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),75 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
78 Id.ArgTuple => unreachable,76 Id.ArgTuple => unreachable,
79 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),77 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
...@@ -89,7 +87,6 @@ pub const Type = struct {...@@ -89,7 +87,6 @@ pub const Type = struct {
89 Id.ComptimeInt,87 Id.ComptimeInt,
90 Id.Undefined,88 Id.Undefined,
91 Id.Null,89 Id.Null,
92 Id.Namespace,
93 Id.BoundFn,90 Id.BoundFn,
94 Id.ArgTuple,91 Id.ArgTuple,
95 Id.Opaque,92 Id.Opaque,
...@@ -123,7 +120,6 @@ pub const Type = struct {...@@ -123,7 +120,6 @@ pub const Type = struct {
123 Id.ComptimeInt,120 Id.ComptimeInt,
124 Id.Undefined,121 Id.Undefined,
125 Id.Null,122 Id.Null,
126 Id.Namespace,
127 Id.BoundFn,123 Id.BoundFn,
128 Id.ArgTuple,124 Id.ArgTuple,
129 Id.Opaque,125 Id.Opaque,
...@@ -1020,14 +1016,6 @@ pub const Type = struct {...@@ -1020,14 +1016,6 @@ pub const Type = struct {
1020 }1016 }
1021 };1017 };
10221018
1023 pub const Namespace = struct {
1024 base: Type,
1025
1026 pub fn destroy(self: *Namespace, comp: *Compilation) void {
1027 comp.gpa().destroy(self);
1028 }
1029 };
1030
1031 pub const BoundFn = struct {1019 pub const BoundFn = struct {
1032 base: Type,1020 base: Type,
10331021
src/all_types.hpp+51-49
...@@ -21,7 +21,6 @@...@@ -21,7 +21,6 @@
21#include "libc_installation.hpp"21#include "libc_installation.hpp"
2222
23struct AstNode;23struct AstNode;
24struct ImportTableEntry;
25struct ZigFn;24struct ZigFn;
26struct Scope;25struct Scope;
27struct ScopeBlock;26struct ScopeBlock;
...@@ -317,7 +316,6 @@ struct ConstExprValue {...@@ -317,7 +316,6 @@ struct ConstExprValue {
317 ConstUnionValue x_union;316 ConstUnionValue x_union;
318 ConstArrayValue x_array;317 ConstArrayValue x_array;
319 ConstPtrValue x_ptr;318 ConstPtrValue x_ptr;
320 ImportTableEntry *x_import;
321 ConstArgTuple x_arg_tuple;319 ConstArgTuple x_arg_tuple;
322320
323 // populated if special == ConstValSpecialRuntime321 // populated if special == ConstValSpecialRuntime
...@@ -369,10 +367,8 @@ struct Tld {...@@ -369,10 +367,8 @@ struct Tld {
369 VisibMod visib_mod;367 VisibMod visib_mod;
370 AstNode *source_node;368 AstNode *source_node;
371369
372 ImportTableEntry *import;370 ZigType *import;
373 Scope *parent_scope;371 Scope *parent_scope;
374 // set this flag temporarily to detect infinite loops
375 bool dep_loop_flag;
376 TldResolution resolution;372 TldResolution resolution;
377};373};
378374
...@@ -382,6 +378,7 @@ struct TldVar {...@@ -382,6 +378,7 @@ struct TldVar {
382 ZigVar *var;378 ZigVar *var;
383 Buf *extern_lib_name;379 Buf *extern_lib_name;
384 Buf *section_name;380 Buf *section_name;
381 bool analyzing_type; // flag to detect dependency loops
385};382};
386383
387struct TldFn {384struct TldFn {
...@@ -700,7 +697,7 @@ struct AstNodeUse {...@@ -700,7 +697,7 @@ struct AstNodeUse {
700 AstNode *expr;697 AstNode *expr;
701698
702 TldResolution resolution;699 TldResolution resolution;
703 ConstExprValue *value;700 ConstExprValue *using_namespace_value;
704};701};
705702
706struct AstNodeIfBoolExpr {703struct AstNodeIfBoolExpr {
...@@ -937,7 +934,7 @@ struct AstNode {...@@ -937,7 +934,7 @@ struct AstNode {
937 enum NodeType type;934 enum NodeType type;
938 size_t line;935 size_t line;
939 size_t column;936 size_t column;
940 ImportTableEntry *owner;937 ZigType *owner;
941 union {938 union {
942 AstNodeFnDef fn_def;939 AstNodeFnDef fn_def;
943 AstNodeFnProto fn_proto;940 AstNodeFnProto fn_proto;
...@@ -1075,12 +1072,32 @@ enum ResolveStatus {...@@ -1075,12 +1072,32 @@ enum ResolveStatus {
1075 ResolveStatusSizeKnown,1072 ResolveStatusSizeKnown,
1076};1073};
10771074
1075struct ZigPackage {
1076 Buf root_src_dir;
1077 Buf root_src_path; // relative to root_src_dir
1078 Buf pkg_path; // a.b.c.d which follows the package dependency chain from the root package
1079
1080 // reminder: hash tables must be initialized before use
1081 HashMap<Buf *, ZigPackage *, buf_hash, buf_eql_buf> package_table;
1082};
1083
1084// Stuff that only applies to a struct which is the implicit root struct of a file
1085struct RootStruct {
1086 ZigPackage *package;
1087 Buf *path; // relative to root_package->root_src_dir
1088 ZigList<size_t> *line_offsets;
1089 Buf *source_code;
1090 AstNode *c_import_node;
1091 ZigLLVMDIFile *di_file;
1092};
1093
1078struct ZigTypeStruct {1094struct ZigTypeStruct {
1079 AstNode *decl_node;1095 AstNode *decl_node;
1080 TypeStructField *fields;1096 TypeStructField *fields;
1081 ScopeDecls *decls_scope;1097 ScopeDecls *decls_scope;
1082 uint64_t size_bytes;1098 uint64_t size_bytes;
1083 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;1099 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
1100 RootStruct *root_struct;
10841101
1085 uint32_t src_field_count;1102 uint32_t src_field_count;
1086 uint32_t gen_field_count;1103 uint32_t gen_field_count;
...@@ -1232,7 +1249,6 @@ enum ZigTypeId {...@@ -1232,7 +1249,6 @@ enum ZigTypeId {
1232 ZigTypeIdEnum,1249 ZigTypeIdEnum,
1233 ZigTypeIdUnion,1250 ZigTypeIdUnion,
1234 ZigTypeIdFn,1251 ZigTypeIdFn,
1235 ZigTypeIdNamespace,
1236 ZigTypeIdBoundFn,1252 ZigTypeIdBoundFn,
1237 ZigTypeIdArgTuple,1253 ZigTypeIdArgTuple,
1238 ZigTypeIdOpaque,1254 ZigTypeIdOpaque,
...@@ -1246,6 +1262,10 @@ enum OnePossibleValue {...@@ -1246,6 +1262,10 @@ enum OnePossibleValue {
1246 OnePossibleValueYes,1262 OnePossibleValueYes,
1247};1263};
12481264
1265struct ZigTypeOpaque {
1266 Buf *bare_name;
1267};
1268
1249struct ZigType {1269struct ZigType {
1250 ZigTypeId id;1270 ZigTypeId id;
1251 Buf name;1271 Buf name;
...@@ -1268,6 +1288,7 @@ struct ZigType {...@@ -1268,6 +1288,7 @@ struct ZigType {
1268 ZigTypeBoundFn bound_fn;1288 ZigTypeBoundFn bound_fn;
1269 ZigTypePromise promise;1289 ZigTypePromise promise;
1270 ZigTypeVector vector;1290 ZigTypeVector vector;
1291 ZigTypeOpaque opaque;
1271 } data;1292 } data;
12721293
1273 // use these fields to make sure we don't duplicate type table entries for the same type1294 // use these fields to make sure we don't duplicate type table entries for the same type
...@@ -1285,29 +1306,6 @@ struct ZigType {...@@ -1285,29 +1306,6 @@ struct ZigType {
1285 bool gen_h_loop_flag;1306 bool gen_h_loop_flag;
1286};1307};
12871308
1288struct PackageTableEntry {
1289 Buf root_src_dir;
1290 Buf root_src_path; // relative to root_src_dir
1291
1292 // reminder: hash tables must be initialized before use
1293 HashMap<Buf *, PackageTableEntry *, buf_hash, buf_eql_buf> package_table;
1294};
1295
1296struct ImportTableEntry {
1297 AstNode *root;
1298 Buf *path; // relative to root_package->root_src_dir
1299 PackageTableEntry *package;
1300 ZigLLVMDIFile *di_file;
1301 Buf *source_code;
1302 ZigList<size_t> *line_offsets;
1303 ScopeDecls *decls_scope;
1304 AstNode *c_import_node;
1305 bool any_imports_failed;
1306 bool scanned;
1307
1308 ZigList<AstNode *> use_decls;
1309};
1310
1311enum FnAnalState {1309enum FnAnalState {
1312 FnAnalStateReady,1310 FnAnalStateReady,
1313 FnAnalStateProbing,1311 FnAnalStateProbing,
...@@ -1670,7 +1668,7 @@ struct CodeGen {...@@ -1670,7 +1668,7 @@ struct CodeGen {
1670 LLVMValueRef return_err_fn;1668 LLVMValueRef return_err_fn;
16711669
1672 // reminder: hash tables must be initialized before use1670 // reminder: hash tables must be initialized before use
1673 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;1671 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;
1674 HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;1672 HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
1675 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> primitive_type_table;1673 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> primitive_type_table;
1676 HashMap<TypeId, ZigType *, type_id_hash, type_id_eql> type_table;1674 HashMap<TypeId, ZigType *, type_id_hash, type_id_eql> type_table;
...@@ -1684,8 +1682,6 @@ struct CodeGen {...@@ -1684,8 +1682,6 @@ struct CodeGen {
1684 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;1682 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
1685 HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;1683 HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
16861684
1687 ZigList<ImportTableEntry *> import_queue;
1688 size_t import_queue_index;
1689 ZigList<Tld *> resolve_queue;1685 ZigList<Tld *> resolve_queue;
1690 size_t resolve_queue_index;1686 size_t resolve_queue_index;
1691 ZigList<AstNode *> use_queue;1687 ZigList<AstNode *> use_queue;
...@@ -1699,14 +1695,14 @@ struct CodeGen {...@@ -1699,14 +1695,14 @@ struct CodeGen {
1699 ZigList<ErrorTableEntry *> errors_by_index;1695 ZigList<ErrorTableEntry *> errors_by_index;
1700 size_t largest_err_name_len;1696 size_t largest_err_name_len;
17011697
1702 PackageTableEntry *std_package;1698 ZigPackage *std_package;
1703 PackageTableEntry *panic_package;1699 ZigPackage *panic_package;
1704 PackageTableEntry *test_runner_package;1700 ZigPackage *test_runner_package;
1705 PackageTableEntry *compile_var_package;1701 ZigPackage *compile_var_package;
1706 ImportTableEntry *compile_var_import;1702 ZigType *compile_var_import;
1707 ImportTableEntry *root_import;1703 ZigType *root_import;
1708 ImportTableEntry *bootstrap_import;1704 ZigType *bootstrap_import;
1709 ImportTableEntry *test_runner_import;1705 ZigType *test_runner_import;
17101706
1711 struct {1707 struct {
1712 ZigType *entry_bool;1708 ZigType *entry_bool;
...@@ -1731,7 +1727,6 @@ struct CodeGen {...@@ -1731,7 +1727,6 @@ struct CodeGen {
1731 ZigType *entry_unreachable;1727 ZigType *entry_unreachable;
1732 ZigType *entry_type;1728 ZigType *entry_type;
1733 ZigType *entry_invalid;1729 ZigType *entry_invalid;
1734 ZigType *entry_namespace;
1735 ZigType *entry_block;1730 ZigType *entry_block;
1736 ZigType *entry_num_lit_int;1731 ZigType *entry_num_lit_int;
1737 ZigType *entry_num_lit_float;1732 ZigType *entry_num_lit_float;
...@@ -1851,7 +1846,7 @@ struct CodeGen {...@@ -1851,7 +1846,7 @@ struct CodeGen {
1851 Buf *root_out_name;1846 Buf *root_out_name;
1852 Buf *test_filter;1847 Buf *test_filter;
1853 Buf *test_name_prefix;1848 Buf *test_name_prefix;
1854 PackageTableEntry *root_package;1849 ZigPackage *root_package;
1855 Buf *zig_lib_dir;1850 Buf *zig_lib_dir;
1856 Buf *zig_std_dir;1851 Buf *zig_std_dir;
18571852
...@@ -1945,13 +1940,17 @@ struct ScopeDecls {...@@ -1945,13 +1940,17 @@ struct ScopeDecls {
1945 Scope base;1940 Scope base;
19461941
1947 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;1942 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
1948 bool safety_off;1943 ZigList<AstNode *> use_decls;
1949 AstNode *safety_set_node;1944 AstNode *safety_set_node;
1950 bool fast_math_on;
1951 AstNode *fast_math_set_node;1945 AstNode *fast_math_set_node;
1952 ImportTableEntry *import;1946 ZigType *import;
1953 // If this is a scope from a container, this is the type entry, otherwise null1947 // If this is a scope from a container, this is the type entry, otherwise null
1954 ZigType *container_type;1948 ZigType *container_type;
1949 Buf *bare_name;
1950
1951 bool safety_off;
1952 bool fast_math_on;
1953 bool any_imports_failed;
1955};1954};
19561955
1957// This scope comes from a block expression in user code.1956// This scope comes from a block expression in user code.
...@@ -3463,7 +3462,8 @@ static const size_t err_union_err_index = 0;...@@ -3463,7 +3462,8 @@ static const size_t err_union_err_index = 0;
3463static const size_t err_union_payload_index = 1;3462static const size_t err_union_payload_index = 1;
34643463
3465// TODO call graph analysis to find out what this number needs to be for every function3464// TODO call graph analysis to find out what this number needs to be for every function
3466static const size_t stack_trace_ptr_count = 30;3465// MUST BE A POWER OF TWO.
3466static const size_t stack_trace_ptr_count = 32;
34673467
3468// these belong to the async function3468// these belong to the async function
3469#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"3469#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
...@@ -3476,6 +3476,8 @@ static const size_t stack_trace_ptr_count = 30;...@@ -3476,6 +3476,8 @@ static const size_t stack_trace_ptr_count = 30;
3476#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"3476#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3477#define RESULT_PTR_FIELD_NAME "result_ptr"3477#define RESULT_PTR_FIELD_NAME "result_ptr"
34783478
3479#define NAMESPACE_SEP_CHAR '.'
3480#define NAMESPACE_SEP_STR "."
34793481
3480enum FloatMode {3482enum FloatMode {
3481 FloatModeStrict,3483 FloatModeStrict,
...@@ -3507,7 +3509,7 @@ struct FnWalkTypes {...@@ -3507,7 +3509,7 @@ struct FnWalkTypes {
3507};3509};
35083510
3509struct FnWalkVars {3511struct FnWalkVars {
3510 ImportTableEntry *import;3512 ZigType *import;
3511 LLVMValueRef llvm_fn;3513 LLVMValueRef llvm_fn;
3512 ZigFn *fn;3514 ZigFn *fn;
3513 ZigVar *var;3515 ZigVar *var;
src/analyze.cpp+295-234
...@@ -28,10 +28,14 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum...@@ -28,10 +28,14 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum
28static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);28static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
29static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);29static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
3030
31static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTableEntry *owner, Token *token,31static bool is_top_level_struct(ZigType *import) {
32 Buf *msg)32 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
33{33}
34 if (owner->c_import_node != nullptr) {34
35static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, Token *token, Buf *msg) {
36 assert(is_top_level_struct(owner));
37 RootStruct *root_struct = owner->data.structure.root_struct;
38 if (root_struct->c_import_node != nullptr) {
35 // if this happens, then translate_c generated code that39 // if this happens, then translate_c generated code that
36 // failed semantic analysis, which isn't supposed to happen40 // failed semantic analysis, which isn't supposed to happen
3741
...@@ -46,18 +50,20 @@ static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTa...@@ -46,18 +50,20 @@ static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTa
46 return note;50 return note;
47 }51 }
4852
49 ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,53 ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
50 owner->source_code, owner->line_offsets, msg);54 root_struct->source_code, root_struct->line_offsets, msg);
5155
52 err_msg_add_note(parent_msg, err);56 err_msg_add_note(parent_msg, err);
53 return err;57 return err;
54}58}
5559
56ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg) {60ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
57 if (owner->c_import_node != nullptr) {61 assert(is_top_level_struct(owner));
62 RootStruct *root_struct = owner->data.structure.root_struct;
63 if (root_struct->c_import_node != nullptr) {
58 // if this happens, then translate_c generated code that64 // if this happens, then translate_c generated code that
59 // failed semantic analysis, which isn't supposed to happen65 // failed semantic analysis, which isn't supposed to happen
60 ErrorMsg *err = add_node_error(g, owner->c_import_node,66 ErrorMsg *err = add_node_error(g, root_struct->c_import_node,
61 buf_sprintf("compiler bug: @cImport generated invalid zig code"));67 buf_sprintf("compiler bug: @cImport generated invalid zig code"));
6268
63 add_error_note_token(g, err, owner, token, msg);69 add_error_note_token(g, err, owner, token, msg);
...@@ -65,8 +71,8 @@ ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf...@@ -65,8 +71,8 @@ ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf
65 g->errors.append(err);71 g->errors.append(err);
66 return err;72 return err;
67 }73 }
68 ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,74 ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
69 owner->source_code, owner->line_offsets, msg);75 root_struct->source_code, root_struct->line_offsets, msg);
7076
71 g->errors.append(err);77 g->errors.append(err);
72 return err;78 return err;
...@@ -114,13 +120,16 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope...@@ -114,13 +120,16 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope
114 dest->parent = parent;120 dest->parent = parent;
115}121}
116122
117ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ImportTableEntry *import) {123static ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type,
124 ZigType *import, Buf *bare_name)
125{
118 assert(node == nullptr || node->type == NodeTypeContainerDecl || node->type == NodeTypeFnCallExpr);126 assert(node == nullptr || node->type == NodeTypeContainerDecl || node->type == NodeTypeFnCallExpr);
119 ScopeDecls *scope = allocate<ScopeDecls>(1);127 ScopeDecls *scope = allocate<ScopeDecls>(1);
120 init_scope(g, &scope->base, ScopeIdDecls, node, parent);128 init_scope(g, &scope->base, ScopeIdDecls, node, parent);
121 scope->decl_table.init(4);129 scope->decl_table.init(4);
122 scope->container_type = container_type;130 scope->container_type = container_type;
123 scope->import = import;131 scope->import = import;
132 scope->bare_name = bare_name;
124 return scope;133 return scope;
125}134}
126135
...@@ -207,11 +216,11 @@ Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {...@@ -207,11 +216,11 @@ Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {
207 return &scope->base;216 return &scope->base;
208}217}
209218
210ImportTableEntry *get_scope_import(Scope *scope) {219ZigType *get_scope_import(Scope *scope) {
211 while (scope) {220 while (scope) {
212 if (scope->id == ScopeIdDecls) {221 if (scope->id == ScopeIdDecls) {
213 ScopeDecls *decls_scope = (ScopeDecls *)scope;222 ScopeDecls *decls_scope = (ScopeDecls *)scope;
214 assert(decls_scope->import);223 assert(is_top_level_struct(decls_scope->import));
215 return decls_scope->import;224 return decls_scope->import;
216 }225 }
217 scope = scope->parent;226 scope = scope->parent;
...@@ -219,9 +228,12 @@ ImportTableEntry *get_scope_import(Scope *scope) {...@@ -219,9 +228,12 @@ ImportTableEntry *get_scope_import(Scope *scope) {
219 zig_unreachable();228 zig_unreachable();
220}229}
221230
222static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope) {231static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope,
232 Buf *bare_name)
233{
223 ZigType *entry = new_type_table_entry(id);234 ZigType *entry = new_type_table_entry(id);
224 *get_container_scope_ptr(entry) = create_decls_scope(g, source_node, parent_scope, entry, get_scope_import(parent_scope));235 *get_container_scope_ptr(entry) = create_decls_scope(g, source_node, parent_scope, entry,
236 get_scope_import(parent_scope), bare_name);
225 return entry;237 return entry;
226}238}
227239
...@@ -261,7 +273,6 @@ AstNode *type_decl_node(ZigType *type_entry) {...@@ -261,7 +273,6 @@ AstNode *type_decl_node(ZigType *type_entry) {
261 case ZigTypeIdErrorUnion:273 case ZigTypeIdErrorUnion:
262 case ZigTypeIdErrorSet:274 case ZigTypeIdErrorSet:
263 case ZigTypeIdFn:275 case ZigTypeIdFn:
264 case ZigTypeIdNamespace:
265 case ZigTypeIdBoundFn:276 case ZigTypeIdBoundFn:
266 case ZigTypeIdArgTuple:277 case ZigTypeIdArgTuple:
267 case ZigTypeIdPromise:278 case ZigTypeIdPromise:
...@@ -323,7 +334,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {...@@ -323,7 +334,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
323 case ZigTypeIdErrorUnion:334 case ZigTypeIdErrorUnion:
324 case ZigTypeIdErrorSet:335 case ZigTypeIdErrorSet:
325 case ZigTypeIdFn:336 case ZigTypeIdFn:
326 case ZigTypeIdNamespace:
327 case ZigTypeIdBoundFn:337 case ZigTypeIdBoundFn:
328 case ZigTypeIdArgTuple:338 case ZigTypeIdArgTuple:
329 case ZigTypeIdPromise:339 case ZigTypeIdPromise:
...@@ -616,7 +626,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {...@@ -616,7 +626,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
616 if (child_type->zero_bits) {626 if (child_type->zero_bits) {
617 entry->type_ref = LLVMInt1Type();627 entry->type_ref = LLVMInt1Type();
618 entry->di_type = g->builtin_types.entry_bool->di_type;628 entry->di_type = g->builtin_types.entry_bool->di_type;
619 } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {629 } else if (type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
620 assert(child_type->di_type);630 assert(child_type->di_type);
621 // this is an optimization but also is necessary for calling C631 // this is an optimization but also is necessary for calling C
622 // functions where all pointers are maybe pointers632 // functions where all pointers are maybe pointers
...@@ -1005,21 +1015,22 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {...@@ -1005,21 +1015,22 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
1005 return entry;1015 return entry;
1006}1016}
10071017
1008ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name) {1018ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name) {
1009 ZigType *entry = new_type_table_entry(ZigTypeIdOpaque);1019 ZigType *entry = new_type_table_entry(ZigTypeIdOpaque);
10101020
1011 buf_init_from_str(&entry->name, name);1021 buf_init_from_str(&entry->name, full_name);
10121022
1013 ImportTableEntry *import = scope ? get_scope_import(scope) : nullptr;1023 ZigType *import = scope ? get_scope_import(scope) : nullptr;
1014 unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;1024 unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
10151025
1016 entry->type_ref = LLVMInt8Type();1026 entry->type_ref = LLVMInt8Type();
1017 entry->di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,1027 entry->di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
1018 ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),1028 ZigLLVMTag_DW_structure_type(), full_name,
1019 import ? ZigLLVMFileToScope(import->di_file) : nullptr,1029 import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
1020 import ? import->di_file : nullptr,1030 import ? import->data.structure.root_struct->di_file : nullptr,
1021 line);1031 line);
1022 entry->zero_bits = false;1032 entry->zero_bits = false;
1033 entry->data.opaque.bare_name = bare_name;
10231034
1024 return entry;1035 return entry;
1025}1036}
...@@ -1288,11 +1299,32 @@ static ZigTypeId container_to_type(ContainerKind kind) {...@@ -1288,11 +1299,32 @@ static ZigTypeId container_to_type(ContainerKind kind) {
1288 zig_unreachable();1299 zig_unreachable();
1289}1300}
12901301
1302// This is like get_partial_container_type except it's for the implicit root struct of files.
1303ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
1304 RootStruct *root_struct)
1305{
1306 ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
1307 entry->data.structure.decls_scope = create_decls_scope(g, nullptr, nullptr, entry, entry, bare_name);
1308 entry->data.structure.root_struct = root_struct;
1309 entry->data.structure.layout = ContainerLayoutAuto;
1310 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
1311
1312 size_t line = 0; // root therefore first line
1313 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
1314
1315 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
1316 dwarf_kind, full_name,
1317 ZigLLVMFileToScope(root_struct->di_file), root_struct->di_file, (unsigned)(line + 1));
1318
1319 buf_init_from_str(&entry->name, full_name);
1320 return entry;
1321}
1322
1291ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,1323ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
1292 AstNode *decl_node, const char *name, ContainerLayout layout)1324 AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout)
1293{1325{
1294 ZigTypeId type_id = container_to_type(kind);1326 ZigTypeId type_id = container_to_type(kind);
1295 ZigType *entry = new_container_type_entry(g, type_id, decl_node, scope);1327 ZigType *entry = new_container_type_entry(g, type_id, decl_node, scope, bare_name);
12961328
1297 switch (kind) {1329 switch (kind) {
1298 case ContainerKindStruct:1330 case ContainerKindStruct:
...@@ -1312,13 +1344,14 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind...@@ -1312,13 +1344,14 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
1312 size_t line = decl_node ? decl_node->line : 0;1344 size_t line = decl_node ? decl_node->line : 0;
1313 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();1345 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
13141346
1315 ImportTableEntry *import = get_scope_import(scope);1347 ZigType *import = get_scope_import(scope);
1316 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);1348 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
1317 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,1349 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
1318 dwarf_kind, name,1350 dwarf_kind, full_name,
1319 ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));1351 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
1352 import->data.structure.root_struct->di_file, (unsigned)(line + 1));
13201353
1321 buf_init_from_str(&entry->name, name);1354 buf_init_from_str(&entry->name, full_name);
13221355
1323 return entry;1356 return entry;
1324}1357}
...@@ -1459,7 +1492,6 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType...@@ -1459,7 +1492,6 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
1459 case ZigTypeIdNull:1492 case ZigTypeIdNull:
1460 case ZigTypeIdErrorUnion:1493 case ZigTypeIdErrorUnion:
1461 case ZigTypeIdErrorSet:1494 case ZigTypeIdErrorSet:
1462 case ZigTypeIdNamespace:
1463 case ZigTypeIdBoundFn:1495 case ZigTypeIdBoundFn:
1464 case ZigTypeIdArgTuple:1496 case ZigTypeIdArgTuple:
1465 case ZigTypeIdOpaque:1497 case ZigTypeIdOpaque:
...@@ -1547,7 +1579,6 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {...@@ -1547,7 +1579,6 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
1547 case ZigTypeIdNull:1579 case ZigTypeIdNull:
1548 case ZigTypeIdErrorUnion:1580 case ZigTypeIdErrorUnion:
1549 case ZigTypeIdErrorSet:1581 case ZigTypeIdErrorSet:
1550 case ZigTypeIdNamespace:
1551 case ZigTypeIdBoundFn:1582 case ZigTypeIdBoundFn:
1552 case ZigTypeIdArgTuple:1583 case ZigTypeIdArgTuple:
1553 case ZigTypeIdPromise:1584 case ZigTypeIdPromise:
...@@ -1706,7 +1737,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1706,7 +1737,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1706 return g->builtin_types.entry_invalid;1737 return g->builtin_types.entry_invalid;
1707 case ZigTypeIdComptimeFloat:1738 case ZigTypeIdComptimeFloat:
1708 case ZigTypeIdComptimeInt:1739 case ZigTypeIdComptimeInt:
1709 case ZigTypeIdNamespace:
1710 case ZigTypeIdBoundFn:1740 case ZigTypeIdBoundFn:
1711 case ZigTypeIdMetaType:1741 case ZigTypeIdMetaType:
1712 case ZigTypeIdVoid:1742 case ZigTypeIdVoid:
...@@ -1801,7 +1831,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1801,7 +1831,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
18011831
1802 case ZigTypeIdComptimeFloat:1832 case ZigTypeIdComptimeFloat:
1803 case ZigTypeIdComptimeInt:1833 case ZigTypeIdComptimeInt:
1804 case ZigTypeIdNamespace:
1805 case ZigTypeIdBoundFn:1834 case ZigTypeIdBoundFn:
1806 case ZigTypeIdMetaType:1835 case ZigTypeIdMetaType:
1807 case ZigTypeIdUnreachable:1836 case ZigTypeIdUnreachable:
...@@ -1880,7 +1909,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {...@@ -1880,7 +1909,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
1880 if (!enum_type->data.enumeration.reported_infinite_err) {1909 if (!enum_type->data.enumeration.reported_infinite_err) {
1881 enum_type->data.enumeration.is_invalid = true;1910 enum_type->data.enumeration.is_invalid = true;
1882 enum_type->data.enumeration.reported_infinite_err = true;1911 enum_type->data.enumeration.reported_infinite_err = true;
1883 add_node_error(g, decl_node, buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name)));1912 ErrorMsg *msg = add_node_error(g, decl_node,
1913 buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name)));
1914 emit_error_notes_for_ref_stack(g, msg);
1884 }1915 }
1885 return ErrorSemanticAnalyzeFail;1916 return ErrorSemanticAnalyzeFail;
1886 }1917 }
...@@ -1895,7 +1926,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {...@@ -1895,7 +1926,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
1895 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);1926 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
18961927
1897 Scope *scope = &enum_type->data.enumeration.decls_scope->base;1928 Scope *scope = &enum_type->data.enumeration.decls_scope->base;
1898 ImportTableEntry *import = get_scope_import(scope);1929 ZigType *import = get_scope_import(scope);
18991930
1900 // set temporary flag1931 // set temporary flag
1901 enum_type->data.enumeration.embedded_in_current = true;1932 enum_type->data.enumeration.embedded_in_current = true;
...@@ -1924,9 +1955,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {...@@ -1924,9 +1955,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
1924 ZigLLVMDIType **di_root_members = nullptr;1955 ZigLLVMDIType **di_root_members = nullptr;
1925 size_t debug_member_count = 0;1956 size_t debug_member_count = 0;
1926 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,1957 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1927 ZigLLVMFileToScope(import->di_file),1958 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
1928 buf_ptr(&enum_type->name),1959 buf_ptr(&enum_type->name),
1929 import->di_file, (unsigned)(decl_node->line + 1),1960 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
1930 debug_size_in_bits,1961 debug_size_in_bits,
1931 debug_align_in_bits,1962 debug_align_in_bits,
1932 0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");1963 0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");
...@@ -1942,8 +1973,8 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {...@@ -1942,8 +1973,8 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
1942 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);1973 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);
1943 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);1974 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1944 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,1975 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1945 ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),1976 ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name),
1946 import->di_file, (unsigned)(decl_node->line + 1),1977 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
1947 tag_debug_size_in_bits,1978 tag_debug_size_in_bits,
1948 tag_debug_align_in_bits,1979 tag_debug_align_in_bits,
1949 di_enumerators, field_count,1980 di_enumerators, field_count,
...@@ -2051,8 +2082,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2051,8 +2082,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2051 if (struct_type->data.structure.resolve_loop_flag) {2082 if (struct_type->data.structure.resolve_loop_flag) {
2052 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {2083 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
2053 struct_type->data.structure.resolve_status = ResolveStatusInvalid;2084 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2054 add_node_error(g, decl_node,2085 ErrorMsg *msg = add_node_error(g, decl_node,
2055 buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));2086 buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
2087 emit_error_notes_for_ref_stack(g, msg);
2056 }2088 }
2057 return ErrorSemanticAnalyzeFail;2089 return ErrorSemanticAnalyzeFail;
2058 }2090 }
...@@ -2159,15 +2191,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2159,15 +2191,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2159 if (struct_type->zero_bits) {2191 if (struct_type->zero_bits) {
2160 struct_type->type_ref = LLVMVoidType();2192 struct_type->type_ref = LLVMVoidType();
21612193
2162 ImportTableEntry *import = get_scope_import(scope);2194 ZigType *import = get_scope_import(scope);
2163 uint64_t debug_size_in_bits = 0;2195 uint64_t debug_size_in_bits = 0;
2164 uint64_t debug_align_in_bits = 0;2196 uint64_t debug_align_in_bits = 0;
2165 ZigLLVMDIType **di_element_types = nullptr;2197 ZigLLVMDIType **di_element_types = nullptr;
2166 size_t debug_field_count = 0;2198 size_t debug_field_count = 0;
2167 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,2199 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2168 ZigLLVMFileToScope(import->di_file),2200 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
2169 buf_ptr(&struct_type->name),2201 buf_ptr(&struct_type->name),
2170 import->di_file, (unsigned)(decl_node->line + 1),2202 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2171 debug_size_in_bits,2203 debug_size_in_bits,
2172 debug_align_in_bits,2204 debug_align_in_bits,
2173 0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");2205 0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");
...@@ -2191,7 +2223,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2191,7 +2223,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
21912223
2192 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);2224 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
21932225
2194 ImportTableEntry *import = get_scope_import(scope);2226 ZigType *import = get_scope_import(scope);
2195 size_t debug_field_index = 0;2227 size_t debug_field_index = 0;
2196 for (size_t i = 0; i < field_count; i += 1) {2228 for (size_t i = 0; i < field_count; i += 1) {
2197 AstNode *field_node = decl_node->data.container_decl.fields.at(i);2229 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
...@@ -2234,7 +2266,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2234,7 +2266,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2234 }2266 }
2235 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,2267 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
2236 ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),2268 ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
2237 import->di_file, (unsigned)(field_node->line + 1),2269 import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
2238 debug_size_in_bits,2270 debug_size_in_bits,
2239 debug_align_in_bits,2271 debug_align_in_bits,
2240 debug_offset_in_bits,2272 debug_offset_in_bits,
...@@ -2247,9 +2279,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2247,9 +2279,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2247 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);2279 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);
2248 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);2280 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
2249 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,2281 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2250 ZigLLVMFileToScope(import->di_file),2282 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
2251 buf_ptr(&struct_type->name),2283 buf_ptr(&struct_type->name),
2252 import->di_file, (unsigned)(decl_node->line + 1),2284 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2253 debug_size_in_bits,2285 debug_size_in_bits,
2254 debug_align_in_bits,2286 debug_align_in_bits,
2255 0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");2287 0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");
...@@ -2276,7 +2308,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2276,7 +2308,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
2276 if (!union_type->data.unionation.reported_infinite_err) {2308 if (!union_type->data.unionation.reported_infinite_err) {
2277 union_type->data.unionation.reported_infinite_err = true;2309 union_type->data.unionation.reported_infinite_err = true;
2278 union_type->data.unionation.is_invalid = true;2310 union_type->data.unionation.is_invalid = true;
2279 add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));2311 ErrorMsg *msg = add_node_error(g, decl_node,
2312 buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
2313 emit_error_notes_for_ref_stack(g, msg);
2280 }2314 }
2281 return ErrorSemanticAnalyzeFail;2315 return ErrorSemanticAnalyzeFail;
2282 }2316 }
...@@ -2298,7 +2332,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2298,7 +2332,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
2298 uint64_t biggest_size_in_bits = 0;2332 uint64_t biggest_size_in_bits = 0;
22992333
2300 Scope *scope = &union_type->data.unionation.decls_scope->base;2334 Scope *scope = &union_type->data.unionation.decls_scope->base;
2301 ImportTableEntry *import = get_scope_import(scope);2335 ZigType *import = get_scope_import(scope);
23022336
2303 // set temporary flag2337 // set temporary flag
2304 union_type->data.unionation.embedded_in_current = true;2338 union_type->data.unionation.embedded_in_current = true;
...@@ -2325,7 +2359,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2325,7 +2359,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
23252359
2326 union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,2360 union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
2327 ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name),2361 ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name),
2328 import->di_file, (unsigned)(field_node->line + 1),2362 import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
2329 store_size_in_bits,2363 store_size_in_bits,
2330 abi_align_in_bits,2364 abi_align_in_bits,
2331 0,2365 0,
...@@ -2358,9 +2392,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2358,9 +2392,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
2358 ZigLLVMDIType **di_root_members = nullptr;2392 ZigLLVMDIType **di_root_members = nullptr;
2359 size_t debug_member_count = 0;2393 size_t debug_member_count = 0;
2360 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,2394 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
2361 ZigLLVMFileToScope(import->di_file),2395 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
2362 buf_ptr(&union_type->name),2396 buf_ptr(&union_type->name),
2363 import->di_file, (unsigned)(decl_node->line + 1),2397 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2364 debug_size_in_bits,2398 debug_size_in_bits,
2365 debug_align_in_bits,2399 debug_align_in_bits,
2366 0, di_root_members, (int)debug_member_count, 0, "");2400 0, di_root_members, (int)debug_member_count, 0, "");
...@@ -2396,8 +2430,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2396,8 +2430,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
23962430
2397 // create debug type for union2431 // create debug type for union
2398 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,2432 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
2399 ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),2433 ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name),
2400 import->di_file, (unsigned)(decl_node->line + 1),2434 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2401 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,2435 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
2402 gen_field_count, 0, "");2436 gen_field_count, 0, "");
24032437
...@@ -2452,7 +2486,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2452,7 +2486,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
2452 // create debug type for union2486 // create debug type for union
2453 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,2487 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
2454 ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",2488 ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
2455 import->di_file, (unsigned)(decl_node->line + 1),2489 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2456 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,2490 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
2457 gen_field_count, 0, "");2491 gen_field_count, 0, "");
24582492
...@@ -2463,7 +2497,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2463,7 +2497,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24632497
2464 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,2498 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
2465 ZigLLVMTypeToScope(union_type->di_type), "payload",2499 ZigLLVMTypeToScope(union_type->di_type), "payload",
2466 import->di_file, (unsigned)(decl_node->line + 1),2500 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2467 biggest_size_in_bits,2501 biggest_size_in_bits,
2468 biggest_align_in_bits,2502 biggest_align_in_bits,
2469 union_offset_in_bits,2503 union_offset_in_bits,
...@@ -2474,7 +2508,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2474,7 +2508,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24742508
2475 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,2509 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
2476 ZigLLVMTypeToScope(union_type->di_type), "tag",2510 ZigLLVMTypeToScope(union_type->di_type), "tag",
2477 import->di_file, (unsigned)(decl_node->line + 1),2511 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2478 tag_debug_size_in_bits,2512 tag_debug_size_in_bits,
2479 tag_debug_align_in_bits,2513 tag_debug_align_in_bits,
2480 tag_offset_in_bits,2514 tag_offset_in_bits,
...@@ -2487,9 +2521,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2487,9 +2521,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
2487 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);2521 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);
2488 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);2522 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);
2489 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,2523 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2490 ZigLLVMFileToScope(import->di_file),2524 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
2491 buf_ptr(&union_type->name),2525 buf_ptr(&union_type->name),
2492 import->di_file, (unsigned)(decl_node->line + 1),2526 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
2493 debug_size_in_bits,2527 debug_size_in_bits,
2494 debug_align_in_bits,2528 debug_align_in_bits,
2495 0, nullptr, di_root_members, 2, 0, nullptr, "");2529 0, nullptr, di_root_members, 2, 0, nullptr, "");
...@@ -2507,8 +2541,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2507,8 +2541,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2507 return ErrorNone;2541 return ErrorNone;
25082542
2509 if (enum_type->data.enumeration.zero_bits_loop_flag) {2543 if (enum_type->data.enumeration.zero_bits_loop_flag) {
2510 add_node_error(g, enum_type->data.enumeration.decl_node,2544 ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node,
2511 buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));2545 buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
2546 emit_error_notes_for_ref_stack(g, msg);
2512 enum_type->data.enumeration.is_invalid = true;2547 enum_type->data.enumeration.is_invalid = true;
2513 return ErrorSemanticAnalyzeFail;2548 return ErrorSemanticAnalyzeFail;
2514 }2549 }
...@@ -2780,8 +2815,9 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {...@@ -2780,8 +2815,9 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
2780 if (struct_type->data.structure.resolve_loop_flag) {2815 if (struct_type->data.structure.resolve_loop_flag) {
2781 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {2816 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
2782 struct_type->data.structure.resolve_status = ResolveStatusInvalid;2817 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2783 add_node_error(g, decl_node,2818 ErrorMsg *msg = add_node_error(g, decl_node,
2784 buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));2819 buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
2820 emit_error_notes_for_ref_stack(g, msg);
2785 }2821 }
2786 return ErrorSemanticAnalyzeFail;2822 return ErrorSemanticAnalyzeFail;
2787 }2823 }
...@@ -3185,15 +3221,15 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {...@@ -3185,15 +3221,15 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
3185 }3221 }
31863222
3187 if (create_enum_type) {3223 if (create_enum_type) {
3188 ImportTableEntry *import = get_scope_import(scope);3224 ZigType *import = get_scope_import(scope);
3189 uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 :3225 uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 :
3190 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);3226 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
3191 uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 :3227 uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 :
3192 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);3228 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
3193 // TODO get a more accurate debug scope3229 // TODO get a more accurate debug scope
3194 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,3230 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
3195 ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),3231 ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&tag_type->name),
3196 import->di_file, (unsigned)(decl_node->line + 1),3232 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
3197 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,3233 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
3198 tag_type->di_type, "");3234 tag_type->di_type, "");
3199 tag_type->di_type = tag_di_type;3235 tag_type->di_type = tag_di_type;
...@@ -3210,27 +3246,16 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {...@@ -3210,27 +3246,16 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
3210 return ErrorNone;3246 return ErrorNone;
3211}3247}
32123248
3213static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {3249static void get_fully_qualified_decl_name(Buf *buf, Tld *tld) {
3214 if (!scope)3250 buf_resize(buf, 0);
3215 return;
3216
3217 if (scope->id == ScopeIdDecls) {
3218 get_fully_qualified_decl_name_internal(buf, scope->parent, sep);
32193251
3220 ScopeDecls *scope_decls = (ScopeDecls *)scope;3252 Scope *scope = tld->parent_scope;
3221 if (scope_decls->container_type) {3253 while (scope->id != ScopeIdDecls) {
3222 buf_append_buf(buf, &scope_decls->container_type->name);3254 scope = scope->parent;
3223 buf_append_char(buf, sep);
3224 }
3225 return;
3226 }3255 }
32273256 ScopeDecls *decls_scope = reinterpret_cast<ScopeDecls *>(scope);
3228 get_fully_qualified_decl_name_internal(buf, scope->parent, sep);3257 buf_append_buf(buf, &decls_scope->container_type->name);
3229}3258 if (buf_len(buf) != 0) buf_append_char(buf, NAMESPACE_SEP_CHAR);
3230
3231static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) {
3232 buf_resize(buf, 0);
3233 get_fully_qualified_decl_name_internal(buf, tld->parent_scope, sep);
3234 buf_append_buf(buf, tld->name);3259 buf_append_buf(buf, tld->name);
3235}3260}
32363261
...@@ -3265,7 +3290,7 @@ static bool scope_is_root_decls(Scope *scope) {...@@ -3265,7 +3290,7 @@ static bool scope_is_root_decls(Scope *scope) {
3265 while (scope) {3290 while (scope) {
3266 if (scope->id == ScopeIdDecls) {3291 if (scope->id == ScopeIdDecls) {
3267 ScopeDecls *scope_decls = (ScopeDecls *)scope;3292 ScopeDecls *scope_decls = (ScopeDecls *)scope;
3268 return (scope_decls->container_type == nullptr);3293 return is_top_level_struct(scope_decls->container_type);
3269 }3294 }
3270 scope = scope->parent;3295 scope = scope->parent;
3271 }3296 }
...@@ -3281,7 +3306,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {...@@ -3281,7 +3306,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {
3281 AstNode *fake_decl = allocate<AstNode>(1);3306 AstNode *fake_decl = allocate<AstNode>(1);
3282 *fake_decl = *panic_fn->proto_node;3307 *fake_decl = *panic_fn->proto_node;
3283 fake_decl->type = NodeTypeSymbol;3308 fake_decl->type = NodeTypeSymbol;
3284 fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name;3309 fake_decl->data.symbol_expr.symbol = tld_fn->base.name;
32853310
3286 // call this for the side effects of casting to panic_fn_type3311 // call this for the side effects of casting to panic_fn_type
3287 analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr);3312 analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr);
...@@ -3326,7 +3351,7 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi...@@ -3326,7 +3351,7 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi
3326}3351}
33273352
3328static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {3353static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3329 ImportTableEntry *import = tld_fn->base.import;3354 ZigType *import = tld_fn->base.import;
3330 AstNode *source_node = tld_fn->base.source_node;3355 AstNode *source_node = tld_fn->base.source_node;
3331 if (source_node->type == NodeTypeFnProto) {3356 if (source_node->type == NodeTypeFnProto) {
3332 AstNodeFnProto *fn_proto = &source_node->data.fn_proto;3357 AstNodeFnProto *fn_proto = &source_node->data.fn_proto;
...@@ -3334,16 +3359,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -3334,16 +3359,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3334 AstNode *fn_def_node = fn_proto->fn_def_node;3359 AstNode *fn_def_node = fn_proto->fn_def_node;
33353360
3336 ZigFn *fn_table_entry = create_fn(g, source_node);3361 ZigFn *fn_table_entry = create_fn(g, source_node);
3337 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');3362 tld_fn->fn_entry = fn_table_entry;
3363
3364 bool is_extern = (fn_table_entry->body_node == nullptr);
3365 if (fn_proto->is_export || is_extern) {
3366 buf_init_from_buf(&fn_table_entry->symbol_name, tld_fn->base.name);
3367 } else {
3368 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base);
3369 }
33383370
3339 if (fn_proto->is_export) {3371 if (fn_proto->is_export) {
3340 bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC);3372 bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC);
3341 add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc);3373 add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc);
3342 }3374 }
33433375
3344 tld_fn->fn_entry = fn_table_entry;3376 if (!is_extern) {
3345
3346 if (fn_table_entry->body_node) {
3347 fn_table_entry->fndef_scope = create_fndef_scope(g,3377 fn_table_entry->fndef_scope = create_fndef_scope(g,
3348 fn_table_entry->body_node, tld_fn->base.parent_scope, fn_table_entry);3378 fn_table_entry->body_node, tld_fn->base.parent_scope, fn_table_entry);
33493379
...@@ -3382,12 +3412,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -3382,12 +3412,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3382 }3412 }
33833413
3384 if (scope_is_root_decls(tld_fn->base.parent_scope) &&3414 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
3385 (import == g->root_import || import->package == g->panic_package))3415 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
3386 {3416 {
3387 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {3417 if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) {
3388 g->main_fn = fn_table_entry;3418 g->main_fn = fn_table_entry;
3389 } else if ((import->package == g->panic_package || g->have_pub_panic) &&3419 } else if ((import->data.structure.root_struct->package == g->panic_package || g->have_pub_panic) &&
3390 buf_eql_str(&fn_table_entry->symbol_name, "panic"))3420 buf_eql_str(tld_fn->base.name, "panic"))
3391 {3421 {
3392 g->panic_fn = fn_table_entry;3422 g->panic_fn = fn_table_entry;
3393 g->panic_tld_fn = tld_fn;3423 g->panic_tld_fn = tld_fn;
...@@ -3396,7 +3426,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -3396,7 +3426,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3396 } else if (source_node->type == NodeTypeTestDecl) {3426 } else if (source_node->type == NodeTypeTestDecl) {
3397 ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto);3427 ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto);
33983428
3399 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');3429 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base);
34003430
3401 tld_fn->fn_entry = fn_table_entry;3431 tld_fn->fn_entry = fn_table_entry;
34023432
...@@ -3473,8 +3503,8 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope...@@ -3473,8 +3503,8 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
3473 if (!g->is_test_build)3503 if (!g->is_test_build)
3474 return;3504 return;
34753505
3476 ImportTableEntry *import = get_scope_import(&decls_scope->base);3506 ZigType *import = get_scope_import(&decls_scope->base);
3477 if (import->package != g->root_package)3507 if (import->data.structure.root_struct->package != g->root_package)
3478 return;3508 return;
34793509
3480 Buf *decl_name_buf = node->data.test_decl.name;3510 Buf *decl_name_buf = node->data.test_decl.name;
...@@ -3511,8 +3541,8 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source...@@ -3511,8 +3541,8 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source
3511}3541}
35123542
3513void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {3543void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
3514 Tld *tld = g->compile_var_import->decls_scope->decl_table.get(name);3544 Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name);
3515 resolve_top_level_decl(g, tld, false, tld->source_node);3545 resolve_top_level_decl(g, tld, tld->source_node);
3516 assert(tld->id == TldIdVar);3546 assert(tld->id == TldIdVar);
3517 TldVar *tld_var = (TldVar *)tld;3547 TldVar *tld_var = (TldVar *)tld;
3518 tld_var->var->const_value = value;3548 tld_var->var->const_value = value;
...@@ -3561,8 +3591,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3561,8 +3591,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3561 case NodeTypeUse:3591 case NodeTypeUse:
3562 {3592 {
3563 g->use_queue.append(node);3593 g->use_queue.append(node);
3564 ImportTableEntry *import = get_scope_import(&decls_scope->base);3594 decls_scope->use_decls.append(node);
3565 import->use_decls.append(node);
3566 break;3595 break;
3567 }3596 }
3568 case NodeTypeTestDecl:3597 case NodeTypeTestDecl:
...@@ -3654,7 +3683,6 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry...@@ -3654,7 +3683,6 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
3654 return g->builtin_types.entry_invalid;3683 return g->builtin_types.entry_invalid;
3655 case ZigTypeIdComptimeFloat:3684 case ZigTypeIdComptimeFloat:
3656 case ZigTypeIdComptimeInt:3685 case ZigTypeIdComptimeInt:
3657 case ZigTypeIdNamespace:
3658 case ZigTypeIdMetaType:3686 case ZigTypeIdMetaType:
3659 case ZigTypeIdVoid:3687 case ZigTypeIdVoid:
3660 case ZigTypeIdBool:3688 case ZigTypeIdBool:
...@@ -3763,8 +3791,16 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {...@@ -3763,8 +3791,16 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
37633791
3764 ZigType *explicit_type = nullptr;3792 ZigType *explicit_type = nullptr;
3765 if (var_decl->type) {3793 if (var_decl->type) {
3766 ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type);3794 if (tld_var->analyzing_type) {
3767 explicit_type = validate_var_type(g, var_decl->type, proposed_type);3795 ErrorMsg *msg = add_node_error(g, var_decl->type,
3796 buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name)));
3797 emit_error_notes_for_ref_stack(g, msg);
3798 explicit_type = g->builtin_types.entry_invalid;
3799 } else {
3800 tld_var->analyzing_type = true;
3801 ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type);
3802 explicit_type = validate_var_type(g, var_decl->type, proposed_type);
3803 }
3768 }3804 }
37693805
3770 assert(!is_export || !is_extern);3806 assert(!is_export || !is_extern);
...@@ -3847,17 +3883,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {...@@ -3847,17 +3883,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
3847 g->global_vars.append(tld_var);3883 g->global_vars.append(tld_var);
3848}3884}
38493885
3850void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node) {3886void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
3851 if (tld->resolution != TldResolutionUnresolved)3887 if (tld->resolution != TldResolutionUnresolved)
3852 return;3888 return;
38533889
3854 if (tld->dep_loop_flag) {3890 assert(tld->resolution != TldResolutionResolving);
3855 add_node_error(g, tld->source_node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name)));3891 tld->resolution = TldResolutionResolving;
3856 tld->resolution = TldResolutionInvalid;
3857 return;
3858 }
3859
3860 tld->dep_loop_flag = true;
3861 g->tld_ref_source_node_stack.append(source_node);3892 g->tld_ref_source_node_stack.append(source_node);
38623893
3863 switch (tld->id) {3894 switch (tld->id) {
...@@ -3888,27 +3919,31 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so...@@ -3888,27 +3919,31 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
3888 }3919 }
38893920
3890 tld->resolution = TldResolutionOk;3921 tld->resolution = TldResolutionOk;
3891 tld->dep_loop_flag = false;
3892 g->tld_ref_source_node_stack.pop();3922 g->tld_ref_source_node_stack.pop();
3893}3923}
38943924
3895Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {3925Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
3896 // we must resolve all the use decls3926 // resolve all the use decls
3897 ImportTableEntry *import = get_scope_import(scope);3927 for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
3898 for (size_t i = 0; i < import->use_decls.length; i += 1) {3928 AstNode *use_decl_node = decls_scope->use_decls.at(i);
3899 AstNode *use_decl_node = import->use_decls.at(i);
3900 if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {3929 if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {
3901 preview_use_decl(g, use_decl_node);3930 preview_use_decl(g, use_decl_node);
3902 resolve_use_decl(g, use_decl_node);3931 resolve_use_decl(g, use_decl_node);
3903 }3932 }
3904 }3933 }
39053934
3935 auto entry = decls_scope->decl_table.maybe_get(name);
3936 return (entry == nullptr) ? nullptr : entry->value;
3937}
3938
3939Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
3906 while (scope) {3940 while (scope) {
3907 if (scope->id == ScopeIdDecls) {3941 if (scope->id == ScopeIdDecls) {
3908 ScopeDecls *decls_scope = (ScopeDecls *)scope;3942 ScopeDecls *decls_scope = (ScopeDecls *)scope;
3909 auto entry = decls_scope->decl_table.maybe_get(name);3943
3910 if (entry)3944 Tld *result = find_container_decl(g, decls_scope, name);
3911 return entry->value;3945 if (result != nullptr)
3946 return result;
3912 }3947 }
3913 scope = scope->parent;3948 scope = scope->parent;
3914 }3949 }
...@@ -3959,6 +3994,12 @@ ZigFn *scope_fn_entry(Scope *scope) {...@@ -3959,6 +3994,12 @@ ZigFn *scope_fn_entry(Scope *scope) {
3959 return nullptr;3994 return nullptr;
3960}3995}
39613996
3997ZigPackage *scope_package(Scope *scope) {
3998 ZigType *import = get_scope_import(scope);
3999 assert(is_top_level_struct(import));
4000 return import->data.structure.root_struct->package;
4001}
4002
3962TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {4003TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {
3963 assert(enum_type->id == ZigTypeIdEnum);4004 assert(enum_type->id == ZigTypeIdEnum);
3964 if (enum_type->data.enumeration.src_field_count == 0)4005 if (enum_type->data.enumeration.src_field_count == 0)
...@@ -4039,7 +4080,6 @@ static bool is_container(ZigType *type_entry) {...@@ -4039,7 +4080,6 @@ static bool is_container(ZigType *type_entry) {
4039 case ZigTypeIdErrorUnion:4080 case ZigTypeIdErrorUnion:
4040 case ZigTypeIdErrorSet:4081 case ZigTypeIdErrorSet:
4041 case ZigTypeIdFn:4082 case ZigTypeIdFn:
4042 case ZigTypeIdNamespace:
4043 case ZigTypeIdBoundFn:4083 case ZigTypeIdBoundFn:
4044 case ZigTypeIdArgTuple:4084 case ZigTypeIdArgTuple:
4045 case ZigTypeIdOpaque:4085 case ZigTypeIdOpaque:
...@@ -4098,7 +4138,6 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {...@@ -4098,7 +4138,6 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {
4098 case ZigTypeIdErrorUnion:4138 case ZigTypeIdErrorUnion:
4099 case ZigTypeIdErrorSet:4139 case ZigTypeIdErrorSet:
4100 case ZigTypeIdFn:4140 case ZigTypeIdFn:
4101 case ZigTypeIdNamespace:
4102 case ZigTypeIdBoundFn:4141 case ZigTypeIdBoundFn:
4103 case ZigTypeIdInvalid:4142 case ZigTypeIdInvalid:
4104 case ZigTypeIdArgTuple:4143 case ZigTypeIdArgTuple:
...@@ -4131,10 +4170,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {...@@ -4131,10 +4170,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
4131}4170}
41324171
4133bool type_is_nonnull_ptr(ZigType *type) {4172bool type_is_nonnull_ptr(ZigType *type) {
4134 return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type);4173 return type_is_non_optional_pointer(type) && !ptr_allows_addr_zero(type);
4135}4174}
41364175
4137bool type_is_codegen_pointer(ZigType *type) {4176bool type_is_non_optional_pointer(ZigType *type) {
4138 return get_codegen_ptr_type(type) == type;4177 return get_codegen_ptr_type(type) == type;
4139}4178}
41404179
...@@ -4342,9 +4381,9 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *...@@ -4342,9 +4381,9 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
4342 preview_use_decl(g, src_use_node);4381 preview_use_decl(g, src_use_node);
4343 }4382 }
43444383
4345 ConstExprValue *use_target_value = src_use_node->data.use.value;4384 ConstExprValue *use_target_value = src_use_node->data.use.using_namespace_value;
4346 if (type_is_invalid(use_target_value->type)) {4385 if (type_is_invalid(use_target_value->type)) {
4347 dst_use_node->owner->any_imports_failed = true;4386 get_container_scope(dst_use_node->owner)->any_imports_failed = true;
4348 return;4387 return;
4349 }4388 }
43504389
...@@ -4352,14 +4391,14 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *...@@ -4352,14 +4391,14 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
43524391
4353 assert(use_target_value->special != ConstValSpecialRuntime);4392 assert(use_target_value->special != ConstValSpecialRuntime);
43544393
4355 ImportTableEntry *target_import = use_target_value->data.x_import;4394 ZigType *target_import = use_target_value->data.x_type;
4356 assert(target_import);4395 assert(target_import);
43574396
4358 if (target_import->any_imports_failed) {4397 if (get_container_scope(target_import)->any_imports_failed) {
4359 dst_use_node->owner->any_imports_failed = true;4398 get_container_scope(dst_use_node->owner)->any_imports_failed = true;
4360 }4399 }
43614400
4362 auto it = target_import->decls_scope->decl_table.entry_iterator();4401 auto it = get_container_scope(target_import)->decl_table.entry_iterator();
4363 for (;;) {4402 for (;;) {
4364 auto *entry = it.next();4403 auto *entry = it.next();
4365 if (!entry)4404 if (!entry)
...@@ -4374,7 +4413,7 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *...@@ -4374,7 +4413,7 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
43744413
4375 Buf *target_tld_name = entry->key;4414 Buf *target_tld_name = entry->key;
43764415
4377 auto existing_entry = dst_use_node->owner->decls_scope->decl_table.put_unique(target_tld_name, target_tld);4416 auto existing_entry = get_container_scope(dst_use_node->owner)->decl_table.put_unique(target_tld_name, target_tld);
4378 if (existing_entry) {4417 if (existing_entry) {
4379 Tld *existing_decl = existing_entry->value;4418 Tld *existing_decl = existing_entry->value;
4380 if (existing_decl != target_tld) {4419 if (existing_decl != target_tld) {
...@@ -4387,8 +4426,8 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *...@@ -4387,8 +4426,8 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
4387 }4426 }
4388 }4427 }
43894428
4390 for (size_t i = 0; i < target_import->use_decls.length; i += 1) {4429 for (size_t i = 0; i < get_container_scope(target_import)->use_decls.length; i += 1) {
4391 AstNode *use_decl_node = target_import->use_decls.at(i);4430 AstNode *use_decl_node = get_container_scope(target_import)->use_decls.at(i);
4392 if (use_decl_node->data.use.visib_mod != VisibModPrivate)4431 if (use_decl_node->data.use.visib_mod != VisibModPrivate)
4393 add_symbols_from_import(g, use_decl_node, dst_use_node);4432 add_symbols_from_import(g, use_decl_node, dst_use_node);
4394 }4433 }
...@@ -4415,16 +4454,18 @@ void preview_use_decl(CodeGen *g, AstNode *node) {...@@ -4415,16 +4454,18 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
4415 }4454 }
44164455
4417 node->data.use.resolution = TldResolutionResolving;4456 node->data.use.resolution = TldResolutionResolving;
4418 ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base,4457 ConstExprValue *result = analyze_const_value(g, &get_container_scope(node->owner)->base,
4419 node->data.use.expr, g->builtin_types.entry_namespace, nullptr);4458 node->data.use.expr, g->builtin_types.entry_type, nullptr);
44204459
4421 if (type_is_invalid(result->type))4460 if (type_is_invalid(result->type))
4422 node->owner->any_imports_failed = true;4461 get_container_scope(node->owner)->any_imports_failed = true;
44234462
4424 node->data.use.value = result;4463 node->data.use.using_namespace_value = result;
4425}4464}
44264465
4427ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *resolved_path, Buf *source_code) {4466ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code,
4467 SourceKind source_kind)
4468{
4428 if (g->verbose_tokenize) {4469 if (g->verbose_tokenize) {
4429 fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(resolved_path));4470 fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(resolved_path));
4430 fprintf(stderr, "----------------\n");4471 fprintf(stderr, "----------------\n");
...@@ -4452,87 +4493,102 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r...@@ -4452,87 +4493,102 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r
4452 fprintf(stderr, "------\n");4493 fprintf(stderr, "------\n");
4453 }4494 }
44544495
4455 ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
4456 import_entry->package = package;
4457 import_entry->source_code = source_code;
4458 import_entry->line_offsets = tokenization.line_offsets;
4459 import_entry->path = resolved_path;
4460
4461 import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
4462 assert(import_entry->root);
4463 if (g->verbose_ast) {
4464 ast_print(stderr, import_entry->root, 0);
4465 }
4466
4467 Buf *src_dirname = buf_alloc();4496 Buf *src_dirname = buf_alloc();
4468 Buf *src_basename = buf_alloc();4497 Buf *src_basename = buf_alloc();
4469 os_path_split(resolved_path, src_dirname, src_basename);4498 os_path_split(resolved_path, src_dirname, src_basename);
44704499
4471 import_entry->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));4500 Buf noextname = BUF_INIT;
4472 g->import_table.put(resolved_path, import_entry);4501 os_path_extname(resolved_path, &noextname, nullptr);
4473 g->import_queue.append(import_entry);
4474
4475 import_entry->decls_scope = create_decls_scope(g, import_entry->root, nullptr, nullptr, import_entry);
44764502
4503 Buf *pkg_root_src_dir = &package->root_src_dir;
4504 Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1);
44774505
4478 assert(import_entry->root->type == NodeTypeContainerDecl);4506 assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir));
4479 for (size_t decl_i = 0; decl_i < import_entry->root->data.container_decl.decls.length; decl_i += 1) {
4480 AstNode *top_level_decl = import_entry->root->data.container_decl.decls.at(decl_i);
44814507
4482 if (top_level_decl->type == NodeTypeFnDef) {4508 Buf namespace_name = BUF_INIT;
4483 AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;4509 buf_init_from_buf(&namespace_name, &package->pkg_path);
4484 assert(proto_node->type == NodeTypeFnProto);4510 if (source_kind == SourceKindNonRoot) {
4485 Buf *proto_name = proto_node->data.fn_proto.name;4511 if (buf_len(&namespace_name) != 0) buf_append_char(&namespace_name, NAMESPACE_SEP_CHAR);
4512 buf_append_mem(&namespace_name, buf_ptr(&noextname) + buf_len(&resolved_root_src_dir) + 1,
4513 buf_len(&noextname) - (buf_len(&resolved_root_src_dir) + 1));
4514 buf_replace(&namespace_name, ZIG_OS_SEP_CHAR, NAMESPACE_SEP_CHAR);
4515 }
4516 Buf *bare_name = buf_alloc();
4517 os_path_extname(src_basename, bare_name, nullptr);
44864518
4487 bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);4519 RootStruct *root_struct = allocate<RootStruct>(1);
4488 bool ok_cc = (proto_node->data.fn_proto.cc == CallingConventionUnspecified ||4520 root_struct->package = package;
4489 proto_node->data.fn_proto.cc == CallingConventionCold);4521 root_struct->source_code = source_code;
4522 root_struct->line_offsets = tokenization.line_offsets;
4523 root_struct->path = resolved_path;
4524 root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
4525 ZigType *import_entry = get_root_container_type(g, buf_ptr(&namespace_name), bare_name, root_struct);
4526 if (source_kind == SourceKindRoot) {
4527 assert(g->root_import == nullptr);
4528 g->root_import = import_entry;
4529 }
4530 g->import_table.put(resolved_path, import_entry);
44904531
4491 if (is_pub && ok_cc) {4532 AstNode *root_node = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
4492 if (buf_eql_str(proto_name, "main")) {4533 assert(root_node != nullptr);
4493 g->have_pub_main = true;4534 assert(root_node->type == NodeTypeContainerDecl);
4494 g->subsystem = TargetSubsystemConsole;4535 import_entry->data.structure.decl_node = root_node;
4495 } else if (buf_eql_str(proto_name, "panic")) {4536 import_entry->data.structure.decls_scope->base.source_node = root_node;
4496 g->have_pub_panic = true;4537 if (g->verbose_ast) {
4538 ast_print(stderr, root_node, 0);
4539 }
4540
4541 if (source_kind == SourceKindRoot || package == g->panic_package) {
4542 // Look for panic and main
4543 for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
4544 AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
4545
4546 if (top_level_decl->type == NodeTypeFnDef) {
4547 AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
4548 assert(proto_node->type == NodeTypeFnProto);
4549 Buf *proto_name = proto_node->data.fn_proto.name;
4550
4551 bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);
4552 if (is_pub) {
4553 if (buf_eql_str(proto_name, "main")) {
4554 g->have_pub_main = true;
4555 g->subsystem = TargetSubsystemConsole;
4556 } else if (buf_eql_str(proto_name, "panic")) {
4557 g->have_pub_panic = true;
4558 }
4497 }4559 }
4498 }4560 }
4499 }4561 }
4500 }4562 }
45014563
4502 return import_entry;4564 for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
4503}4565 AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
45044566 scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl);
4505void scan_import(CodeGen *g, ImportTableEntry *import) {
4506 if (!import->scanned) {
4507 import->scanned = true;
4508 scan_decls(g, import->decls_scope, import->root);
4509 }4567 }
4510}
45114568
4512void semantic_analyze(CodeGen *g) {4569 TldContainer *tld_container = allocate<TldContainer>(1);
4513 for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) {4570 init_tld(&tld_container->base, TldIdContainer, &namespace_name, VisibModPub, root_node, nullptr);
4514 ImportTableEntry *import = g->import_queue.at(g->import_queue_index);4571 tld_container->type_entry = import_entry;
4515 scan_import(g, import);4572 tld_container->decls_scope = import_entry->data.structure.decls_scope;
4516 }4573 g->resolve_queue.append(&tld_container->base);
45174574
4518 for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {4575 return import_entry;
4519 AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);4576}
4520 preview_use_decl(g, use_decl_node);
4521 }
4522
4523 for (size_t i = 0; i < g->use_queue.length; i += 1) {
4524 AstNode *use_decl_node = g->use_queue.at(i);
4525 resolve_use_decl(g, use_decl_node);
4526 }
45274577
4578void semantic_analyze(CodeGen *g) {
4528 while (g->resolve_queue_index < g->resolve_queue.length ||4579 while (g->resolve_queue_index < g->resolve_queue.length ||
4529 g->fn_defs_index < g->fn_defs.length)4580 g->fn_defs_index < g->fn_defs.length ||
4581 g->use_queue_index < g->use_queue.length)
4530 {4582 {
4583 for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
4584 AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
4585 preview_use_decl(g, use_decl_node);
4586 resolve_use_decl(g, use_decl_node);
4587 }
4531 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {4588 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
4532 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);4589 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
4533 bool pointer_only = false;
4534 AstNode *source_node = nullptr;4590 AstNode *source_node = nullptr;
4535 resolve_top_level_decl(g, tld, pointer_only, source_node);4591 resolve_top_level_decl(g, tld, source_node);
4536 }4592 }
45374593
4538 for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {4594 for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
...@@ -4613,7 +4669,6 @@ bool handle_is_ptr(ZigType *type_entry) {...@@ -4613,7 +4669,6 @@ bool handle_is_ptr(ZigType *type_entry) {
4613 case ZigTypeIdComptimeInt:4669 case ZigTypeIdComptimeInt:
4614 case ZigTypeIdUndefined:4670 case ZigTypeIdUndefined:
4615 case ZigTypeIdNull:4671 case ZigTypeIdNull:
4616 case ZigTypeIdNamespace:
4617 case ZigTypeIdBoundFn:4672 case ZigTypeIdBoundFn:
4618 case ZigTypeIdArgTuple:4673 case ZigTypeIdArgTuple:
4619 case ZigTypeIdOpaque:4674 case ZigTypeIdOpaque:
...@@ -4637,7 +4692,7 @@ bool handle_is_ptr(ZigType *type_entry) {...@@ -4637,7 +4692,7 @@ bool handle_is_ptr(ZigType *type_entry) {
4637 return type_has_bits(type_entry->data.error_union.payload_type);4692 return type_has_bits(type_entry->data.error_union.payload_type);
4638 case ZigTypeIdOptional:4693 case ZigTypeIdOptional:
4639 return type_has_bits(type_entry->data.maybe.child_type) &&4694 return type_has_bits(type_entry->data.maybe.child_type) &&
4640 !type_is_codegen_pointer(type_entry->data.maybe.child_type) &&4695 !type_is_non_optional_pointer(type_entry->data.maybe.child_type) &&
4641 type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;4696 type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
4642 case ZigTypeIdUnion:4697 case ZigTypeIdUnion:
4643 assert(type_entry->data.unionation.zero_bits_known);4698 assert(type_entry->data.unionation.zero_bits_known);
...@@ -4880,8 +4935,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4880,8 +4935,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4880 return 3415065496;4935 return 3415065496;
4881 case ZigTypeIdErrorSet:4936 case ZigTypeIdErrorSet:
4882 return hash_const_val_error_set(const_val);4937 return hash_const_val_error_set(const_val);
4883 case ZigTypeIdNamespace:
4884 return hash_ptr(const_val->data.x_import);
4885 case ZigTypeIdVector:4938 case ZigTypeIdVector:
4886 // TODO better hashing algorithm4939 // TODO better hashing algorithm
4887 return 3647867726;4940 return 3647867726;
...@@ -4943,7 +4996,6 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {...@@ -4943,7 +4996,6 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
4943 case ZigTypeIdComptimeInt:4996 case ZigTypeIdComptimeInt:
4944 case ZigTypeIdUndefined:4997 case ZigTypeIdUndefined:
4945 case ZigTypeIdNull:4998 case ZigTypeIdNull:
4946 case ZigTypeIdNamespace:
4947 case ZigTypeIdBoundFn:4999 case ZigTypeIdBoundFn:
4948 case ZigTypeIdFn:5000 case ZigTypeIdFn:
4949 case ZigTypeIdOpaque:5001 case ZigTypeIdOpaque:
...@@ -5013,7 +5065,6 @@ static bool return_type_is_cacheable(ZigType *return_type) {...@@ -5013,7 +5065,6 @@ static bool return_type_is_cacheable(ZigType *return_type) {
5013 case ZigTypeIdComptimeInt:5065 case ZigTypeIdComptimeInt:
5014 case ZigTypeIdUndefined:5066 case ZigTypeIdUndefined:
5015 case ZigTypeIdNull:5067 case ZigTypeIdNull:
5016 case ZigTypeIdNamespace:
5017 case ZigTypeIdBoundFn:5068 case ZigTypeIdBoundFn:
5018 case ZigTypeIdFn:5069 case ZigTypeIdFn:
5019 case ZigTypeIdOpaque:5070 case ZigTypeIdOpaque:
...@@ -5143,7 +5194,6 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {...@@ -5143,7 +5194,6 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
5143 case ZigTypeIdComptimeFloat:5194 case ZigTypeIdComptimeFloat:
5144 case ZigTypeIdComptimeInt:5195 case ZigTypeIdComptimeInt:
5145 case ZigTypeIdMetaType:5196 case ZigTypeIdMetaType:
5146 case ZigTypeIdNamespace:
5147 case ZigTypeIdBoundFn:5197 case ZigTypeIdBoundFn:
5148 case ZigTypeIdArgTuple:5198 case ZigTypeIdArgTuple:
5149 case ZigTypeIdOptional:5199 case ZigTypeIdOptional:
...@@ -5209,7 +5259,6 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {...@@ -5209,7 +5259,6 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
5209 case ZigTypeIdUndefined:5259 case ZigTypeIdUndefined:
5210 case ZigTypeIdNull:5260 case ZigTypeIdNull:
5211 case ZigTypeIdMetaType:5261 case ZigTypeIdMetaType:
5212 case ZigTypeIdNamespace:
5213 case ZigTypeIdBoundFn:5262 case ZigTypeIdBoundFn:
5214 case ZigTypeIdArgTuple:5263 case ZigTypeIdArgTuple:
5215 return ReqCompTimeYes;5264 return ReqCompTimeYes;
...@@ -5797,8 +5846,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {...@@ -5797,8 +5846,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
5797 }5846 }
5798 case ZigTypeIdErrorUnion:5847 case ZigTypeIdErrorUnion:
5799 zig_panic("TODO");5848 zig_panic("TODO");
5800 case ZigTypeIdNamespace:
5801 return a->data.x_import == b->data.x_import;
5802 case ZigTypeIdArgTuple:5849 case ZigTypeIdArgTuple:
5803 return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&5850 return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
5804 a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index;5851 a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index;
...@@ -6072,16 +6119,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {...@@ -6072,16 +6119,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
6072 }6119 }
6073 return;6120 return;
6074 }6121 }
6075 case ZigTypeIdNamespace:
6076 {
6077 ImportTableEntry *import = const_val->data.x_import;
6078 if (import->c_import_node) {
6079 buf_appendf(buf, "(namespace from C import)");
6080 } else {
6081 buf_appendf(buf, "(namespace: %s)", buf_ptr(import->path));
6082 }
6083 return;
6084 }
6085 case ZigTypeIdBoundFn:6122 case ZigTypeIdBoundFn:
6086 {6123 {
6087 ZigFn *fn_entry = const_val->data.x_bound_fn.fn;6124 ZigFn *fn_entry = const_val->data.x_bound_fn.fn;
...@@ -6203,7 +6240,6 @@ uint32_t type_id_hash(TypeId x) {...@@ -6203,7 +6240,6 @@ uint32_t type_id_hash(TypeId x) {
6203 case ZigTypeIdEnum:6240 case ZigTypeIdEnum:
6204 case ZigTypeIdUnion:6241 case ZigTypeIdUnion:
6205 case ZigTypeIdFn:6242 case ZigTypeIdFn:
6206 case ZigTypeIdNamespace:
6207 case ZigTypeIdBoundFn:6243 case ZigTypeIdBoundFn:
6208 case ZigTypeIdArgTuple:6244 case ZigTypeIdArgTuple:
6209 case ZigTypeIdPromise:6245 case ZigTypeIdPromise:
...@@ -6252,7 +6288,6 @@ bool type_id_eql(TypeId a, TypeId b) {...@@ -6252,7 +6288,6 @@ bool type_id_eql(TypeId a, TypeId b) {
6252 case ZigTypeIdEnum:6288 case ZigTypeIdEnum:
6253 case ZigTypeIdUnion:6289 case ZigTypeIdUnion:
6254 case ZigTypeIdFn:6290 case ZigTypeIdFn:
6255 case ZigTypeIdNamespace:
6256 case ZigTypeIdBoundFn:6291 case ZigTypeIdBoundFn:
6257 case ZigTypeIdArgTuple:6292 case ZigTypeIdArgTuple:
6258 case ZigTypeIdOpaque:6293 case ZigTypeIdOpaque:
...@@ -6419,7 +6454,6 @@ static const ZigTypeId all_type_ids[] = {...@@ -6419,7 +6454,6 @@ static const ZigTypeId all_type_ids[] = {
6419 ZigTypeIdEnum,6454 ZigTypeIdEnum,
6420 ZigTypeIdUnion,6455 ZigTypeIdUnion,
6421 ZigTypeIdFn,6456 ZigTypeIdFn,
6422 ZigTypeIdNamespace,
6423 ZigTypeIdBoundFn,6457 ZigTypeIdBoundFn,
6424 ZigTypeIdArgTuple,6458 ZigTypeIdArgTuple,
6425 ZigTypeIdOpaque,6459 ZigTypeIdOpaque,
...@@ -6480,18 +6514,16 @@ size_t type_id_index(ZigType *entry) {...@@ -6480,18 +6514,16 @@ size_t type_id_index(ZigType *entry) {
6480 return 17;6514 return 17;
6481 case ZigTypeIdFn:6515 case ZigTypeIdFn:
6482 return 18;6516 return 18;
6483 case ZigTypeIdNamespace:
6484 return 19;
6485 case ZigTypeIdBoundFn:6517 case ZigTypeIdBoundFn:
6486 return 20;6518 return 19;
6487 case ZigTypeIdArgTuple:6519 case ZigTypeIdArgTuple:
6488 return 21;6520 return 20;
6489 case ZigTypeIdOpaque:6521 case ZigTypeIdOpaque:
6490 return 22;6522 return 21;
6491 case ZigTypeIdPromise:6523 case ZigTypeIdPromise:
6492 return 23;6524 return 22;
6493 case ZigTypeIdVector:6525 case ZigTypeIdVector:
6494 return 24;6526 return 23;
6495 }6527 }
6496 zig_unreachable();6528 zig_unreachable();
6497}6529}
...@@ -6538,8 +6570,6 @@ const char *type_id_name(ZigTypeId id) {...@@ -6538,8 +6570,6 @@ const char *type_id_name(ZigTypeId id) {
6538 return "Union";6570 return "Union";
6539 case ZigTypeIdFn:6571 case ZigTypeIdFn:
6540 return "Fn";6572 return "Fn";
6541 case ZigTypeIdNamespace:
6542 return "Namespace";
6543 case ZigTypeIdBoundFn:6573 case ZigTypeIdBoundFn:
6544 return "BoundFn";6574 return "BoundFn";
6545 case ZigTypeIdArgTuple:6575 case ZigTypeIdArgTuple:
...@@ -6619,8 +6649,8 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) {...@@ -6619,8 +6649,8 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) {
6619}6649}
66206650
6621ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {6651ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
6622 Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));6652 Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name));
6623 resolve_top_level_decl(codegen, tld, false, nullptr);6653 resolve_top_level_decl(codegen, tld, nullptr);
6624 assert(tld->id == TldIdVar);6654 assert(tld->id == TldIdVar);
6625 TldVar *tld_var = (TldVar *)tld;6655 TldVar *tld_var = (TldVar *)tld;
6626 ConstExprValue *var_value = tld_var->var->const_value;6656 ConstExprValue *var_value = tld_var->var->const_value;
...@@ -6812,3 +6842,34 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) {...@@ -6812,3 +6842,34 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) {
6812 }6842 }
6813 return false;6843 return false;
6814}6844}
6845
6846void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg) {
6847 size_t i = g->tld_ref_source_node_stack.length;
6848 for (;;) {
6849 if (i == 0)
6850 break;
6851 i -= 1;
6852 AstNode *source_node = g->tld_ref_source_node_stack.at(i);
6853 if (source_node) {
6854 msg = add_error_note(g, msg, source_node, buf_sprintf("referenced here"));
6855 }
6856 }
6857}
6858
6859Buf *type_bare_name(ZigType *type_entry) {
6860 if (is_slice(type_entry)) {
6861 return &type_entry->name;
6862 } else if (is_container(type_entry)) {
6863 return get_container_scope(type_entry)->bare_name;
6864 } else if (type_entry->id == ZigTypeIdOpaque) {
6865 return type_entry->data.opaque.bare_name;
6866 } else {
6867 return &type_entry->name;
6868 }
6869}
6870
6871// TODO this will have to be more clever, probably using the full name
6872// and replacing '.' with '_' or something like that
6873Buf *type_h_name(ZigType *t) {
6874 return type_bare_name(t);
6875}
src/analyze.hpp+21-11
...@@ -12,8 +12,9 @@...@@ -12,8 +12,9 @@
1212
13void semantic_analyze(CodeGen *g);13void semantic_analyze(CodeGen *g);
14ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);14ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
15ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg);15ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
17ZigType *new_type_table_entry(ZigTypeId id);18ZigType *new_type_table_entry(ZigTypeId id);
18ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);19ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
19ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,20ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
...@@ -29,11 +30,13 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type);...@@ -29,11 +30,13 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type);
29ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);30ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);
30ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);31ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
31ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,32ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
32 AstNode *decl_node, const char *name, ContainerLayout layout);33 AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout);
34ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
35 RootStruct *root_struct);
33ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);36ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
34ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);37ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
35ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);38ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
36ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);39ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);
37ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],40ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
38 ZigType *field_types[], size_t field_count);41 ZigType *field_types[], size_t field_count);
39ZigType *get_promise_type(CodeGen *g, ZigType *result_type);42ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
...@@ -46,13 +49,19 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);...@@ -46,13 +49,19 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
46bool ptr_allows_addr_zero(ZigType *ptr_type);49bool ptr_allows_addr_zero(ZigType *ptr_type);
47bool type_is_nonnull_ptr(ZigType *type);50bool type_is_nonnull_ptr(ZigType *type);
4851
49ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);52enum SourceKind {
5053 SourceKindRoot,
54 SourceKindPkgMain,
55 SourceKindNonRoot,
56};
57ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Buf *source_code,
58 SourceKind source_kind);
5159
52ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);60ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);
53Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);61Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
54void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);62Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name);
55bool type_is_codegen_pointer(ZigType *type);63void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node);
64bool type_is_non_optional_pointer(ZigType *type);
5665
57ZigType *get_src_ptr_type(ZigType *type);66ZigType *get_src_ptr_type(ZigType *type);
58ZigType *get_codegen_ptr_type(ZigType *type);67ZigType *get_codegen_ptr_type(ZigType *type);
...@@ -77,11 +86,11 @@ bool is_array_ref(ZigType *type_entry);...@@ -77,11 +86,11 @@ bool is_array_ref(ZigType *type_entry);
77bool is_container_ref(ZigType *type_entry);86bool is_container_ref(ZigType *type_entry);
78bool is_valid_vector_elem_type(ZigType *elem_type);87bool is_valid_vector_elem_type(ZigType *elem_type);
79void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);88void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
80void scan_import(CodeGen *g, ImportTableEntry *import);
81void preview_use_decl(CodeGen *g, AstNode *node);89void preview_use_decl(CodeGen *g, AstNode *node);
82void resolve_use_decl(CodeGen *g, AstNode *node);90void resolve_use_decl(CodeGen *g, AstNode *node);
83ZigFn *scope_fn_entry(Scope *scope);91ZigFn *scope_fn_entry(Scope *scope);
84ImportTableEntry *get_scope_import(Scope *scope);92ZigPackage *scope_package(Scope *scope);
93ZigType *get_scope_import(Scope *scope);
85void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);94void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
86ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,95ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
87 bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);96 bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);
...@@ -109,7 +118,6 @@ ScopeCImport *create_cimport_scope(CodeGen *g, AstNode *node, Scope *parent);...@@ -109,7 +118,6 @@ ScopeCImport *create_cimport_scope(CodeGen *g, AstNode *node, Scope *parent);
109ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);118ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
110ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);119ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
111ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);120ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
112ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ImportTableEntry *import);
113Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);121Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
114Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);122Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
115Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);123Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
...@@ -186,7 +194,7 @@ LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);...@@ -186,7 +194,7 @@ LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
186194
187uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry);195uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry);
188ZigType *get_align_amt_type(CodeGen *g);196ZigType *get_align_amt_type(CodeGen *g);
189PackageTableEntry *new_anonymous_package(void);197ZigPackage *new_anonymous_package(void);
190198
191Buf *const_value_to_buffer(ConstExprValue *const_val);199Buf *const_value_to_buffer(ConstExprValue *const_val);
192void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);200void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);
...@@ -232,4 +240,6 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no...@@ -232,4 +240,6 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no
232 ConstExprValue *const_val, ZigType *wanted_type);240 ConstExprValue *const_val, ZigType *wanted_type);
233241
234void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);242void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
243Buf *type_bare_name(ZigType *t);
244Buf *type_h_name(ZigType *t);
235#endif245#endif
src/buffer.hpp+3-3
...@@ -59,7 +59,7 @@ static inline void buf_deinit(Buf *buf) {...@@ -59,7 +59,7 @@ static inline void buf_deinit(Buf *buf) {
59static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) {59static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) {
60 assert(len != SIZE_MAX);60 assert(len != SIZE_MAX);
61 buf->list.resize(len + 1);61 buf->list.resize(len + 1);
62 safe_memcpy(buf_ptr(buf), ptr, len);62 memcpy(buf_ptr(buf), ptr, len);
63 buf->list.at(buf_len(buf)) = 0;63 buf->list.at(buf_len(buf)) = 0;
64}64}
6565
...@@ -98,7 +98,7 @@ static inline Buf *buf_slice(Buf *in_buf, size_t start, size_t end) {...@@ -98,7 +98,7 @@ static inline Buf *buf_slice(Buf *in_buf, size_t start, size_t end) {
98 assert(end <= buf_len(in_buf));98 assert(end <= buf_len(in_buf));
99 Buf *out_buf = allocate<Buf>(1);99 Buf *out_buf = allocate<Buf>(1);
100 out_buf->list.resize(end - start + 1);100 out_buf->list.resize(end - start + 1);
101 safe_memcpy(buf_ptr(out_buf), buf_ptr(in_buf) + start, end - start);101 memcpy(buf_ptr(out_buf), buf_ptr(in_buf) + start, end - start);
102 out_buf->list.at(buf_len(out_buf)) = 0;102 out_buf->list.at(buf_len(out_buf)) = 0;
103 return out_buf;103 return out_buf;
104}104}
...@@ -108,7 +108,7 @@ static inline void buf_append_mem(Buf *buf, const char *mem, size_t mem_len) {...@@ -108,7 +108,7 @@ static inline void buf_append_mem(Buf *buf, const char *mem, size_t mem_len) {
108 assert(mem_len != SIZE_MAX);108 assert(mem_len != SIZE_MAX);
109 size_t old_len = buf_len(buf);109 size_t old_len = buf_len(buf);
110 buf_resize(buf, old_len + mem_len);110 buf_resize(buf, old_len + mem_len);
111 safe_memcpy(buf_ptr(buf) + old_len, mem, mem_len);111 memcpy(buf_ptr(buf) + old_len, mem, mem_len);
112 buf->list.at(buf_len(buf)) = 0;112 buf->list.at(buf_len(buf)) = 0;
113}113}
114114
src/codegen.cpp+118-94
...@@ -48,16 +48,17 @@ static void init_darwin_native(CodeGen *g) {...@@ -48,16 +48,17 @@ static void init_darwin_native(CodeGen *g) {
48 }48 }
49}49}
5050
51static PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) {51static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {
52 PackageTableEntry *entry = allocate<PackageTableEntry>(1);52 ZigPackage *entry = allocate<ZigPackage>(1);
53 entry->package_table.init(4);53 entry->package_table.init(4);
54 buf_init_from_str(&entry->root_src_dir, root_src_dir);54 buf_init_from_str(&entry->root_src_dir, root_src_dir);
55 buf_init_from_str(&entry->root_src_path, root_src_path);55 buf_init_from_str(&entry->root_src_path, root_src_path);
56 buf_init_from_str(&entry->pkg_path, pkg_path);
56 return entry;57 return entry;
57}58}
5859
59PackageTableEntry *new_anonymous_package(void) {60ZigPackage *new_anonymous_package() {
60 return new_package("", "");61 return new_package("", "", "");
61}62}
6263
63static const char *symbols_that_llvm_depends_on[] = {64static const char *symbols_that_llvm_depends_on[] = {
...@@ -87,8 +88,8 @@ static const char *symbols_that_llvm_depends_on[] = {...@@ -87,8 +88,8 @@ static const char *symbols_that_llvm_depends_on[] = {
87 // TODO probably all of compiler-rt needs to go here88 // TODO probably all of compiler-rt needs to go here
88};89};
8990
90CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,91CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
91 Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc)92 OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc)
92{93{
93 CodeGen *g = allocate<CodeGen>(1);94 CodeGen *g = allocate<CodeGen>(1);
9495
...@@ -132,20 +133,39 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -132,20 +133,39 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
132 }133 }
133134
134 if (root_src_path) {135 if (root_src_path) {
135 Buf *src_basename = buf_alloc();136 Buf *root_pkg_path;
136 Buf *src_dir = buf_alloc();137 Buf *rel_root_src_path;
137 os_path_split(root_src_path, src_dir, src_basename);138 if (main_pkg_path == nullptr) {
139 Buf *src_basename = buf_alloc();
140 Buf *src_dir = buf_alloc();
141 os_path_split(root_src_path, src_dir, src_basename);
142
143 if (buf_len(src_basename) == 0) {
144 fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
145 exit(1);
146 }
147 root_pkg_path = src_dir;
148 rel_root_src_path = src_basename;
149 } else {
150 Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1);
151 Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
138152
139 if (buf_len(src_basename) == 0) {153 if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
140 fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));154 fprintf(stderr, "Root source path '%s' outside main package path '%s'",
141 exit(1);155 buf_ptr(root_src_path), buf_ptr(main_pkg_path));
156 exit(1);
157 }
158 root_pkg_path = main_pkg_path;
159 rel_root_src_path = buf_create_from_mem(
160 buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1,
161 buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1);
142 }162 }
143163
144 g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename));164 g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
145 g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig");165 g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
146 g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);166 g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
147 } else {167 } else {
148 g->root_package = new_package(".", "");168 g->root_package = new_package(".", "", "");
149 }169 }
150170
151 g->zig_std_special_dir = buf_alloc();171 g->zig_std_special_dir = buf_alloc();
...@@ -621,7 +641,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -621,7 +641,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
621 if (scope->di_scope)641 if (scope->di_scope)
622 return scope->di_scope;642 return scope->di_scope;
623643
624 ImportTableEntry *import = get_scope_import(scope);644 ZigType *import = get_scope_import(scope);
625 switch (scope->id) {645 switch (scope->id) {
626 case ScopeIdCImport:646 case ScopeIdCImport:
627 zig_unreachable();647 zig_unreachable();
...@@ -644,7 +664,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -644,7 +664,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
644 assert(fn_di_scope != nullptr);664 assert(fn_di_scope != nullptr);
645 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,665 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
646 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",666 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
647 import->di_file, line_number,667 import->data.structure.root_struct->di_file, line_number,
648 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,668 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,
649 is_definition, scope_line, flags, is_optimized, nullptr);669 is_definition, scope_line, flags, is_optimized, nullptr);
650670
...@@ -658,7 +678,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -658,7 +678,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
658 assert(decls_scope->container_type);678 assert(decls_scope->container_type);
659 scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);679 scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
660 } else {680 } else {
661 scope->di_scope = ZigLLVMFileToScope(import->di_file);681 scope->di_scope = ZigLLVMFileToScope(import->data.structure.root_struct->di_file);
662 }682 }
663 return scope->di_scope;683 return scope->di_scope;
664 case ScopeIdBlock:684 case ScopeIdBlock:
...@@ -668,7 +688,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -668,7 +688,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
668 assert(scope->parent);688 assert(scope->parent);
669 ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,689 ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
670 get_di_scope(g, scope->parent),690 get_di_scope(g, scope->parent),
671 import->di_file,691 import->data.structure.root_struct->di_file,
672 (unsigned)scope->source_node->line + 1,692 (unsigned)scope->source_node->line + 1,
673 (unsigned)scope->source_node->column + 1);693 (unsigned)scope->source_node->column + 1);
674 scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);694 scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
...@@ -1236,7 +1256,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1236,7 +1256,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
12361256
1237 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;1257 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
12381258
1239 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;1259 // stack_trace.instruction_addresses[stack_trace.index & (stack_trace.instruction_addresses.len - 1)] = return_address;
12401260
1241 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);1261 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1242 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);1262 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
...@@ -1254,9 +1274,10 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1254,9 +1274,10 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
12541274
1255 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");1275 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
1256 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");1276 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
1257 LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, len_value, "");1277 LLVMValueRef len_val_minus_one = LLVMBuildSub(g->builder, len_value, LLVMConstInt(usize_type_ref, 1, false), "");
1278 LLVMValueRef masked_val = LLVMBuildAnd(g->builder, index_val, len_val_minus_one, "");
1258 LLVMValueRef address_indices[] = {1279 LLVMValueRef address_indices[] = {
1259 modded_val,1280 masked_val,
1260 };1281 };
12611282
1262 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");1283 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
...@@ -2196,7 +2217,7 @@ var_ok:...@@ -2196,7 +2217,7 @@ var_ok:
2196 if (dest_ty != nullptr && var->decl_node) {2217 if (dest_ty != nullptr && var->decl_node) {
2197 // arg index + 1 because the 0 index is return value2218 // arg index + 1 because the 0 index is return value
2198 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),2219 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
2199 buf_ptr(&var->name), fn_walk->data.vars.import->di_file,2220 buf_ptr(&var->name), fn_walk->data.vars.import->data.structure.root_struct->di_file,
2200 (unsigned)(var->decl_node->line + 1),2221 (unsigned)(var->decl_node->line + 1),
2201 dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);2222 dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
2202 }2223 }
...@@ -3938,7 +3959,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR...@@ -3938,7 +3959,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
3938 if (child_type->zero_bits) {3959 if (child_type->zero_bits) {
3939 return maybe_handle;3960 return maybe_handle;
3940 } else {3961 } else {
3941 bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;3962 bool is_scalar = type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
3942 if (is_scalar) {3963 if (is_scalar) {
3943 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");3964 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
3944 } else {3965 } else {
...@@ -3978,7 +3999,7 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec...@@ -3978,7 +3999,7 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec
3978 if (child_type->zero_bits) {3999 if (child_type->zero_bits) {
3979 return nullptr;4000 return nullptr;
3980 } else {4001 } else {
3981 bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;4002 bool is_scalar = type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
3982 if (is_scalar) {4003 if (is_scalar) {
3983 return maybe_ptr;4004 return maybe_ptr;
3984 } else {4005 } else {
...@@ -4549,7 +4570,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst...@@ -4549,7 +4570,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
45494570
4550 return tmp_struct_ptr;4571 return tmp_struct_ptr;
4551 } else if (array_type->id == ZigTypeIdPointer) {4572 } else if (array_type->id == ZigTypeIdPointer) {
4552 assert(array_type->data.pointer.ptr_len == PtrLenUnknown);4573 assert(array_type->data.pointer.ptr_len != PtrLenSingle);
4553 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);4574 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
4554 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);4575 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
45554576
...@@ -4640,7 +4661,8 @@ static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executabl...@@ -4640,7 +4661,8 @@ static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executabl
4640 IrInstructionReturnAddress *instruction)4661 IrInstructionReturnAddress *instruction)
4641{4662{
4642 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);4663 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
4643 return LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");4664 LLVMValueRef ptr_val = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
4665 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->type_ref, "");
4644}4666}
46454667
4646static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {4668static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {
...@@ -4661,7 +4683,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable...@@ -4661,7 +4683,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
4661 IrInstructionFrameAddress *instruction)4683 IrInstructionFrameAddress *instruction)
4662{4684{
4663 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);4685 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
4664 return LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");4686 LLVMValueRef ptr_val = LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");
4687 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->type_ref, "");
4665}4688}
46664689
4667static LLVMValueRef get_handle_fn_val(CodeGen *g) {4690static LLVMValueRef get_handle_fn_val(CodeGen *g) {
...@@ -4839,7 +4862,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I...@@ -4839,7 +4862,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
4839 }4862 }
48404863
4841 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);4864 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
4842 if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {4865 if (type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
4843 return payload_val;4866 return payload_val;
4844 }4867 }
48454868
...@@ -5800,7 +5823,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con...@@ -5800,7 +5823,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
5800 case ZigTypeIdNull:5823 case ZigTypeIdNull:
5801 case ZigTypeIdErrorUnion:5824 case ZigTypeIdErrorUnion:
5802 case ZigTypeIdErrorSet:5825 case ZigTypeIdErrorSet:
5803 case ZigTypeIdNamespace:
5804 case ZigTypeIdBoundFn:5826 case ZigTypeIdBoundFn:
5805 case ZigTypeIdArgTuple:5827 case ZigTypeIdArgTuple:
5806 case ZigTypeIdVoid:5828 case ZigTypeIdVoid:
...@@ -6077,9 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6077,9 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6077 case ZigTypeIdOptional:6099 case ZigTypeIdOptional:
6078 {6100 {
6079 ZigType *child_type = type_entry->data.maybe.child_type;6101 ZigType *child_type = type_entry->data.maybe.child_type;
6080 if (child_type->zero_bits) {6102 if (!type_has_bits(child_type)) {
6081 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);6103 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
6082 } else if (type_is_codegen_pointer(child_type)) {6104 } else if (get_codegen_ptr_type(type_entry) != nullptr) {
6083 return gen_const_val_ptr(g, const_val, name);6105 return gen_const_val_ptr(g, const_val, name);
6084 } else if (child_type->id == ZigTypeIdErrorSet) {6106 } else if (child_type->id == ZigTypeIdErrorSet) {
6085 return gen_const_val_err_set(g, const_val, name);6107 return gen_const_val_err_set(g, const_val, name);
...@@ -6400,7 +6422,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6400,7 +6422,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6400 case ZigTypeIdComptimeInt:6422 case ZigTypeIdComptimeInt:
6401 case ZigTypeIdUndefined:6423 case ZigTypeIdUndefined:
6402 case ZigTypeIdNull:6424 case ZigTypeIdNull:
6403 case ZigTypeIdNamespace:
6404 case ZigTypeIdBoundFn:6425 case ZigTypeIdBoundFn:
6405 case ZigTypeIdArgTuple:6426 case ZigTypeIdArgTuple:
6406 case ZigTypeIdOpaque:6427 case ZigTypeIdOpaque:
...@@ -6506,12 +6527,12 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,...@@ -6506,12 +6527,12 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
6506 assert(var->gen_is_const);6527 assert(var->gen_is_const);
6507 assert(type_entry);6528 assert(type_entry);
65086529
6509 ImportTableEntry *import = get_scope_import(var->parent_scope);6530 ZigType *import = get_scope_import(var->parent_scope);
6510 assert(import);6531 assert(import);
65116532
6512 bool is_local_to_unit = true;6533 bool is_local_to_unit = true;
6513 ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),6534 ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
6514 buf_ptr(&var->name), import->di_file,6535 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
6515 (unsigned)(var->decl_node->line + 1),6536 (unsigned)(var->decl_node->line + 1),
6516 type_entry->di_type, is_local_to_unit);6537 type_entry->di_type, is_local_to_unit);
65176538
...@@ -6767,7 +6788,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6767,7 +6788,7 @@ static void do_code_gen(CodeGen *g) {
6767 *slot = build_alloca(g, slot_type, "", alignment_bytes);6788 *slot = build_alloca(g, slot_type, "", alignment_bytes);
6768 }6789 }
67696790
6770 ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);6791 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
67716792
6772 unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0;6793 unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0;
67736794
...@@ -6799,7 +6820,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6799,7 +6820,7 @@ static void do_code_gen(CodeGen *g) {
6799 var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);6820 var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
68006821
6801 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),6822 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
6802 buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),6823 buf_ptr(&var->name), import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1),
6803 var->var_type->di_type, !g->strip_debug_symbols, 0);6824 var->var_type->di_type, !g->strip_debug_symbols, 0);
68046825
6805 } else if (is_c_abi) {6826 } else if (is_c_abi) {
...@@ -6823,7 +6844,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6823,7 +6844,7 @@ static void do_code_gen(CodeGen *g) {
6823 }6844 }
6824 if (var->decl_node) {6845 if (var->decl_node) {
6825 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),6846 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
6826 buf_ptr(&var->name), import->di_file,6847 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
6827 (unsigned)(var->decl_node->line + 1),6848 (unsigned)(var->decl_node->line + 1),
6828 gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));6849 gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
6829 }6850 }
...@@ -6971,12 +6992,6 @@ static void define_builtin_types(CodeGen *g) {...@@ -6971,12 +6992,6 @@ static void define_builtin_types(CodeGen *g) {
6971 entry->zero_bits = true;6992 entry->zero_bits = true;
6972 g->builtin_types.entry_invalid = entry;6993 g->builtin_types.entry_invalid = entry;
6973 }6994 }
6974 {
6975 ZigType *entry = new_type_table_entry(ZigTypeIdNamespace);
6976 buf_init_from_str(&entry->name, "(namespace)");
6977 entry->zero_bits = true;
6978 g->builtin_types.entry_namespace = entry;
6979 }
6980 {6995 {
6981 ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);6996 ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);
6982 buf_init_from_str(&entry->name, "comptime_float");6997 buf_init_from_str(&entry->name, "comptime_float");
...@@ -7130,7 +7145,8 @@ static void define_builtin_types(CodeGen *g) {...@@ -7130,7 +7145,8 @@ static void define_builtin_types(CodeGen *g) {
7130 g->builtin_types.entry_i64 = get_int_type(g, true, 64);7145 g->builtin_types.entry_i64 = get_int_type(g, true, 64);
71317146
7132 {7147 {
7133 g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");7148 g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void",
7149 buf_create_from_str("c_void"));
7134 g->primitive_type_table.put(&g->builtin_types.entry_c_void->name, g->builtin_types.entry_c_void);7150 g->primitive_type_table.put(&g->builtin_types.entry_c_void->name, g->builtin_types.entry_c_void);
7135 }7151 }
71367152
...@@ -7470,7 +7486,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7470,7 +7486,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7470 " Enum: Enum,\n"7486 " Enum: Enum,\n"
7471 " Union: Union,\n"7487 " Union: Union,\n"
7472 " Fn: Fn,\n"7488 " Fn: Fn,\n"
7473 " Namespace: void,\n"
7474 " BoundFn: Fn,\n"7489 " BoundFn: Fn,\n"
7475 " ArgTuple: void,\n"7490 " ArgTuple: void,\n"
7476 " Opaque: void,\n"7491 " Opaque: void,\n"
...@@ -7479,18 +7494,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7479,18 +7494,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7479 "\n\n"7494 "\n\n"
7480 " pub const Int = struct {\n"7495 " pub const Int = struct {\n"
7481 " is_signed: bool,\n"7496 " is_signed: bool,\n"
7482 " bits: u8,\n"7497 " bits: comptime_int,\n"
7483 " };\n"7498 " };\n"
7484 "\n"7499 "\n"
7485 " pub const Float = struct {\n"7500 " pub const Float = struct {\n"
7486 " bits: u8,\n"7501 " bits: comptime_int,\n"
7487 " };\n"7502 " };\n"
7488 "\n"7503 "\n"
7489 " pub const Pointer = struct {\n"7504 " pub const Pointer = struct {\n"
7490 " size: Size,\n"7505 " size: Size,\n"
7491 " is_const: bool,\n"7506 " is_const: bool,\n"
7492 " is_volatile: bool,\n"7507 " is_volatile: bool,\n"
7493 " alignment: u32,\n"7508 " alignment: comptime_int,\n"
7494 " child: type,\n"7509 " child: type,\n"
7495 "\n"7510 "\n"
7496 " pub const Size = enum {\n"7511 " pub const Size = enum {\n"
...@@ -7502,7 +7517,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7502,7 +7517,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7502 " };\n"7517 " };\n"
7503 "\n"7518 "\n"
7504 " pub const Array = struct {\n"7519 " pub const Array = struct {\n"
7505 " len: usize,\n"7520 " len: comptime_int,\n"
7506 " child: type,\n"7521 " child: type,\n"
7507 " };\n"7522 " };\n"
7508 "\n"7523 "\n"
...@@ -7514,7 +7529,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7514,7 +7529,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7514 "\n"7529 "\n"
7515 " pub const StructField = struct {\n"7530 " pub const StructField = struct {\n"
7516 " name: []const u8,\n"7531 " name: []const u8,\n"
7517 " offset: ?usize,\n"7532 " offset: ?comptime_int,\n"
7518 " field_type: type,\n"7533 " field_type: type,\n"
7519 " };\n"7534 " };\n"
7520 "\n"7535 "\n"
...@@ -7535,7 +7550,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7535,7 +7550,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7535 "\n"7550 "\n"
7536 " pub const Error = struct {\n"7551 " pub const Error = struct {\n"
7537 " name: []const u8,\n"7552 " name: []const u8,\n"
7538 " value: usize,\n"7553 " value: comptime_int,\n"
7539 " };\n"7554 " };\n"
7540 "\n"7555 "\n"
7541 " pub const ErrorSet = struct {\n"7556 " pub const ErrorSet = struct {\n"
...@@ -7544,7 +7559,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7544,7 +7559,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7544 "\n"7559 "\n"
7545 " pub const EnumField = struct {\n"7560 " pub const EnumField = struct {\n"
7546 " name: []const u8,\n"7561 " name: []const u8,\n"
7547 " value: usize,\n"7562 " value: comptime_int,\n"
7548 " };\n"7563 " };\n"
7549 "\n"7564 "\n"
7550 " pub const Enum = struct {\n"7565 " pub const Enum = struct {\n"
...@@ -7596,7 +7611,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7596,7 +7611,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7596 " };\n"7611 " };\n"
7597 "\n"7612 "\n"
7598 " pub const Vector = struct {\n"7613 " pub const Vector = struct {\n"
7599 " len: u32,\n"7614 " len: comptime_int,\n"
7600 " child: type,\n"7615 " child: type,\n"
7601 " };\n"7616 " };\n"
7602 "\n"7617 "\n"
...@@ -7751,12 +7766,12 @@ static Error define_builtin_compile_vars(CodeGen *g) {...@@ -7751,12 +7766,12 @@ static Error define_builtin_compile_vars(CodeGen *g) {
77517766
7752 assert(g->root_package);7767 assert(g->root_package);
7753 assert(g->std_package);7768 assert(g->std_package);
7754 g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename);7769 g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename, "builtin");
7755 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);7770 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
7756 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);7771 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
7757 g->std_package->package_table.put(buf_create_from_str("std"), g->std_package);7772 g->std_package->package_table.put(buf_create_from_str("std"), g->std_package);
7758 g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents);7773 g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents,
7759 scan_import(g, g->compile_var_import);7774 SourceKindPkgMain);
77607775
7761 return ErrorNone;7776 return ErrorNone;
7762}7777}
...@@ -7948,17 +7963,20 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {...@@ -7948,17 +7963,20 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
7948 Buf *src_dirname = buf_alloc();7963 Buf *src_dirname = buf_alloc();
7949 os_path_split(full_path, src_dirname, src_basename);7964 os_path_split(full_path, src_dirname, src_basename);
79507965
7951 ImportTableEntry *import = allocate<ImportTableEntry>(1);7966 Buf noextname = BUF_INIT;
7952 import->source_code = nullptr;7967 os_path_extname(src_basename, &noextname, nullptr);
7953 import->path = full_path;
7954 g->root_import = import;
7955 import->decls_scope = create_decls_scope(g, nullptr, nullptr, nullptr, import);
79567968
7957 detect_libc(g);7969 detect_libc(g);
79587970
7959 init(g);7971 init(g);
79607972
7961 import->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));7973 RootStruct *root_struct = allocate<RootStruct>(1);
7974 root_struct->source_code = nullptr;
7975 root_struct->path = full_path;
7976 root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
7977
7978 ZigType *import = get_root_container_type(g, buf_ptr(&noextname), &noextname, root_struct);
7979 g->root_import = import;
79627980
7963 ZigList<ErrorMsg *> errors = {0};7981 ZigList<ErrorMsg *> errors = {0};
7964 Error err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr);7982 Error err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr);
...@@ -7977,7 +7995,7 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {...@@ -7977,7 +7995,7 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
7977 }7995 }
7978}7996}
79797997
7980static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {7998static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *basename) {
7981 Buf *code_basename = buf_create_from_str(basename);7999 Buf *code_basename = buf_create_from_str(basename);
7982 Buf path_to_code_src = BUF_INIT;8000 Buf path_to_code_src = BUF_INIT;
7983 os_path_join(g->zig_std_special_dir, code_basename, &path_to_code_src);8001 os_path_join(g->zig_std_special_dir, code_basename, &path_to_code_src);
...@@ -7991,21 +8009,21 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package...@@ -7991,21 +8009,21 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
7991 zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));8009 zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
7992 }8010 }
79938011
7994 return add_source_file(g, package, resolved_path, import_code);8012 return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain);
7995}8013}
79968014
7997static PackageTableEntry *create_bootstrap_pkg(CodeGen *g, PackageTableEntry *pkg_with_main) {8015static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) {
7998 PackageTableEntry *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig");8016 ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special");
7999 package->package_table.put(buf_create_from_str("@root"), pkg_with_main);8017 package->package_table.put(buf_create_from_str("@root"), pkg_with_main);
8000 return package;8018 return package;
8001}8019}
80028020
8003static PackageTableEntry *create_test_runner_pkg(CodeGen *g) {8021static ZigPackage *create_test_runner_pkg(CodeGen *g) {
8004 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig");8022 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
8005}8023}
80068024
8007static PackageTableEntry *create_panic_pkg(CodeGen *g) {8025static ZigPackage *create_panic_pkg(CodeGen *g) {
8008 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig");8026 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
8009}8027}
80108028
8011static void create_test_compile_var_and_add_test_runner(CodeGen *g) {8029static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
...@@ -8089,24 +8107,24 @@ static void gen_root_source(CodeGen *g) {...@@ -8089,24 +8107,24 @@ static void gen_root_source(CodeGen *g) {
8089 exit(1);8107 exit(1);
8090 }8108 }
80918109
8092 g->root_import = add_source_file(g, g->root_package, resolved_path, source_code);8110 ZigType *root_import_alias = add_source_file(g, g->root_package, resolved_path, source_code, SourceKindRoot);
8111 assert(root_import_alias == g->root_import);
80938112
8094 assert(g->root_out_name);8113 assert(g->root_out_name);
8095 assert(g->out_type != OutTypeUnknown);8114 assert(g->out_type != OutTypeUnknown);
80968115
8097 {8116 {
8098 // Zig has lazy top level definitions. Here we semantically analyze the panic function.8117 // Zig has lazy top level definitions. Here we semantically analyze the panic function.
8099 ImportTableEntry *import_with_panic;8118 ZigType *import_with_panic;
8100 if (g->have_pub_panic) {8119 if (g->have_pub_panic) {
8101 import_with_panic = g->root_import;8120 import_with_panic = g->root_import;
8102 } else {8121 } else {
8103 g->panic_package = create_panic_pkg(g);8122 g->panic_package = create_panic_pkg(g);
8104 import_with_panic = add_special_code(g, g->panic_package, "panic.zig");8123 import_with_panic = add_special_code(g, g->panic_package, "panic.zig");
8105 }8124 }
8106 scan_import(g, import_with_panic);8125 Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic"));
8107 Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic"));
8108 assert(panic_tld != nullptr);8126 assert(panic_tld != nullptr);
8109 resolve_top_level_decl(g, panic_tld, false, nullptr);8127 resolve_top_level_decl(g, panic_tld, nullptr);
8110 }8128 }
81118129
81128130
...@@ -8358,7 +8376,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e...@@ -8358,7 +8376,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
8358 case ZigTypeIdComptimeInt:8376 case ZigTypeIdComptimeInt:
8359 case ZigTypeIdUndefined:8377 case ZigTypeIdUndefined:
8360 case ZigTypeIdNull:8378 case ZigTypeIdNull:
8361 case ZigTypeIdNamespace:
8362 case ZigTypeIdBoundFn:8379 case ZigTypeIdBoundFn:
8363 case ZigTypeIdArgTuple:8380 case ZigTypeIdArgTuple:
8364 case ZigTypeIdErrorUnion:8381 case ZigTypeIdErrorUnion:
...@@ -8496,7 +8513,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -8496,7 +8513,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
8496 if (child_type->zero_bits) {8513 if (child_type->zero_bits) {
8497 buf_init_from_str(out_buf, "bool");8514 buf_init_from_str(out_buf, "bool");
8498 return;8515 return;
8499 } else if (type_is_codegen_pointer(child_type)) {8516 } else if (type_is_non_optional_pointer(child_type)) {
8500 return get_c_type(g, gen_h, child_type, out_buf);8517 return get_c_type(g, gen_h, child_type, out_buf);
8501 } else {8518 } else {
8502 zig_unreachable();8519 zig_unreachable();
...@@ -8506,19 +8523,19 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -8506,19 +8523,19 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
8506 case ZigTypeIdOpaque:8523 case ZigTypeIdOpaque:
8507 {8524 {
8508 buf_init_from_str(out_buf, "struct ");8525 buf_init_from_str(out_buf, "struct ");
8509 buf_append_buf(out_buf, &type_entry->name);8526 buf_append_buf(out_buf, type_h_name(type_entry));
8510 return;8527 return;
8511 }8528 }
8512 case ZigTypeIdUnion:8529 case ZigTypeIdUnion:
8513 {8530 {
8514 buf_init_from_str(out_buf, "union ");8531 buf_init_from_str(out_buf, "union ");
8515 buf_append_buf(out_buf, &type_entry->name);8532 buf_append_buf(out_buf, type_h_name(type_entry));
8516 return;8533 return;
8517 }8534 }
8518 case ZigTypeIdEnum:8535 case ZigTypeIdEnum:
8519 {8536 {
8520 buf_init_from_str(out_buf, "enum ");8537 buf_init_from_str(out_buf, "enum ");
8521 buf_append_buf(out_buf, &type_entry->name);8538 buf_append_buf(out_buf, type_h_name(type_entry));
8522 return;8539 return;
8523 }8540 }
8524 case ZigTypeIdArray:8541 case ZigTypeIdArray:
...@@ -8541,7 +8558,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -8541,7 +8558,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
8541 case ZigTypeIdInvalid:8558 case ZigTypeIdInvalid:
8542 case ZigTypeIdMetaType:8559 case ZigTypeIdMetaType:
8543 case ZigTypeIdBoundFn:8560 case ZigTypeIdBoundFn:
8544 case ZigTypeIdNamespace:
8545 case ZigTypeIdComptimeFloat:8561 case ZigTypeIdComptimeFloat:
8546 case ZigTypeIdComptimeInt:8562 case ZigTypeIdComptimeInt:
8547 case ZigTypeIdUndefined:8563 case ZigTypeIdUndefined:
...@@ -8614,10 +8630,17 @@ static void gen_h_file(CodeGen *g) {...@@ -8614,10 +8630,17 @@ static void gen_h_file(CodeGen *g) {
8614 Buf return_type_c = BUF_INIT;8630 Buf return_type_c = BUF_INIT;
8615 get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c);8631 get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c);
86168632
8633 Buf *symbol_name;
8634 if (fn_table_entry->export_list.length == 0) {
8635 symbol_name = &fn_table_entry->symbol_name;
8636 } else {
8637 FnExport *fn_export = &fn_table_entry->export_list.items[0];
8638 symbol_name = &fn_export->name;
8639 }
8617 buf_appendf(&h_buf, "%s %s %s(",8640 buf_appendf(&h_buf, "%s %s %s(",
8618 buf_ptr(export_macro),8641 buf_ptr(export_macro),
8619 buf_ptr(&return_type_c),8642 buf_ptr(&return_type_c),
8620 buf_ptr(&fn_table_entry->symbol_name));8643 buf_ptr(symbol_name));
86218644
8622 Buf param_type_c = BUF_INIT;8645 Buf param_type_c = BUF_INIT;
8623 if (fn_type_id->param_count > 0) {8646 if (fn_type_id->param_count > 0) {
...@@ -8693,7 +8716,6 @@ static void gen_h_file(CodeGen *g) {...@@ -8693,7 +8716,6 @@ static void gen_h_file(CodeGen *g) {
8693 case ZigTypeIdNull:8716 case ZigTypeIdNull:
8694 case ZigTypeIdErrorUnion:8717 case ZigTypeIdErrorUnion:
8695 case ZigTypeIdErrorSet:8718 case ZigTypeIdErrorSet:
8696 case ZigTypeIdNamespace:
8697 case ZigTypeIdBoundFn:8719 case ZigTypeIdBoundFn:
8698 case ZigTypeIdArgTuple:8720 case ZigTypeIdArgTuple:
8699 case ZigTypeIdOptional:8721 case ZigTypeIdOptional:
...@@ -8703,7 +8725,7 @@ static void gen_h_file(CodeGen *g) {...@@ -8703,7 +8725,7 @@ static void gen_h_file(CodeGen *g) {
8703 zig_unreachable();8725 zig_unreachable();
8704 case ZigTypeIdEnum:8726 case ZigTypeIdEnum:
8705 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {8727 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
8706 fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name));8728 fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));
8707 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {8729 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
8708 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];8730 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
8709 Buf *value_buf = buf_alloc();8731 Buf *value_buf = buf_alloc();
...@@ -8716,12 +8738,12 @@ static void gen_h_file(CodeGen *g) {...@@ -8716,12 +8738,12 @@ static void gen_h_file(CodeGen *g) {
8716 }8738 }
8717 fprintf(out_h, "};\n\n");8739 fprintf(out_h, "};\n\n");
8718 } else {8740 } else {
8719 fprintf(out_h, "enum %s;\n", buf_ptr(&type_entry->name));8741 fprintf(out_h, "enum %s;\n", buf_ptr(type_h_name(type_entry)));
8720 }8742 }
8721 break;8743 break;
8722 case ZigTypeIdStruct:8744 case ZigTypeIdStruct:
8723 if (type_entry->data.structure.layout == ContainerLayoutExtern) {8745 if (type_entry->data.structure.layout == ContainerLayoutExtern) {
8724 fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name));8746 fprintf(out_h, "struct %s {\n", buf_ptr(type_h_name(type_entry)));
8725 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {8747 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
8726 TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];8748 TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
87278749
...@@ -8739,12 +8761,12 @@ static void gen_h_file(CodeGen *g) {...@@ -8739,12 +8761,12 @@ static void gen_h_file(CodeGen *g) {
8739 }8761 }
8740 fprintf(out_h, "};\n\n");8762 fprintf(out_h, "};\n\n");
8741 } else {8763 } else {
8742 fprintf(out_h, "struct %s;\n", buf_ptr(&type_entry->name));8764 fprintf(out_h, "struct %s;\n", buf_ptr(type_h_name(type_entry)));
8743 }8765 }
8744 break;8766 break;
8745 case ZigTypeIdUnion:8767 case ZigTypeIdUnion:
8746 if (type_entry->data.unionation.layout == ContainerLayoutExtern) {8768 if (type_entry->data.unionation.layout == ContainerLayoutExtern) {
8747 fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name));8769 fprintf(out_h, "union %s {\n", buf_ptr(type_h_name(type_entry)));
8748 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {8770 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
8749 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];8771 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
87508772
...@@ -8754,11 +8776,11 @@ static void gen_h_file(CodeGen *g) {...@@ -8754,11 +8776,11 @@ static void gen_h_file(CodeGen *g) {
8754 }8776 }
8755 fprintf(out_h, "};\n\n");8777 fprintf(out_h, "};\n\n");
8756 } else {8778 } else {
8757 fprintf(out_h, "union %s;\n", buf_ptr(&type_entry->name));8779 fprintf(out_h, "union %s;\n", buf_ptr(type_h_name(type_entry)));
8758 }8780 }
8759 break;8781 break;
8760 case ZigTypeIdOpaque:8782 case ZigTypeIdOpaque:
8761 fprintf(out_h, "struct %s;\n\n", buf_ptr(&type_entry->name));8783 fprintf(out_h, "struct %s;\n\n", buf_ptr(type_h_name(type_entry)));
8762 break;8784 break;
8763 }8785 }
8764 }8786 }
...@@ -8792,7 +8814,7 @@ void codegen_add_time_event(CodeGen *g, const char *name) {...@@ -8792,7 +8814,7 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
8792 g->timing_events.append({os_get_time(), name});8814 g->timing_events.append({os_get_time(), name});
8793}8815}
87948816
8795static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {8817static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) {
8796 if (buf_len(&pkg->root_src_path) == 0)8818 if (buf_len(&pkg->root_src_path) == 0)
8797 return;8819 return;
87988820
...@@ -9046,9 +9068,11 @@ void codegen_build_and_link(CodeGen *g) {...@@ -9046,9 +9068,11 @@ void codegen_build_and_link(CodeGen *g) {
9046 codegen_add_time_event(g, "Done");9068 codegen_add_time_event(g, "Done");
9047}9069}
90489070
9049PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {9071ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
9072 const char *pkg_path)
9073{
9050 init(g);9074 init(g);
9051 PackageTableEntry *pkg = new_package(root_src_dir, root_src_path);9075 ZigPackage *pkg = new_package(root_src_dir, root_src_path, pkg_path);
9052 if (g->std_package != nullptr) {9076 if (g->std_package != nullptr) {
9053 assert(g->compile_var_package != nullptr);9077 assert(g->compile_var_package != nullptr);
9054 pkg->package_table.put(buf_create_from_str("std"), g->std_package);9078 pkg->package_table.put(buf_create_from_str("std"), g->std_package);
src/codegen.hpp+4-3
...@@ -15,8 +15,8 @@...@@ -15,8 +15,8 @@
1515
16#include <stdio.h>16#include <stdio.h>
1717
18CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,18CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
19 Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);19 OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
2020
21void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);21void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
22void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);22void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
...@@ -48,7 +48,8 @@ void codegen_print_timing_report(CodeGen *g, FILE *f);...@@ -48,7 +48,8 @@ void codegen_print_timing_report(CodeGen *g, FILE *f);
48void codegen_link(CodeGen *g);48void codegen_link(CodeGen *g);
49void codegen_build_and_link(CodeGen *g);49void codegen_build_and_link(CodeGen *g);
5050
51PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path);51ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
52 const char *pkg_path);
52void codegen_add_assembly(CodeGen *g, Buf *path);53void codegen_add_assembly(CodeGen *g, Buf *path);
53void codegen_add_object(CodeGen *g, Buf *object_path);54void codegen_add_object(CodeGen *g, Buf *object_path);
5455
src/compiler.cpp+3-3
...@@ -78,8 +78,8 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {...@@ -78,8 +78,8 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
78 Buf std_buf = BUF_INIT;78 Buf std_buf = BUF_INIT;
79 buf_init_from_str(&std_buf, "std");79 buf_init_from_str(&std_buf, "std");
8080
81 Buf index_zig_buf = BUF_INIT;81 Buf std_zig_buf = BUF_INIT;
82 buf_init_from_str(&index_zig_buf, "index.zig");82 buf_init_from_str(&std_zig_buf, "std.zig");
8383
84 Buf test_lib_dir = BUF_INIT;84 Buf test_lib_dir = BUF_INIT;
85 Buf test_zig_dir = BUF_INIT;85 Buf test_zig_dir = BUF_INIT;
...@@ -89,7 +89,7 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {...@@ -89,7 +89,7 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
89 os_path_join(test_path, &lib_buf, &test_lib_dir);89 os_path_join(test_path, &lib_buf, &test_lib_dir);
90 os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir);90 os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir);
91 os_path_join(&test_zig_dir, &std_buf, &test_std_dir);91 os_path_join(&test_zig_dir, &std_buf, &test_std_dir);
92 os_path_join(&test_std_dir, &index_zig_buf, &test_index_file);92 os_path_join(&test_std_dir, &std_zig_buf, &test_index_file);
9393
94 int err;94 int err;
95 bool exists;95 bool exists;
src/ir.cpp+149-143
...@@ -258,7 +258,6 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {...@@ -258,7 +258,6 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
258 case ZigTypeIdPointer:258 case ZigTypeIdPointer:
259 case ZigTypeIdUndefined:259 case ZigTypeIdUndefined:
260 case ZigTypeIdNull:260 case ZigTypeIdNull:
261 case ZigTypeIdNamespace:
262 case ZigTypeIdBoundFn:261 case ZigTypeIdBoundFn:
263 case ZigTypeIdErrorSet:262 case ZigTypeIdErrorSet:
264 case ZigTypeIdOpaque:263 case ZigTypeIdOpaque:
...@@ -1123,11 +1122,11 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *...@@ -1123,11 +1122,11 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *
1123 return &const_instruction->base;1122 return &const_instruction->base;
1124}1123}
11251124
1126static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) {1125static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigType *import) {
1127 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);1126 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
1128 const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace;1127 const_instruction->base.value.type = irb->codegen->builtin_types.entry_type;
1129 const_instruction->base.value.special = ConstValSpecialStatic;1128 const_instruction->base.value.special = ConstValSpecialStatic;
1130 const_instruction->base.value.data.x_import = import;1129 const_instruction->base.value.data.x_type = import;
1131 return &const_instruction->base;1130 return &const_instruction->base;
1132}1131}
11331132
...@@ -3824,7 +3823,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3824,7 +3823,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
3824 if (tld)3823 if (tld)
3825 return ir_build_decl_ref(irb, scope, node, tld, lval);3824 return ir_build_decl_ref(irb, scope, node, tld, lval);
38263825
3827 if (node->owner->any_imports_failed) {3826 if (get_container_scope(node->owner)->any_imports_failed) {
3828 // skip the error message since we had a failing import in this file3827 // skip the error message since we had a failing import in this file
3829 // if an import breaks we don't need redundant undeclared identifier errors3828 // if an import breaks we don't need redundant undeclared identifier errors
3830 return irb->codegen->invalid_instruction;3829 return irb->codegen->invalid_instruction;
...@@ -6609,20 +6608,32 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o...@@ -6609,20 +6608,32 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
6609 return true;6608 return true;
6610}6609}
66116610
6612static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) {6611static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name,
6612 Scope *scope, AstNode *source_node, Buf *out_bare_name)
6613{
6613 if (exec->name) {6614 if (exec->name) {
6614 return exec->name;6615 ZigType *import = get_scope_import(scope);
6616 Buf *namespace_name = buf_create_from_buf(&import->name);
6617 if (buf_len(namespace_name) != 0) buf_append_char(namespace_name, NAMESPACE_SEP_CHAR);
6618 buf_append_buf(namespace_name, exec->name);
6619 buf_init_from_buf(out_bare_name, exec->name);
6620 return namespace_name;
6615 } else if (exec->name_fn != nullptr) {6621 } else if (exec->name_fn != nullptr) {
6616 Buf *name = buf_alloc();6622 Buf *name = buf_alloc();
6617 buf_append_buf(name, &exec->name_fn->symbol_name);6623 buf_append_buf(name, &exec->name_fn->symbol_name);
6618 buf_appendf(name, "(");6624 buf_appendf(name, "(");
6619 render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);6625 render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);
6620 buf_appendf(name, ")");6626 buf_appendf(name, ")");
6627 buf_init_from_buf(out_bare_name, name);
6621 return name;6628 return name;
6622 } else {6629 } else {
6623 //Note: C-imports do not have valid location information6630 ZigType *import = get_scope_import(scope);
6624 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,6631 Buf *namespace_name = buf_create_from_buf(&import->name);
6625 (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);6632 if (buf_len(namespace_name) != 0) buf_append_char(namespace_name, NAMESPACE_SEP_CHAR);
6633 buf_appendf(namespace_name, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize, kind_name,
6634 source_node->line + 1, source_node->column + 1);
6635 buf_init_from_buf(out_bare_name, namespace_name);
6636 return namespace_name;
6626 }6637 }
6627}6638}
66286639
...@@ -6630,24 +6641,23 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,...@@ -6630,24 +6641,23 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
6630 assert(node->type == NodeTypeContainerDecl);6641 assert(node->type == NodeTypeContainerDecl);
66316642
6632 ContainerKind kind = node->data.container_decl.kind;6643 ContainerKind kind = node->data.container_decl.kind;
6633 Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), node);6644 Buf *bare_name = buf_alloc();
66346645 Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), parent_scope, node, bare_name);
6635 VisibMod visib_mod = VisibModPub;
6636 TldContainer *tld_container = allocate<TldContainer>(1);
6637 init_tld(&tld_container->base, TldIdContainer, name, visib_mod, node, parent_scope);
66386646
6639 ContainerLayout layout = node->data.container_decl.layout;6647 ContainerLayout layout = node->data.container_decl.layout;
6640 ZigType *container_type = get_partial_container_type(irb->codegen, parent_scope,6648 ZigType *container_type = get_partial_container_type(irb->codegen, parent_scope,
6641 kind, node, buf_ptr(name), layout);6649 kind, node, buf_ptr(name), bare_name, layout);
6642 ScopeDecls *child_scope = get_container_scope(container_type);6650 ScopeDecls *child_scope = get_container_scope(container_type);
66436651
6644 tld_container->type_entry = container_type;
6645 tld_container->decls_scope = child_scope;
6646
6647 for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) {6652 for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) {
6648 AstNode *child_node = node->data.container_decl.decls.at(i);6653 AstNode *child_node = node->data.container_decl.decls.at(i);
6649 scan_decls(irb->codegen, child_scope, child_node);6654 scan_decls(irb->codegen, child_scope, child_node);
6650 }6655 }
6656
6657 TldContainer *tld_container = allocate<TldContainer>(1);
6658 init_tld(&tld_container->base, TldIdContainer, bare_name, VisibModPub, node, parent_scope);
6659 tld_container->type_entry = container_type;
6660 tld_container->decls_scope = child_scope;
6651 irb->codegen->resolve_queue.append(&tld_container->base);6661 irb->codegen->resolve_queue.append(&tld_container->base);
66526662
6653 // Add this to the list to mark as invalid if analyzing this exec fails.6663 // Add this to the list to mark as invalid if analyzing this exec fails.
...@@ -6732,7 +6742,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A...@@ -6732,7 +6742,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
67326742
6733 uint32_t err_count = node->data.err_set_decl.decls.length;6743 uint32_t err_count = node->data.err_set_decl.decls.length;
67346744
6735 Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node);6745 Buf bare_name = BUF_INIT;
6746 Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error", parent_scope, node, &bare_name);
6736 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);6747 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
6737 buf_init_from_buf(&err_set_type->name, type_name);6748 buf_init_from_buf(&err_set_type->name, type_name);
6738 err_set_type->data.error_set.err_count = err_count;6749 err_set_type->data.error_set.err_count = err_count;
...@@ -12065,7 +12076,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -12065,7 +12076,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
12065 case ZigTypeIdErrorSet:12076 case ZigTypeIdErrorSet:
12066 case ZigTypeIdFn:12077 case ZigTypeIdFn:
12067 case ZigTypeIdOpaque:12078 case ZigTypeIdOpaque:
12068 case ZigTypeIdNamespace:
12069 case ZigTypeIdBoundFn:12079 case ZigTypeIdBoundFn:
12070 case ZigTypeIdArgTuple:12080 case ZigTypeIdArgTuple:
12071 case ZigTypeIdPromise:12081 case ZigTypeIdPromise:
...@@ -13407,7 +13417,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13407,7 +13417,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13407 case ZigTypeIdOptional:13417 case ZigTypeIdOptional:
13408 case ZigTypeIdErrorUnion:13418 case ZigTypeIdErrorUnion:
13409 case ZigTypeIdErrorSet:13419 case ZigTypeIdErrorSet:
13410 case ZigTypeIdNamespace:
13411 case ZigTypeIdBoundFn:13420 case ZigTypeIdBoundFn:
13412 case ZigTypeIdArgTuple:13421 case ZigTypeIdArgTuple:
13413 case ZigTypeIdOpaque:13422 case ZigTypeIdOpaque:
...@@ -13432,7 +13441,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13432,7 +13441,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13432 case ZigTypeIdErrorSet:13441 case ZigTypeIdErrorSet:
13433 case ZigTypeIdVector:13442 case ZigTypeIdVector:
13434 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));13443 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
13435 case ZigTypeIdNamespace:
13436 case ZigTypeIdBoundFn:13444 case ZigTypeIdBoundFn:
13437 case ZigTypeIdArgTuple:13445 case ZigTypeIdArgTuple:
13438 case ZigTypeIdOpaque:13446 case ZigTypeIdOpaque:
...@@ -14616,7 +14624,6 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_...@@ -14616,7 +14624,6 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
14616 case ZigTypeIdEnum:14624 case ZigTypeIdEnum:
14617 case ZigTypeIdUnion:14625 case ZigTypeIdUnion:
14618 case ZigTypeIdFn:14626 case ZigTypeIdFn:
14619 case ZigTypeIdNamespace:
14620 case ZigTypeIdBoundFn:14627 case ZigTypeIdBoundFn:
14621 case ZigTypeIdArgTuple:14628 case ZigTypeIdArgTuple:
14622 case ZigTypeIdPromise:14629 case ZigTypeIdPromise:
...@@ -15368,7 +15375,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -15368,7 +15375,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
15368 auto entry = container_scope->decl_table.maybe_get(field_name);15375 auto entry = container_scope->decl_table.maybe_get(field_name);
15369 Tld *tld = entry ? entry->value : nullptr;15376 Tld *tld = entry ? entry->value : nullptr;
15370 if (tld && tld->id == TldIdFn) {15377 if (tld && tld->id == TldIdFn) {
15371 resolve_top_level_decl(ira->codegen, tld, false, source_instr->source_node);15378 resolve_top_level_decl(ira->codegen, tld, source_instr->source_node);
15372 if (tld->resolution == TldResolutionInvalid)15379 if (tld->resolution == TldResolutionInvalid)
15373 return ira->codegen->invalid_instruction;15380 return ira->codegen->invalid_instruction;
15374 TldFn *tld_fn = (TldFn *)tld;15381 TldFn *tld_fn = (TldFn *)tld;
...@@ -15557,8 +15564,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name,...@@ -15557,8 +15564,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name,
1555715564
1555815565
15559static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {15566static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
15560 bool pointer_only = false;15567 resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node);
15561 resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node);
15562 if (tld->resolution == TldResolutionInvalid)15568 if (tld->resolution == TldResolutionInvalid)
15563 return ira->codegen->invalid_instruction;15569 return ira->codegen->invalid_instruction;
1556415570
...@@ -15735,12 +15741,17 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc...@@ -15735,12 +15741,17 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
15735 }15741 }
15736 }15742 }
15737 ScopeDecls *container_scope = get_container_scope(child_type);15743 ScopeDecls *container_scope = get_container_scope(child_type);
15738 if (container_scope != nullptr) {15744 Tld *tld = find_container_decl(ira->codegen, container_scope, field_name);
15739 auto entry = container_scope->decl_table.maybe_get(field_name);15745 if (tld) {
15740 Tld *tld = entry ? entry->value : nullptr;15746 if (tld->visib_mod == VisibModPrivate &&
15741 if (tld) {15747 tld->import != get_scope_import(field_ptr_instruction->base.scope))
15742 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);15748 {
15749 ErrorMsg *msg = ir_add_error(ira, &field_ptr_instruction->base,
15750 buf_sprintf("'%s' is private", buf_ptr(field_name)));
15751 add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
15752 return ira->codegen->invalid_instruction;
15743 }15753 }
15754 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
15744 }15755 }
15745 if (child_type->id == ZigTypeIdUnion &&15756 if (child_type->id == ZigTypeIdUnion &&
15746 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||15757 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
...@@ -15758,9 +15769,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc...@@ -15758,9 +15769,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
15758 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);15769 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);
15759 }15770 }
15760 }15771 }
15772 const char *container_name = (child_type == ira->codegen->root_import) ?
15773 "root source file" : buf_ptr(buf_sprintf("container '%s'", buf_ptr(&child_type->name)));
15761 ir_add_error(ira, &field_ptr_instruction->base,15774 ir_add_error(ira, &field_ptr_instruction->base,
15762 buf_sprintf("container '%s' has no member called '%s'",15775 buf_sprintf("%s has no member called '%s'",
15763 buf_ptr(&child_type->name), buf_ptr(field_name)));15776 container_name, buf_ptr(field_name)));
15764 return ira->codegen->invalid_instruction;15777 return ira->codegen->invalid_instruction;
15765 } else if (child_type->id == ZigTypeIdErrorSet) {15778 } else if (child_type->id == ZigTypeIdErrorSet) {
15766 ErrorTableEntry *err_entry;15779 ErrorTableEntry *err_entry;
...@@ -15971,37 +15984,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc...@@ -15971,37 +15984,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
15971 buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));15984 buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
15972 return ira->codegen->invalid_instruction;15985 return ira->codegen->invalid_instruction;
15973 }15986 }
15974 } else if (container_type->id == ZigTypeIdNamespace) {
15975 assert(container_ptr->value.type->id == ZigTypeIdPointer);
15976 ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
15977 if (!container_ptr_val)
15978 return ira->codegen->invalid_instruction;
15979
15980 ConstExprValue *namespace_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val,
15981 field_ptr_instruction->base.source_node);
15982 if (namespace_val == nullptr)
15983 return ira->codegen->invalid_instruction;
15984 assert(namespace_val->special == ConstValSpecialStatic);
15985
15986 ImportTableEntry *namespace_import = namespace_val->data.x_import;
15987
15988 Tld *tld = find_decl(ira->codegen, &namespace_import->decls_scope->base, field_name);
15989 if (tld) {
15990 if (tld->visib_mod == VisibModPrivate &&
15991 tld->import != source_node->owner)
15992 {
15993 ErrorMsg *msg = ir_add_error_node(ira, source_node,
15994 buf_sprintf("'%s' is private", buf_ptr(field_name)));
15995 add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
15996 return ira->codegen->invalid_instruction;
15997 }
15998 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
15999 } else {
16000 const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
16001 ir_add_error_node(ira, source_node,
16002 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), import_name));
16003 return ira->codegen->invalid_instruction;
16004 }
16005 } else {15987 } else {
16006 ir_add_error_node(ira, field_ptr_instruction->base.source_node,15988 ir_add_error_node(ira, field_ptr_instruction->base.source_node,
16007 buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name)));15989 buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name)));
...@@ -16281,7 +16263,6 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -16281,7 +16263,6 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
16281 case ZigTypeIdEnum:16263 case ZigTypeIdEnum:
16282 case ZigTypeIdUnion:16264 case ZigTypeIdUnion:
16283 case ZigTypeIdFn:16265 case ZigTypeIdFn:
16284 case ZigTypeIdNamespace:
16285 case ZigTypeIdBoundFn:16266 case ZigTypeIdBoundFn:
16286 case ZigTypeIdPromise:16267 case ZigTypeIdPromise:
16287 case ZigTypeIdVector:16268 case ZigTypeIdVector:
...@@ -16402,7 +16383,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -16402,7 +16383,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
16402 case ZigTypeIdEnum:16383 case ZigTypeIdEnum:
16403 case ZigTypeIdUnion:16384 case ZigTypeIdUnion:
16404 case ZigTypeIdFn:16385 case ZigTypeIdFn:
16405 case ZigTypeIdNamespace:
16406 case ZigTypeIdBoundFn:16386 case ZigTypeIdBoundFn:
16407 case ZigTypeIdPromise:16387 case ZigTypeIdPromise:
16408 case ZigTypeIdVector:16388 case ZigTypeIdVector:
...@@ -16452,7 +16432,6 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -16452,7 +16432,6 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
16452 case ZigTypeIdComptimeInt:16432 case ZigTypeIdComptimeInt:
16453 case ZigTypeIdBoundFn:16433 case ZigTypeIdBoundFn:
16454 case ZigTypeIdMetaType:16434 case ZigTypeIdMetaType:
16455 case ZigTypeIdNamespace:
16456 case ZigTypeIdArgTuple:16435 case ZigTypeIdArgTuple:
16457 case ZigTypeIdOpaque:16436 case ZigTypeIdOpaque:
16458 ir_add_error_node(ira, size_of_instruction->base.source_node,16437 ir_add_error_node(ira, size_of_instruction->base.source_node,
...@@ -16860,7 +16839,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -16860,7 +16839,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
16860 case ZigTypeIdPointer:16839 case ZigTypeIdPointer:
16861 case ZigTypeIdPromise:16840 case ZigTypeIdPromise:
16862 case ZigTypeIdFn:16841 case ZigTypeIdFn:
16863 case ZigTypeIdNamespace:
16864 case ZigTypeIdErrorSet: {16842 case ZigTypeIdErrorSet: {
16865 if (pointee_val) {16843 if (pointee_val) {
16866 IrInstruction *result = ir_const(ira, &switch_target_instruction->base, nullptr);16844 IrInstruction *result = ir_const(ira, &switch_target_instruction->base, nullptr);
...@@ -17009,25 +16987,29 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio...@@ -17009,25 +16987,29 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
17009 return ira->codegen->invalid_instruction;16987 return ira->codegen->invalid_instruction;
1701016988
17011 AstNode *source_node = import_instruction->base.source_node;16989 AstNode *source_node = import_instruction->base.source_node;
17012 ImportTableEntry *import = source_node->owner;16990 ZigType *import = source_node->owner;
1701316991
17014 Buf *import_target_path;16992 Buf *import_target_path;
17015 Buf *search_dir;16993 Buf *search_dir;
17016 assert(import->package);16994 assert(import->data.structure.root_struct->package);
17017 PackageTableEntry *target_package;16995 ZigPackage *target_package;
17018 auto package_entry = import->package->package_table.maybe_get(import_target_str);16996 auto package_entry = import->data.structure.root_struct->package->package_table.maybe_get(import_target_str);
16997 SourceKind source_kind;
17019 if (package_entry) {16998 if (package_entry) {
17020 target_package = package_entry->value;16999 target_package = package_entry->value;
17021 import_target_path = &target_package->root_src_path;17000 import_target_path = &target_package->root_src_path;
17022 search_dir = &target_package->root_src_dir;17001 search_dir = &target_package->root_src_dir;
17002 source_kind = SourceKindPkgMain;
17023 } else {17003 } else {
17024 // try it as a filename17004 // try it as a filename
17025 target_package = import->package;17005 target_package = import->data.structure.root_struct->package;
17026 import_target_path = import_target_str;17006 import_target_path = import_target_str;
1702717007
17028 // search relative to importing file17008 // search relative to importing file
17029 search_dir = buf_alloc();17009 search_dir = buf_alloc();
17030 os_path_dirname(import->path, search_dir);17010 os_path_dirname(import->data.structure.root_struct->path, search_dir);
17011
17012 source_kind = SourceKindNonRoot;
17031 }17013 }
1703217014
17033 Buf full_path = BUF_INIT;17015 Buf full_path = BUF_INIT;
...@@ -17041,10 +17023,19 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio...@@ -17041,10 +17023,19 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
1704117023
17042 auto import_entry = ira->codegen->import_table.maybe_get(resolved_path);17024 auto import_entry = ira->codegen->import_table.maybe_get(resolved_path);
17043 if (import_entry) {17025 if (import_entry) {
17044 IrInstruction *result = ir_const(ira, &import_instruction->base,17026 return ir_const_type(ira, &import_instruction->base, import_entry->value);
17045 ira->codegen->builtin_types.entry_namespace);17027 }
17046 result->value.data.x_import = import_entry->value;17028
17047 return result;17029 if (source_kind == SourceKindNonRoot) {
17030 ZigPackage *cur_scope_pkg = scope_package(import_instruction->base.scope);
17031 Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir;
17032 Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1);
17033 if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) {
17034 ir_add_error_node(ira, source_node,
17035 buf_sprintf("import of file outside package path: '%s'",
17036 buf_ptr(import_target_path)));
17037 return ira->codegen->invalid_instruction;
17038 }
17048 }17039 }
1704917040
17050 if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {17041 if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {
...@@ -17059,13 +17050,9 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio...@@ -17059,13 +17050,9 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
17059 }17050 }
17060 }17051 }
1706117052
17062 ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code);17053 ZigType *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code, source_kind);
17063
17064 scan_import(ira->codegen, target_import);
1706517054
17066 IrInstruction *result = ir_const(ira, &import_instruction->base, ira->codegen->builtin_types.entry_namespace);17055 return ir_const_type(ira, &import_instruction->base, target_import);
17067 result->value.data.x_import = target_import;
17068 return result;
17069}17056}
1707017057
17071static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) {17058static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) {
...@@ -17398,17 +17385,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,...@@ -17398,17 +17385,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,
17398 return ira->codegen->invalid_instruction;17385 return ira->codegen->invalid_instruction;
1739917386
17400 ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf);17387 ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf);
17401 size_t i = ira->codegen->tld_ref_source_node_stack.length;17388 emit_error_notes_for_ref_stack(ira->codegen, msg);
17402 for (;;) {
17403 if (i == 0)
17404 break;
17405 i -= 1;
17406 AstNode *source_node = ira->codegen->tld_ref_source_node_stack.at(i);
17407 if (source_node) {
17408 add_error_note(ira->codegen, msg, source_node,
17409 buf_sprintf("referenced here"));
17410 }
17411 }
1741217389
17413 return ira->codegen->invalid_instruction;17390 return ira->codegen->invalid_instruction;
17414}17391}
...@@ -17665,6 +17642,12 @@ static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,...@@ -17665,6 +17642,12 @@ static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
17665 return ir_const_unsigned(ira, &instruction->base, bit_offset);17642 return ir_const_unsigned(ira, &instruction->base, bit_offset);
17666}17643}
1766717644
17645static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) {
17646 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected"));
17647 emit_error_notes_for_ref_stack(ira->codegen, msg);
17648 return ira->codegen->invalid_instruction;
17649}
17650
17668static void ensure_field_index(ZigType *type, const char *field_name, size_t index) {17651static void ensure_field_index(ZigType *type, const char *field_name, size_t index) {
17669 Buf *field_name_buf;17652 Buf *field_name_buf;
1767017653
...@@ -17711,7 +17694,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig...@@ -17711,7 +17694,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
17711 return var->const_value->data.x_type;17694 return var->const_value->data.x_type;
17712}17695}
1771317696
17714static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) {17697static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val,
17698 ScopeDecls *decls_scope)
17699{
17715 Error err;17700 Error err;
17716 ZigType *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr);17701 ZigType *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr);
17717 if ((err = ensure_complete_type(ira->codegen, type_info_definition_type)))17702 if ((err = ensure_complete_type(ira->codegen, type_info_definition_type)))
...@@ -17741,7 +17726,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco...@@ -17741,7 +17726,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
17741 while ((curr_entry = decl_it.next()) != nullptr) {17726 while ((curr_entry = decl_it.next()) != nullptr) {
17742 // If the definition is unresolved, force it to be resolved again.17727 // If the definition is unresolved, force it to be resolved again.
17743 if (curr_entry->value->resolution == TldResolutionUnresolved) {17728 if (curr_entry->value->resolution == TldResolutionUnresolved) {
17744 resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node);17729 resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node);
17745 if (curr_entry->value->resolution != TldResolutionOk) {17730 if (curr_entry->value->resolution != TldResolutionOk) {
17746 return ErrorSemanticAnalyzeFail;17731 return ErrorSemanticAnalyzeFail;
17747 }17732 }
...@@ -17831,6 +17816,11 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco...@@ -17831,6 +17816,11 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
17831 ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;17816 ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
17832 assert(!fn_entry->is_test);17817 assert(!fn_entry->is_test);
1783317818
17819 if (fn_entry->type_entry == nullptr) {
17820 ir_error_dependency_loop(ira, source_instr);
17821 return ErrorSemanticAnalyzeFail;
17822 }
17823
17834 AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);17824 AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
1783517825
17836 ConstExprValue *fn_def_val = create_const_vals(1);17826 ConstExprValue *fn_def_val = create_const_vals(1);
...@@ -18007,7 +17997,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty...@@ -18007,7 +17997,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
18007 // alignment: u3217997 // alignment: u32
18008 ensure_field_index(result->type, "alignment", 3);17998 ensure_field_index(result->type, "alignment", 3);
18009 fields[3].special = ConstValSpecialStatic;17999 fields[3].special = ConstValSpecialStatic;
18010 fields[3].type = get_int_type(ira->codegen, false, 29);18000 fields[3].type = ira->codegen->builtin_types.entry_num_lit_int;
18011 bigint_init_unsigned(&fields[3].data.x_bigint, get_ptr_align(ira->codegen, attrs_type));18001 bigint_init_unsigned(&fields[3].data.x_bigint, get_ptr_align(ira->codegen, attrs_type));
18012 // child: type18002 // child: type
18013 ensure_field_index(result->type, "child", 4);18003 ensure_field_index(result->type, "child", 4);
...@@ -18026,7 +18016,7 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,...@@ -18026,7 +18016,7 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,
1802618016
18027 ConstExprValue *inner_fields = create_const_vals(2);18017 ConstExprValue *inner_fields = create_const_vals(2);
18028 inner_fields[1].special = ConstValSpecialStatic;18018 inner_fields[1].special = ConstValSpecialStatic;
18029 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;18019 inner_fields[1].type = ira->codegen->builtin_types.entry_num_lit_int;
1803018020
18031 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);18021 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
18032 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true);18022 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true);
...@@ -18036,7 +18026,9 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,...@@ -18036,7 +18026,9 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,
18036 enum_field_val->data.x_struct.fields = inner_fields;18026 enum_field_val->data.x_struct.fields = inner_fields;
18037}18027}
1803818028
18039static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigType *type_entry, ConstExprValue **out) {18029static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry,
18030 ConstExprValue **out)
18031{
18040 Error err;18032 Error err;
18041 assert(type_entry != nullptr);18033 assert(type_entry != nullptr);
18042 assert(!type_is_invalid(type_entry));18034 assert(!type_is_invalid(type_entry));
...@@ -18056,7 +18048,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18056,7 +18048,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18056 case ZigTypeIdComptimeInt:18048 case ZigTypeIdComptimeInt:
18057 case ZigTypeIdUndefined:18049 case ZigTypeIdUndefined:
18058 case ZigTypeIdNull:18050 case ZigTypeIdNull:
18059 case ZigTypeIdNamespace:
18060 case ZigTypeIdArgTuple:18051 case ZigTypeIdArgTuple:
18061 case ZigTypeIdOpaque:18052 case ZigTypeIdOpaque:
18062 *out = nullptr;18053 *out = nullptr;
...@@ -18089,7 +18080,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18089,7 +18080,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18089 // bits: u818080 // bits: u8
18090 ensure_field_index(result->type, "bits", 1);18081 ensure_field_index(result->type, "bits", 1);
18091 fields[1].special = ConstValSpecialStatic;18082 fields[1].special = ConstValSpecialStatic;
18092 fields[1].type = ira->codegen->builtin_types.entry_u8;18083 fields[1].type = ira->codegen->builtin_types.entry_num_lit_int;
18093 bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count);18084 bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count);
1809418085
18095 break;18086 break;
...@@ -18106,7 +18097,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18106,7 +18097,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18106 // bits: u818097 // bits: u8
18107 ensure_field_index(result->type, "bits", 0);18098 ensure_field_index(result->type, "bits", 0);
18108 fields[0].special = ConstValSpecialStatic;18099 fields[0].special = ConstValSpecialStatic;
18109 fields[0].type = ira->codegen->builtin_types.entry_u8;18100 fields[0].type = ira->codegen->builtin_types.entry_num_lit_int;
18110 bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count);18101 bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count);
1811118102
18112 break;18103 break;
...@@ -18130,7 +18121,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18130,7 +18121,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18130 // len: usize18121 // len: usize
18131 ensure_field_index(result->type, "len", 0);18122 ensure_field_index(result->type, "len", 0);
18132 fields[0].special = ConstValSpecialStatic;18123 fields[0].special = ConstValSpecialStatic;
18133 fields[0].type = ira->codegen->builtin_types.entry_usize;18124 fields[0].type = ira->codegen->builtin_types.entry_num_lit_int;
18134 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len);18125 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len);
18135 // child: type18126 // child: type
18136 ensure_field_index(result->type, "child", 1);18127 ensure_field_index(result->type, "child", 1);
...@@ -18151,7 +18142,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18151,7 +18142,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18151 // len: usize18142 // len: usize
18152 ensure_field_index(result->type, "len", 0);18143 ensure_field_index(result->type, "len", 0);
18153 fields[0].special = ConstValSpecialStatic;18144 fields[0].special = ConstValSpecialStatic;
18154 fields[0].type = ira->codegen->builtin_types.entry_u32;18145 fields[0].type = ira->codegen->builtin_types.entry_num_lit_int;
18155 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len);18146 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len);
18156 // child: type18147 // child: type
18157 ensure_field_index(result->type, "child", 1);18148 ensure_field_index(result->type, "child", 1);
...@@ -18248,8 +18239,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18248,8 +18239,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18248 }18239 }
18249 // defs: []TypeInfo.Definition18240 // defs: []TypeInfo.Definition
18250 ensure_field_index(result->type, "defs", 3);18241 ensure_field_index(result->type, "defs", 3);
18251 if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope)))18242 if ((err = ir_make_type_info_defs(ira, source_instr, &fields[3],
18243 type_entry->data.enumeration.decls_scope)))
18244 {
18252 return err;18245 return err;
18246 }
1825318247
18254 break;18248 break;
18255 }18249 }
...@@ -18266,11 +18260,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18266,11 +18260,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18266 ensure_field_index(result->type, "errors", 0);18260 ensure_field_index(result->type, "errors", 0);
1826718261
18268 ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr);18262 ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr);
18269 if (!resolve_inferred_error_set(ira->codegen, type_entry, source_node)) {18263 if (!resolve_inferred_error_set(ira->codegen, type_entry, source_instr->source_node)) {
18270 return ErrorSemanticAnalyzeFail;18264 return ErrorSemanticAnalyzeFail;
18271 }18265 }
18272 if (type_is_global_error_set(type_entry)) {18266 if (type_is_global_error_set(type_entry)) {
18273 ir_add_error_node(ira, source_node,18267 ir_add_error(ira, source_instr,
18274 buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936"));18268 buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936"));
18275 return ErrorSemanticAnalyzeFail;18269 return ErrorSemanticAnalyzeFail;
18276 }18270 }
...@@ -18292,7 +18286,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18292,7 +18286,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1829218286
18293 ConstExprValue *inner_fields = create_const_vals(2);18287 ConstExprValue *inner_fields = create_const_vals(2);
18294 inner_fields[1].special = ConstValSpecialStatic;18288 inner_fields[1].special = ConstValSpecialStatic;
18295 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;18289 inner_fields[1].type = ira->codegen->builtin_types.entry_num_lit_int;
1829618290
18297 ConstExprValue *name = nullptr;18291 ConstExprValue *name = nullptr;
18298 if (error->cached_error_name_val != nullptr)18292 if (error->cached_error_name_val != nullptr)
...@@ -18412,8 +18406,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18412,8 +18406,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18412 }18406 }
18413 // defs: []TypeInfo.Definition18407 // defs: []TypeInfo.Definition
18414 ensure_field_index(result->type, "defs", 3);18408 ensure_field_index(result->type, "defs", 3);
18415 if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope)))18409 if ((err = ir_make_type_info_defs(ira, source_instr, &fields[3],
18410 type_entry->data.unionation.decls_scope)))
18411 {
18416 return err;18412 return err;
18413 }
1841718414
18418 break;18415 break;
18419 }18416 }
...@@ -18461,7 +18458,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18461,7 +18458,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1846118458
18462 ConstExprValue *inner_fields = create_const_vals(3);18459 ConstExprValue *inner_fields = create_const_vals(3);
18463 inner_fields[1].special = ConstValSpecialStatic;18460 inner_fields[1].special = ConstValSpecialStatic;
18464 inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_usize);18461 inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int);
1846518462
18466 if (!type_has_bits(struct_field->type_entry)) {18463 if (!type_has_bits(struct_field->type_entry)) {
18467 inner_fields[1].data.x_optional = nullptr;18464 inner_fields[1].data.x_optional = nullptr;
...@@ -18487,8 +18484,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18487,8 +18484,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18487 }18484 }
18488 // defs: []TypeInfo.Definition18485 // defs: []TypeInfo.Definition
18489 ensure_field_index(result->type, "defs", 2);18486 ensure_field_index(result->type, "defs", 2);
18490 if ((err = ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope)))18487 if ((err = ir_make_type_info_defs(ira, source_instr, &fields[2],
18488 type_entry->data.structure.decls_scope)))
18489 {
18491 return err;18490 return err;
18491 }
1849218492
18493 break;18493 break;
18494 }18494 }
...@@ -18600,7 +18600,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy...@@ -18600,7 +18600,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
18600 {18600 {
18601 ZigType *fn_type = type_entry->data.bound_fn.fn_type;18601 ZigType *fn_type = type_entry->data.bound_fn.fn_type;
18602 assert(fn_type->id == ZigTypeIdFn);18602 assert(fn_type->id == ZigTypeIdFn);
18603 if ((err = ir_make_type_info_value(ira, source_node, fn_type, &result)))18603 if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))
18604 return err;18604 return err;
1860518605
18606 break;18606 break;
...@@ -18625,7 +18625,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,...@@ -18625,7 +18625,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,
18625 ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr);18625 ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr);
1862618626
18627 ConstExprValue *payload;18627 ConstExprValue *payload;
18628 if ((err = ir_make_type_info_value(ira, instruction->base.source_node, type_entry, &payload)))18628 if ((err = ir_make_type_info_value(ira, &instruction->base, type_entry, &payload)))
18629 return ira->codegen->invalid_instruction;18629 return ira->codegen->invalid_instruction;
1863018630
18631 IrInstruction *result = ir_const(ira, &instruction->base, result_type);18631 IrInstruction *result = ir_const(ira, &instruction->base, result_type);
...@@ -18680,7 +18680,7 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc...@@ -18680,7 +18680,7 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
18680 return ira->codegen->invalid_instruction;18680 return ira->codegen->invalid_instruction;
1868118681
18682 if (!type_entry->cached_const_name_val) {18682 if (!type_entry->cached_const_name_val) {
18683 type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, &type_entry->name);18683 type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, type_bare_name(type_entry));
18684 }18684 }
18685 IrInstruction *result = ir_const(ira, &instruction->base, nullptr);18685 IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
18686 copy_const_val(&result->value, type_entry->cached_const_name_val, true);18686 copy_const_val(&result->value, type_entry->cached_const_name_val, true);
...@@ -18702,14 +18702,21 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct...@@ -18702,14 +18702,21 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
18702 if (type_is_invalid(cimport_result->type))18702 if (type_is_invalid(cimport_result->type))
18703 return ira->codegen->invalid_instruction;18703 return ira->codegen->invalid_instruction;
1870418704
18705 ImportTableEntry *child_import = allocate<ImportTableEntry>(1);18705 ZigPackage *cur_scope_pkg = scope_package(instruction->base.scope);
18706 child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import);18706 Buf *namespace_name = buf_sprintf("%s.cimport:%" ZIG_PRI_usize ":%" ZIG_PRI_usize,
18707 child_import->c_import_node = node;18707 buf_ptr(&cur_scope_pkg->pkg_path), node->line + 1, node->column + 1);
18708 child_import->package = new_anonymous_package();18708
18709 child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);18709 RootStruct *root_struct = allocate<RootStruct>(1);
18710 child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);18710 root_struct->package = new_anonymous_package();
18711 child_import->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,18711 root_struct->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);
18712 root_struct->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
18713 root_struct->c_import_node = node;
18714 // TODO create namespace_name file in zig-cache instead of /tmp and use it
18715 // for this DIFile
18716 root_struct->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,
18712 buf_ptr(buf_create_from_str("cimport.h")), buf_ptr(buf_create_from_str(".")));18717 buf_ptr(buf_create_from_str("cimport.h")), buf_ptr(buf_create_from_str(".")));
18718 ZigType *child_import = get_root_container_type(ira->codegen, buf_ptr(namespace_name),
18719 namespace_name, root_struct);
1871318720
18714 ZigList<ErrorMsg *> errors = {0};18721 ZigList<ErrorMsg *> errors = {0};
1871518722
...@@ -18738,14 +18745,12 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct...@@ -18738,14 +18745,12 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
18738 if (ira->codegen->verbose_cimport) {18745 if (ira->codegen->verbose_cimport) {
18739 fprintf(stderr, "\nC imports:\n");18746 fprintf(stderr, "\nC imports:\n");
18740 fprintf(stderr, "-----------\n");18747 fprintf(stderr, "-----------\n");
18741 ast_render(ira->codegen, stderr, child_import->root, 4);18748 ast_render(ira->codegen, stderr, child_import->data.structure.decl_node, 4);
18742 }18749 }
1874318750
18744 scan_decls(ira->codegen, child_import->decls_scope, child_import->root);18751 scan_decls(ira->codegen, get_container_scope(child_import), child_import->data.structure.decl_node);
1874518752
18746 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_namespace);18753 return ir_const_type(ira, &instruction->base, child_import);
18747 result->value.data.x_import = child_import;
18748 return result;
18749}18754}
1875018755
18751static IrInstruction *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {18756static IrInstruction *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {
...@@ -18819,10 +18824,10 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru...@@ -18819,10 +18824,10 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
18819 if (!rel_file_path)18824 if (!rel_file_path)
18820 return ira->codegen->invalid_instruction;18825 return ira->codegen->invalid_instruction;
1882118826
18822 ImportTableEntry *import = get_scope_import(instruction->base.scope);18827 ZigType *import = get_scope_import(instruction->base.scope);
18823 // figure out absolute path to resource18828 // figure out absolute path to resource
18824 Buf source_dir_path = BUF_INIT;18829 Buf source_dir_path = BUF_INIT;
18825 os_path_dirname(import->path, &source_dir_path);18830 os_path_dirname(import->data.structure.root_struct->path, &source_dir_path);
1882618831
18827 Buf *resolve_paths[] = {18832 Buf *resolve_paths[] = {
18828 &source_dir_path,18833 &source_dir_path,
...@@ -19752,6 +19757,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction...@@ -19752,6 +19757,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
19752 return ira->codegen->invalid_instruction;19757 return ira->codegen->invalid_instruction;
19753 }19758 }
19754 } else {19759 } else {
19760 if (array_type->data.pointer.ptr_len == PtrLenC) {
19761 array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
19762 }
19755 return_type = get_slice_type(ira->codegen, array_type);19763 return_type = get_slice_type(ira->codegen, array_type);
19756 if (!end) {19764 if (!end) {
19757 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));19765 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
...@@ -20137,18 +20145,14 @@ static IrInstruction *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstru...@@ -20137,18 +20145,14 @@ static IrInstruction *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstru
20137static IrInstruction *ir_analyze_instruction_return_address(IrAnalyze *ira, IrInstructionReturnAddress *instruction) {20145static IrInstruction *ir_analyze_instruction_return_address(IrAnalyze *ira, IrInstructionReturnAddress *instruction) {
20138 IrInstruction *result = ir_build_return_address(&ira->new_irb,20146 IrInstruction *result = ir_build_return_address(&ira->new_irb,
20139 instruction->base.scope, instruction->base.source_node);20147 instruction->base.scope, instruction->base.source_node);
20140 ZigType *u8 = ira->codegen->builtin_types.entry_u8;20148 result->value.type = ira->codegen->builtin_types.entry_usize;
20141 ZigType *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
20142 result->value.type = u8_ptr_const;
20143 return result;20149 return result;
20144}20150}
2014520151
20146static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrInstructionFrameAddress *instruction) {20152static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrInstructionFrameAddress *instruction) {
20147 IrInstruction *result = ir_build_frame_address(&ira->new_irb,20153 IrInstruction *result = ir_build_frame_address(&ira->new_irb,
20148 instruction->base.scope, instruction->base.source_node);20154 instruction->base.scope, instruction->base.source_node);
20149 ZigType *u8 = ira->codegen->builtin_types.entry_u8;20155 result->value.type = ira->codegen->builtin_types.entry_usize;
20150 ZigType *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
20151 result->value.type = u8_ptr_const;
20152 return result;20156 return result;
20153}20157}
2015420158
...@@ -20179,7 +20183,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct...@@ -20179,7 +20183,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
20179 case ZigTypeIdComptimeInt:20183 case ZigTypeIdComptimeInt:
20180 case ZigTypeIdUndefined:20184 case ZigTypeIdUndefined:
20181 case ZigTypeIdNull:20185 case ZigTypeIdNull:
20182 case ZigTypeIdNamespace:
20183 case ZigTypeIdBoundFn:20186 case ZigTypeIdBoundFn:
20184 case ZigTypeIdArgTuple:20187 case ZigTypeIdArgTuple:
20185 case ZigTypeIdVoid:20188 case ZigTypeIdVoid:
...@@ -21025,7 +21028,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -21025,7 +21028,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
21025 case ZigTypeIdOpaque:21028 case ZigTypeIdOpaque:
21026 case ZigTypeIdBoundFn:21029 case ZigTypeIdBoundFn:
21027 case ZigTypeIdArgTuple:21030 case ZigTypeIdArgTuple:
21028 case ZigTypeIdNamespace:
21029 case ZigTypeIdUnreachable:21031 case ZigTypeIdUnreachable:
21030 case ZigTypeIdComptimeFloat:21032 case ZigTypeIdComptimeFloat:
21031 case ZigTypeIdComptimeInt:21033 case ZigTypeIdComptimeInt:
...@@ -21185,7 +21187,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou...@@ -21185,7 +21187,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
21185 case ZigTypeIdOpaque:21187 case ZigTypeIdOpaque:
21186 case ZigTypeIdBoundFn:21188 case ZigTypeIdBoundFn:
21187 case ZigTypeIdArgTuple:21189 case ZigTypeIdArgTuple:
21188 case ZigTypeIdNamespace:
21189 case ZigTypeIdUnreachable:21190 case ZigTypeIdUnreachable:
21190 case ZigTypeIdComptimeFloat:21191 case ZigTypeIdComptimeFloat:
21191 case ZigTypeIdComptimeInt:21192 case ZigTypeIdComptimeInt:
...@@ -21343,7 +21344,6 @@ static bool type_can_bit_cast(ZigType *t) {...@@ -21343,7 +21344,6 @@ static bool type_can_bit_cast(ZigType *t) {
21343 case ZigTypeIdOpaque:21344 case ZigTypeIdOpaque:
21344 case ZigTypeIdBoundFn:21345 case ZigTypeIdBoundFn:
21345 case ZigTypeIdArgTuple:21346 case ZigTypeIdArgTuple:
21346 case ZigTypeIdNamespace:
21347 case ZigTypeIdUnreachable:21347 case ZigTypeIdUnreachable:
21348 case ZigTypeIdComptimeFloat:21348 case ZigTypeIdComptimeFloat:
21349 case ZigTypeIdComptimeInt:21349 case ZigTypeIdComptimeInt:
...@@ -21516,7 +21516,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,...@@ -21516,7 +21516,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
21516 Tld *tld = instruction->tld;21516 Tld *tld = instruction->tld;
21517 LVal lval = instruction->lval;21517 LVal lval = instruction->lval;
2151821518
21519 resolve_top_level_decl(ira->codegen, tld, lval == LValPtr, instruction->base.source_node);21519 resolve_top_level_decl(ira->codegen, tld, instruction->base.source_node);
21520 if (tld->resolution == TldResolutionInvalid)21520 if (tld->resolution == TldResolutionInvalid)
21521 return ira->codegen->invalid_instruction;21521 return ira->codegen->invalid_instruction;
2152221522
...@@ -21528,6 +21528,10 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,...@@ -21528,6 +21528,10 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
21528 TldVar *tld_var = (TldVar *)tld;21528 TldVar *tld_var = (TldVar *)tld;
21529 ZigVar *var = tld_var->var;21529 ZigVar *var = tld_var->var;
2153021530
21531 if (var == nullptr) {
21532 return ir_error_dependency_loop(ira, &instruction->base);
21533 }
21534
21531 IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);21535 IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);
21532 if (type_is_invalid(var_ptr->value.type))21536 if (type_is_invalid(var_ptr->value.type))
21533 return ira->codegen->invalid_instruction;21537 return ira->codegen->invalid_instruction;
...@@ -21664,9 +21668,11 @@ static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstru...@@ -21664,9 +21668,11 @@ static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstru
21664}21668}
2166521669
21666static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstructionOpaqueType *instruction) {21670static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstructionOpaqueType *instruction) {
21667 Buf *name = get_anon_type_name(ira->codegen, ira->new_irb.exec, "opaque", instruction->base.source_node);21671 Buf *bare_name = buf_alloc();
21672 Buf *full_name = get_anon_type_name(ira->codegen, ira->new_irb.exec, "opaque",
21673 instruction->base.scope, instruction->base.source_node, bare_name);
21668 ZigType *result_type = get_opaque_type(ira->codegen, instruction->base.scope, instruction->base.source_node,21674 ZigType *result_type = get_opaque_type(ira->codegen, instruction->base.scope, instruction->base.source_node,
21669 buf_ptr(name));21675 buf_ptr(full_name), bare_name);
21670 return ir_const_type(ira, &instruction->base, result_type);21676 return ir_const_type(ira, &instruction->base, result_type);
21671}21677}
2167221678
src/link.cpp+2-4
...@@ -41,7 +41,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)...@@ -41,7 +41,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
41 child_out_type = OutTypeObj;41 child_out_type = OutTypeObj;
42 }42 }
4343
44 CodeGen *child_gen = codegen_create(full_path, parent_gen->zig_target, child_out_type,44 CodeGen *child_gen = codegen_create(nullptr, full_path, parent_gen->zig_target, child_out_type,
45 parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir,45 parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir,
46 parent_gen->libc);46 parent_gen->libc);
4747
...@@ -87,10 +87,8 @@ static Buf *build_a(CodeGen *parent_gen, const char *aname) {...@@ -87,10 +87,8 @@ static Buf *build_a(CodeGen *parent_gen, const char *aname) {
87}87}
8888
89static Buf *build_compiler_rt(CodeGen *parent_gen) {89static Buf *build_compiler_rt(CodeGen *parent_gen) {
90 Buf *dir_path = buf_alloc();
91 os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt"), dir_path);
92 Buf *full_path = buf_alloc();90 Buf *full_path = buf_alloc();
93 os_path_join(dir_path, buf_create_from_str("index.zig"), full_path);91 os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt.zig"), full_path);
9492
95 return build_a_raw(parent_gen, "compiler_rt", full_path);93 return build_a_raw(parent_gen, "compiler_rt", full_path);
96}94}
src/main.cpp+19-15
...@@ -63,6 +63,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -63,6 +63,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
63 " --output-lib [file] override import library path\n"63 " --output-lib [file] override import library path\n"
64 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"64 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
65 " --pkg-end pop current pkg\n"65 " --pkg-end pop current pkg\n"
66 " --main-pkg-path set the directory of the root package\n"
66 " --release-fast build with optimizations on and safety off\n"67 " --release-fast build with optimizations on and safety off\n"
67 " --release-safe build with optimizations on and safety on\n"68 " --release-safe build with optimizations on and safety on\n"
68 " --release-small build with size optimizations on and safety off\n"69 " --release-small build with size optimizations on and safety off\n"
...@@ -215,7 +216,7 @@ struct CliPkg {...@@ -215,7 +216,7 @@ struct CliPkg {
215 CliPkg *parent;216 CliPkg *parent;
216};217};
217218
218static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {219static void add_package(CodeGen *g, CliPkg *cli_pkg, ZigPackage *pkg) {
219 for (size_t i = 0; i < cli_pkg->children.length; i += 1) {220 for (size_t i = 0; i < cli_pkg->children.length; i += 1) {
220 CliPkg *child_cli_pkg = cli_pkg->children.at(i);221 CliPkg *child_cli_pkg = cli_pkg->children.at(i);
221222
...@@ -223,10 +224,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {...@@ -223,10 +224,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
223 Buf *basename = buf_alloc();224 Buf *basename = buf_alloc();
224 os_path_split(buf_create_from_str(child_cli_pkg->path), dirname, basename);225 os_path_split(buf_create_from_str(child_cli_pkg->path), dirname, basename);
225226
226 PackageTableEntry *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename));227 ZigPackage *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename),
228 buf_ptr(buf_sprintf("%s.%s", buf_ptr(&pkg->pkg_path), child_cli_pkg->name)));
227 auto entry = pkg->package_table.put_unique(buf_create_from_str(child_cli_pkg->name), child_pkg);229 auto entry = pkg->package_table.put_unique(buf_create_from_str(child_cli_pkg->name), child_pkg);
228 if (entry) {230 if (entry) {
229 PackageTableEntry *existing_pkg = entry->value;231 ZigPackage *existing_pkg = entry->value;
230 Buf *full_path = buf_alloc();232 Buf *full_path = buf_alloc();
231 os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path);233 os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path);
232 fprintf(stderr, "Unable to add package '%s'->'%s': already exists as '%s'\n",234 fprintf(stderr, "Unable to add package '%s'->'%s': already exists as '%s'\n",
...@@ -437,6 +439,7 @@ int main(int argc, char **argv) {...@@ -437,6 +439,7 @@ int main(int argc, char **argv) {
437 TargetSubsystem subsystem = TargetSubsystemAuto;439 TargetSubsystem subsystem = TargetSubsystemAuto;
438 bool is_single_threaded = false;440 bool is_single_threaded = false;
439 Buf *override_std_dir = nullptr;441 Buf *override_std_dir = nullptr;
442 Buf *main_pkg_path = nullptr;
440 ValgrindSupport valgrind_support = ValgrindSupportAuto;443 ValgrindSupport valgrind_support = ValgrindSupportAuto;
441444
442 if (argc >= 2 && strcmp(argv[1], "build") == 0) {445 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
...@@ -475,8 +478,8 @@ int main(int argc, char **argv) {...@@ -475,8 +478,8 @@ int main(int argc, char **argv) {
475478
476 ZigTarget target;479 ZigTarget target;
477 get_native_target(&target);480 get_native_target(&target);
478 CodeGen *g = codegen_create(build_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),481 CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe,
479 override_std_dir, nullptr);482 BuildModeDebug, get_zig_lib_dir(), override_std_dir, nullptr);
480 g->valgrind_support = valgrind_support;483 g->valgrind_support = valgrind_support;
481 g->enable_time_report = timing_info;484 g->enable_time_report = timing_info;
482 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);485 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
...@@ -543,8 +546,8 @@ int main(int argc, char **argv) {...@@ -543,8 +546,8 @@ int main(int argc, char **argv) {
543 return EXIT_FAILURE;546 return EXIT_FAILURE;
544 }547 }
545548
546 PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),549 ZigPackage *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
547 buf_ptr(&build_file_basename));550 buf_ptr(&build_file_basename), "std.special");
548 g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);551 g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
549 g->enable_cache = get_cache_opt(enable_cache, true);552 g->enable_cache = get_cache_opt(enable_cache, true);
550 codegen_build_and_link(g);553 codegen_build_and_link(g);
...@@ -566,8 +569,8 @@ int main(int argc, char **argv) {...@@ -566,8 +569,8 @@ int main(int argc, char **argv) {
566 get_native_target(&target);569 get_native_target(&target);
567 Buf *fmt_runner_path = buf_alloc();570 Buf *fmt_runner_path = buf_alloc();
568 os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);571 os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
569 CodeGen *g = codegen_create(fmt_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),572 CodeGen *g = codegen_create(main_pkg_path, fmt_runner_path, &target, OutTypeExe,
570 nullptr, nullptr);573 BuildModeDebug, get_zig_lib_dir(), nullptr, nullptr);
571 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);574 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
572 g->valgrind_support = valgrind_support;575 g->valgrind_support = valgrind_support;
573 g->is_single_threaded = true;576 g->is_single_threaded = true;
...@@ -728,6 +731,8 @@ int main(int argc, char **argv) {...@@ -728,6 +731,8 @@ int main(int argc, char **argv) {
728 llvm_argv.append(argv[i]);731 llvm_argv.append(argv[i]);
729 } else if (strcmp(arg, "--override-std-dir") == 0) {732 } else if (strcmp(arg, "--override-std-dir") == 0) {
730 override_std_dir = buf_create_from_str(argv[i]);733 override_std_dir = buf_create_from_str(argv[i]);
734 } else if (strcmp(arg, "--main-pkg-path") == 0) {
735 main_pkg_path = buf_create_from_str(argv[i]);
731 } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {736 } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
732 lib_dirs.append(argv[i]);737 lib_dirs.append(argv[i]);
733 } else if (strcmp(arg, "--library") == 0) {738 } else if (strcmp(arg, "--library") == 0) {
...@@ -907,8 +912,8 @@ int main(int argc, char **argv) {...@@ -907,8 +912,8 @@ int main(int argc, char **argv) {
907 return EXIT_SUCCESS;912 return EXIT_SUCCESS;
908 }913 }
909 case CmdBuiltin: {914 case CmdBuiltin: {
910 CodeGen *g = codegen_create(nullptr, &target, out_type, build_mode, get_zig_lib_dir(), override_std_dir,915 CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
911 nullptr);916 out_type, build_mode, get_zig_lib_dir(), override_std_dir, nullptr);
912 g->valgrind_support = valgrind_support;917 g->valgrind_support = valgrind_support;
913 g->is_single_threaded = is_single_threaded;918 g->is_single_threaded = is_single_threaded;
914 Buf *builtin_source = codegen_generate_builtin_source(g);919 Buf *builtin_source = codegen_generate_builtin_source(g);
...@@ -1011,8 +1016,8 @@ int main(int argc, char **argv) {...@@ -1011,8 +1016,8 @@ int main(int argc, char **argv) {
1011 return EXIT_FAILURE;1016 return EXIT_FAILURE;
1012 }1017 }
1013 }1018 }
1014 CodeGen *g = codegen_create(zig_root_source_file, &target, out_type, build_mode, get_zig_lib_dir(),1019 CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,
1015 override_std_dir, libc);1020 get_zig_lib_dir(), override_std_dir, libc);
1016 g->valgrind_support = valgrind_support;1021 g->valgrind_support = valgrind_support;
1017 g->subsystem = subsystem;1022 g->subsystem = subsystem;
10181023
...@@ -1095,7 +1100,6 @@ int main(int argc, char **argv) {...@@ -1095,7 +1100,6 @@ int main(int argc, char **argv) {
1095 if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)1100 if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
1096 codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));1101 codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
10971102
1098
1099 add_package(g, cur_pkg, g->root_package);1103 add_package(g, cur_pkg, g->root_package);
11001104
1101 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {1105 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
...@@ -1145,7 +1149,7 @@ int main(int argc, char **argv) {...@@ -1145,7 +1149,7 @@ int main(int argc, char **argv) {
1145 }1149 }
1146 } else if (cmd == CmdTranslateC) {1150 } else if (cmd == CmdTranslateC) {
1147 codegen_translate_c(g, in_file_buf);1151 codegen_translate_c(g, in_file_buf);
1148 ast_render(g, stdout, g->root_import->root, 4);1152 ast_render(g, stdout, g->root_import->data.structure.decl_node, 4);
1149 if (timing_info)1153 if (timing_info)
1150 codegen_print_timing_report(g, stdout);1154 codegen_print_timing_report(g, stdout);
1151 return EXIT_SUCCESS;1155 return EXIT_SUCCESS;
src/os.cpp+1-1
...@@ -264,7 +264,7 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {...@@ -264,7 +264,7 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
264 buf_append_buf(out_full_path, basename);264 buf_append_buf(out_full_path, basename);
265}265}
266266
267int os_path_real(Buf *rel_path, Buf *out_abs_path) {267Error os_path_real(Buf *rel_path, Buf *out_abs_path) {
268#if defined(ZIG_OS_WINDOWS)268#if defined(ZIG_OS_WINDOWS)
269 buf_resize(out_abs_path, 4096);269 buf_resize(out_abs_path, 4096);
270 if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) {270 if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) {
src/os.hpp+1-1
...@@ -96,7 +96,7 @@ void os_path_dirname(Buf *full_path, Buf *out_dirname);...@@ -96,7 +96,7 @@ void os_path_dirname(Buf *full_path, Buf *out_dirname);
96void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);96void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
97void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);97void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
98void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);98void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
99int os_path_real(Buf *rel_path, Buf *out_abs_path);99Error os_path_real(Buf *rel_path, Buf *out_abs_path);
100Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);100Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
101bool os_path_is_absolute(Buf *path);101bool os_path_is_absolute(Buf *path);
102102
src/parser.cpp+10-8
...@@ -18,7 +18,7 @@ struct ParseContext {...@@ -18,7 +18,7 @@ struct ParseContext {
18 Buf *buf;18 Buf *buf;
19 size_t current_token;19 size_t current_token;
20 ZigList<Token> *tokens;20 ZigList<Token> *tokens;
21 ImportTableEntry *owner;21 ZigType *owner;
22 ErrColor err_color;22 ErrColor err_color;
23};23};
2424
...@@ -130,8 +130,10 @@ static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {...@@ -130,8 +130,10 @@ static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
130 va_end(ap);130 va_end(ap);
131131
132132
133 ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column,133 ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path,
134 pc->owner->source_code, pc->owner->line_offsets, msg);134 token->start_line, token->start_column,
135 pc->owner->data.structure.root_struct->source_code,
136 pc->owner->data.structure.root_struct->line_offsets, msg);
135 err->line_start = token->start_line;137 err->line_start = token->start_line;
136 err->column_start = token->start_column;138 err->column_start = token->start_column;
137139
...@@ -148,8 +150,10 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, size_t offset, const...@@ -148,8 +150,10 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, size_t offset, const
148 Buf *msg = buf_vprintf(format, ap);150 Buf *msg = buf_vprintf(format, ap);
149 va_end(ap);151 va_end(ap);
150152
151 ErrorMsg *err = err_msg_create_with_line(pc->owner->path, node->line, node->column,153 ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path,
152 pc->owner->source_code, pc->owner->line_offsets, msg);154 node->line, node->column,
155 pc->owner->data.structure.root_struct->source_code,
156 pc->owner->data.structure.root_struct->line_offsets, msg);
153157
154 print_err_msg(err, pc->err_color);158 print_err_msg(err, pc->err_color);
155 exit(EXIT_FAILURE);159 exit(EXIT_FAILURE);
...@@ -570,9 +574,7 @@ static void ast_parse_asm_template(ParseContext *pc, AstNode *node) {...@@ -570,9 +574,7 @@ static void ast_parse_asm_template(ParseContext *pc, AstNode *node) {
570 }574 }
571}575}
572576
573AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,577AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ZigType *owner, ErrColor err_color) {
574 ErrColor err_color)
575{
576 ParseContext pc = {};578 ParseContext pc = {};
577 pc.err_color = err_color;579 pc.err_color = err_color;
578 pc.owner = owner;580 pc.owner = owner;
src/parser.hpp+1-1
...@@ -16,7 +16,7 @@ ATTRIBUTE_PRINTF(2, 3)...@@ -16,7 +16,7 @@ ATTRIBUTE_PRINTF(2, 3)
16void ast_token_error(Token *token, const char *format, ...);16void ast_token_error(Token *token, const char *format, ...);
1717
1818
19AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);19AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ZigType *owner, ErrColor err_color);
2020
21void ast_print(AstNode *node, int indent);21void ast_print(AstNode *node, int indent);
2222
src/target.cpp+3-3
...@@ -676,15 +676,15 @@ Error target_parse_triple(ZigTarget *target, const char *triple) {...@@ -676,15 +676,15 @@ Error target_parse_triple(ZigTarget *target, const char *triple) {
676 if (!opt_archsub.is_some)676 if (!opt_archsub.is_some)
677 return ErrorMissingArchitecture;677 return ErrorMissingArchitecture;
678678
679 if (!opt_os.is_some)
680 return ErrorMissingOperatingSystem;
681
682 if ((err = target_parse_archsub(&target->arch, &target->sub_arch,679 if ((err = target_parse_archsub(&target->arch, &target->sub_arch,
683 (char*)opt_archsub.value.ptr, opt_archsub.value.len)))680 (char*)opt_archsub.value.ptr, opt_archsub.value.len)))
684 {681 {
685 return err;682 return err;
686 }683 }
687684
685 if (!opt_os.is_some)
686 return ErrorMissingOperatingSystem;
687
688 if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {688 if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
689 return err;689 return err;
690 }690 }
src/translate_c.cpp+5-4
...@@ -76,7 +76,7 @@ struct TransScopeWhile {...@@ -76,7 +76,7 @@ struct TransScopeWhile {
76};76};
7777
78struct Context {78struct Context {
79 ImportTableEntry *import;79 ZigType *import;
80 ZigList<ErrorMsg *> *errors;80 ZigList<ErrorMsg *> *errors;
81 VisibMod visib_mod;81 VisibMod visib_mod;
82 bool want_export;82 bool want_export;
...@@ -4779,7 +4779,7 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) {...@@ -4779,7 +4779,7 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) {
4779 }4779 }
4780}4780}
47814781
4782Error parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source,4782Error parse_h_buf(ZigType *import, ZigList<ErrorMsg *> *errors, Buf *source,
4783 CodeGen *codegen, AstNode *source_node)4783 CodeGen *codegen, AstNode *source_node)
4784{4784{
4785 Error err;4785 Error err;
...@@ -4795,7 +4795,7 @@ Error parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *so...@@ -4795,7 +4795,7 @@ Error parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *so
4795 return err;4795 return err;
4796}4796}
47974797
4798Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,4798Error parse_h_file(ZigType *import, ZigList<ErrorMsg *> *errors, const char *target_file,
4799 CodeGen *codegen, AstNode *source_node)4799 CodeGen *codegen, AstNode *source_node)
4800{4800{
4801 Context context = {0};4801 Context context = {0};
...@@ -5005,7 +5005,8 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const...@@ -5005,7 +5005,8 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
5005 render_macros(c);5005 render_macros(c);
5006 render_aliases(c);5006 render_aliases(c);
50075007
5008 import->root = c->root;5008 import->data.structure.decl_node = c->root;
5009 import->data.structure.decls_scope->base.source_node = c->root;
50095010
5010 return ErrorNone;5011 return ErrorNone;
5011}5012}
src/translate_c.hpp+2-2
...@@ -11,10 +11,10 @@...@@ -11,10 +11,10 @@
1111
12#include "all_types.hpp"12#include "all_types.hpp"
1313
14Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,14Error parse_h_file(ZigType *import, ZigList<ErrorMsg *> *errors, const char *target_file,
15 CodeGen *codegen, AstNode *source_node);15 CodeGen *codegen, AstNode *source_node);
1616
17Error parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source,17Error parse_h_buf(ZigType *import, ZigList<ErrorMsg *> *errors, Buf *source,
18 CodeGen *codegen, AstNode *source_node);18 CodeGen *codegen, AstNode *source_node);
1919
20#endif20#endif
src/util.hpp-12
...@@ -93,18 +93,6 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {...@@ -93,18 +93,6 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
93 return ptr;93 return ptr;
94}94}
9595
96template<typename T>
97static inline void safe_memcpy(T *dest, const T *src, size_t count) {
98#ifdef NDEBUG
99 memcpy(dest, src, count * sizeof(T));
100#else
101 // manually assign every elment to trigger compile error for non-copyable structs
102 for (size_t i = 0; i < count; i += 1) {
103 dest[i] = src[i];
104 }
105#endif
106}
107
108template<typename T>96template<typename T>
109static inline T *reallocate(T *old, size_t old_count, size_t new_count) {97static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
110 T *ptr = reallocate_nonzero(old, old_count, new_count);98 T *ptr = reallocate_nonzero(old, old_count, new_count);
std/array_list.zig+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const testing = std.testing;4const testing = std.testing;
...@@ -406,6 +406,6 @@ const Item = struct {...@@ -406,6 +406,6 @@ const Item = struct {
406406
407test "std.ArrayList: ArrayList(T) of struct T" {407test "std.ArrayList: ArrayList(T) of struct T" {
408 var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };408 var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
409 try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );409 try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) });
410 testing.expect(root.sub_items.items[0].integer == 42);410 testing.expect(root.sub_items.items[0].integer == 42);
411}411}
std/atomic.zig created+9
...@@ -0,0 +1,9 @@
1pub const Stack = @import("atomic/stack.zig").Stack;
2pub const Queue = @import("atomic/queue.zig").Queue;
3pub const Int = @import("atomic/int.zig").Int;
4
5test "std.atomic" {
6 _ = @import("atomic/stack.zig");
7 _ = @import("atomic/queue.zig");
8 _ = @import("atomic/int.zig");
9}
std/atomic/index.zig deleted-9
...@@ -1,9 +0,0 @@
1pub const Stack = @import("stack.zig").Stack;
2pub const Queue = @import("queue.zig").Queue;
3pub const Int = @import("int.zig").Int;
4
5test "std.atomic" {
6 _ = @import("stack.zig");
7 _ = @import("queue.zig");
8 _ = @import("int.zig");
9}
std/atomic/queue.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;3const AtomicOrder = builtin.AtomicOrder;
4const AtomicRmwOp = builtin.AtomicRmwOp;4const AtomicRmwOp = builtin.AtomicRmwOp;
std/atomic/stack.zig+1-1
...@@ -68,7 +68,7 @@ pub fn Stack(comptime T: type) type {...@@ -68,7 +68,7 @@ pub fn Stack(comptime T: type) type {
68 };68 };
69}69}
7070
71const std = @import("../index.zig");71const std = @import("../std.zig");
72const Context = struct {72const Context = struct {
73 allocator: *std.mem.Allocator,73 allocator: *std.mem.Allocator,
74 stack: *Stack(i32),74 stack: *Stack(i32),
std/base64.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const mem = std.mem;4const mem = std.mem;
std/buf_map.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const HashMap = std.HashMap;2const HashMap = std.HashMap;
3const mem = std.mem;3const mem = std.mem;
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
std/buf_set.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const HashMap = @import("hash_map.zig").HashMap;2const HashMap = @import("hash_map.zig").HashMap;
3const mem = @import("mem.zig");3const mem = @import("mem.zig");
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
std/buffer.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const mem = std.mem;3const mem = std.mem;
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
std/build.zig+13-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const io = std.io;3const io = std.io;
4const mem = std.mem;4const mem = std.mem;
...@@ -859,6 +859,7 @@ pub const LibExeObjStep = struct {...@@ -859,6 +859,7 @@ pub const LibExeObjStep = struct {
859 verbose_cc: bool,859 verbose_cc: bool,
860 c_std: Builder.CStd,860 c_std: Builder.CStd,
861 override_std_dir: ?[]const u8,861 override_std_dir: ?[]const u8,
862 main_pkg_path: ?[]const u8,
862 exec_cmd_args: ?[]const ?[]const u8,863 exec_cmd_args: ?[]const ?[]const u8,
863 name_prefix: []const u8,864 name_prefix: []const u8,
864 filter: ?[]const u8,865 filter: ?[]const u8,
...@@ -950,6 +951,7 @@ pub const LibExeObjStep = struct {...@@ -950,6 +951,7 @@ pub const LibExeObjStep = struct {
950 .c_std = Builder.CStd.C99,951 .c_std = Builder.CStd.C99,
951 .system_linker_hack = false,952 .system_linker_hack = false,
952 .override_std_dir = null,953 .override_std_dir = null,
954 .main_pkg_path = null,
953 .exec_cmd_args = null,955 .exec_cmd_args = null,
954 .name_prefix = "",956 .name_prefix = "",
955 .filter = null,957 .filter = null,
...@@ -1098,6 +1100,10 @@ pub const LibExeObjStep = struct {...@@ -1098,6 +1100,10 @@ pub const LibExeObjStep = struct {
1098 self.override_std_dir = dir_path;1100 self.override_std_dir = dir_path;
1099 }1101 }
11001102
1103 pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void {
1104 self.main_pkg_path = dir_path;
1105 }
1106
1101 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {1107 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
1102 self.output_path = file_path;1108 self.output_path = file_path;
11031109
...@@ -1320,7 +1326,7 @@ pub const LibExeObjStep = struct {...@@ -1320,7 +1326,7 @@ pub const LibExeObjStep = struct {
1320 zig_args.append("--ver-patch") catch unreachable;1326 zig_args.append("--ver-patch") catch unreachable;
1321 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;1327 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
1322 }1328 }
1323 if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {1329 if (self.static) {
1324 zig_args.append("--static") catch unreachable;1330 zig_args.append("--static") catch unreachable;
1325 }1331 }
13261332
...@@ -1424,6 +1430,11 @@ pub const LibExeObjStep = struct {...@@ -1424,6 +1430,11 @@ pub const LibExeObjStep = struct {
1424 try zig_args.append(builder.pathFromRoot(dir));1430 try zig_args.append(builder.pathFromRoot(dir));
1425 }1431 }
14261432
1433 if (self.main_pkg_path) |dir| {
1434 try zig_args.append("--main-pkg-path");
1435 try zig_args.append(builder.pathFromRoot(dir));
1436 }
1437
1427 try builder.spawnChild(zig_args.toSliceConst());1438 try builder.spawnChild(zig_args.toSliceConst());
14281439
1429 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {1440 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
std/build/fmt.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const build = @import("../build.zig");2const build = @import("../build.zig");
3const Step = build.Step;3const Step = build.Step;
4const Builder = build.Builder;4const Builder = build.Builder;
std/c.zig created+68
...@@ -0,0 +1,68 @@
1const builtin = @import("builtin");
2const Os = builtin.Os;
3
4pub use switch (builtin.os) {
5 Os.linux => @import("c/linux.zig"),
6 Os.windows => @import("c/windows.zig"),
7 Os.macosx, Os.ios => @import("c/darwin.zig"),
8 Os.freebsd => @import("c/freebsd.zig"),
9 Os.netbsd => @import("c/netbsd.zig"),
10 else => empty_import,
11};
12const empty_import = @import("empty.zig");
13
14// TODO https://github.com/ziglang/zig/issues/265 on this whole file
15
16pub extern "c" fn abort() noreturn;
17pub extern "c" fn exit(code: c_int) noreturn;
18pub extern "c" fn isatty(fd: c_int) c_int;
19pub extern "c" fn close(fd: c_int) c_int;
20pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;
21pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
22pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
23pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
24pub extern "c" fn raise(sig: c_int) c_int;
25pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
26pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;
27pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
28pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
29pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;
30pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
31pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
32pub extern "c" fn unlink(path: [*]const u8) c_int;
33pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
34pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
35pub extern "c" fn fork() c_int;
36pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
37pub extern "c" fn pipe(fds: *[2]c_int) c_int;
38pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
39pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
40pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
41pub extern "c" fn chdir(path: [*]const u8) c_int;
42pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
43pub extern "c" fn dup(fd: c_int) c_int;
44pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
45pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
46pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
47pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
48pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
49pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
50pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
51pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
52pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
53pub extern "c" fn rmdir(path: [*]const u8) c_int;
54
55pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
56pub extern "c" fn malloc(usize) ?*c_void;
57pub extern "c" fn realloc(*c_void, usize) ?*c_void;
58pub extern "c" fn free(*c_void) void;
59pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
60
61pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
62pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
63pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
64pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
65pub extern "pthread" fn pthread_self() pthread_t;
66pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
67
68pub const pthread_t = *@OpaqueType();
std/c/darwin.zig+1-1
...@@ -163,7 +163,7 @@ pub const Kevent = extern struct {...@@ -163,7 +163,7 @@ pub const Kevent = extern struct {
163// sys/types.h on macos uses #pragma pack(4) so these checks are163// sys/types.h on macos uses #pragma pack(4) so these checks are
164// to make sure the struct is laid out the same. These values were164// to make sure the struct is laid out the same. These values were
165// produced from C code using the offsetof macro.165// produced from C code using the offsetof macro.
166const std = @import("../index.zig");166const std = @import("../std.zig");
167const assert = std.debug.assert;167const assert = std.debug.assert;
168168
169comptime {169comptime {
std/c/index.zig deleted-68
...@@ -1,68 +0,0 @@
1const builtin = @import("builtin");
2const Os = builtin.Os;
3
4pub use switch (builtin.os) {
5 Os.linux => @import("linux.zig"),
6 Os.windows => @import("windows.zig"),
7 Os.macosx, Os.ios => @import("darwin.zig"),
8 Os.freebsd => @import("freebsd.zig"),
9 Os.netbsd => @import("netbsd.zig"),
10 else => empty_import,
11};
12const empty_import = @import("../empty.zig");
13
14// TODO https://github.com/ziglang/zig/issues/265 on this whole file
15
16pub extern "c" fn abort() noreturn;
17pub extern "c" fn exit(code: c_int) noreturn;
18pub extern "c" fn isatty(fd: c_int) c_int;
19pub extern "c" fn close(fd: c_int) c_int;
20pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;
21pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
22pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
23pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
24pub extern "c" fn raise(sig: c_int) c_int;
25pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
26pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;
27pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
28pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
29pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;
30pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
31pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
32pub extern "c" fn unlink(path: [*]const u8) c_int;
33pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
34pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
35pub extern "c" fn fork() c_int;
36pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
37pub extern "c" fn pipe(fds: *[2]c_int) c_int;
38pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
39pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
40pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
41pub extern "c" fn chdir(path: [*]const u8) c_int;
42pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
43pub extern "c" fn dup(fd: c_int) c_int;
44pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
45pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
46pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
47pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
48pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
49pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
50pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
51pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
52pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
53pub extern "c" fn rmdir(path: [*]const u8) c_int;
54
55pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
56pub extern "c" fn malloc(usize) ?*c_void;
57pub extern "c" fn realloc(*c_void, usize) ?*c_void;
58pub extern "c" fn free(*c_void) void;
59pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
60
61pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
62pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
63pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
64pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
65pub extern "pthread" fn pthread_self() pthread_t;
66pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
67
68pub const pthread_t = *@OpaqueType();
std/coff.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("index.zig");2const std = @import("std.zig");
3const io = std.io;3const io = std.io;
4const mem = std.mem;4const mem = std.mem;
5const os = std.os;5const os = std.os;
std/crypto.zig created+45
...@@ -0,0 +1,45 @@
1pub const Md5 = @import("crypto/md5.zig").Md5;
2pub const Sha1 = @import("crypto/sha1.zig").Sha1;
3
4const sha2 = @import("crypto/sha2.zig");
5pub const Sha224 = sha2.Sha224;
6pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;
9
10const sha3 = @import("crypto/sha3.zig");
11pub const Sha3_224 = sha3.Sha3_224;
12pub const Sha3_256 = sha3.Sha3_256;
13pub const Sha3_384 = sha3.Sha3_384;
14pub const Sha3_512 = sha3.Sha3_512;
15
16const blake2 = @import("crypto/blake2.zig");
17pub const Blake2s224 = blake2.Blake2s224;
18pub const Blake2s256 = blake2.Blake2s256;
19pub const Blake2b384 = blake2.Blake2b384;
20pub const Blake2b512 = blake2.Blake2b512;
21
22const hmac = @import("crypto/hmac.zig");
23pub const HmacMd5 = hmac.HmacMd5;
24pub const HmacSha1 = hmac.HmacSha1;
25pub const HmacSha256 = hmac.HmacSha256;
26pub const HmacBlake2s256 = hmac.HmacBlake2s256;
27
28const import_chaCha20 = @import("crypto/chacha20.zig");
29pub const chaCha20IETF = import_chaCha20.chaCha20IETF;
30pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
31
32pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
33pub const X25519 = @import("crypto/x25519.zig").X25519;
34
35test "crypto" {
36 _ = @import("crypto/blake2.zig");
37 _ = @import("crypto/chacha20.zig");
38 _ = @import("crypto/hmac.zig");
39 _ = @import("crypto/md5.zig");
40 _ = @import("crypto/poly1305.zig");
41 _ = @import("crypto/sha1.zig");
42 _ = @import("crypto/sha2.zig");
43 _ = @import("crypto/sha3.zig");
44 _ = @import("crypto/x25519.zig");
45}
std/crypto/blake2.zig+4-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");4const debug = @import("../debug.zig");
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const htest = @import("test.zig");6const htest = @import("test.zig");
77
...@@ -34,8 +34,8 @@ pub const Blake2s256 = Blake2s(256);...@@ -34,8 +34,8 @@ pub const Blake2s256 = Blake2s(256);
34fn Blake2s(comptime out_len: usize) type {34fn Blake2s(comptime out_len: usize) type {
35 return struct {35 return struct {
36 const Self = @This();36 const Self = @This();
37 const block_length = 64;37 pub const block_length = 64;
38 const digest_length = out_len / 8;38 pub const digest_length = out_len / 8;
3939
40 const iv = [8]u32{40 const iv = [8]u32{
41 0x6A09E667,41 0x6A09E667,
std/crypto/chacha20.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1// Based on public domain Supercop by Daniel J. Bernstein1// Based on public domain Supercop by Daniel J. Bernstein
22
3const std = @import("../index.zig");3const std = @import("../std.zig");
4const mem = std.mem;4const mem = std.mem;
5const endian = std.endian;5const endian = std.endian;
6const assert = std.debug.assert;6const assert = std.debug.assert;
std/crypto/hmac.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const crypto = std.crypto;2const crypto = std.crypto;
3const debug = std.debug;3const debug = std.debug;
4const mem = std.mem;4const mem = std.mem;
std/crypto/index.zig deleted-45
...@@ -1,45 +0,0 @@
1pub const Md5 = @import("md5.zig").Md5;
2pub const Sha1 = @import("sha1.zig").Sha1;
3
4const sha2 = @import("sha2.zig");
5pub const Sha224 = sha2.Sha224;
6pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;
9
10const sha3 = @import("sha3.zig");
11pub const Sha3_224 = sha3.Sha3_224;
12pub const Sha3_256 = sha3.Sha3_256;
13pub const Sha3_384 = sha3.Sha3_384;
14pub const Sha3_512 = sha3.Sha3_512;
15
16const blake2 = @import("blake2.zig");
17pub const Blake2s224 = blake2.Blake2s224;
18pub const Blake2s256 = blake2.Blake2s256;
19pub const Blake2b384 = blake2.Blake2b384;
20pub const Blake2b512 = blake2.Blake2b512;
21
22const hmac = @import("hmac.zig");
23pub const HmacMd5 = hmac.HmacMd5;
24pub const HmacSha1 = hmac.HmacSha1;
25pub const HmacSha256 = hmac.HmacSha256;
26pub const HmacBlake2s256 = hmac.HmacBlake2s256;
27
28const import_chaCha20 = @import("chacha20.zig");
29pub const chaCha20IETF = import_chaCha20.chaCha20IETF;
30pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
31
32pub const Poly1305 = @import("poly1305.zig").Poly1305;
33pub const X25519 = @import("x25519.zig").X25519;
34
35test "crypto" {
36 _ = @import("blake2.zig");
37 _ = @import("chacha20.zig");
38 _ = @import("hmac.zig");
39 _ = @import("md5.zig");
40 _ = @import("poly1305.zig");
41 _ = @import("sha1.zig");
42 _ = @import("sha2.zig");
43 _ = @import("sha3.zig");
44 _ = @import("x25519.zig");
45}
std/crypto/md5.zig+5-5
...@@ -1,9 +1,9 @@...@@ -1,9 +1,9 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const builtin = @import("builtin");4const builtin = @import("builtin");
5const debug = @import("../debug/index.zig");5const debug = @import("../debug.zig");
6const fmt = @import("../fmt/index.zig");6const fmt = @import("../fmt.zig");
77
8const RoundParam = struct {8const RoundParam = struct {
9 a: usize,9 a: usize,
...@@ -29,8 +29,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar...@@ -29,8 +29,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
2929
30pub const Md5 = struct {30pub const Md5 = struct {
31 const Self = @This();31 const Self = @This();
32 const block_length = 64;32 pub const block_length = 64;
33 const digest_length = 16;33 pub const digest_length = 16;
3434
35 s: [4]u32,35 s: [4]u32,
36 // Streaming Cache36 // Streaming Cache
std/crypto/poly1305.zig+1-1
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2//2//
3// https://monocypher.org/3// https://monocypher.org/
44
5const std = @import("../index.zig");5const std = @import("../std.zig");
6const builtin = @import("builtin");6const builtin = @import("builtin");
77
8const Endian = builtin.Endian;8const Endian = builtin.Endian;
std/crypto/sha1.zig+4-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");4const debug = @import("../debug.zig");
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7const RoundParam = struct {7const RoundParam = struct {
...@@ -26,8 +26,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {...@@ -26,8 +26,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
2626
27pub const Sha1 = struct {27pub const Sha1 = struct {
28 const Self = @This();28 const Self = @This();
29 const block_length = 64;29 pub const block_length = 64;
30 const digest_length = 20;30 pub const digest_length = 20;
3131
32 s: [5]u32,32 s: [5]u32,
33 // Streaming Cache33 // Streaming Cache
std/crypto/sha2.zig+4-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");4const debug = @import("../debug.zig");
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const htest = @import("test.zig");6const htest = @import("test.zig");
77
...@@ -78,8 +78,8 @@ pub const Sha256 = Sha2_32(Sha256Params);...@@ -78,8 +78,8 @@ pub const Sha256 = Sha2_32(Sha256Params);
78fn Sha2_32(comptime params: Sha2Params32) type {78fn Sha2_32(comptime params: Sha2Params32) type {
79 return struct {79 return struct {
80 const Self = @This();80 const Self = @This();
81 const block_length = 64;81 pub const block_length = 64;
82 const digest_length = params.out_len / 8;82 pub const digest_length = params.out_len / 8;
8383
84 s: [8]u32,84 s: [8]u32,
85 // Streaming Cache85 // Streaming Cache
std/crypto/sha3.zig+4-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const mem = @import("../mem.zig");1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");2const math = @import("../math.zig");
3const endian = @import("../endian.zig");3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");4const debug = @import("../debug.zig");
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const htest = @import("test.zig");6const htest = @import("test.zig");
77
...@@ -13,8 +13,8 @@ pub const Sha3_512 = Keccak(512, 0x06);...@@ -13,8 +13,8 @@ pub const Sha3_512 = Keccak(512, 0x06);
13fn Keccak(comptime bits: usize, comptime delim: u8) type {13fn Keccak(comptime bits: usize, comptime delim: u8) type {
14 return struct {14 return struct {
15 const Self = @This();15 const Self = @This();
16 const block_length = 200;16 pub const block_length = 200;
17 const digest_length = bits / 8;17 pub const digest_length = bits / 8;
1818
19 s: [200]u8,19 s: [200]u8,
20 offset: usize,20 offset: usize,
std/crypto/test.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const mem = std.mem;3const mem = std.mem;
4const fmt = std.fmt;4const fmt = std.fmt;
std/crypto/throughput_test.zig+1-1
...@@ -2,7 +2,7 @@ const builtin = @import("builtin");...@@ -2,7 +2,7 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const time = std.os.time;3const time = std.os.time;
4const Timer = time.Timer;4const Timer = time.Timer;
5const crypto = @import("index.zig");5const crypto = @import("../crypto.zig");
66
7const KiB = 1024;7const KiB = 1024;
8const MiB = 1024 * KiB;8const MiB = 1024 * KiB;
std/crypto/x25519.zig+1-1
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2//2//
3// https://monocypher.org/3// https://monocypher.org/
44
5const std = @import("../index.zig");5const std = @import("../std.zig");
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const fmt = std.fmt;7const fmt = std.fmt;
88
std/cstr.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const debug = std.debug;3const debug = std.debug;
4const mem = std.mem;4const mem = std.mem;
std/debug.zig created+2205
...@@ -0,0 +1,2205 @@
1const std = @import("std.zig");
2const math = std.math;
3const mem = std.mem;
4const io = std.io;
5const os = std.os;
6const elf = std.elf;
7const DW = std.dwarf;
8const macho = std.macho;
9const coff = std.coff;
10const pdb = std.pdb;
11const windows = os.windows;
12const ArrayList = std.ArrayList;
13const builtin = @import("builtin");
14const maxInt = std.math.maxInt;
15
16pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator;
17pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
18
19pub const runtime_safety = switch (builtin.mode) {
20 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,
21 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
22};
23
24const Module = struct {
25 mod_info: pdb.ModInfo,
26 module_name: []u8,
27 obj_file_name: []u8,
28
29 populated: bool,
30 symbols: []u8,
31 subsect_info: []u8,
32 checksum_offset: ?usize,
33};
34
35/// Tries to write to stderr, unbuffered, and ignores any error returned.
36/// Does not append a newline.
37var stderr_file: os.File = undefined;
38var stderr_file_out_stream: os.File.OutStream = undefined;
39
40var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
41var stderr_mutex = std.Mutex.init();
42pub fn warn(comptime fmt: []const u8, args: ...) void {
43 const held = stderr_mutex.acquire();
44 defer held.release();
45 const stderr = getStderrStream() catch return;
46 stderr.print(fmt, args) catch return;
47}
48
49pub fn getStderrStream() !*io.OutStream(os.File.WriteError) {
50 if (stderr_stream) |st| {
51 return st;
52 } else {
53 stderr_file = try io.getStdErr();
54 stderr_file_out_stream = stderr_file.outStream();
55 const st = &stderr_file_out_stream.stream;
56 stderr_stream = st;
57 return st;
58 }
59}
60
61/// TODO multithreaded awareness
62var self_debug_info: ?DebugInfo = null;
63
64pub fn getSelfDebugInfo() !*DebugInfo {
65 if (self_debug_info) |*info| {
66 return info;
67 } else {
68 self_debug_info = try openSelfDebugInfo(getDebugInfoAllocator());
69 return &self_debug_info.?;
70 }
71}
72
73fn wantTtyColor() bool {
74 var bytes: [128]u8 = undefined;
75 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
76 return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
77}
78
79/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
80/// TODO multithreaded awareness
81pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
82 const stderr = getStderrStream() catch return;
83 const debug_info = getSelfDebugInfo() catch |err| {
84 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
85 return;
86 };
87 writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
88 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
89 return;
90 };
91}
92
93/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
94/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
95/// and then try to find the first address. If addresses.len is more than 32, we
96/// capture that many stack frames exactly, and then look for the first address,
97/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
98/// equals the passed in addresses pointer.
99pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
100 switch (builtin.os) {
101 builtin.Os.windows => {
102 const addrs = stack_trace.instruction_addresses;
103 const u32_addrs_len = @intCast(u32, addrs.len);
104 const first_addr = first_address orelse {
105 stack_trace.index = windows.RtlCaptureStackBackTrace(
106 0,
107 u32_addrs_len,
108 @ptrCast(**c_void, addrs.ptr),
109 null,
110 );
111 return;
112 };
113 var addr_buf_stack: [32]usize = undefined;
114 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
115 const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
116 const first_index = for (addr_buf[0..n]) |addr, i| {
117 if (addr == first_addr) {
118 break i;
119 }
120 } else {
121 stack_trace.index = 0;
122 return;
123 };
124 const slice = addr_buf[first_index..n];
125 // We use a for loop here because slice and addrs may alias.
126 for (slice) |addr, i| {
127 addrs[i] = addr;
128 }
129 stack_trace.index = slice.len;
130 },
131 else => {
132 var it = StackIterator.init(first_address);
133 for (stack_trace.instruction_addresses) |*addr, i| {
134 addr.* = it.next() orelse {
135 stack_trace.index = i;
136 return;
137 };
138 }
139 stack_trace.index = stack_trace.instruction_addresses.len;
140 },
141 }
142}
143
144/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
145/// TODO multithreaded awareness
146pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
147 const stderr = getStderrStream() catch return;
148 const debug_info = getSelfDebugInfo() catch |err| {
149 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
150 return;
151 };
152 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {
153 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
154 return;
155 };
156}
157
158/// This function invokes undefined behavior when `ok` is `false`.
159/// In Debug and ReleaseSafe modes, calls to this function are always
160/// generated, and the `unreachable` statement triggers a panic.
161/// In ReleaseFast and ReleaseSmall modes, calls to this function are
162/// optimized away, and in fact the optimizer is able to use the assertion
163/// in its heuristics.
164/// Inside a test block, it is best to use the `std.testing` module rather
165/// than this function, because this function may not detect a test failure
166/// in ReleaseFast and ReleaseSafe mode. Outside of a test block, this assert
167/// function is the correct function to use.
168pub fn assert(ok: bool) void {
169 if (!ok) unreachable; // assertion failure
170}
171
172pub fn panic(comptime format: []const u8, args: ...) noreturn {
173 @setCold(true);
174 const first_trace_addr = @returnAddress();
175 panicExtra(null, first_trace_addr, format, args);
176}
177
178/// TODO multithreaded awareness
179var panicking: u8 = 0; // TODO make this a bool
180
181pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
182 @setCold(true);
183
184 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
185 // Panicked during a panic.
186
187 // TODO detect if a different thread caused the panic, because in that case
188 // we would want to return here instead of calling abort, so that the thread
189 // which first called panic can finish printing a stack trace.
190 os.abort();
191 }
192 const stderr = getStderrStream() catch os.abort();
193 stderr.print(format ++ "\n", args) catch os.abort();
194 if (trace) |t| {
195 dumpStackTrace(t.*);
196 }
197 dumpCurrentStackTrace(first_trace_addr);
198
199 os.abort();
200}
201
202const RED = "\x1b[31;1m";
203const GREEN = "\x1b[32;1m";
204const CYAN = "\x1b[36;1m";
205const WHITE = "\x1b[37;1m";
206const DIM = "\x1b[2m";
207const RESET = "\x1b[0m";
208
209pub fn writeStackTrace(
210 stack_trace: builtin.StackTrace,
211 out_stream: var,
212 allocator: *mem.Allocator,
213 debug_info: *DebugInfo,
214 tty_color: bool,
215) !void {
216 var frame_index: usize = 0;
217 var frames_left: usize = stack_trace.index;
218
219 while (frames_left != 0) : ({
220 frames_left -= 1;
221 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
222 }) {
223 const return_address = stack_trace.instruction_addresses[frame_index];
224 try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
225 }
226}
227
228pub const StackIterator = struct {
229 first_addr: ?usize,
230 fp: usize,
231
232 pub fn init(first_addr: ?usize) StackIterator {
233 return StackIterator{
234 .first_addr = first_addr,
235 .fp = @frameAddress(),
236 };
237 }
238
239 fn next(self: *StackIterator) ?usize {
240 if (self.fp == 0) return null;
241 self.fp = @intToPtr(*const usize, self.fp).*;
242 if (self.fp == 0) return null;
243
244 if (self.first_addr) |addr| {
245 while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
246 const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
247 if (addr == return_address) {
248 self.first_addr = null;
249 return return_address;
250 }
251 }
252 }
253
254 const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
255 return return_address;
256 }
257};
258
259pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
260 switch (builtin.os) {
261 builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
262 else => {},
263 }
264 var it = StackIterator.init(start_addr);
265 while (it.next()) |return_address| {
266 try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
267 }
268}
269
270pub fn writeCurrentStackTraceWindows(
271 out_stream: var,
272 debug_info: *DebugInfo,
273 tty_color: bool,
274 start_addr: ?usize,
275) !void {
276 var addr_buf: [1024]usize = undefined;
277 const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
278 const addrs = addr_buf[0..n];
279 var start_i: usize = if (start_addr) |saddr| blk: {
280 for (addrs) |addr, i| {
281 if (addr == saddr) break :blk i;
282 }
283 return;
284 } else 0;
285 for (addrs[start_i..]) |addr| {
286 try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
287 }
288}
289
290pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
291 switch (builtin.os) {
292 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
293 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
294 builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
295 else => return error.UnsupportedOperatingSystem,
296 }
297}
298
299fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
300 const allocator = getDebugInfoAllocator();
301 const base_address = os.getBaseAddress();
302 const relative_address = relocated_address - base_address;
303
304 var coff_section: *coff.Section = undefined;
305 const mod_index = for (di.sect_contribs) |sect_contrib| {
306 if (sect_contrib.Section > di.coff.sections.len) continue;
307 // Remember that SectionContribEntry.Section is 1-based.
308 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
309
310 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
311 const vaddr_end = vaddr_start + sect_contrib.Size;
312 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
313 break sect_contrib.ModuleIndex;
314 }
315 } else {
316 // we have no information to add to the address
317 if (tty_color) {
318 try out_stream.print("???:?:?: ");
319 setTtyColor(TtyColor.Dim);
320 try out_stream.print("0x{x} in ??? (???)", relocated_address);
321 setTtyColor(TtyColor.Reset);
322 try out_stream.print("\n\n\n");
323 } else {
324 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
325 }
326 return;
327 };
328
329 const mod = &di.modules[mod_index];
330 try populateModule(di, mod);
331 const obj_basename = os.path.basename(mod.obj_file_name);
332
333 var symbol_i: usize = 0;
334 const symbol_name = while (symbol_i != mod.symbols.len) {
335 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
336 if (prefix.RecordLen < 2)
337 return error.InvalidDebugInfo;
338 switch (prefix.RecordKind) {
339 pdb.SymbolKind.S_LPROC32 => {
340 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
341 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
342 const vaddr_end = vaddr_start + proc_sym.CodeSize;
343 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
344 break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
345 }
346 },
347 else => {},
348 }
349 symbol_i += prefix.RecordLen + @sizeOf(u16);
350 if (symbol_i > mod.symbols.len)
351 return error.InvalidDebugInfo;
352 } else "???";
353
354 const subsect_info = mod.subsect_info;
355
356 var sect_offset: usize = 0;
357 var skip_len: usize = undefined;
358 const opt_line_info = subsections: {
359 const checksum_offset = mod.checksum_offset orelse break :subsections null;
360 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
361 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
362 skip_len = subsect_hdr.Length;
363 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
364
365 switch (subsect_hdr.Kind) {
366 pdb.DebugSubsectionKind.Lines => {
367 var line_index = sect_offset;
368
369 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
370 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
371 line_index += @sizeOf(pdb.LineFragmentHeader);
372 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
373 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
374
375 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
376 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
377 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
378 const subsection_end_index = sect_offset + subsect_hdr.Length;
379 while (line_index < subsection_end_index) {
380 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
381 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
382 const start_line_index = line_index;
383
384 const has_column = line_hdr.Flags.LF_HaveColumns;
385
386 if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
387 // All line entries are stored inside their line block by ascending start address.
388 // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address.
389 // This is done with a simple linear search.
390 var line_i: u32 = 0;
391 while (line_i < block_hdr.NumLines) : (line_i += 1) {
392 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
393 line_index += @sizeOf(pdb.LineNumberEntry);
394
395 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
396 if (relative_address <= vaddr_start) {
397 break;
398 }
399 }
400
401 // line_i == 0 would mean that no matching LineNumberEntry was found.
402 if (line_i > 0) {
403 const subsect_index = checksum_offset + block_hdr.NameIndex;
404 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
405 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
406 try di.pdb.string_table.seekTo(strtab_offset);
407 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
408
409 const line_entry_idx = line_i - 1;
410
411 const column = if (has_column) blk: {
412 const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
413 const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
414 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
415 break :blk col_num_entry.StartColumn;
416 } else 0;
417
418 const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
419 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
420 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
421
422 break :subsections LineInfo{
423 .allocator = allocator,
424 .file_name = source_file_name,
425 .line = flags.Start,
426 .column = column,
427 };
428 }
429 }
430 }
431
432 // Checking that we are not reading garbage after the (possibly) multiple block fragments.
433 if (line_index != subsection_end_index) {
434 return error.InvalidDebugInfo;
435 }
436 },
437 else => {},
438 }
439
440 if (sect_offset > subsect_info.len)
441 return error.InvalidDebugInfo;
442 } else {
443 break :subsections null;
444 }
445 };
446
447 if (tty_color) {
448 setTtyColor(TtyColor.White);
449 if (opt_line_info) |li| {
450 try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
451 } else {
452 try out_stream.print("???:?:?");
453 }
454 setTtyColor(TtyColor.Reset);
455 try out_stream.print(": ");
456 setTtyColor(TtyColor.Dim);
457 try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
458 setTtyColor(TtyColor.Reset);
459
460 if (opt_line_info) |line_info| {
461 try out_stream.print("\n");
462 if (printLineFromFileAnyOs(out_stream, line_info)) {
463 if (line_info.column == 0) {
464 try out_stream.write("\n");
465 } else {
466 {
467 var col_i: usize = 1;
468 while (col_i < line_info.column) : (col_i += 1) {
469 try out_stream.writeByte(' ');
470 }
471 }
472 setTtyColor(TtyColor.Green);
473 try out_stream.write("^");
474 setTtyColor(TtyColor.Reset);
475 try out_stream.write("\n");
476 }
477 } else |err| switch (err) {
478 error.EndOfFile => {},
479 else => return err,
480 }
481 } else {
482 try out_stream.print("\n\n\n");
483 }
484 } else {
485 if (opt_line_info) |li| {
486 try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
487 } else {
488 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
489 }
490 }
491}
492
493const TtyColor = enum {
494 Red,
495 Green,
496 Cyan,
497 White,
498 Dim,
499 Bold,
500 Reset,
501};
502
503/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
504fn setTtyColor(tty_color: TtyColor) void {
505 if (os.supportsAnsiEscapeCodes(stderr_file.handle)) {
506 switch (tty_color) {
507 TtyColor.Red => {
508 stderr_file.write(RED) catch return;
509 },
510 TtyColor.Green => {
511 stderr_file.write(GREEN) catch return;
512 },
513 TtyColor.Cyan => {
514 stderr_file.write(CYAN) catch return;
515 },
516 TtyColor.White, TtyColor.Bold => {
517 stderr_file.write(WHITE) catch return;
518 },
519 TtyColor.Dim => {
520 stderr_file.write(DIM) catch return;
521 },
522 TtyColor.Reset => {
523 stderr_file.write(RESET) catch return;
524 },
525 }
526 } else {
527 const S = struct {
528 var attrs: windows.WORD = undefined;
529 var init_attrs = false;
530 };
531 if (!S.init_attrs) {
532 S.init_attrs = true;
533 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
534 // TODO handle error
535 _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
536 S.attrs = info.wAttributes;
537 }
538
539 // TODO handle errors
540 switch (tty_color) {
541 TtyColor.Red => {
542 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);
543 },
544 TtyColor.Green => {
545 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);
546 },
547 TtyColor.Cyan => {
548 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
549 },
550 TtyColor.White, TtyColor.Bold => {
551 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
552 },
553 TtyColor.Dim => {
554 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
555 },
556 TtyColor.Reset => {
557 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
558 },
559 }
560 }
561}
562
563fn populateModule(di: *DebugInfo, mod: *Module) !void {
564 if (mod.populated)
565 return;
566 const allocator = getDebugInfoAllocator();
567
568 if (mod.mod_info.C11ByteSize != 0)
569 return error.InvalidDebugInfo;
570
571 if (mod.mod_info.C13ByteSize == 0)
572 return error.MissingDebugInfo;
573
574 const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
575
576 const signature = try modi.stream.readIntLittle(u32);
577 if (signature != 4)
578 return error.InvalidDebugInfo;
579
580 mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
581 try modi.stream.readNoEof(mod.symbols);
582
583 mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
584 try modi.stream.readNoEof(mod.subsect_info);
585
586 var sect_offset: usize = 0;
587 var skip_len: usize = undefined;
588 while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
589 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
590 skip_len = subsect_hdr.Length;
591 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
592
593 switch (subsect_hdr.Kind) {
594 pdb.DebugSubsectionKind.FileChecksums => {
595 mod.checksum_offset = sect_offset;
596 break;
597 },
598 else => {},
599 }
600
601 if (sect_offset > mod.subsect_info.len)
602 return error.InvalidDebugInfo;
603 }
604
605 mod.populated = true;
606}
607
608fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
609 var min: usize = 0;
610 var max: usize = symbols.len - 1; // Exclude sentinel.
611 while (min < max) {
612 const mid = min + (max - min) / 2;
613 const curr = &symbols[mid];
614 const next = &symbols[mid + 1];
615 if (address >= next.address()) {
616 min = mid + 1;
617 } else if (address < curr.address()) {
618 max = mid;
619 } else {
620 return curr;
621 }
622 }
623 return null;
624}
625
626fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
627 const base_addr = std.os.getBaseAddress();
628 const adjusted_addr = 0x100000000 + (address - base_addr);
629
630 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
631 if (tty_color) {
632 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
633 } else {
634 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
635 }
636 return;
637 };
638
639 const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
640 const compile_unit_name = if (symbol.ofile) |ofile| blk: {
641 const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
642 break :blk os.path.basename(ofile_path);
643 } else "???";
644 if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
645 defer line_info.deinit();
646 try printLineInfo(
647 out_stream,
648 line_info,
649 address,
650 symbol_name,
651 compile_unit_name,
652 tty_color,
653 printLineFromFileAnyOs,
654 );
655 } else |err| switch (err) {
656 error.MissingDebugInfo, error.InvalidDebugInfo => {
657 if (tty_color) {
658 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n\n\n", address, symbol_name, compile_unit_name);
659 } else {
660 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", address, symbol_name, compile_unit_name);
661 }
662 },
663 else => return err,
664 }
665}
666
667/// This function works in freestanding mode.
668/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
669pub fn printSourceAtAddressDwarf(
670 debug_info: *DwarfInfo,
671 out_stream: var,
672 address: usize,
673 tty_color: bool,
674 comptime printLineFromFile: var,
675) !void {
676 const compile_unit = findCompileUnit(debug_info, address) catch {
677 if (tty_color) {
678 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
679 } else {
680 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
681 }
682 return;
683 };
684 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
685 if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
686 defer line_info.deinit();
687 const symbol_name = "???";
688 try printLineInfo(
689 out_stream,
690 line_info,
691 address,
692 symbol_name,
693 compile_unit_name,
694 tty_color,
695 printLineFromFile,
696 );
697 } else |err| switch (err) {
698 error.MissingDebugInfo, error.InvalidDebugInfo => {
699 if (tty_color) {
700 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
701 } else {
702 try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
703 }
704 },
705 else => return err,
706 }
707}
708
709pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
710 return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
711}
712
713fn printLineInfo(
714 out_stream: var,
715 line_info: LineInfo,
716 address: usize,
717 symbol_name: []const u8,
718 compile_unit_name: []const u8,
719 tty_color: bool,
720 comptime printLineFromFile: var,
721) !void {
722 if (tty_color) {
723 try out_stream.print(
724 WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n",
725 line_info.file_name,
726 line_info.line,
727 line_info.column,
728 address,
729 symbol_name,
730 compile_unit_name,
731 );
732 if (printLineFromFile(out_stream, line_info)) {
733 if (line_info.column == 0) {
734 try out_stream.write("\n");
735 } else {
736 {
737 var col_i: usize = 1;
738 while (col_i < line_info.column) : (col_i += 1) {
739 try out_stream.writeByte(' ');
740 }
741 }
742 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
743 }
744 } else |err| switch (err) {
745 error.EndOfFile => {},
746 else => return err,
747 }
748 } else {
749 try out_stream.print(
750 "{}:{}:{}: 0x{x} in {} ({})\n",
751 line_info.file_name,
752 line_info.line,
753 line_info.column,
754 address,
755 symbol_name,
756 compile_unit_name,
757 );
758 }
759}
760
761// TODO use this
762pub const OpenSelfDebugInfoError = error{
763 MissingDebugInfo,
764 OutOfMemory,
765 UnsupportedOperatingSystem,
766};
767
768pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
769 switch (builtin.os) {
770 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
771 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
772 builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
773 else => return error.UnsupportedOperatingSystem,
774 }
775}
776
777fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
778 const self_file = try os.openSelfExe();
779 defer self_file.close();
780
781 const coff_obj = try allocator.create(coff.Coff);
782 coff_obj.* = coff.Coff{
783 .in_file = self_file,
784 .allocator = allocator,
785 .coff_header = undefined,
786 .pe_header = undefined,
787 .sections = undefined,
788 .guid = undefined,
789 .age = undefined,
790 };
791
792 var di = DebugInfo{
793 .coff = coff_obj,
794 .pdb = undefined,
795 .sect_contribs = undefined,
796 .modules = undefined,
797 };
798
799 try di.coff.loadHeader();
800
801 var path_buf: [windows.MAX_PATH]u8 = undefined;
802 const len = try di.coff.getPdbPath(path_buf[0..]);
803 const raw_path = path_buf[0..len];
804
805 const path = try os.path.resolve(allocator, [][]const u8{raw_path});
806
807 try di.pdb.openFile(di.coff, path);
808
809 var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
810 const version = try pdb_stream.stream.readIntLittle(u32);
811 const signature = try pdb_stream.stream.readIntLittle(u32);
812 const age = try pdb_stream.stream.readIntLittle(u32);
813 var guid: [16]u8 = undefined;
814 try pdb_stream.stream.readNoEof(guid[0..]);
815 if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
816 return error.InvalidDebugInfo;
817 // We validated the executable and pdb match.
818
819 const string_table_index = str_tab_index: {
820 const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
821 const name_bytes = try allocator.alloc(u8, name_bytes_len);
822 try pdb_stream.stream.readNoEof(name_bytes);
823
824 const HashTableHeader = packed struct {
825 Size: u32,
826 Capacity: u32,
827
828 fn maxLoad(cap: u32) u32 {
829 return cap * 2 / 3 + 1;
830 }
831 };
832 const hash_tbl_hdr = try pdb_stream.stream.readStruct(HashTableHeader);
833 if (hash_tbl_hdr.Capacity == 0)
834 return error.InvalidDebugInfo;
835
836 if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
837 return error.InvalidDebugInfo;
838
839 const present = try readSparseBitVector(&pdb_stream.stream, allocator);
840 if (present.len != hash_tbl_hdr.Size)
841 return error.InvalidDebugInfo;
842 const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
843
844 const Bucket = struct {
845 first: u32,
846 second: u32,
847 };
848 const bucket_list = try allocator.alloc(Bucket, present.len);
849 for (present) |_| {
850 const name_offset = try pdb_stream.stream.readIntLittle(u32);
851 const name_index = try pdb_stream.stream.readIntLittle(u32);
852 const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
853 if (mem.eql(u8, name, "/names")) {
854 break :str_tab_index name_index;
855 }
856 }
857 return error.MissingDebugInfo;
858 };
859
860 di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
861 di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
862
863 const dbi = di.pdb.dbi;
864
865 // Dbi Header
866 const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
867 const mod_info_size = dbi_stream_header.ModInfoSize;
868 const section_contrib_size = dbi_stream_header.SectionContributionSize;
869
870 var modules = ArrayList(Module).init(allocator);
871
872 // Module Info Substream
873 var mod_info_offset: usize = 0;
874 while (mod_info_offset != mod_info_size) {
875 const mod_info = try dbi.stream.readStruct(pdb.ModInfo);
876 var this_record_len: usize = @sizeOf(pdb.ModInfo);
877
878 const module_name = try dbi.readNullTermString(allocator);
879 this_record_len += module_name.len + 1;
880
881 const obj_file_name = try dbi.readNullTermString(allocator);
882 this_record_len += obj_file_name.len + 1;
883
884 const march_forward_bytes = this_record_len % 4;
885 if (march_forward_bytes != 0) {
886 try dbi.seekForward(march_forward_bytes);
887 this_record_len += march_forward_bytes;
888 }
889
890 try modules.append(Module{
891 .mod_info = mod_info,
892 .module_name = module_name,
893 .obj_file_name = obj_file_name,
894
895 .populated = false,
896 .symbols = undefined,
897 .subsect_info = undefined,
898 .checksum_offset = null,
899 });
900
901 mod_info_offset += this_record_len;
902 if (mod_info_offset > mod_info_size)
903 return error.InvalidDebugInfo;
904 }
905
906 di.modules = modules.toOwnedSlice();
907
908 // Section Contribution Substream
909 var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
910 var sect_cont_offset: usize = 0;
911 if (section_contrib_size != 0) {
912 const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
913 if (ver != pdb.SectionContrSubstreamVersion.Ver60)
914 return error.InvalidDebugInfo;
915 sect_cont_offset += @sizeOf(u32);
916 }
917 while (sect_cont_offset != section_contrib_size) {
918 const entry = try sect_contribs.addOne();
919 entry.* = try dbi.stream.readStruct(pdb.SectionContribEntry);
920 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
921
922 if (sect_cont_offset > section_contrib_size)
923 return error.InvalidDebugInfo;
924 }
925
926 di.sect_contribs = sect_contribs.toOwnedSlice();
927
928 return di;
929}
930
931fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
932 const num_words = try stream.readIntLittle(u32);
933 var word_i: usize = 0;
934 var list = ArrayList(usize).init(allocator);
935 while (word_i != num_words) : (word_i += 1) {
936 const word = try stream.readIntLittle(u32);
937 var bit_i: u5 = 0;
938 while (true) : (bit_i += 1) {
939 if (word & (u32(1) << bit_i) != 0) {
940 try list.append(word_i * 32 + bit_i);
941 }
942 if (bit_i == maxInt(u5)) break;
943 }
944 }
945 return list.toOwnedSlice();
946}
947
948fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
949 const elf_header = (try elf_file.findSection(name)) orelse return null;
950 return DwarfInfo.Section{
951 .offset = elf_header.offset,
952 .size = elf_header.size,
953 };
954}
955
956/// Initialize DWARF info. The caller has the responsibility to initialize most
957/// the DwarfInfo fields before calling. These fields can be left undefined:
958/// * abbrev_table_list
959/// * compile_unit_list
960pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
961 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
962 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
963 try scanAllCompileUnits(di);
964}
965
966pub fn openElfDebugInfo(
967 allocator: *mem.Allocator,
968 elf_seekable_stream: *DwarfSeekableStream,
969 elf_in_stream: *DwarfInStream,
970) !DwarfInfo {
971 var efile: elf.Elf = undefined;
972 try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
973 errdefer efile.close();
974
975 var di = DwarfInfo{
976 .dwarf_seekable_stream = elf_seekable_stream,
977 .dwarf_in_stream = elf_in_stream,
978 .endian = efile.endian,
979 .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
980 .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
981 .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
982 .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
983 .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
984 .abbrev_table_list = undefined,
985 .compile_unit_list = undefined,
986 };
987 try openDwarfDebugInfo(&di, allocator);
988 return di;
989}
990
991fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
992 const S = struct {
993 var self_exe_file: os.File = undefined;
994 var self_exe_seekable_stream: os.File.SeekableStream = undefined;
995 var self_exe_in_stream: os.File.InStream = undefined;
996 };
997 S.self_exe_file = try os.openSelfExe();
998 errdefer S.self_exe_file.close();
999
1000 S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
1001 S.self_exe_in_stream = S.self_exe_file.inStream();
1002
1003 return openElfDebugInfo(
1004 allocator,
1005 // TODO https://github.com/ziglang/zig/issues/764
1006 @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
1007 // TODO https://github.com/ziglang/zig/issues/764
1008 @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
1009 );
1010}
1011
1012fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1013 const hdr = &std.c._mh_execute_header;
1014 assert(hdr.magic == std.macho.MH_MAGIC_64);
1015
1016 const hdr_base = @ptrCast([*]u8, hdr);
1017 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1018 var ncmd: u32 = hdr.ncmds;
1019 const symtab = while (ncmd != 0) : (ncmd -= 1) {
1020 const lc = @ptrCast(*std.macho.load_command, ptr);
1021 switch (lc.cmd) {
1022 std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr),
1023 else => {},
1024 }
1025 ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
1026 } else {
1027 return error.MissingDebugInfo;
1028 };
1029 const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
1030 const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize];
1031
1032 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
1033
1034 var ofile: ?*macho.nlist_64 = null;
1035 var reloc: u64 = 0;
1036 var symbol_index: usize = 0;
1037 var last_len: u64 = 0;
1038 for (syms) |*sym| {
1039 if (sym.n_type & std.macho.N_STAB != 0) {
1040 switch (sym.n_type) {
1041 std.macho.N_OSO => {
1042 ofile = sym;
1043 reloc = 0;
1044 },
1045 std.macho.N_FUN => {
1046 if (sym.n_sect == 0) {
1047 last_len = sym.n_value;
1048 } else {
1049 symbols_buf[symbol_index] = MachoSymbol{
1050 .nlist = sym,
1051 .ofile = ofile,
1052 .reloc = reloc,
1053 };
1054 symbol_index += 1;
1055 }
1056 },
1057 std.macho.N_BNSYM => {
1058 if (reloc == 0) {
1059 reloc = sym.n_value;
1060 }
1061 },
1062 else => continue,
1063 }
1064 }
1065 }
1066 const sentinel = try allocator.create(macho.nlist_64);
1067 sentinel.* = macho.nlist_64{
1068 .n_strx = 0,
1069 .n_type = 36,
1070 .n_sect = 0,
1071 .n_desc = 0,
1072 .n_value = symbols_buf[symbol_index - 1].nlist.n_value + last_len,
1073 };
1074
1075 const symbols = allocator.shrink(MachoSymbol, symbols_buf, symbol_index);
1076
1077 // Even though lld emits symbols in ascending order, this debug code
1078 // should work for programs linked in any valid way.
1079 // This sort is so that we can binary search later.
1080 std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
1081
1082 return DebugInfo{
1083 .ofiles = DebugInfo.OFileTable.init(allocator),
1084 .symbols = symbols,
1085 .strings = strings,
1086 };
1087}
1088
1089fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
1090 var f = try os.File.openRead(line_info.file_name);
1091 defer f.close();
1092 // TODO fstat and make sure that the file has the correct size
1093
1094 var buf: [os.page_size]u8 = undefined;
1095 var line: usize = 1;
1096 var column: usize = 1;
1097 var abs_index: usize = 0;
1098 while (true) {
1099 const amt_read = try f.read(buf[0..]);
1100 const slice = buf[0..amt_read];
1101
1102 for (slice) |byte| {
1103 if (line == line_info.line) {
1104 try out_stream.writeByte(byte);
1105 if (byte == '\n') {
1106 return;
1107 }
1108 }
1109 if (byte == '\n') {
1110 line += 1;
1111 column = 1;
1112 } else {
1113 column += 1;
1114 }
1115 }
1116
1117 if (amt_read < buf.len) return error.EndOfFile;
1118 }
1119}
1120
1121const MachoSymbol = struct {
1122 nlist: *macho.nlist_64,
1123 ofile: ?*macho.nlist_64,
1124 reloc: u64,
1125
1126 /// Returns the address from the macho file
1127 fn address(self: MachoSymbol) u64 {
1128 return self.nlist.n_value;
1129 }
1130
1131 fn addressLessThan(lhs: MachoSymbol, rhs: MachoSymbol) bool {
1132 return lhs.address() < rhs.address();
1133 }
1134};
1135
1136const MachOFile = struct {
1137 bytes: []align(@alignOf(macho.mach_header_64)) const u8,
1138 sect_debug_info: ?*const macho.section_64,
1139 sect_debug_line: ?*const macho.section_64,
1140};
1141
1142pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
1143pub const DwarfInStream = io.InStream(anyerror);
1144
1145pub const DwarfInfo = struct {
1146 dwarf_seekable_stream: *DwarfSeekableStream,
1147 dwarf_in_stream: *DwarfInStream,
1148 endian: builtin.Endian,
1149 debug_info: Section,
1150 debug_abbrev: Section,
1151 debug_str: Section,
1152 debug_line: Section,
1153 debug_ranges: ?Section,
1154 abbrev_table_list: ArrayList(AbbrevTableHeader),
1155 compile_unit_list: ArrayList(CompileUnit),
1156
1157 pub const Section = struct {
1158 offset: usize,
1159 size: usize,
1160 };
1161
1162 pub fn allocator(self: DwarfInfo) *mem.Allocator {
1163 return self.abbrev_table_list.allocator;
1164 }
1165
1166 pub fn readString(self: *DwarfInfo) ![]u8 {
1167 return readStringRaw(self.allocator(), self.dwarf_in_stream);
1168 }
1169};
1170
1171pub const DebugInfo = switch (builtin.os) {
1172 builtin.Os.macosx => struct {
1173 symbols: []const MachoSymbol,
1174 strings: []const u8,
1175 ofiles: OFileTable,
1176
1177 const OFileTable = std.HashMap(
1178 *macho.nlist_64,
1179 MachOFile,
1180 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
1181 std.hash_map.getTrivialEqlFn(*macho.nlist_64),
1182 );
1183
1184 pub fn allocator(self: DebugInfo) *mem.Allocator {
1185 return self.ofiles.allocator;
1186 }
1187 },
1188 builtin.Os.uefi, builtin.Os.windows => struct {
1189 pdb: pdb.Pdb,
1190 coff: *coff.Coff,
1191 sect_contribs: []pdb.SectionContribEntry,
1192 modules: []Module,
1193 },
1194 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
1195 else => @compileError("Unsupported OS"),
1196};
1197
1198const PcRange = struct {
1199 start: u64,
1200 end: u64,
1201};
1202
1203const CompileUnit = struct {
1204 version: u16,
1205 is_64: bool,
1206 die: *Die,
1207 index: usize,
1208 pc_range: ?PcRange,
1209};
1210
1211const AbbrevTable = ArrayList(AbbrevTableEntry);
1212
1213const AbbrevTableHeader = struct {
1214 // offset from .debug_abbrev
1215 offset: u64,
1216 table: AbbrevTable,
1217};
1218
1219const AbbrevTableEntry = struct {
1220 has_children: bool,
1221 abbrev_code: u64,
1222 tag_id: u64,
1223 attrs: ArrayList(AbbrevAttr),
1224};
1225
1226const AbbrevAttr = struct {
1227 attr_id: u64,
1228 form_id: u64,
1229};
1230
1231const FormValue = union(enum) {
1232 Address: u64,
1233 Block: []u8,
1234 Const: Constant,
1235 ExprLoc: []u8,
1236 Flag: bool,
1237 SecOffset: u64,
1238 Ref: []u8,
1239 RefAddr: u64,
1240 RefSig8: u64,
1241 String: []u8,
1242 StrPtr: u64,
1243};
1244
1245const Constant = struct {
1246 payload: []u8,
1247 signed: bool,
1248
1249 fn asUnsignedLe(self: *const Constant) !u64 {
1250 if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
1251 if (self.signed) return error.InvalidDebugInfo;
1252 return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
1253 }
1254};
1255
1256const Die = struct {
1257 tag_id: u64,
1258 has_children: bool,
1259 attrs: ArrayList(Attr),
1260
1261 const Attr = struct {
1262 id: u64,
1263 value: FormValue,
1264 };
1265
1266 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
1267 for (self.attrs.toSliceConst()) |*attr| {
1268 if (attr.id == id) return &attr.value;
1269 }
1270 return null;
1271 }
1272
1273 fn getAttrAddr(self: *const Die, id: u64) !u64 {
1274 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1275 return switch (form_value.*) {
1276 FormValue.Address => |value| value,
1277 else => error.InvalidDebugInfo,
1278 };
1279 }
1280
1281 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
1282 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1283 return switch (form_value.*) {
1284 FormValue.Const => |value| value.asUnsignedLe(),
1285 FormValue.SecOffset => |value| value,
1286 else => error.InvalidDebugInfo,
1287 };
1288 }
1289
1290 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
1291 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1292 return switch (form_value.*) {
1293 FormValue.Const => |value| value.asUnsignedLe(),
1294 else => error.InvalidDebugInfo,
1295 };
1296 }
1297
1298 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
1299 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1300 return switch (form_value.*) {
1301 FormValue.String => |value| value,
1302 FormValue.StrPtr => |offset| getString(di, offset),
1303 else => error.InvalidDebugInfo,
1304 };
1305 }
1306};
1307
1308const FileEntry = struct {
1309 file_name: []const u8,
1310 dir_index: usize,
1311 mtime: usize,
1312 len_bytes: usize,
1313};
1314
1315pub const LineInfo = struct {
1316 line: usize,
1317 column: usize,
1318 file_name: []const u8,
1319 allocator: ?*mem.Allocator,
1320
1321 fn deinit(self: LineInfo) void {
1322 const allocator = self.allocator orelse return;
1323 allocator.free(self.file_name);
1324 }
1325};
1326
1327const LineNumberProgram = struct {
1328 address: usize,
1329 file: usize,
1330 line: isize,
1331 column: usize,
1332 is_stmt: bool,
1333 basic_block: bool,
1334 end_sequence: bool,
1335
1336 target_address: usize,
1337 include_dirs: []const []const u8,
1338 file_entries: *ArrayList(FileEntry),
1339
1340 prev_address: usize,
1341 prev_file: usize,
1342 prev_line: isize,
1343 prev_column: usize,
1344 prev_is_stmt: bool,
1345 prev_basic_block: bool,
1346 prev_end_sequence: bool,
1347
1348 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
1349 return LineNumberProgram{
1350 .address = 0,
1351 .file = 1,
1352 .line = 1,
1353 .column = 0,
1354 .is_stmt = is_stmt,
1355 .basic_block = false,
1356 .end_sequence = false,
1357 .include_dirs = include_dirs,
1358 .file_entries = file_entries,
1359 .target_address = target_address,
1360 .prev_address = 0,
1361 .prev_file = undefined,
1362 .prev_line = undefined,
1363 .prev_column = undefined,
1364 .prev_is_stmt = undefined,
1365 .prev_basic_block = undefined,
1366 .prev_end_sequence = undefined,
1367 };
1368 }
1369
1370 pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {
1371 if (self.target_address >= self.prev_address and self.target_address < self.address) {
1372 const file_entry = if (self.prev_file == 0) {
1373 return error.MissingDebugInfo;
1374 } else if (self.prev_file - 1 >= self.file_entries.len) {
1375 return error.InvalidDebugInfo;
1376 } else
1377 &self.file_entries.items[self.prev_file - 1];
1378
1379 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
1380 return error.InvalidDebugInfo;
1381 } else
1382 self.include_dirs[file_entry.dir_index];
1383 const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
1384 errdefer self.file_entries.allocator.free(file_name);
1385 return LineInfo{
1386 .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
1387 .column = self.prev_column,
1388 .file_name = file_name,
1389 .allocator = self.file_entries.allocator,
1390 };
1391 }
1392
1393 self.prev_address = self.address;
1394 self.prev_file = self.file;
1395 self.prev_line = self.line;
1396 self.prev_column = self.column;
1397 self.prev_is_stmt = self.is_stmt;
1398 self.prev_basic_block = self.basic_block;
1399 self.prev_end_sequence = self.end_sequence;
1400 return null;
1401 }
1402};
1403
1404fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
1405 var buf = ArrayList(u8).init(allocator);
1406 while (true) {
1407 const byte = try in_stream.readByte();
1408 if (byte == 0) break;
1409 try buf.append(byte);
1410 }
1411 return buf.toSlice();
1412}
1413
1414fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
1415 const pos = di.debug_str.offset + offset;
1416 try di.dwarf_seekable_stream.seekTo(pos);
1417 return di.readString();
1418}
1419
1420fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
1421 const buf = try allocator.alloc(u8, size);
1422 errdefer allocator.free(buf);
1423 if ((try in_stream.read(buf)) < size) return error.EndOfFile;
1424 return buf;
1425}
1426
1427fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1428 const buf = try readAllocBytes(allocator, in_stream, size);
1429 return FormValue{ .Block = buf };
1430}
1431
1432fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1433 const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
1434 return parseFormValueBlockLen(allocator, in_stream, block_len);
1435}
1436
1437fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
1438 return FormValue{
1439 .Const = Constant{
1440 .signed = signed,
1441 .payload = try readAllocBytes(allocator, in_stream, size),
1442 },
1443 };
1444}
1445
1446fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
1447 return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
1448}
1449
1450fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
1451 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
1452}
1453
1454fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1455 const buf = try readAllocBytes(allocator, in_stream, size);
1456 return FormValue{ .Ref = buf };
1457}
1458
1459fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
1460 const block_len = try in_stream.readIntLittle(T);
1461 return parseFormValueRefLen(allocator, in_stream, block_len);
1462}
1463
1464fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
1465 return switch (form_id) {
1466 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
1467 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
1468 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
1469 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
1470 DW.FORM_block => x: {
1471 const block_len = try readULeb128(in_stream);
1472 return parseFormValueBlockLen(allocator, in_stream, block_len);
1473 },
1474 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
1475 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
1476 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
1477 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
1478 DW.FORM_udata, DW.FORM_sdata => {
1479 const block_len = try readULeb128(in_stream);
1480 const signed = form_id == DW.FORM_sdata;
1481 return parseFormValueConstant(allocator, in_stream, signed, block_len);
1482 },
1483 DW.FORM_exprloc => {
1484 const size = try readULeb128(in_stream);
1485 const buf = try readAllocBytes(allocator, in_stream, size);
1486 return FormValue{ .ExprLoc = buf };
1487 },
1488 DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
1489 DW.FORM_flag_present => FormValue{ .Flag = true },
1490 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1491
1492 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
1493 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
1494 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
1495 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
1496 DW.FORM_ref_udata => {
1497 const ref_len = try readULeb128(in_stream);
1498 return parseFormValueRefLen(allocator, in_stream, ref_len);
1499 },
1500
1501 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1502 DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
1503
1504 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
1505 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1506 DW.FORM_indirect => {
1507 const child_form_id = try readULeb128(in_stream);
1508 return parseFormValue(allocator, in_stream, child_form_id, is_64);
1509 },
1510 else => error.InvalidDebugInfo,
1511 };
1512}
1513
1514fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
1515 var result = AbbrevTable.init(di.allocator());
1516 while (true) {
1517 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1518 if (abbrev_code == 0) return result;
1519 try result.append(AbbrevTableEntry{
1520 .abbrev_code = abbrev_code,
1521 .tag_id = try readULeb128(di.dwarf_in_stream),
1522 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
1523 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1524 });
1525 const attrs = &result.items[result.len - 1].attrs;
1526
1527 while (true) {
1528 const attr_id = try readULeb128(di.dwarf_in_stream);
1529 const form_id = try readULeb128(di.dwarf_in_stream);
1530 if (attr_id == 0 and form_id == 0) break;
1531 try attrs.append(AbbrevAttr{
1532 .attr_id = attr_id,
1533 .form_id = form_id,
1534 });
1535 }
1536 }
1537}
1538
1539/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
1540/// seeks in the stream and parses it.
1541fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
1542 for (di.abbrev_table_list.toSlice()) |*header| {
1543 if (header.offset == abbrev_offset) {
1544 return &header.table;
1545 }
1546 }
1547 try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
1548 try di.abbrev_table_list.append(AbbrevTableHeader{
1549 .offset = abbrev_offset,
1550 .table = try parseAbbrevTable(di),
1551 });
1552 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
1553}
1554
1555fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
1556 for (abbrev_table.toSliceConst()) |*table_entry| {
1557 if (table_entry.abbrev_code == abbrev_code) return table_entry;
1558 }
1559 return null;
1560}
1561
1562fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
1563 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1564 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1565
1566 var result = Die{
1567 .tag_id = table_entry.tag_id,
1568 .has_children = table_entry.has_children,
1569 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1570 };
1571 try result.attrs.resize(table_entry.attrs.len);
1572 for (table_entry.attrs.toSliceConst()) |attr, i| {
1573 result.attrs.items[i] = Die.Attr{
1574 .id = attr.attr_id,
1575 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
1576 };
1577 }
1578 return result;
1579}
1580
1581fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
1582 const ofile = symbol.ofile orelse return error.MissingDebugInfo;
1583 const gop = try di.ofiles.getOrPut(ofile);
1584 const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: {
1585 errdefer _ = di.ofiles.remove(ofile);
1586 const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
1587
1588 gop.kv.value = MachOFile{
1589 .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(macho.mach_header_64)),
1590 .sect_debug_info = null,
1591 .sect_debug_line = null,
1592 };
1593 const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr);
1594 if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;
1595
1596 const hdr_base = @ptrCast([*]const u8, hdr);
1597 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1598 var ncmd: u32 = hdr.ncmds;
1599 const segcmd = while (ncmd != 0) : (ncmd -= 1) {
1600 const lc = @ptrCast(*const std.macho.load_command, ptr);
1601 switch (lc.cmd) {
1602 std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)),
1603 else => {},
1604 }
1605 ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
1606 } else {
1607 return error.MissingDebugInfo;
1608 };
1609 const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
1610 for (sections) |*sect| {
1611 if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
1612 (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
1613 {
1614 const sect_name = mem.toSliceConst(u8, &sect.sectname);
1615 if (mem.eql(u8, sect_name, "__debug_line")) {
1616 gop.kv.value.sect_debug_line = sect;
1617 } else if (mem.eql(u8, sect_name, "__debug_info")) {
1618 gop.kv.value.sect_debug_info = sect;
1619 }
1620 }
1621 }
1622
1623 break :blk &gop.kv.value;
1624 };
1625
1626 const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo;
1627 var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset;
1628
1629 var is_64: bool = undefined;
1630 const unit_length = try readInitialLengthMem(&ptr, &is_64);
1631 if (unit_length == 0) return error.MissingDebugInfo;
1632
1633 const version = readIntMem(&ptr, u16, builtin.Endian.Little);
1634 // TODO support 3 and 5
1635 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1636
1637 const prologue_length = if (is_64)
1638 readIntMem(&ptr, u64, builtin.Endian.Little)
1639 else
1640 readIntMem(&ptr, u32, builtin.Endian.Little);
1641 const prog_start = ptr + prologue_length;
1642
1643 const minimum_instruction_length = readByteMem(&ptr);
1644 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1645
1646 if (version >= 4) {
1647 // maximum_operations_per_instruction
1648 ptr += 1;
1649 }
1650
1651 const default_is_stmt = readByteMem(&ptr) != 0;
1652 const line_base = readByteSignedMem(&ptr);
1653
1654 const line_range = readByteMem(&ptr);
1655 if (line_range == 0) return error.InvalidDebugInfo;
1656
1657 const opcode_base = readByteMem(&ptr);
1658
1659 const standard_opcode_lengths = ptr[0 .. opcode_base - 1];
1660 ptr += opcode_base - 1;
1661
1662 var include_directories = ArrayList([]const u8).init(di.allocator());
1663 try include_directories.append("");
1664 while (true) {
1665 const dir = readStringMem(&ptr);
1666 if (dir.len == 0) break;
1667 try include_directories.append(dir);
1668 }
1669
1670 var file_entries = ArrayList(FileEntry).init(di.allocator());
1671 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1672
1673 while (true) {
1674 const file_name = readStringMem(&ptr);
1675 if (file_name.len == 0) break;
1676 const dir_index = try readULeb128Mem(&ptr);
1677 const mtime = try readULeb128Mem(&ptr);
1678 const len_bytes = try readULeb128Mem(&ptr);
1679 try file_entries.append(FileEntry{
1680 .file_name = file_name,
1681 .dir_index = dir_index,
1682 .mtime = mtime,
1683 .len_bytes = len_bytes,
1684 });
1685 }
1686
1687 ptr = prog_start;
1688 while (true) {
1689 const opcode = readByteMem(&ptr);
1690
1691 if (opcode == DW.LNS_extended_op) {
1692 const op_size = try readULeb128Mem(&ptr);
1693 if (op_size < 1) return error.InvalidDebugInfo;
1694 var sub_op = readByteMem(&ptr);
1695 switch (sub_op) {
1696 DW.LNE_end_sequence => {
1697 prog.end_sequence = true;
1698 if (try prog.checkLineMatch()) |info| return info;
1699 return error.MissingDebugInfo;
1700 },
1701 DW.LNE_set_address => {
1702 const addr = readIntMem(&ptr, usize, builtin.Endian.Little);
1703 prog.address = symbol.reloc + addr;
1704 },
1705 DW.LNE_define_file => {
1706 const file_name = readStringMem(&ptr);
1707 const dir_index = try readULeb128Mem(&ptr);
1708 const mtime = try readULeb128Mem(&ptr);
1709 const len_bytes = try readULeb128Mem(&ptr);
1710 try file_entries.append(FileEntry{
1711 .file_name = file_name,
1712 .dir_index = dir_index,
1713 .mtime = mtime,
1714 .len_bytes = len_bytes,
1715 });
1716 },
1717 else => {
1718 ptr += op_size - 1;
1719 },
1720 }
1721 } else if (opcode >= opcode_base) {
1722 // special opcodes
1723 const adjusted_opcode = opcode - opcode_base;
1724 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1725 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
1726 prog.line += inc_line;
1727 prog.address += inc_addr;
1728 if (try prog.checkLineMatch()) |info| return info;
1729 prog.basic_block = false;
1730 } else {
1731 switch (opcode) {
1732 DW.LNS_copy => {
1733 if (try prog.checkLineMatch()) |info| return info;
1734 prog.basic_block = false;
1735 },
1736 DW.LNS_advance_pc => {
1737 const arg = try readULeb128Mem(&ptr);
1738 prog.address += arg * minimum_instruction_length;
1739 },
1740 DW.LNS_advance_line => {
1741 const arg = try readILeb128Mem(&ptr);
1742 prog.line += arg;
1743 },
1744 DW.LNS_set_file => {
1745 const arg = try readULeb128Mem(&ptr);
1746 prog.file = arg;
1747 },
1748 DW.LNS_set_column => {
1749 const arg = try readULeb128Mem(&ptr);
1750 prog.column = arg;
1751 },
1752 DW.LNS_negate_stmt => {
1753 prog.is_stmt = !prog.is_stmt;
1754 },
1755 DW.LNS_set_basic_block => {
1756 prog.basic_block = true;
1757 },
1758 DW.LNS_const_add_pc => {
1759 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1760 prog.address += inc_addr;
1761 },
1762 DW.LNS_fixed_advance_pc => {
1763 const arg = readIntMem(&ptr, u16, builtin.Endian.Little);
1764 prog.address += arg;
1765 },
1766 DW.LNS_set_prologue_end => {},
1767 else => {
1768 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1769 const len_bytes = standard_opcode_lengths[opcode - 1];
1770 ptr += len_bytes;
1771 },
1772 }
1773 }
1774 }
1775
1776 return error.MissingDebugInfo;
1777}
1778
1779fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
1780 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
1781
1782 const debug_line_end = di.debug_line.offset + di.debug_line.size;
1783 var this_offset = di.debug_line.offset;
1784 var this_index: usize = 0;
1785
1786 while (this_offset < debug_line_end) : (this_index += 1) {
1787 try di.dwarf_seekable_stream.seekTo(this_offset);
1788
1789 var is_64: bool = undefined;
1790 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1791 if (unit_length == 0) return error.MissingDebugInfo;
1792 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
1793
1794 if (compile_unit.index != this_index) {
1795 this_offset += next_offset;
1796 continue;
1797 }
1798
1799 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1800 // TODO support 3 and 5
1801 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1802
1803 const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
1804 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
1805
1806 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
1807 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1808
1809 if (version >= 4) {
1810 // maximum_operations_per_instruction
1811 _ = try di.dwarf_in_stream.readByte();
1812 }
1813
1814 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1815 const line_base = try di.dwarf_in_stream.readByteSigned();
1816
1817 const line_range = try di.dwarf_in_stream.readByte();
1818 if (line_range == 0) return error.InvalidDebugInfo;
1819
1820 const opcode_base = try di.dwarf_in_stream.readByte();
1821
1822 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
1823
1824 {
1825 var i: usize = 0;
1826 while (i < opcode_base - 1) : (i += 1) {
1827 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
1828 }
1829 }
1830
1831 var include_directories = ArrayList([]u8).init(di.allocator());
1832 try include_directories.append(compile_unit_cwd);
1833 while (true) {
1834 const dir = try di.readString();
1835 if (dir.len == 0) break;
1836 try include_directories.append(dir);
1837 }
1838
1839 var file_entries = ArrayList(FileEntry).init(di.allocator());
1840 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1841
1842 while (true) {
1843 const file_name = try di.readString();
1844 if (file_name.len == 0) break;
1845 const dir_index = try readULeb128(di.dwarf_in_stream);
1846 const mtime = try readULeb128(di.dwarf_in_stream);
1847 const len_bytes = try readULeb128(di.dwarf_in_stream);
1848 try file_entries.append(FileEntry{
1849 .file_name = file_name,
1850 .dir_index = dir_index,
1851 .mtime = mtime,
1852 .len_bytes = len_bytes,
1853 });
1854 }
1855
1856 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
1857
1858 while (true) {
1859 const opcode = try di.dwarf_in_stream.readByte();
1860
1861 if (opcode == DW.LNS_extended_op) {
1862 const op_size = try readULeb128(di.dwarf_in_stream);
1863 if (op_size < 1) return error.InvalidDebugInfo;
1864 var sub_op = try di.dwarf_in_stream.readByte();
1865 switch (sub_op) {
1866 DW.LNE_end_sequence => {
1867 prog.end_sequence = true;
1868 if (try prog.checkLineMatch()) |info| return info;
1869 return error.MissingDebugInfo;
1870 },
1871 DW.LNE_set_address => {
1872 const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
1873 prog.address = addr;
1874 },
1875 DW.LNE_define_file => {
1876 const file_name = try di.readString();
1877 const dir_index = try readULeb128(di.dwarf_in_stream);
1878 const mtime = try readULeb128(di.dwarf_in_stream);
1879 const len_bytes = try readULeb128(di.dwarf_in_stream);
1880 try file_entries.append(FileEntry{
1881 .file_name = file_name,
1882 .dir_index = dir_index,
1883 .mtime = mtime,
1884 .len_bytes = len_bytes,
1885 });
1886 },
1887 else => {
1888 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1889 try di.dwarf_seekable_stream.seekForward(fwd_amt);
1890 },
1891 }
1892 } else if (opcode >= opcode_base) {
1893 // special opcodes
1894 const adjusted_opcode = opcode - opcode_base;
1895 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1896 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
1897 prog.line += inc_line;
1898 prog.address += inc_addr;
1899 if (try prog.checkLineMatch()) |info| return info;
1900 prog.basic_block = false;
1901 } else {
1902 switch (opcode) {
1903 DW.LNS_copy => {
1904 if (try prog.checkLineMatch()) |info| return info;
1905 prog.basic_block = false;
1906 },
1907 DW.LNS_advance_pc => {
1908 const arg = try readULeb128(di.dwarf_in_stream);
1909 prog.address += arg * minimum_instruction_length;
1910 },
1911 DW.LNS_advance_line => {
1912 const arg = try readILeb128(di.dwarf_in_stream);
1913 prog.line += arg;
1914 },
1915 DW.LNS_set_file => {
1916 const arg = try readULeb128(di.dwarf_in_stream);
1917 prog.file = arg;
1918 },
1919 DW.LNS_set_column => {
1920 const arg = try readULeb128(di.dwarf_in_stream);
1921 prog.column = arg;
1922 },
1923 DW.LNS_negate_stmt => {
1924 prog.is_stmt = !prog.is_stmt;
1925 },
1926 DW.LNS_set_basic_block => {
1927 prog.basic_block = true;
1928 },
1929 DW.LNS_const_add_pc => {
1930 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1931 prog.address += inc_addr;
1932 },
1933 DW.LNS_fixed_advance_pc => {
1934 const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
1935 prog.address += arg;
1936 },
1937 DW.LNS_set_prologue_end => {},
1938 else => {
1939 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1940 const len_bytes = standard_opcode_lengths[opcode - 1];
1941 try di.dwarf_seekable_stream.seekForward(len_bytes);
1942 },
1943 }
1944 }
1945 }
1946
1947 this_offset += next_offset;
1948 }
1949
1950 return error.MissingDebugInfo;
1951}
1952
1953fn scanAllCompileUnits(di: *DwarfInfo) !void {
1954 const debug_info_end = di.debug_info.offset + di.debug_info.size;
1955 var this_unit_offset = di.debug_info.offset;
1956 var cu_index: usize = 0;
1957
1958 while (this_unit_offset < debug_info_end) {
1959 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
1960
1961 var is_64: bool = undefined;
1962 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1963 if (unit_length == 0) return;
1964 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
1965
1966 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1967 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1968
1969 const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
1970
1971 const address_size = try di.dwarf_in_stream.readByte();
1972 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1973
1974 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
1975 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
1976
1977 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
1978
1979 const compile_unit_die = try di.allocator().create(Die);
1980 compile_unit_die.* = try parseDie(di, abbrev_table, is_64);
1981
1982 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
1983
1984 const pc_range = x: {
1985 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1986 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
1987 const pc_end = switch (high_pc_value.*) {
1988 FormValue.Address => |value| value,
1989 FormValue.Const => |value| b: {
1990 const offset = try value.asUnsignedLe();
1991 break :b (low_pc + offset);
1992 },
1993 else => return error.InvalidDebugInfo,
1994 };
1995 break :x PcRange{
1996 .start = low_pc,
1997 .end = pc_end,
1998 };
1999 } else {
2000 break :x null;
2001 }
2002 } else |err| {
2003 if (err != error.MissingDebugInfo) return err;
2004 break :x null;
2005 }
2006 };
2007
2008 try di.compile_unit_list.append(CompileUnit{
2009 .version = version,
2010 .is_64 = is_64,
2011 .pc_range = pc_range,
2012 .die = compile_unit_die,
2013 .index = cu_index,
2014 });
2015
2016 this_unit_offset += next_offset;
2017 cu_index += 1;
2018 }
2019}
2020
2021fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
2022 for (di.compile_unit_list.toSlice()) |*compile_unit| {
2023 if (compile_unit.pc_range) |range| {
2024 if (target_address >= range.start and target_address < range.end) return compile_unit;
2025 }
2026 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
2027 var base_address: usize = 0;
2028 if (di.debug_ranges) |debug_ranges| {
2029 try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
2030 while (true) {
2031 const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
2032 const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
2033 if (begin_addr == 0 and end_addr == 0) {
2034 break;
2035 }
2036 if (begin_addr == maxInt(usize)) {
2037 base_address = begin_addr;
2038 continue;
2039 }
2040 if (target_address >= begin_addr and target_address < end_addr) {
2041 return compile_unit;
2042 }
2043 }
2044 }
2045 } else |err| {
2046 if (err != error.MissingDebugInfo) return err;
2047 continue;
2048 }
2049 }
2050 return error.MissingDebugInfo;
2051}
2052
2053fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
2054 // TODO https://github.com/ziglang/zig/issues/863
2055 const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
2056 ptr.* += @sizeOf(T);
2057 return result;
2058}
2059
2060fn readByteMem(ptr: *[*]const u8) u8 {
2061 const result = ptr.*[0];
2062 ptr.* += 1;
2063 return result;
2064}
2065
2066fn readByteSignedMem(ptr: *[*]const u8) i8 {
2067 return @bitCast(i8, readByteMem(ptr));
2068}
2069
2070fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
2071 // TODO this code can be improved with https://github.com/ziglang/zig/issues/863
2072 const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
2073 is_64.* = (first_32_bits == 0xffffffff);
2074 if (is_64.*) {
2075 ptr.* += 4;
2076 const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
2077 ptr.* += 8;
2078 return result;
2079 } else {
2080 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
2081 ptr.* += 4;
2082 return u64(first_32_bits);
2083 }
2084}
2085
2086fn readStringMem(ptr: *[*]const u8) []const u8 {
2087 const result = mem.toSliceConst(u8, ptr.*);
2088 ptr.* += result.len + 1;
2089 return result;
2090}
2091
2092fn readULeb128Mem(ptr: *[*]const u8) !u64 {
2093 var result: u64 = 0;
2094 var shift: usize = 0;
2095 var i: usize = 0;
2096
2097 while (true) {
2098 const byte = ptr.*[i];
2099 i += 1;
2100
2101 var operand: u64 = undefined;
2102
2103 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2104
2105 result |= operand;
2106
2107 if ((byte & 0b10000000) == 0) {
2108 ptr.* += i;
2109 return result;
2110 }
2111
2112 shift += 7;
2113 }
2114}
2115fn readILeb128Mem(ptr: *[*]const u8) !i64 {
2116 var result: i64 = 0;
2117 var shift: usize = 0;
2118 var i: usize = 0;
2119
2120 while (true) {
2121 const byte = ptr.*[i];
2122 i += 1;
2123
2124 var operand: i64 = undefined;
2125 if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2126
2127 result |= operand;
2128 shift += 7;
2129
2130 if ((byte & 0b10000000) == 0) {
2131 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
2132 ptr.* += i;
2133 return result;
2134 }
2135 }
2136}
2137
2138fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
2139 const first_32_bits = try in_stream.readIntLittle(u32);
2140 is_64.* = (first_32_bits == 0xffffffff);
2141 if (is_64.*) {
2142 return in_stream.readIntLittle(u64);
2143 } else {
2144 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
2145 return u64(first_32_bits);
2146 }
2147}
2148
2149fn readULeb128(in_stream: var) !u64 {
2150 var result: u64 = 0;
2151 var shift: usize = 0;
2152
2153 while (true) {
2154 const byte = try in_stream.readByte();
2155
2156 var operand: u64 = undefined;
2157
2158 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2159
2160 result |= operand;
2161
2162 if ((byte & 0b10000000) == 0) return result;
2163
2164 shift += 7;
2165 }
2166}
2167
2168fn readILeb128(in_stream: var) !i64 {
2169 var result: i64 = 0;
2170 var shift: usize = 0;
2171
2172 while (true) {
2173 const byte = try in_stream.readByte();
2174
2175 var operand: i64 = undefined;
2176
2177 if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2178
2179 result |= operand;
2180 shift += 7;
2181
2182 if ((byte & 0b10000000) == 0) {
2183 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
2184 return result;
2185 }
2186 }
2187}
2188
2189/// This should only be used in temporary test programs.
2190pub const global_allocator = &global_fixed_allocator.allocator;
2191var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);
2192var global_allocator_mem: [100 * 1024]u8 = undefined;
2193
2194/// TODO multithreaded awareness
2195var debug_info_allocator: ?*mem.Allocator = null;
2196var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
2197var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
2198fn getDebugInfoAllocator() *mem.Allocator {
2199 if (debug_info_allocator) |a| return a;
2200
2201 debug_info_direct_allocator = std.heap.DirectAllocator.init();
2202 debug_info_arena_allocator = std.heap.ArenaAllocator.init(&debug_info_direct_allocator.allocator);
2203 debug_info_allocator = &debug_info_arena_allocator.allocator;
2204 return &debug_info_arena_allocator.allocator;
2205}
std/debug/failing_allocator.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const mem = std.mem;2const mem = std.mem;
33
4/// Allocator that fails after N allocations, useful for making sure out of4/// Allocator that fails after N allocations, useful for making sure out of
std/debug/index.zig deleted-2205
...@@ -1,2205 +0,0 @@
1const std = @import("../index.zig");
2const math = std.math;
3const mem = std.mem;
4const io = std.io;
5const os = std.os;
6const elf = std.elf;
7const DW = std.dwarf;
8const macho = std.macho;
9const coff = std.coff;
10const pdb = std.pdb;
11const windows = os.windows;
12const ArrayList = std.ArrayList;
13const builtin = @import("builtin");
14const maxInt = std.math.maxInt;
15
16pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
17pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
18
19pub const runtime_safety = switch (builtin.mode) {
20 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,
21 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
22};
23
24const Module = struct {
25 mod_info: pdb.ModInfo,
26 module_name: []u8,
27 obj_file_name: []u8,
28
29 populated: bool,
30 symbols: []u8,
31 subsect_info: []u8,
32 checksum_offset: ?usize,
33};
34
35/// Tries to write to stderr, unbuffered, and ignores any error returned.
36/// Does not append a newline.
37var stderr_file: os.File = undefined;
38var stderr_file_out_stream: os.File.OutStream = undefined;
39
40var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
41var stderr_mutex = std.Mutex.init();
42pub fn warn(comptime fmt: []const u8, args: ...) void {
43 const held = stderr_mutex.acquire();
44 defer held.release();
45 const stderr = getStderrStream() catch return;
46 stderr.print(fmt, args) catch return;
47}
48
49pub fn getStderrStream() !*io.OutStream(os.File.WriteError) {
50 if (stderr_stream) |st| {
51 return st;
52 } else {
53 stderr_file = try io.getStdErr();
54 stderr_file_out_stream = stderr_file.outStream();
55 const st = &stderr_file_out_stream.stream;
56 stderr_stream = st;
57 return st;
58 }
59}
60
61/// TODO multithreaded awareness
62var self_debug_info: ?DebugInfo = null;
63
64pub fn getSelfDebugInfo() !*DebugInfo {
65 if (self_debug_info) |*info| {
66 return info;
67 } else {
68 self_debug_info = try openSelfDebugInfo(getDebugInfoAllocator());
69 return &self_debug_info.?;
70 }
71}
72
73fn wantTtyColor() bool {
74 var bytes: [128]u8 = undefined;
75 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
76 return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
77}
78
79/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
80/// TODO multithreaded awareness
81pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
82 const stderr = getStderrStream() catch return;
83 const debug_info = getSelfDebugInfo() catch |err| {
84 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
85 return;
86 };
87 writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
88 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
89 return;
90 };
91}
92
93/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
94/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
95/// and then try to find the first address. If addresses.len is more than 32, we
96/// capture that many stack frames exactly, and then look for the first address,
97/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
98/// equals the passed in addresses pointer.
99pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
100 switch (builtin.os) {
101 builtin.Os.windows => {
102 const addrs = stack_trace.instruction_addresses;
103 const u32_addrs_len = @intCast(u32, addrs.len);
104 const first_addr = first_address orelse {
105 stack_trace.index = windows.RtlCaptureStackBackTrace(
106 0,
107 u32_addrs_len,
108 @ptrCast(**c_void, addrs.ptr),
109 null,
110 );
111 return;
112 };
113 var addr_buf_stack: [32]usize = undefined;
114 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
115 const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
116 const first_index = for (addr_buf[0..n]) |addr, i| {
117 if (addr == first_addr) {
118 break i;
119 }
120 } else {
121 stack_trace.index = 0;
122 return;
123 };
124 const slice = addr_buf[first_index..n];
125 // We use a for loop here because slice and addrs may alias.
126 for (slice) |addr, i| {
127 addrs[i] = addr;
128 }
129 stack_trace.index = slice.len;
130 },
131 else => {
132 var it = StackIterator.init(first_address);
133 for (stack_trace.instruction_addresses) |*addr, i| {
134 addr.* = it.next() orelse {
135 stack_trace.index = i;
136 return;
137 };
138 }
139 stack_trace.index = stack_trace.instruction_addresses.len;
140 },
141 }
142}
143
144/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
145/// TODO multithreaded awareness
146pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
147 const stderr = getStderrStream() catch return;
148 const debug_info = getSelfDebugInfo() catch |err| {
149 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
150 return;
151 };
152 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {
153 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
154 return;
155 };
156}
157
158/// This function invokes undefined behavior when `ok` is `false`.
159/// In Debug and ReleaseSafe modes, calls to this function are always
160/// generated, and the `unreachable` statement triggers a panic.
161/// In ReleaseFast and ReleaseSmall modes, calls to this function are
162/// optimized away, and in fact the optimizer is able to use the assertion
163/// in its heuristics.
164/// Inside a test block, it is best to use the `std.testing` module rather
165/// than this function, because this function may not detect a test failure
166/// in ReleaseFast and ReleaseSafe mode. Outside of a test block, this assert
167/// function is the correct function to use.
168pub fn assert(ok: bool) void {
169 if (!ok) unreachable; // assertion failure
170}
171
172pub fn panic(comptime format: []const u8, args: ...) noreturn {
173 @setCold(true);
174 const first_trace_addr = @ptrToInt(@returnAddress());
175 panicExtra(null, first_trace_addr, format, args);
176}
177
178/// TODO multithreaded awareness
179var panicking: u8 = 0; // TODO make this a bool
180
181pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
182 @setCold(true);
183
184 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
185 // Panicked during a panic.
186
187 // TODO detect if a different thread caused the panic, because in that case
188 // we would want to return here instead of calling abort, so that the thread
189 // which first called panic can finish printing a stack trace.
190 os.abort();
191 }
192 const stderr = getStderrStream() catch os.abort();
193 stderr.print(format ++ "\n", args) catch os.abort();
194 if (trace) |t| {
195 dumpStackTrace(t.*);
196 }
197 dumpCurrentStackTrace(first_trace_addr);
198
199 os.abort();
200}
201
202const RED = "\x1b[31;1m";
203const GREEN = "\x1b[32;1m";
204const CYAN = "\x1b[36;1m";
205const WHITE = "\x1b[37;1m";
206const DIM = "\x1b[2m";
207const RESET = "\x1b[0m";
208
209pub fn writeStackTrace(
210 stack_trace: builtin.StackTrace,
211 out_stream: var,
212 allocator: *mem.Allocator,
213 debug_info: *DebugInfo,
214 tty_color: bool,
215) !void {
216 var frame_index: usize = 0;
217 var frames_left: usize = stack_trace.index;
218
219 while (frames_left != 0) : ({
220 frames_left -= 1;
221 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
222 }) {
223 const return_address = stack_trace.instruction_addresses[frame_index];
224 try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
225 }
226}
227
228pub const StackIterator = struct {
229 first_addr: ?usize,
230 fp: usize,
231
232 pub fn init(first_addr: ?usize) StackIterator {
233 return StackIterator{
234 .first_addr = first_addr,
235 .fp = @ptrToInt(@frameAddress()),
236 };
237 }
238
239 fn next(self: *StackIterator) ?usize {
240 if (self.fp == 0) return null;
241 self.fp = @intToPtr(*const usize, self.fp).*;
242 if (self.fp == 0) return null;
243
244 if (self.first_addr) |addr| {
245 while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
246 const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
247 if (addr == return_address) {
248 self.first_addr = null;
249 return return_address;
250 }
251 }
252 }
253
254 const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
255 return return_address;
256 }
257};
258
259pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
260 switch (builtin.os) {
261 builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
262 else => {},
263 }
264 var it = StackIterator.init(start_addr);
265 while (it.next()) |return_address| {
266 try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
267 }
268}
269
270pub fn writeCurrentStackTraceWindows(
271 out_stream: var,
272 debug_info: *DebugInfo,
273 tty_color: bool,
274 start_addr: ?usize,
275) !void {
276 var addr_buf: [1024]usize = undefined;
277 const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
278 const addrs = addr_buf[0..n];
279 var start_i: usize = if (start_addr) |saddr| blk: {
280 for (addrs) |addr, i| {
281 if (addr == saddr) break :blk i;
282 }
283 return;
284 } else 0;
285 for (addrs[start_i..]) |addr| {
286 try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
287 }
288}
289
290pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
291 switch (builtin.os) {
292 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
293 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
294 builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
295 else => return error.UnsupportedOperatingSystem,
296 }
297}
298
299fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
300 const allocator = getDebugInfoAllocator();
301 const base_address = os.getBaseAddress();
302 const relative_address = relocated_address - base_address;
303
304 var coff_section: *coff.Section = undefined;
305 const mod_index = for (di.sect_contribs) |sect_contrib| {
306 if (sect_contrib.Section > di.coff.sections.len) continue;
307 // Remember that SectionContribEntry.Section is 1-based.
308 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
309
310 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
311 const vaddr_end = vaddr_start + sect_contrib.Size;
312 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
313 break sect_contrib.ModuleIndex;
314 }
315 } else {
316 // we have no information to add to the address
317 if (tty_color) {
318 try out_stream.print("???:?:?: ");
319 setTtyColor(TtyColor.Dim);
320 try out_stream.print("0x{x} in ??? (???)", relocated_address);
321 setTtyColor(TtyColor.Reset);
322 try out_stream.print("\n\n\n");
323 } else {
324 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
325 }
326 return;
327 };
328
329 const mod = &di.modules[mod_index];
330 try populateModule(di, mod);
331 const obj_basename = os.path.basename(mod.obj_file_name);
332
333 var symbol_i: usize = 0;
334 const symbol_name = while (symbol_i != mod.symbols.len) {
335 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
336 if (prefix.RecordLen < 2)
337 return error.InvalidDebugInfo;
338 switch (prefix.RecordKind) {
339 pdb.SymbolKind.S_LPROC32 => {
340 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
341 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
342 const vaddr_end = vaddr_start + proc_sym.CodeSize;
343 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
344 break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
345 }
346 },
347 else => {},
348 }
349 symbol_i += prefix.RecordLen + @sizeOf(u16);
350 if (symbol_i > mod.symbols.len)
351 return error.InvalidDebugInfo;
352 } else "???";
353
354 const subsect_info = mod.subsect_info;
355
356 var sect_offset: usize = 0;
357 var skip_len: usize = undefined;
358 const opt_line_info = subsections: {
359 const checksum_offset = mod.checksum_offset orelse break :subsections null;
360 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
361 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
362 skip_len = subsect_hdr.Length;
363 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
364
365 switch (subsect_hdr.Kind) {
366 pdb.DebugSubsectionKind.Lines => {
367 var line_index = sect_offset;
368
369 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
370 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
371 line_index += @sizeOf(pdb.LineFragmentHeader);
372 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
373 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
374
375 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
376 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
377 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
378 const subsection_end_index = sect_offset + subsect_hdr.Length;
379 while (line_index < subsection_end_index) {
380 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
381 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
382 const start_line_index = line_index;
383
384 const has_column = line_hdr.Flags.LF_HaveColumns;
385
386 if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
387 // All line entries are stored inside their line block by ascending start address.
388 // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address.
389 // This is done with a simple linear search.
390 var line_i: u32 = 0;
391 while (line_i < block_hdr.NumLines) : (line_i += 1) {
392 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
393 line_index += @sizeOf(pdb.LineNumberEntry);
394
395 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
396 if (relative_address <= vaddr_start) {
397 break;
398 }
399 }
400
401 // line_i == 0 would mean that no matching LineNumberEntry was found.
402 if (line_i > 0) {
403 const subsect_index = checksum_offset + block_hdr.NameIndex;
404 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
405 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
406 try di.pdb.string_table.seekTo(strtab_offset);
407 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
408
409 const line_entry_idx = line_i - 1;
410
411 const column = if (has_column) blk: {
412 const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
413 const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
414 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
415 break :blk col_num_entry.StartColumn;
416 } else 0;
417
418 const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
419 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
420 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
421
422 break :subsections LineInfo{
423 .allocator = allocator,
424 .file_name = source_file_name,
425 .line = flags.Start,
426 .column = column,
427 };
428 }
429 }
430 }
431
432 // Checking that we are not reading garbage after the (possibly) multiple block fragments.
433 if (line_index != subsection_end_index) {
434 return error.InvalidDebugInfo;
435 }
436 },
437 else => {},
438 }
439
440 if (sect_offset > subsect_info.len)
441 return error.InvalidDebugInfo;
442 } else {
443 break :subsections null;
444 }
445 };
446
447 if (tty_color) {
448 setTtyColor(TtyColor.White);
449 if (opt_line_info) |li| {
450 try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
451 } else {
452 try out_stream.print("???:?:?");
453 }
454 setTtyColor(TtyColor.Reset);
455 try out_stream.print(": ");
456 setTtyColor(TtyColor.Dim);
457 try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
458 setTtyColor(TtyColor.Reset);
459
460 if (opt_line_info) |line_info| {
461 try out_stream.print("\n");
462 if (printLineFromFileAnyOs(out_stream, line_info)) {
463 if (line_info.column == 0) {
464 try out_stream.write("\n");
465 } else {
466 {
467 var col_i: usize = 1;
468 while (col_i < line_info.column) : (col_i += 1) {
469 try out_stream.writeByte(' ');
470 }
471 }
472 setTtyColor(TtyColor.Green);
473 try out_stream.write("^");
474 setTtyColor(TtyColor.Reset);
475 try out_stream.write("\n");
476 }
477 } else |err| switch (err) {
478 error.EndOfFile => {},
479 else => return err,
480 }
481 } else {
482 try out_stream.print("\n\n\n");
483 }
484 } else {
485 if (opt_line_info) |li| {
486 try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
487 } else {
488 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
489 }
490 }
491}
492
493const TtyColor = enum {
494 Red,
495 Green,
496 Cyan,
497 White,
498 Dim,
499 Bold,
500 Reset,
501};
502
503/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
504fn setTtyColor(tty_color: TtyColor) void {
505 if (os.supportsAnsiEscapeCodes(stderr_file.handle)) {
506 switch (tty_color) {
507 TtyColor.Red => {
508 stderr_file.write(RED) catch return;
509 },
510 TtyColor.Green => {
511 stderr_file.write(GREEN) catch return;
512 },
513 TtyColor.Cyan => {
514 stderr_file.write(CYAN) catch return;
515 },
516 TtyColor.White, TtyColor.Bold => {
517 stderr_file.write(WHITE) catch return;
518 },
519 TtyColor.Dim => {
520 stderr_file.write(DIM) catch return;
521 },
522 TtyColor.Reset => {
523 stderr_file.write(RESET) catch return;
524 },
525 }
526 } else {
527 const S = struct {
528 var attrs: windows.WORD = undefined;
529 var init_attrs = false;
530 };
531 if (!S.init_attrs) {
532 S.init_attrs = true;
533 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
534 // TODO handle error
535 _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
536 S.attrs = info.wAttributes;
537 }
538
539 // TODO handle errors
540 switch (tty_color) {
541 TtyColor.Red => {
542 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);
543 },
544 TtyColor.Green => {
545 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);
546 },
547 TtyColor.Cyan => {
548 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
549 },
550 TtyColor.White, TtyColor.Bold => {
551 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
552 },
553 TtyColor.Dim => {
554 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
555 },
556 TtyColor.Reset => {
557 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
558 },
559 }
560 }
561}
562
563fn populateModule(di: *DebugInfo, mod: *Module) !void {
564 if (mod.populated)
565 return;
566 const allocator = getDebugInfoAllocator();
567
568 if (mod.mod_info.C11ByteSize != 0)
569 return error.InvalidDebugInfo;
570
571 if (mod.mod_info.C13ByteSize == 0)
572 return error.MissingDebugInfo;
573
574 const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
575
576 const signature = try modi.stream.readIntLittle(u32);
577 if (signature != 4)
578 return error.InvalidDebugInfo;
579
580 mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
581 try modi.stream.readNoEof(mod.symbols);
582
583 mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
584 try modi.stream.readNoEof(mod.subsect_info);
585
586 var sect_offset: usize = 0;
587 var skip_len: usize = undefined;
588 while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
589 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
590 skip_len = subsect_hdr.Length;
591 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
592
593 switch (subsect_hdr.Kind) {
594 pdb.DebugSubsectionKind.FileChecksums => {
595 mod.checksum_offset = sect_offset;
596 break;
597 },
598 else => {},
599 }
600
601 if (sect_offset > mod.subsect_info.len)
602 return error.InvalidDebugInfo;
603 }
604
605 mod.populated = true;
606}
607
608fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
609 var min: usize = 0;
610 var max: usize = symbols.len - 1; // Exclude sentinel.
611 while (min < max) {
612 const mid = min + (max - min) / 2;
613 const curr = &symbols[mid];
614 const next = &symbols[mid + 1];
615 if (address >= next.address()) {
616 min = mid + 1;
617 } else if (address < curr.address()) {
618 max = mid;
619 } else {
620 return curr;
621 }
622 }
623 return null;
624}
625
626fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
627 const base_addr = std.os.getBaseAddress();
628 const adjusted_addr = 0x100000000 + (address - base_addr);
629
630 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
631 if (tty_color) {
632 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
633 } else {
634 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
635 }
636 return;
637 };
638
639 const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
640 const compile_unit_name = if (symbol.ofile) |ofile| blk: {
641 const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
642 break :blk os.path.basename(ofile_path);
643 } else "???";
644 if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
645 defer line_info.deinit();
646 try printLineInfo(
647 out_stream,
648 line_info,
649 address,
650 symbol_name,
651 compile_unit_name,
652 tty_color,
653 printLineFromFileAnyOs,
654 );
655 } else |err| switch (err) {
656 error.MissingDebugInfo, error.InvalidDebugInfo => {
657 if (tty_color) {
658 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n\n\n", address, symbol_name, compile_unit_name);
659 } else {
660 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", address, symbol_name, compile_unit_name);
661 }
662 },
663 else => return err,
664 }
665}
666
667/// This function works in freestanding mode.
668/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
669pub fn printSourceAtAddressDwarf(
670 debug_info: *DwarfInfo,
671 out_stream: var,
672 address: usize,
673 tty_color: bool,
674 comptime printLineFromFile: var,
675) !void {
676 const compile_unit = findCompileUnit(debug_info, address) catch {
677 if (tty_color) {
678 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
679 } else {
680 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
681 }
682 return;
683 };
684 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
685 if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
686 defer line_info.deinit();
687 const symbol_name = "???";
688 try printLineInfo(
689 out_stream,
690 line_info,
691 address,
692 symbol_name,
693 compile_unit_name,
694 tty_color,
695 printLineFromFile,
696 );
697 } else |err| switch (err) {
698 error.MissingDebugInfo, error.InvalidDebugInfo => {
699 if (tty_color) {
700 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
701 } else {
702 try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
703 }
704 },
705 else => return err,
706 }
707}
708
709pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
710 return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
711}
712
713fn printLineInfo(
714 out_stream: var,
715 line_info: LineInfo,
716 address: usize,
717 symbol_name: []const u8,
718 compile_unit_name: []const u8,
719 tty_color: bool,
720 comptime printLineFromFile: var,
721) !void {
722 if (tty_color) {
723 try out_stream.print(
724 WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n",
725 line_info.file_name,
726 line_info.line,
727 line_info.column,
728 address,
729 symbol_name,
730 compile_unit_name,
731 );
732 if (printLineFromFile(out_stream, line_info)) {
733 if (line_info.column == 0) {
734 try out_stream.write("\n");
735 } else {
736 {
737 var col_i: usize = 1;
738 while (col_i < line_info.column) : (col_i += 1) {
739 try out_stream.writeByte(' ');
740 }
741 }
742 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
743 }
744 } else |err| switch (err) {
745 error.EndOfFile => {},
746 else => return err,
747 }
748 } else {
749 try out_stream.print(
750 "{}:{}:{}: 0x{x} in {} ({})\n",
751 line_info.file_name,
752 line_info.line,
753 line_info.column,
754 address,
755 symbol_name,
756 compile_unit_name,
757 );
758 }
759}
760
761// TODO use this
762pub const OpenSelfDebugInfoError = error{
763 MissingDebugInfo,
764 OutOfMemory,
765 UnsupportedOperatingSystem,
766};
767
768pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
769 switch (builtin.os) {
770 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
771 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
772 builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
773 else => return error.UnsupportedOperatingSystem,
774 }
775}
776
777fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
778 const self_file = try os.openSelfExe();
779 defer self_file.close();
780
781 const coff_obj = try allocator.create(coff.Coff);
782 coff_obj.* = coff.Coff{
783 .in_file = self_file,
784 .allocator = allocator,
785 .coff_header = undefined,
786 .pe_header = undefined,
787 .sections = undefined,
788 .guid = undefined,
789 .age = undefined,
790 };
791
792 var di = DebugInfo{
793 .coff = coff_obj,
794 .pdb = undefined,
795 .sect_contribs = undefined,
796 .modules = undefined,
797 };
798
799 try di.coff.loadHeader();
800
801 var path_buf: [windows.MAX_PATH]u8 = undefined;
802 const len = try di.coff.getPdbPath(path_buf[0..]);
803 const raw_path = path_buf[0..len];
804
805 const path = try os.path.resolve(allocator, [][]const u8{raw_path});
806
807 try di.pdb.openFile(di.coff, path);
808
809 var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
810 const version = try pdb_stream.stream.readIntLittle(u32);
811 const signature = try pdb_stream.stream.readIntLittle(u32);
812 const age = try pdb_stream.stream.readIntLittle(u32);
813 var guid: [16]u8 = undefined;
814 try pdb_stream.stream.readNoEof(guid[0..]);
815 if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
816 return error.InvalidDebugInfo;
817 // We validated the executable and pdb match.
818
819 const string_table_index = str_tab_index: {
820 const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
821 const name_bytes = try allocator.alloc(u8, name_bytes_len);
822 try pdb_stream.stream.readNoEof(name_bytes);
823
824 const HashTableHeader = packed struct {
825 Size: u32,
826 Capacity: u32,
827
828 fn maxLoad(cap: u32) u32 {
829 return cap * 2 / 3 + 1;
830 }
831 };
832 const hash_tbl_hdr = try pdb_stream.stream.readStruct(HashTableHeader);
833 if (hash_tbl_hdr.Capacity == 0)
834 return error.InvalidDebugInfo;
835
836 if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
837 return error.InvalidDebugInfo;
838
839 const present = try readSparseBitVector(&pdb_stream.stream, allocator);
840 if (present.len != hash_tbl_hdr.Size)
841 return error.InvalidDebugInfo;
842 const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
843
844 const Bucket = struct {
845 first: u32,
846 second: u32,
847 };
848 const bucket_list = try allocator.alloc(Bucket, present.len);
849 for (present) |_| {
850 const name_offset = try pdb_stream.stream.readIntLittle(u32);
851 const name_index = try pdb_stream.stream.readIntLittle(u32);
852 const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
853 if (mem.eql(u8, name, "/names")) {
854 break :str_tab_index name_index;
855 }
856 }
857 return error.MissingDebugInfo;
858 };
859
860 di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
861 di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
862
863 const dbi = di.pdb.dbi;
864
865 // Dbi Header
866 const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
867 const mod_info_size = dbi_stream_header.ModInfoSize;
868 const section_contrib_size = dbi_stream_header.SectionContributionSize;
869
870 var modules = ArrayList(Module).init(allocator);
871
872 // Module Info Substream
873 var mod_info_offset: usize = 0;
874 while (mod_info_offset != mod_info_size) {
875 const mod_info = try dbi.stream.readStruct(pdb.ModInfo);
876 var this_record_len: usize = @sizeOf(pdb.ModInfo);
877
878 const module_name = try dbi.readNullTermString(allocator);
879 this_record_len += module_name.len + 1;
880
881 const obj_file_name = try dbi.readNullTermString(allocator);
882 this_record_len += obj_file_name.len + 1;
883
884 const march_forward_bytes = this_record_len % 4;
885 if (march_forward_bytes != 0) {
886 try dbi.seekForward(march_forward_bytes);
887 this_record_len += march_forward_bytes;
888 }
889
890 try modules.append(Module{
891 .mod_info = mod_info,
892 .module_name = module_name,
893 .obj_file_name = obj_file_name,
894
895 .populated = false,
896 .symbols = undefined,
897 .subsect_info = undefined,
898 .checksum_offset = null,
899 });
900
901 mod_info_offset += this_record_len;
902 if (mod_info_offset > mod_info_size)
903 return error.InvalidDebugInfo;
904 }
905
906 di.modules = modules.toOwnedSlice();
907
908 // Section Contribution Substream
909 var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
910 var sect_cont_offset: usize = 0;
911 if (section_contrib_size != 0) {
912 const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
913 if (ver != pdb.SectionContrSubstreamVersion.Ver60)
914 return error.InvalidDebugInfo;
915 sect_cont_offset += @sizeOf(u32);
916 }
917 while (sect_cont_offset != section_contrib_size) {
918 const entry = try sect_contribs.addOne();
919 entry.* = try dbi.stream.readStruct(pdb.SectionContribEntry);
920 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
921
922 if (sect_cont_offset > section_contrib_size)
923 return error.InvalidDebugInfo;
924 }
925
926 di.sect_contribs = sect_contribs.toOwnedSlice();
927
928 return di;
929}
930
931fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
932 const num_words = try stream.readIntLittle(u32);
933 var word_i: usize = 0;
934 var list = ArrayList(usize).init(allocator);
935 while (word_i != num_words) : (word_i += 1) {
936 const word = try stream.readIntLittle(u32);
937 var bit_i: u5 = 0;
938 while (true) : (bit_i += 1) {
939 if (word & (u32(1) << bit_i) != 0) {
940 try list.append(word_i * 32 + bit_i);
941 }
942 if (bit_i == maxInt(u5)) break;
943 }
944 }
945 return list.toOwnedSlice();
946}
947
948fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
949 const elf_header = (try elf_file.findSection(name)) orelse return null;
950 return DwarfInfo.Section{
951 .offset = elf_header.offset,
952 .size = elf_header.size,
953 };
954}
955
956/// Initialize DWARF info. The caller has the responsibility to initialize most
957/// the DwarfInfo fields before calling. These fields can be left undefined:
958/// * abbrev_table_list
959/// * compile_unit_list
960pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
961 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
962 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
963 try scanAllCompileUnits(di);
964}
965
966pub fn openElfDebugInfo(
967 allocator: *mem.Allocator,
968 elf_seekable_stream: *DwarfSeekableStream,
969 elf_in_stream: *DwarfInStream,
970) !DwarfInfo {
971 var efile: elf.Elf = undefined;
972 try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
973 errdefer efile.close();
974
975 var di = DwarfInfo{
976 .dwarf_seekable_stream = elf_seekable_stream,
977 .dwarf_in_stream = elf_in_stream,
978 .endian = efile.endian,
979 .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
980 .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
981 .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
982 .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
983 .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
984 .abbrev_table_list = undefined,
985 .compile_unit_list = undefined,
986 };
987 try openDwarfDebugInfo(&di, allocator);
988 return di;
989}
990
991fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
992 const S = struct {
993 var self_exe_file: os.File = undefined;
994 var self_exe_seekable_stream: os.File.SeekableStream = undefined;
995 var self_exe_in_stream: os.File.InStream = undefined;
996 };
997 S.self_exe_file = try os.openSelfExe();
998 errdefer S.self_exe_file.close();
999
1000 S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
1001 S.self_exe_in_stream = S.self_exe_file.inStream();
1002
1003 return openElfDebugInfo(
1004 allocator,
1005 // TODO https://github.com/ziglang/zig/issues/764
1006 @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
1007 // TODO https://github.com/ziglang/zig/issues/764
1008 @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
1009 );
1010}
1011
1012fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1013 const hdr = &std.c._mh_execute_header;
1014 assert(hdr.magic == std.macho.MH_MAGIC_64);
1015
1016 const hdr_base = @ptrCast([*]u8, hdr);
1017 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1018 var ncmd: u32 = hdr.ncmds;
1019 const symtab = while (ncmd != 0) : (ncmd -= 1) {
1020 const lc = @ptrCast(*std.macho.load_command, ptr);
1021 switch (lc.cmd) {
1022 std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr),
1023 else => {},
1024 }
1025 ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
1026 } else {
1027 return error.MissingDebugInfo;
1028 };
1029 const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
1030 const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize];
1031
1032 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
1033
1034 var ofile: ?*macho.nlist_64 = null;
1035 var reloc: u64 = 0;
1036 var symbol_index: usize = 0;
1037 var last_len: u64 = 0;
1038 for (syms) |*sym| {
1039 if (sym.n_type & std.macho.N_STAB != 0) {
1040 switch (sym.n_type) {
1041 std.macho.N_OSO => {
1042 ofile = sym;
1043 reloc = 0;
1044 },
1045 std.macho.N_FUN => {
1046 if (sym.n_sect == 0) {
1047 last_len = sym.n_value;
1048 } else {
1049 symbols_buf[symbol_index] = MachoSymbol{
1050 .nlist = sym,
1051 .ofile = ofile,
1052 .reloc = reloc,
1053 };
1054 symbol_index += 1;
1055 }
1056 },
1057 std.macho.N_BNSYM => {
1058 if (reloc == 0) {
1059 reloc = sym.n_value;
1060 }
1061 },
1062 else => continue,
1063 }
1064 }
1065 }
1066 const sentinel = try allocator.create(macho.nlist_64);
1067 sentinel.* = macho.nlist_64{
1068 .n_strx = 0,
1069 .n_type = 36,
1070 .n_sect = 0,
1071 .n_desc = 0,
1072 .n_value = symbols_buf[symbol_index - 1].nlist.n_value + last_len,
1073 };
1074
1075 const symbols = allocator.shrink(MachoSymbol, symbols_buf, symbol_index);
1076
1077 // Even though lld emits symbols in ascending order, this debug code
1078 // should work for programs linked in any valid way.
1079 // This sort is so that we can binary search later.
1080 std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
1081
1082 return DebugInfo{
1083 .ofiles = DebugInfo.OFileTable.init(allocator),
1084 .symbols = symbols,
1085 .strings = strings,
1086 };
1087}
1088
1089fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
1090 var f = try os.File.openRead(line_info.file_name);
1091 defer f.close();
1092 // TODO fstat and make sure that the file has the correct size
1093
1094 var buf: [os.page_size]u8 = undefined;
1095 var line: usize = 1;
1096 var column: usize = 1;
1097 var abs_index: usize = 0;
1098 while (true) {
1099 const amt_read = try f.read(buf[0..]);
1100 const slice = buf[0..amt_read];
1101
1102 for (slice) |byte| {
1103 if (line == line_info.line) {
1104 try out_stream.writeByte(byte);
1105 if (byte == '\n') {
1106 return;
1107 }
1108 }
1109 if (byte == '\n') {
1110 line += 1;
1111 column = 1;
1112 } else {
1113 column += 1;
1114 }
1115 }
1116
1117 if (amt_read < buf.len) return error.EndOfFile;
1118 }
1119}
1120
1121const MachoSymbol = struct {
1122 nlist: *macho.nlist_64,
1123 ofile: ?*macho.nlist_64,
1124 reloc: u64,
1125
1126 /// Returns the address from the macho file
1127 fn address(self: MachoSymbol) u64 {
1128 return self.nlist.n_value;
1129 }
1130
1131 fn addressLessThan(lhs: MachoSymbol, rhs: MachoSymbol) bool {
1132 return lhs.address() < rhs.address();
1133 }
1134};
1135
1136const MachOFile = struct {
1137 bytes: []align(@alignOf(macho.mach_header_64)) const u8,
1138 sect_debug_info: ?*const macho.section_64,
1139 sect_debug_line: ?*const macho.section_64,
1140};
1141
1142pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
1143pub const DwarfInStream = io.InStream(anyerror);
1144
1145pub const DwarfInfo = struct {
1146 dwarf_seekable_stream: *DwarfSeekableStream,
1147 dwarf_in_stream: *DwarfInStream,
1148 endian: builtin.Endian,
1149 debug_info: Section,
1150 debug_abbrev: Section,
1151 debug_str: Section,
1152 debug_line: Section,
1153 debug_ranges: ?Section,
1154 abbrev_table_list: ArrayList(AbbrevTableHeader),
1155 compile_unit_list: ArrayList(CompileUnit),
1156
1157 pub const Section = struct {
1158 offset: usize,
1159 size: usize,
1160 };
1161
1162 pub fn allocator(self: DwarfInfo) *mem.Allocator {
1163 return self.abbrev_table_list.allocator;
1164 }
1165
1166 pub fn readString(self: *DwarfInfo) ![]u8 {
1167 return readStringRaw(self.allocator(), self.dwarf_in_stream);
1168 }
1169};
1170
1171pub const DebugInfo = switch (builtin.os) {
1172 builtin.Os.macosx => struct {
1173 symbols: []const MachoSymbol,
1174 strings: []const u8,
1175 ofiles: OFileTable,
1176
1177 const OFileTable = std.HashMap(
1178 *macho.nlist_64,
1179 MachOFile,
1180 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
1181 std.hash_map.getTrivialEqlFn(*macho.nlist_64),
1182 );
1183
1184 pub fn allocator(self: DebugInfo) *mem.Allocator {
1185 return self.ofiles.allocator;
1186 }
1187 },
1188 builtin.Os.uefi, builtin.Os.windows => struct {
1189 pdb: pdb.Pdb,
1190 coff: *coff.Coff,
1191 sect_contribs: []pdb.SectionContribEntry,
1192 modules: []Module,
1193 },
1194 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
1195 else => @compileError("Unsupported OS"),
1196};
1197
1198const PcRange = struct {
1199 start: u64,
1200 end: u64,
1201};
1202
1203const CompileUnit = struct {
1204 version: u16,
1205 is_64: bool,
1206 die: *Die,
1207 index: usize,
1208 pc_range: ?PcRange,
1209};
1210
1211const AbbrevTable = ArrayList(AbbrevTableEntry);
1212
1213const AbbrevTableHeader = struct {
1214 // offset from .debug_abbrev
1215 offset: u64,
1216 table: AbbrevTable,
1217};
1218
1219const AbbrevTableEntry = struct {
1220 has_children: bool,
1221 abbrev_code: u64,
1222 tag_id: u64,
1223 attrs: ArrayList(AbbrevAttr),
1224};
1225
1226const AbbrevAttr = struct {
1227 attr_id: u64,
1228 form_id: u64,
1229};
1230
1231const FormValue = union(enum) {
1232 Address: u64,
1233 Block: []u8,
1234 Const: Constant,
1235 ExprLoc: []u8,
1236 Flag: bool,
1237 SecOffset: u64,
1238 Ref: []u8,
1239 RefAddr: u64,
1240 RefSig8: u64,
1241 String: []u8,
1242 StrPtr: u64,
1243};
1244
1245const Constant = struct {
1246 payload: []u8,
1247 signed: bool,
1248
1249 fn asUnsignedLe(self: *const Constant) !u64 {
1250 if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
1251 if (self.signed) return error.InvalidDebugInfo;
1252 return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
1253 }
1254};
1255
1256const Die = struct {
1257 tag_id: u64,
1258 has_children: bool,
1259 attrs: ArrayList(Attr),
1260
1261 const Attr = struct {
1262 id: u64,
1263 value: FormValue,
1264 };
1265
1266 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
1267 for (self.attrs.toSliceConst()) |*attr| {
1268 if (attr.id == id) return &attr.value;
1269 }
1270 return null;
1271 }
1272
1273 fn getAttrAddr(self: *const Die, id: u64) !u64 {
1274 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1275 return switch (form_value.*) {
1276 FormValue.Address => |value| value,
1277 else => error.InvalidDebugInfo,
1278 };
1279 }
1280
1281 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
1282 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1283 return switch (form_value.*) {
1284 FormValue.Const => |value| value.asUnsignedLe(),
1285 FormValue.SecOffset => |value| value,
1286 else => error.InvalidDebugInfo,
1287 };
1288 }
1289
1290 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
1291 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1292 return switch (form_value.*) {
1293 FormValue.Const => |value| value.asUnsignedLe(),
1294 else => error.InvalidDebugInfo,
1295 };
1296 }
1297
1298 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
1299 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1300 return switch (form_value.*) {
1301 FormValue.String => |value| value,
1302 FormValue.StrPtr => |offset| getString(di, offset),
1303 else => error.InvalidDebugInfo,
1304 };
1305 }
1306};
1307
1308const FileEntry = struct {
1309 file_name: []const u8,
1310 dir_index: usize,
1311 mtime: usize,
1312 len_bytes: usize,
1313};
1314
1315pub const LineInfo = struct {
1316 line: usize,
1317 column: usize,
1318 file_name: []const u8,
1319 allocator: ?*mem.Allocator,
1320
1321 fn deinit(self: LineInfo) void {
1322 const allocator = self.allocator orelse return;
1323 allocator.free(self.file_name);
1324 }
1325};
1326
1327const LineNumberProgram = struct {
1328 address: usize,
1329 file: usize,
1330 line: isize,
1331 column: usize,
1332 is_stmt: bool,
1333 basic_block: bool,
1334 end_sequence: bool,
1335
1336 target_address: usize,
1337 include_dirs: []const []const u8,
1338 file_entries: *ArrayList(FileEntry),
1339
1340 prev_address: usize,
1341 prev_file: usize,
1342 prev_line: isize,
1343 prev_column: usize,
1344 prev_is_stmt: bool,
1345 prev_basic_block: bool,
1346 prev_end_sequence: bool,
1347
1348 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
1349 return LineNumberProgram{
1350 .address = 0,
1351 .file = 1,
1352 .line = 1,
1353 .column = 0,
1354 .is_stmt = is_stmt,
1355 .basic_block = false,
1356 .end_sequence = false,
1357 .include_dirs = include_dirs,
1358 .file_entries = file_entries,
1359 .target_address = target_address,
1360 .prev_address = 0,
1361 .prev_file = undefined,
1362 .prev_line = undefined,
1363 .prev_column = undefined,
1364 .prev_is_stmt = undefined,
1365 .prev_basic_block = undefined,
1366 .prev_end_sequence = undefined,
1367 };
1368 }
1369
1370 pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {
1371 if (self.target_address >= self.prev_address and self.target_address < self.address) {
1372 const file_entry = if (self.prev_file == 0) {
1373 return error.MissingDebugInfo;
1374 } else if (self.prev_file - 1 >= self.file_entries.len) {
1375 return error.InvalidDebugInfo;
1376 } else
1377 &self.file_entries.items[self.prev_file - 1];
1378
1379 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
1380 return error.InvalidDebugInfo;
1381 } else
1382 self.include_dirs[file_entry.dir_index];
1383 const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
1384 errdefer self.file_entries.allocator.free(file_name);
1385 return LineInfo{
1386 .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
1387 .column = self.prev_column,
1388 .file_name = file_name,
1389 .allocator = self.file_entries.allocator,
1390 };
1391 }
1392
1393 self.prev_address = self.address;
1394 self.prev_file = self.file;
1395 self.prev_line = self.line;
1396 self.prev_column = self.column;
1397 self.prev_is_stmt = self.is_stmt;
1398 self.prev_basic_block = self.basic_block;
1399 self.prev_end_sequence = self.end_sequence;
1400 return null;
1401 }
1402};
1403
1404fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
1405 var buf = ArrayList(u8).init(allocator);
1406 while (true) {
1407 const byte = try in_stream.readByte();
1408 if (byte == 0) break;
1409 try buf.append(byte);
1410 }
1411 return buf.toSlice();
1412}
1413
1414fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
1415 const pos = di.debug_str.offset + offset;
1416 try di.dwarf_seekable_stream.seekTo(pos);
1417 return di.readString();
1418}
1419
1420fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
1421 const buf = try allocator.alloc(u8, size);
1422 errdefer allocator.free(buf);
1423 if ((try in_stream.read(buf)) < size) return error.EndOfFile;
1424 return buf;
1425}
1426
1427fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1428 const buf = try readAllocBytes(allocator, in_stream, size);
1429 return FormValue{ .Block = buf };
1430}
1431
1432fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1433 const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
1434 return parseFormValueBlockLen(allocator, in_stream, block_len);
1435}
1436
1437fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
1438 return FormValue{
1439 .Const = Constant{
1440 .signed = signed,
1441 .payload = try readAllocBytes(allocator, in_stream, size),
1442 },
1443 };
1444}
1445
1446fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
1447 return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
1448}
1449
1450fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
1451 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
1452}
1453
1454fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1455 const buf = try readAllocBytes(allocator, in_stream, size);
1456 return FormValue{ .Ref = buf };
1457}
1458
1459fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
1460 const block_len = try in_stream.readIntLittle(T);
1461 return parseFormValueRefLen(allocator, in_stream, block_len);
1462}
1463
1464fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
1465 return switch (form_id) {
1466 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
1467 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
1468 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
1469 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
1470 DW.FORM_block => x: {
1471 const block_len = try readULeb128(in_stream);
1472 return parseFormValueBlockLen(allocator, in_stream, block_len);
1473 },
1474 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
1475 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
1476 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
1477 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
1478 DW.FORM_udata, DW.FORM_sdata => {
1479 const block_len = try readULeb128(in_stream);
1480 const signed = form_id == DW.FORM_sdata;
1481 return parseFormValueConstant(allocator, in_stream, signed, block_len);
1482 },
1483 DW.FORM_exprloc => {
1484 const size = try readULeb128(in_stream);
1485 const buf = try readAllocBytes(allocator, in_stream, size);
1486 return FormValue{ .ExprLoc = buf };
1487 },
1488 DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
1489 DW.FORM_flag_present => FormValue{ .Flag = true },
1490 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1491
1492 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
1493 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
1494 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
1495 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
1496 DW.FORM_ref_udata => {
1497 const ref_len = try readULeb128(in_stream);
1498 return parseFormValueRefLen(allocator, in_stream, ref_len);
1499 },
1500
1501 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1502 DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
1503
1504 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
1505 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1506 DW.FORM_indirect => {
1507 const child_form_id = try readULeb128(in_stream);
1508 return parseFormValue(allocator, in_stream, child_form_id, is_64);
1509 },
1510 else => error.InvalidDebugInfo,
1511 };
1512}
1513
1514fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
1515 var result = AbbrevTable.init(di.allocator());
1516 while (true) {
1517 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1518 if (abbrev_code == 0) return result;
1519 try result.append(AbbrevTableEntry{
1520 .abbrev_code = abbrev_code,
1521 .tag_id = try readULeb128(di.dwarf_in_stream),
1522 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
1523 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1524 });
1525 const attrs = &result.items[result.len - 1].attrs;
1526
1527 while (true) {
1528 const attr_id = try readULeb128(di.dwarf_in_stream);
1529 const form_id = try readULeb128(di.dwarf_in_stream);
1530 if (attr_id == 0 and form_id == 0) break;
1531 try attrs.append(AbbrevAttr{
1532 .attr_id = attr_id,
1533 .form_id = form_id,
1534 });
1535 }
1536 }
1537}
1538
1539/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
1540/// seeks in the stream and parses it.
1541fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
1542 for (di.abbrev_table_list.toSlice()) |*header| {
1543 if (header.offset == abbrev_offset) {
1544 return &header.table;
1545 }
1546 }
1547 try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
1548 try di.abbrev_table_list.append(AbbrevTableHeader{
1549 .offset = abbrev_offset,
1550 .table = try parseAbbrevTable(di),
1551 });
1552 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
1553}
1554
1555fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
1556 for (abbrev_table.toSliceConst()) |*table_entry| {
1557 if (table_entry.abbrev_code == abbrev_code) return table_entry;
1558 }
1559 return null;
1560}
1561
1562fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
1563 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1564 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1565
1566 var result = Die{
1567 .tag_id = table_entry.tag_id,
1568 .has_children = table_entry.has_children,
1569 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1570 };
1571 try result.attrs.resize(table_entry.attrs.len);
1572 for (table_entry.attrs.toSliceConst()) |attr, i| {
1573 result.attrs.items[i] = Die.Attr{
1574 .id = attr.attr_id,
1575 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
1576 };
1577 }
1578 return result;
1579}
1580
1581fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
1582 const ofile = symbol.ofile orelse return error.MissingDebugInfo;
1583 const gop = try di.ofiles.getOrPut(ofile);
1584 const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: {
1585 errdefer _ = di.ofiles.remove(ofile);
1586 const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
1587
1588 gop.kv.value = MachOFile{
1589 .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(macho.mach_header_64)),
1590 .sect_debug_info = null,
1591 .sect_debug_line = null,
1592 };
1593 const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr);
1594 if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;
1595
1596 const hdr_base = @ptrCast([*]const u8, hdr);
1597 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1598 var ncmd: u32 = hdr.ncmds;
1599 const segcmd = while (ncmd != 0) : (ncmd -= 1) {
1600 const lc = @ptrCast(*const std.macho.load_command, ptr);
1601 switch (lc.cmd) {
1602 std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)),
1603 else => {},
1604 }
1605 ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
1606 } else {
1607 return error.MissingDebugInfo;
1608 };
1609 const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
1610 for (sections) |*sect| {
1611 if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
1612 (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
1613 {
1614 const sect_name = mem.toSliceConst(u8, &sect.sectname);
1615 if (mem.eql(u8, sect_name, "__debug_line")) {
1616 gop.kv.value.sect_debug_line = sect;
1617 } else if (mem.eql(u8, sect_name, "__debug_info")) {
1618 gop.kv.value.sect_debug_info = sect;
1619 }
1620 }
1621 }
1622
1623 break :blk &gop.kv.value;
1624 };
1625
1626 const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo;
1627 var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset;
1628
1629 var is_64: bool = undefined;
1630 const unit_length = try readInitialLengthMem(&ptr, &is_64);
1631 if (unit_length == 0) return error.MissingDebugInfo;
1632
1633 const version = readIntMem(&ptr, u16, builtin.Endian.Little);
1634 // TODO support 3 and 5
1635 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1636
1637 const prologue_length = if (is_64)
1638 readIntMem(&ptr, u64, builtin.Endian.Little)
1639 else
1640 readIntMem(&ptr, u32, builtin.Endian.Little);
1641 const prog_start = ptr + prologue_length;
1642
1643 const minimum_instruction_length = readByteMem(&ptr);
1644 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1645
1646 if (version >= 4) {
1647 // maximum_operations_per_instruction
1648 ptr += 1;
1649 }
1650
1651 const default_is_stmt = readByteMem(&ptr) != 0;
1652 const line_base = readByteSignedMem(&ptr);
1653
1654 const line_range = readByteMem(&ptr);
1655 if (line_range == 0) return error.InvalidDebugInfo;
1656
1657 const opcode_base = readByteMem(&ptr);
1658
1659 const standard_opcode_lengths = ptr[0 .. opcode_base - 1];
1660 ptr += opcode_base - 1;
1661
1662 var include_directories = ArrayList([]const u8).init(di.allocator());
1663 try include_directories.append("");
1664 while (true) {
1665 const dir = readStringMem(&ptr);
1666 if (dir.len == 0) break;
1667 try include_directories.append(dir);
1668 }
1669
1670 var file_entries = ArrayList(FileEntry).init(di.allocator());
1671 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1672
1673 while (true) {
1674 const file_name = readStringMem(&ptr);
1675 if (file_name.len == 0) break;
1676 const dir_index = try readULeb128Mem(&ptr);
1677 const mtime = try readULeb128Mem(&ptr);
1678 const len_bytes = try readULeb128Mem(&ptr);
1679 try file_entries.append(FileEntry{
1680 .file_name = file_name,
1681 .dir_index = dir_index,
1682 .mtime = mtime,
1683 .len_bytes = len_bytes,
1684 });
1685 }
1686
1687 ptr = prog_start;
1688 while (true) {
1689 const opcode = readByteMem(&ptr);
1690
1691 if (opcode == DW.LNS_extended_op) {
1692 const op_size = try readULeb128Mem(&ptr);
1693 if (op_size < 1) return error.InvalidDebugInfo;
1694 var sub_op = readByteMem(&ptr);
1695 switch (sub_op) {
1696 DW.LNE_end_sequence => {
1697 prog.end_sequence = true;
1698 if (try prog.checkLineMatch()) |info| return info;
1699 return error.MissingDebugInfo;
1700 },
1701 DW.LNE_set_address => {
1702 const addr = readIntMem(&ptr, usize, builtin.Endian.Little);
1703 prog.address = symbol.reloc + addr;
1704 },
1705 DW.LNE_define_file => {
1706 const file_name = readStringMem(&ptr);
1707 const dir_index = try readULeb128Mem(&ptr);
1708 const mtime = try readULeb128Mem(&ptr);
1709 const len_bytes = try readULeb128Mem(&ptr);
1710 try file_entries.append(FileEntry{
1711 .file_name = file_name,
1712 .dir_index = dir_index,
1713 .mtime = mtime,
1714 .len_bytes = len_bytes,
1715 });
1716 },
1717 else => {
1718 ptr += op_size - 1;
1719 },
1720 }
1721 } else if (opcode >= opcode_base) {
1722 // special opcodes
1723 const adjusted_opcode = opcode - opcode_base;
1724 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1725 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
1726 prog.line += inc_line;
1727 prog.address += inc_addr;
1728 if (try prog.checkLineMatch()) |info| return info;
1729 prog.basic_block = false;
1730 } else {
1731 switch (opcode) {
1732 DW.LNS_copy => {
1733 if (try prog.checkLineMatch()) |info| return info;
1734 prog.basic_block = false;
1735 },
1736 DW.LNS_advance_pc => {
1737 const arg = try readULeb128Mem(&ptr);
1738 prog.address += arg * minimum_instruction_length;
1739 },
1740 DW.LNS_advance_line => {
1741 const arg = try readILeb128Mem(&ptr);
1742 prog.line += arg;
1743 },
1744 DW.LNS_set_file => {
1745 const arg = try readULeb128Mem(&ptr);
1746 prog.file = arg;
1747 },
1748 DW.LNS_set_column => {
1749 const arg = try readULeb128Mem(&ptr);
1750 prog.column = arg;
1751 },
1752 DW.LNS_negate_stmt => {
1753 prog.is_stmt = !prog.is_stmt;
1754 },
1755 DW.LNS_set_basic_block => {
1756 prog.basic_block = true;
1757 },
1758 DW.LNS_const_add_pc => {
1759 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1760 prog.address += inc_addr;
1761 },
1762 DW.LNS_fixed_advance_pc => {
1763 const arg = readIntMem(&ptr, u16, builtin.Endian.Little);
1764 prog.address += arg;
1765 },
1766 DW.LNS_set_prologue_end => {},
1767 else => {
1768 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1769 const len_bytes = standard_opcode_lengths[opcode - 1];
1770 ptr += len_bytes;
1771 },
1772 }
1773 }
1774 }
1775
1776 return error.MissingDebugInfo;
1777}
1778
1779fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
1780 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
1781
1782 const debug_line_end = di.debug_line.offset + di.debug_line.size;
1783 var this_offset = di.debug_line.offset;
1784 var this_index: usize = 0;
1785
1786 while (this_offset < debug_line_end) : (this_index += 1) {
1787 try di.dwarf_seekable_stream.seekTo(this_offset);
1788
1789 var is_64: bool = undefined;
1790 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1791 if (unit_length == 0) return error.MissingDebugInfo;
1792 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
1793
1794 if (compile_unit.index != this_index) {
1795 this_offset += next_offset;
1796 continue;
1797 }
1798
1799 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1800 // TODO support 3 and 5
1801 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1802
1803 const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
1804 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
1805
1806 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
1807 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1808
1809 if (version >= 4) {
1810 // maximum_operations_per_instruction
1811 _ = try di.dwarf_in_stream.readByte();
1812 }
1813
1814 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1815 const line_base = try di.dwarf_in_stream.readByteSigned();
1816
1817 const line_range = try di.dwarf_in_stream.readByte();
1818 if (line_range == 0) return error.InvalidDebugInfo;
1819
1820 const opcode_base = try di.dwarf_in_stream.readByte();
1821
1822 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
1823
1824 {
1825 var i: usize = 0;
1826 while (i < opcode_base - 1) : (i += 1) {
1827 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
1828 }
1829 }
1830
1831 var include_directories = ArrayList([]u8).init(di.allocator());
1832 try include_directories.append(compile_unit_cwd);
1833 while (true) {
1834 const dir = try di.readString();
1835 if (dir.len == 0) break;
1836 try include_directories.append(dir);
1837 }
1838
1839 var file_entries = ArrayList(FileEntry).init(di.allocator());
1840 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1841
1842 while (true) {
1843 const file_name = try di.readString();
1844 if (file_name.len == 0) break;
1845 const dir_index = try readULeb128(di.dwarf_in_stream);
1846 const mtime = try readULeb128(di.dwarf_in_stream);
1847 const len_bytes = try readULeb128(di.dwarf_in_stream);
1848 try file_entries.append(FileEntry{
1849 .file_name = file_name,
1850 .dir_index = dir_index,
1851 .mtime = mtime,
1852 .len_bytes = len_bytes,
1853 });
1854 }
1855
1856 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
1857
1858 while (true) {
1859 const opcode = try di.dwarf_in_stream.readByte();
1860
1861 if (opcode == DW.LNS_extended_op) {
1862 const op_size = try readULeb128(di.dwarf_in_stream);
1863 if (op_size < 1) return error.InvalidDebugInfo;
1864 var sub_op = try di.dwarf_in_stream.readByte();
1865 switch (sub_op) {
1866 DW.LNE_end_sequence => {
1867 prog.end_sequence = true;
1868 if (try prog.checkLineMatch()) |info| return info;
1869 return error.MissingDebugInfo;
1870 },
1871 DW.LNE_set_address => {
1872 const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
1873 prog.address = addr;
1874 },
1875 DW.LNE_define_file => {
1876 const file_name = try di.readString();
1877 const dir_index = try readULeb128(di.dwarf_in_stream);
1878 const mtime = try readULeb128(di.dwarf_in_stream);
1879 const len_bytes = try readULeb128(di.dwarf_in_stream);
1880 try file_entries.append(FileEntry{
1881 .file_name = file_name,
1882 .dir_index = dir_index,
1883 .mtime = mtime,
1884 .len_bytes = len_bytes,
1885 });
1886 },
1887 else => {
1888 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1889 try di.dwarf_seekable_stream.seekForward(fwd_amt);
1890 },
1891 }
1892 } else if (opcode >= opcode_base) {
1893 // special opcodes
1894 const adjusted_opcode = opcode - opcode_base;
1895 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1896 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
1897 prog.line += inc_line;
1898 prog.address += inc_addr;
1899 if (try prog.checkLineMatch()) |info| return info;
1900 prog.basic_block = false;
1901 } else {
1902 switch (opcode) {
1903 DW.LNS_copy => {
1904 if (try prog.checkLineMatch()) |info| return info;
1905 prog.basic_block = false;
1906 },
1907 DW.LNS_advance_pc => {
1908 const arg = try readULeb128(di.dwarf_in_stream);
1909 prog.address += arg * minimum_instruction_length;
1910 },
1911 DW.LNS_advance_line => {
1912 const arg = try readILeb128(di.dwarf_in_stream);
1913 prog.line += arg;
1914 },
1915 DW.LNS_set_file => {
1916 const arg = try readULeb128(di.dwarf_in_stream);
1917 prog.file = arg;
1918 },
1919 DW.LNS_set_column => {
1920 const arg = try readULeb128(di.dwarf_in_stream);
1921 prog.column = arg;
1922 },
1923 DW.LNS_negate_stmt => {
1924 prog.is_stmt = !prog.is_stmt;
1925 },
1926 DW.LNS_set_basic_block => {
1927 prog.basic_block = true;
1928 },
1929 DW.LNS_const_add_pc => {
1930 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1931 prog.address += inc_addr;
1932 },
1933 DW.LNS_fixed_advance_pc => {
1934 const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
1935 prog.address += arg;
1936 },
1937 DW.LNS_set_prologue_end => {},
1938 else => {
1939 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1940 const len_bytes = standard_opcode_lengths[opcode - 1];
1941 try di.dwarf_seekable_stream.seekForward(len_bytes);
1942 },
1943 }
1944 }
1945 }
1946
1947 this_offset += next_offset;
1948 }
1949
1950 return error.MissingDebugInfo;
1951}
1952
1953fn scanAllCompileUnits(di: *DwarfInfo) !void {
1954 const debug_info_end = di.debug_info.offset + di.debug_info.size;
1955 var this_unit_offset = di.debug_info.offset;
1956 var cu_index: usize = 0;
1957
1958 while (this_unit_offset < debug_info_end) {
1959 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
1960
1961 var is_64: bool = undefined;
1962 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1963 if (unit_length == 0) return;
1964 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
1965
1966 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1967 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1968
1969 const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
1970
1971 const address_size = try di.dwarf_in_stream.readByte();
1972 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1973
1974 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
1975 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
1976
1977 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
1978
1979 const compile_unit_die = try di.allocator().create(Die);
1980 compile_unit_die.* = try parseDie(di, abbrev_table, is_64);
1981
1982 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
1983
1984 const pc_range = x: {
1985 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1986 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
1987 const pc_end = switch (high_pc_value.*) {
1988 FormValue.Address => |value| value,
1989 FormValue.Const => |value| b: {
1990 const offset = try value.asUnsignedLe();
1991 break :b (low_pc + offset);
1992 },
1993 else => return error.InvalidDebugInfo,
1994 };
1995 break :x PcRange{
1996 .start = low_pc,
1997 .end = pc_end,
1998 };
1999 } else {
2000 break :x null;
2001 }
2002 } else |err| {
2003 if (err != error.MissingDebugInfo) return err;
2004 break :x null;
2005 }
2006 };
2007
2008 try di.compile_unit_list.append(CompileUnit{
2009 .version = version,
2010 .is_64 = is_64,
2011 .pc_range = pc_range,
2012 .die = compile_unit_die,
2013 .index = cu_index,
2014 });
2015
2016 this_unit_offset += next_offset;
2017 cu_index += 1;
2018 }
2019}
2020
2021fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
2022 for (di.compile_unit_list.toSlice()) |*compile_unit| {
2023 if (compile_unit.pc_range) |range| {
2024 if (target_address >= range.start and target_address < range.end) return compile_unit;
2025 }
2026 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
2027 var base_address: usize = 0;
2028 if (di.debug_ranges) |debug_ranges| {
2029 try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
2030 while (true) {
2031 const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
2032 const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
2033 if (begin_addr == 0 and end_addr == 0) {
2034 break;
2035 }
2036 if (begin_addr == maxInt(usize)) {
2037 base_address = begin_addr;
2038 continue;
2039 }
2040 if (target_address >= begin_addr and target_address < end_addr) {
2041 return compile_unit;
2042 }
2043 }
2044 }
2045 } else |err| {
2046 if (err != error.MissingDebugInfo) return err;
2047 continue;
2048 }
2049 }
2050 return error.MissingDebugInfo;
2051}
2052
2053fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
2054 // TODO https://github.com/ziglang/zig/issues/863
2055 const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
2056 ptr.* += @sizeOf(T);
2057 return result;
2058}
2059
2060fn readByteMem(ptr: *[*]const u8) u8 {
2061 const result = ptr.*[0];
2062 ptr.* += 1;
2063 return result;
2064}
2065
2066fn readByteSignedMem(ptr: *[*]const u8) i8 {
2067 return @bitCast(i8, readByteMem(ptr));
2068}
2069
2070fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
2071 // TODO this code can be improved with https://github.com/ziglang/zig/issues/863
2072 const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
2073 is_64.* = (first_32_bits == 0xffffffff);
2074 if (is_64.*) {
2075 ptr.* += 4;
2076 const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
2077 ptr.* += 8;
2078 return result;
2079 } else {
2080 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
2081 ptr.* += 4;
2082 return u64(first_32_bits);
2083 }
2084}
2085
2086fn readStringMem(ptr: *[*]const u8) []const u8 {
2087 const result = mem.toSliceConst(u8, ptr.*);
2088 ptr.* += result.len + 1;
2089 return result;
2090}
2091
2092fn readULeb128Mem(ptr: *[*]const u8) !u64 {
2093 var result: u64 = 0;
2094 var shift: usize = 0;
2095 var i: usize = 0;
2096
2097 while (true) {
2098 const byte = ptr.*[i];
2099 i += 1;
2100
2101 var operand: u64 = undefined;
2102
2103 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2104
2105 result |= operand;
2106
2107 if ((byte & 0b10000000) == 0) {
2108 ptr.* += i;
2109 return result;
2110 }
2111
2112 shift += 7;
2113 }
2114}
2115fn readILeb128Mem(ptr: *[*]const u8) !i64 {
2116 var result: i64 = 0;
2117 var shift: usize = 0;
2118 var i: usize = 0;
2119
2120 while (true) {
2121 const byte = ptr.*[i];
2122 i += 1;
2123
2124 var operand: i64 = undefined;
2125 if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2126
2127 result |= operand;
2128 shift += 7;
2129
2130 if ((byte & 0b10000000) == 0) {
2131 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
2132 ptr.* += i;
2133 return result;
2134 }
2135 }
2136}
2137
2138fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
2139 const first_32_bits = try in_stream.readIntLittle(u32);
2140 is_64.* = (first_32_bits == 0xffffffff);
2141 if (is_64.*) {
2142 return in_stream.readIntLittle(u64);
2143 } else {
2144 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
2145 return u64(first_32_bits);
2146 }
2147}
2148
2149fn readULeb128(in_stream: var) !u64 {
2150 var result: u64 = 0;
2151 var shift: usize = 0;
2152
2153 while (true) {
2154 const byte = try in_stream.readByte();
2155
2156 var operand: u64 = undefined;
2157
2158 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2159
2160 result |= operand;
2161
2162 if ((byte & 0b10000000) == 0) return result;
2163
2164 shift += 7;
2165 }
2166}
2167
2168fn readILeb128(in_stream: var) !i64 {
2169 var result: i64 = 0;
2170 var shift: usize = 0;
2171
2172 while (true) {
2173 const byte = try in_stream.readByte();
2174
2175 var operand: i64 = undefined;
2176
2177 if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2178
2179 result |= operand;
2180 shift += 7;
2181
2182 if ((byte & 0b10000000) == 0) {
2183 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
2184 return result;
2185 }
2186 }
2187}
2188
2189/// This should only be used in temporary test programs.
2190pub const global_allocator = &global_fixed_allocator.allocator;
2191var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);
2192var global_allocator_mem: [100 * 1024]u8 = undefined;
2193
2194/// TODO multithreaded awareness
2195var debug_info_allocator: ?*mem.Allocator = null;
2196var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
2197var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
2198fn getDebugInfoAllocator() *mem.Allocator {
2199 if (debug_info_allocator) |a| return a;
2200
2201 debug_info_direct_allocator = std.heap.DirectAllocator.init();
2202 debug_info_arena_allocator = std.heap.ArenaAllocator.init(&debug_info_direct_allocator.allocator);
2203 debug_info_allocator = &debug_info_arena_allocator.allocator;
2204 return &debug_info_arena_allocator.allocator;
2205}
std/dynamic_library.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const Os = builtin.Os;2const Os = builtin.Os;
33
4const std = @import("index.zig");4const std = @import("std.zig");
5const mem = std.mem;5const mem = std.mem;
6const cstr = std.cstr;6const cstr = std.cstr;
7const os = std.os;7const os = std.os;
std/elf.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("index.zig");2const std = @import("std.zig");
3const io = std.io;3const io = std.io;
4const os = std.os;4const os = std.os;
5const math = std.math;5const math = std.math;
std/event/channel.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/event/fs.zig+3-10
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("../index.zig");2const std = @import("../std.zig");
3const event = std.event;3const event = std.event;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const testing = std.testing;5const testing = std.testing;
...@@ -404,11 +404,7 @@ pub async fn openPosix(...@@ -404,11 +404,7 @@ pub async fn openPosix(
404404
405pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {405pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
406 switch (builtin.os) {406 switch (builtin.os) {
407 builtin.Os.macosx,407 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
408 builtin.Os.linux,
409 builtin.Os.freebsd,
410 builtin.Os.netbsd
411 => {
412 const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;408 const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
413 return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);409 return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
414 },410 },
...@@ -876,10 +872,7 @@ pub fn Watch(comptime V: type) type {...@@ -876,10 +872,7 @@ pub fn Watch(comptime V: type) type {
876872
877 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {873 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
878 switch (builtin.os) {874 switch (builtin.os) {
879 builtin.Os.macosx,875 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
880 builtin.Os.freebsd,
881 builtin.Os.netbsd
882 => return await (async addFileKEvent(self, file_path, value) catch unreachable),
883 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),876 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
884 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),877 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885 else => @compileError("Unsupported OS"),878 else => @compileError("Unsupported OS"),
std/event/future.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const builtin = @import("builtin");4const builtin = @import("builtin");
std/event/group.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Lock = std.event.Lock;3const Lock = std.event.Lock;
4const Loop = std.event.Loop;4const Loop = std.event.Loop;
std/event/io.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;4const assert = std.debug.assert;
std/event/lock.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/event/locked.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const Lock = std.event.Lock;2const Lock = std.event.Lock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
std/event/loop.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/event/net.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const testing = std.testing;3const testing = std.testing;
4const event = std.event;4const event = std.event;
std/event/rwlock.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/event/rwlocked.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const RwLock = std.event.RwLock;2const RwLock = std.event.RwLock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
std/fmt.zig created+1441
...@@ -0,0 +1,1441 @@
1const std = @import("std.zig");
2const math = std.math;
3const debug = std.debug;
4const assert = debug.assert;
5const testing = std.testing;
6const mem = std.mem;
7const builtin = @import("builtin");
8const errol = @import("fmt/errol.zig");
9const lossyCast = std.math.lossyCast;
10
11const max_int_digits = 65;
12
13/// Renders fmt string with args, calling output with slices of bytes.
14/// If `output` returns an error, the error is returned from `format` and
15/// `output` is not called again.
16pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
17 const State = enum {
18 Start,
19 OpenBrace,
20 CloseBrace,
21 FormatString,
22 Pointer,
23 };
24
25 comptime var start_index = 0;
26 comptime var state = State.Start;
27 comptime var next_arg = 0;
28
29 inline for (fmt) |c, i| {
30 switch (state) {
31 State.Start => switch (c) {
32 '{' => {
33 if (start_index < i) {
34 try output(context, fmt[start_index..i]);
35 }
36 start_index = i;
37 state = State.OpenBrace;
38 },
39
40 '}' => {
41 if (start_index < i) {
42 try output(context, fmt[start_index..i]);
43 }
44 state = State.CloseBrace;
45 },
46 else => {},
47 },
48 State.OpenBrace => switch (c) {
49 '{' => {
50 state = State.Start;
51 start_index = i;
52 },
53 '}' => {
54 try formatType(args[next_arg], fmt[0..0], context, Errors, output);
55 next_arg += 1;
56 state = State.Start;
57 start_index = i + 1;
58 },
59 '*' => state = State.Pointer,
60 else => {
61 state = State.FormatString;
62 },
63 },
64 State.CloseBrace => switch (c) {
65 '}' => {
66 state = State.Start;
67 start_index = i;
68 },
69 else => @compileError("Single '}' encountered in format string"),
70 },
71 State.FormatString => switch (c) {
72 '}' => {
73 const s = start_index + 1;
74 try formatType(args[next_arg], fmt[s..i], context, Errors, output);
75 next_arg += 1;
76 state = State.Start;
77 start_index = i + 1;
78 },
79 else => {},
80 },
81 State.Pointer => switch (c) {
82 '}' => {
83 try output(context, @typeName(@typeOf(args[next_arg]).Child));
84 try output(context, "@");
85 try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);
86 next_arg += 1;
87 state = State.Start;
88 start_index = i + 1;
89 },
90 else => @compileError("Unexpected format character after '*'"),
91 },
92 }
93 }
94 comptime {
95 if (args.len != next_arg) {
96 @compileError("Unused arguments");
97 }
98 if (state != State.Start) {
99 @compileError("Incomplete format string: " ++ fmt);
100 }
101 }
102 if (start_index < fmt.len) {
103 try output(context, fmt[start_index..]);
104 }
105}
106
107pub fn formatType(
108 value: var,
109 comptime fmt: []const u8,
110 context: var,
111 comptime Errors: type,
112 output: fn (@typeOf(context), []const u8) Errors!void,
113) Errors!void {
114 const T = @typeOf(value);
115 if (T == anyerror) {
116 try output(context, "error.");
117 return output(context, @errorName(value));
118 }
119 switch (@typeInfo(T)) {
120 builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
121 return formatValue(value, fmt, context, Errors, output);
122 },
123 builtin.TypeId.Void => {
124 return output(context, "void");
125 },
126 builtin.TypeId.Bool => {
127 return output(context, if (value) "true" else "false");
128 },
129 builtin.TypeId.Optional => {
130 if (value) |payload| {
131 return formatType(payload, fmt, context, Errors, output);
132 } else {
133 return output(context, "null");
134 }
135 },
136 builtin.TypeId.ErrorUnion => {
137 if (value) |payload| {
138 return formatType(payload, fmt, context, Errors, output);
139 } else |err| {
140 return formatType(err, fmt, context, Errors, output);
141 }
142 },
143 builtin.TypeId.ErrorSet => {
144 try output(context, "error.");
145 return output(context, @errorName(value));
146 },
147 builtin.TypeId.Promise => {
148 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
149 },
150 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
151 const has_cust_fmt = comptime cf: {
152 const info = @typeInfo(T);
153 const defs = switch (info) {
154 builtin.TypeId.Struct => |s| s.defs,
155 builtin.TypeId.Union => |u| u.defs,
156 builtin.TypeId.Enum => |e| e.defs,
157 else => unreachable,
158 };
159
160 for (defs) |def| {
161 if (mem.eql(u8, def.name, "format")) {
162 break :cf true;
163 }
164 }
165 break :cf false;
166 };
167 if (has_cust_fmt) return value.format(fmt, context, Errors, output);
168
169 try output(context, @typeName(T));
170 switch (comptime @typeId(T)) {
171 builtin.TypeId.Enum => {
172 try output(context, ".");
173 try formatType(@tagName(value), "", context, Errors, output);
174 return;
175 },
176 builtin.TypeId.Struct => {
177 comptime var field_i = 0;
178 inline while (field_i < @memberCount(T)) : (field_i += 1) {
179 if (field_i == 0) {
180 try output(context, "{ .");
181 } else {
182 try output(context, ", .");
183 }
184 try output(context, @memberName(T, field_i));
185 try output(context, " = ");
186 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output);
187 }
188 try output(context, " }");
189 },
190 builtin.TypeId.Union => {
191 const info = @typeInfo(T).Union;
192 if (info.tag_type) |UnionTagType| {
193 try output(context, "{ .");
194 try output(context, @tagName(UnionTagType(value)));
195 try output(context, " = ");
196 inline for (info.fields) |u_field| {
197 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
198 try formatType(@field(value, u_field.name), "", context, Errors, output);
199 }
200 }
201 try output(context, " }");
202 } else {
203 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
204 }
205 },
206 else => unreachable,
207 }
208 return;
209 },
210 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
211 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
212 builtin.TypeId.Array => |info| {
213 if (info.child == u8) {
214 return formatText(value, fmt, context, Errors, output);
215 }
216 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
217 },
218 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
219 return formatType(value.*, fmt, context, Errors, output);
220 },
221 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
222 },
223 builtin.TypeInfo.Pointer.Size.Many => {
224 if (ptr_info.child == u8) {
225 if (fmt.len > 0 and fmt[0] == 's') {
226 const len = std.cstr.len(value);
227 return formatText(value[0..len], fmt, context, Errors, output);
228 }
229 }
230 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
231 },
232 builtin.TypeInfo.Pointer.Size.Slice => {
233 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
234 return formatText(value, fmt, context, Errors, output);
235 }
236 const casted_value = ([]const u8)(value);
237 return output(context, casted_value);
238 },
239 builtin.TypeInfo.Pointer.Size.C => {
240 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
241 },
242 },
243 builtin.TypeId.Array => |info| {
244 if (info.child == u8) {
245 return formatText(value, fmt, context, Errors, output);
246 }
247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
248 },
249 builtin.TypeId.Fn => {
250 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
251 },
252 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
253 }
254}
255
256fn formatValue(
257 value: var,
258 comptime fmt: []const u8,
259 context: var,
260 comptime Errors: type,
261 output: fn (@typeOf(context), []const u8) Errors!void,
262) Errors!void {
263 if (fmt.len > 0) {
264 if (fmt[0] == 'B') {
265 comptime var width: ?usize = null;
266 if (fmt.len > 1) {
267 if (fmt[1] == 'i') {
268 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
269 return formatBytes(value, width, 1024, context, Errors, output);
270 }
271 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
272 }
273 return formatBytes(value, width, 1000, context, Errors, output);
274 }
275 }
276
277 const T = @typeOf(value);
278 switch (@typeId(T)) {
279 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
280 builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
281 builtin.TypeId.ComptimeInt => {
282 const Int = math.IntFittingRange(value, value);
283 return formatIntValue(Int(value), fmt, context, Errors, output);
284 },
285 else => comptime unreachable,
286 }
287}
288
289pub fn formatIntValue(
290 value: var,
291 comptime fmt: []const u8,
292 context: var,
293 comptime Errors: type,
294 output: fn (@typeOf(context), []const u8) Errors!void,
295) Errors!void {
296 comptime var radix = 10;
297 comptime var uppercase = false;
298 comptime var width = 0;
299 if (fmt.len > 0) {
300 switch (fmt[0]) {
301 'c' => {
302 if (@typeOf(value).bit_count <= 8) {
303 if (fmt.len > 1)
304 @compileError("Unknown format character: " ++ []u8{fmt[1]});
305 return formatAsciiChar(u8(value), context, Errors, output);
306 }
307 },
308 'b' => {
309 radix = 2;
310 uppercase = false;
311 width = 0;
312 },
313 'd' => {
314 radix = 10;
315 uppercase = false;
316 width = 0;
317 },
318 'x' => {
319 radix = 16;
320 uppercase = false;
321 width = 0;
322 },
323 'X' => {
324 radix = 16;
325 uppercase = true;
326 width = 0;
327 },
328 else => @compileError("Unknown format character: " ++ []u8{fmt[0]}),
329 }
330 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
331 }
332 return formatInt(value, radix, uppercase, width, context, Errors, output);
333}
334
335fn formatFloatValue(
336 value: var,
337 comptime fmt: []const u8,
338 context: var,
339 comptime Errors: type,
340 output: fn (@typeOf(context), []const u8) Errors!void,
341) Errors!void {
342 comptime var width: ?usize = null;
343 comptime var float_fmt = 'e';
344 if (fmt.len > 0) {
345 float_fmt = fmt[0];
346 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
347 }
348
349 switch (float_fmt) {
350 'e' => try formatFloatScientific(value, width, context, Errors, output),
351 '.' => try formatFloatDecimal(value, width, context, Errors, output),
352 else => @compileError("Unknown format character: " ++ []u8{float_fmt}),
353 }
354}
355
356pub fn formatText(
357 bytes: []const u8,
358 comptime fmt: []const u8,
359 context: var,
360 comptime Errors: type,
361 output: fn (@typeOf(context), []const u8) Errors!void,
362) Errors!void {
363 if (fmt.len > 0) {
364 if (fmt[0] == 's') {
365 comptime var width = 0;
366 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
367 return formatBuf(bytes, width, context, Errors, output);
368 } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {
369 for (bytes) |c| {
370 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
371 }
372 return;
373 } else @compileError("Unknown format character: " ++ []u8{fmt[0]});
374 }
375 return output(context, bytes);
376}
377
378pub fn formatAsciiChar(
379 c: u8,
380 context: var,
381 comptime Errors: type,
382 output: fn (@typeOf(context), []const u8) Errors!void,
383) Errors!void {
384 return output(context, (*[1]u8)(&c)[0..]);
385}
386
387pub fn formatBuf(
388 buf: []const u8,
389 width: usize,
390 context: var,
391 comptime Errors: type,
392 output: fn (@typeOf(context), []const u8) Errors!void,
393) Errors!void {
394 try output(context, buf);
395
396 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
397 const pad_byte: u8 = ' ';
398 while (leftover_padding > 0) : (leftover_padding -= 1) {
399 try output(context, (*[1]u8)(&pad_byte)[0..1]);
400 }
401}
402
403// Print a float in scientific notation to the specified precision. Null uses full precision.
404// It should be the case that every full precision, printed value can be re-parsed back to the
405// same type unambiguously.
406pub fn formatFloatScientific(
407 value: var,
408 maybe_precision: ?usize,
409 context: var,
410 comptime Errors: type,
411 output: fn (@typeOf(context), []const u8) Errors!void,
412) Errors!void {
413 var x = @floatCast(f64, value);
414
415 // Errol doesn't handle these special cases.
416 if (math.signbit(x)) {
417 try output(context, "-");
418 x = -x;
419 }
420
421 if (math.isNan(x)) {
422 return output(context, "nan");
423 }
424 if (math.isPositiveInf(x)) {
425 return output(context, "inf");
426 }
427 if (x == 0.0) {
428 try output(context, "0");
429
430 if (maybe_precision) |precision| {
431 if (precision != 0) {
432 try output(context, ".");
433 var i: usize = 0;
434 while (i < precision) : (i += 1) {
435 try output(context, "0");
436 }
437 }
438 } else {
439 try output(context, ".0");
440 }
441
442 try output(context, "e+00");
443 return;
444 }
445
446 var buffer: [32]u8 = undefined;
447 var float_decimal = errol.errol3(x, buffer[0..]);
448
449 if (maybe_precision) |precision| {
450 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
451
452 try output(context, float_decimal.digits[0..1]);
453
454 // {e0} case prints no `.`
455 if (precision != 0) {
456 try output(context, ".");
457
458 var printed: usize = 0;
459 if (float_decimal.digits.len > 1) {
460 const num_digits = math.min(float_decimal.digits.len, precision + 1);
461 try output(context, float_decimal.digits[1..num_digits]);
462 printed += num_digits - 1;
463 }
464
465 while (printed < precision) : (printed += 1) {
466 try output(context, "0");
467 }
468 }
469 } else {
470 try output(context, float_decimal.digits[0..1]);
471 try output(context, ".");
472 if (float_decimal.digits.len > 1) {
473 const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
474
475 try output(context, float_decimal.digits[1..num_digits]);
476 } else {
477 try output(context, "0");
478 }
479 }
480
481 try output(context, "e");
482 const exp = float_decimal.exp - 1;
483
484 if (exp >= 0) {
485 try output(context, "+");
486 if (exp > -10 and exp < 10) {
487 try output(context, "0");
488 }
489 try formatInt(exp, 10, false, 0, context, Errors, output);
490 } else {
491 try output(context, "-");
492 if (exp > -10 and exp < 10) {
493 try output(context, "0");
494 }
495 try formatInt(-exp, 10, false, 0, context, Errors, output);
496 }
497}
498
499// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
500// By default floats are printed at full precision (no rounding).
501pub fn formatFloatDecimal(
502 value: var,
503 maybe_precision: ?usize,
504 context: var,
505 comptime Errors: type,
506 output: fn (@typeOf(context), []const u8) Errors!void,
507) Errors!void {
508 var x = f64(value);
509
510 // Errol doesn't handle these special cases.
511 if (math.signbit(x)) {
512 try output(context, "-");
513 x = -x;
514 }
515
516 if (math.isNan(x)) {
517 return output(context, "nan");
518 }
519 if (math.isPositiveInf(x)) {
520 return output(context, "inf");
521 }
522 if (x == 0.0) {
523 try output(context, "0");
524
525 if (maybe_precision) |precision| {
526 if (precision != 0) {
527 try output(context, ".");
528 var i: usize = 0;
529 while (i < precision) : (i += 1) {
530 try output(context, "0");
531 }
532 } else {
533 try output(context, ".0");
534 }
535 } else {
536 try output(context, "0");
537 }
538
539 return;
540 }
541
542 // non-special case, use errol3
543 var buffer: [32]u8 = undefined;
544 var float_decimal = errol.errol3(x, buffer[0..]);
545
546 if (maybe_precision) |precision| {
547 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
548
549 // exp < 0 means the leading is always 0 as errol result is normalized.
550 var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
551
552 // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
553 var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
554
555 if (num_digits_whole > 0) {
556 // We may have to zero pad, for instance 1e4 requires zero padding.
557 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
558
559 var i = num_digits_whole_no_pad;
560 while (i < num_digits_whole) : (i += 1) {
561 try output(context, "0");
562 }
563 } else {
564 try output(context, "0");
565 }
566
567 // {.0} special case doesn't want a trailing '.'
568 if (precision == 0) {
569 return;
570 }
571
572 try output(context, ".");
573
574 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
575 var printed: usize = 0;
576
577 // Zero-fill until we reach significant digits or run out of precision.
578 if (float_decimal.exp <= 0) {
579 const zero_digit_count = @intCast(usize, -float_decimal.exp);
580 const zeros_to_print = math.min(zero_digit_count, precision);
581
582 var i: usize = 0;
583 while (i < zeros_to_print) : (i += 1) {
584 try output(context, "0");
585 printed += 1;
586 }
587
588 if (printed >= precision) {
589 return;
590 }
591 }
592
593 // Remaining fractional portion, zero-padding if insufficient.
594 assert(precision >= printed);
595 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
596 try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
597 return;
598 } else {
599 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
600 printed += float_decimal.digits.len - num_digits_whole_no_pad;
601
602 while (printed < precision) : (printed += 1) {
603 try output(context, "0");
604 }
605 }
606 } else {
607 // exp < 0 means the leading is always 0 as errol result is normalized.
608 var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
609
610 // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
611 var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
612
613 if (num_digits_whole > 0) {
614 // We may have to zero pad, for instance 1e4 requires zero padding.
615 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
616
617 var i = num_digits_whole_no_pad;
618 while (i < num_digits_whole) : (i += 1) {
619 try output(context, "0");
620 }
621 } else {
622 try output(context, "0");
623 }
624
625 // Omit `.` if no fractional portion
626 if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
627 return;
628 }
629
630 try output(context, ".");
631
632 // Zero-fill until we reach significant digits or run out of precision.
633 if (float_decimal.exp < 0) {
634 const zero_digit_count = @intCast(usize, -float_decimal.exp);
635
636 var i: usize = 0;
637 while (i < zero_digit_count) : (i += 1) {
638 try output(context, "0");
639 }
640 }
641
642 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
643 }
644}
645
646pub fn formatBytes(
647 value: var,
648 width: ?usize,
649 comptime radix: usize,
650 context: var,
651 comptime Errors: type,
652 output: fn (@typeOf(context), []const u8) Errors!void,
653) Errors!void {
654 if (value == 0) {
655 return output(context, "0B");
656 }
657
658 const mags_si = " kMGTPEZY";
659 const mags_iec = " KMGTPEZY";
660 const magnitude = switch (radix) {
661 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
662 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
663 else => unreachable,
664 };
665 const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
666 const suffix = switch (radix) {
667 1000 => mags_si[magnitude],
668 1024 => mags_iec[magnitude],
669 else => unreachable,
670 };
671
672 try formatFloatDecimal(new_value, width, context, Errors, output);
673
674 if (suffix == ' ') {
675 return output(context, "B");
676 }
677
678 const buf = switch (radix) {
679 1000 => []u8{ suffix, 'B' },
680 1024 => []u8{ suffix, 'i', 'B' },
681 else => unreachable,
682 };
683 return output(context, buf);
684}
685
686pub fn formatInt(
687 value: var,
688 base: u8,
689 uppercase: bool,
690 width: usize,
691 context: var,
692 comptime Errors: type,
693 output: fn (@typeOf(context), []const u8) Errors!void,
694) Errors!void {
695 if (@typeOf(value).is_signed) {
696 return formatIntSigned(value, base, uppercase, width, context, Errors, output);
697 } else {
698 return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
699 }
700}
701
702fn formatIntSigned(
703 value: var,
704 base: u8,
705 uppercase: bool,
706 width: usize,
707 context: var,
708 comptime Errors: type,
709 output: fn (@typeOf(context), []const u8) Errors!void,
710) Errors!void {
711 const uint = @IntType(false, @typeOf(value).bit_count);
712 if (value < 0) {
713 const minus_sign: u8 = '-';
714 try output(context, (*[1]u8)(&minus_sign)[0..]);
715 const new_value = @intCast(uint, -(value + 1)) + 1;
716 const new_width = if (width == 0) 0 else (width - 1);
717 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
718 } else if (width == 0) {
719 return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
720 } else {
721 const plus_sign: u8 = '+';
722 try output(context, (*[1]u8)(&plus_sign)[0..]);
723 const new_value = @intCast(uint, value);
724 const new_width = if (width == 0) 0 else (width - 1);
725 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
726 }
727}
728
729fn formatIntUnsigned(
730 value: var,
731 base: u8,
732 uppercase: bool,
733 width: usize,
734 context: var,
735 comptime Errors: type,
736 output: fn (@typeOf(context), []const u8) Errors!void,
737) Errors!void {
738 // max_int_digits accounts for the minus sign. when printing an unsigned
739 // number we don't need to do that.
740 var buf: [max_int_digits - 1]u8 = undefined;
741 const min_int_bits = comptime math.max(@typeOf(value).bit_count, @typeOf(base).bit_count);
742 const MinInt = @IntType(@typeOf(value).is_signed, min_int_bits);
743 var a: MinInt = value;
744 var index: usize = buf.len;
745
746 while (true) {
747 const digit = a % base;
748 index -= 1;
749 buf[index] = digitToChar(@intCast(u8, digit), uppercase);
750 a /= base;
751 if (a == 0) break;
752 }
753
754 const digits_buf = buf[index..];
755 const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
756
757 if (padding > index) {
758 const zero_byte: u8 = '0';
759 var leftover_padding = padding - index;
760 while (true) {
761 try output(context, (*[1]u8)(&zero_byte)[0..]);
762 leftover_padding -= 1;
763 if (leftover_padding == 0) break;
764 }
765 mem.set(u8, buf[0..index], '0');
766 return output(context, buf);
767 } else {
768 const padded_buf = buf[index - padding ..];
769 mem.set(u8, padded_buf[0..padding], '0');
770 return output(context, padded_buf);
771 }
772}
773
774pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
775 var context = FormatIntBuf{
776 .out_buf = out_buf,
777 .index = 0,
778 };
779 formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
780 return context.index;
781}
782const FormatIntBuf = struct {
783 out_buf: []u8,
784 index: usize,
785};
786fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
787 mem.copy(u8, context.out_buf[context.index..], bytes);
788 context.index += bytes.len;
789}
790
791pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
792 if (!T.is_signed) return parseUnsigned(T, buf, radix);
793 if (buf.len == 0) return T(0);
794 if (buf[0] == '-') {
795 return math.negate(try parseUnsigned(T, buf[1..], radix));
796 } else if (buf[0] == '+') {
797 return parseUnsigned(T, buf[1..], radix);
798 } else {
799 return parseUnsigned(T, buf, radix);
800 }
801}
802
803test "fmt.parseInt" {
804 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
805 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
806 testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
807 testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
808 testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
809 testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
810 testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
811}
812
813const ParseUnsignedError = error{
814 /// The result cannot fit in the type specified
815 Overflow,
816
817 /// The input had a byte that was not a digit
818 InvalidCharacter,
819};
820
821pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
822 var x: T = 0;
823
824 for (buf) |c| {
825 const digit = try charToDigit(c, radix);
826
827 if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
828 x = try math.add(T, x, try math.cast(T, digit));
829 }
830
831 return x;
832}
833
834test "fmt.parseUnsigned" {
835 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
836 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
837 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
838
839 testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
840 testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
841
842 testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
843
844 testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
845 testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
846
847 testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
848 testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
849
850 testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
851
852 // these numbers should fit even though the radix itself doesn't fit in the destination type
853 testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
854 testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
855 testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
856 testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
857 testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
858 testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
859}
860
861pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
862
863test "fmt.parseFloat" {
864 _ = @import("fmt/parse_float.zig");
865}
866
867pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
868 const value = switch (c) {
869 '0'...'9' => c - '0',
870 'A'...'Z' => c - 'A' + 10,
871 'a'...'z' => c - 'a' + 10,
872 else => return error.InvalidCharacter,
873 };
874
875 if (value >= radix) return error.InvalidCharacter;
876
877 return value;
878}
879
880fn digitToChar(digit: u8, uppercase: bool) u8 {
881 return switch (digit) {
882 0...9 => digit + '0',
883 10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
884 else => unreachable,
885 };
886}
887
888const BufPrintContext = struct {
889 remaining: []u8,
890};
891
892fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
893 if (context.remaining.len < bytes.len) return error.BufferTooSmall;
894 mem.copy(u8, context.remaining, bytes);
895 context.remaining = context.remaining[bytes.len..];
896}
897
898pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
899 var context = BufPrintContext{ .remaining = buf };
900 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
901 return buf[0 .. buf.len - context.remaining.len];
902}
903
904pub const AllocPrintError = error{OutOfMemory};
905
906pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) AllocPrintError![]u8 {
907 var size: usize = 0;
908 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
909 const buf = try allocator.alloc(u8, size);
910 return bufPrint(buf, fmt, args) catch |err| switch (err) {
911 error.BufferTooSmall => unreachable, // we just counted the size above
912 };
913}
914
915fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
916 size.* += bytes.len;
917}
918
919test "buf print int" {
920 var buffer: [max_int_digits]u8 = undefined;
921 const buf = buffer[0..];
922 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
923 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
924 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
925 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
926
927 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
928
929 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
930 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
931 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
932
933 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
934 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
935}
936
937fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 {
938 return buf[0..formatIntBuf(buf, value, base, uppercase, width)];
939}
940
941test "parse u64 digit too big" {
942 _ = parseUnsigned(u64, "123a", 10) catch |err| {
943 if (err == error.InvalidCharacter) return;
944 unreachable;
945 };
946 unreachable;
947}
948
949test "parse unsigned comptime" {
950 comptime {
951 testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
952 }
953}
954
955test "fmt.format" {
956 {
957 const value: ?i32 = 1234;
958 try testFmt("optional: 1234\n", "optional: {}\n", value);
959 }
960 {
961 const value: ?i32 = null;
962 try testFmt("optional: null\n", "optional: {}\n", value);
963 }
964 {
965 const value: anyerror!i32 = 1234;
966 try testFmt("error union: 1234\n", "error union: {}\n", value);
967 }
968 {
969 const value: anyerror!i32 = error.InvalidChar;
970 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
971 }
972 {
973 const value: u3 = 0b101;
974 try testFmt("u3: 5\n", "u3: {}\n", value);
975 }
976 {
977 const value: u8 = 'a';
978 try testFmt("u8: a\n", "u8: {c}\n", value);
979 }
980 {
981 const value: u8 = 0b1100;
982 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
983 }
984 {
985 var buf1: [32]u8 = undefined;
986 var context = BufPrintContext{ .remaining = buf1[0..] };
987 try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite);
988 var res = buf1[0 .. buf1.len - context.remaining.len];
989 testing.expect(mem.eql(u8, res, "1234"));
990
991 context = BufPrintContext{ .remaining = buf1[0..] };
992 try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
993 res = buf1[0 .. buf1.len - context.remaining.len];
994 testing.expect(mem.eql(u8, res, "a"));
995
996 context = BufPrintContext{ .remaining = buf1[0..] };
997 try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
998 res = buf1[0 .. buf1.len - context.remaining.len];
999 testing.expect(mem.eql(u8, res, "1100"));
1000 }
1001 {
1002 const value: [3]u8 = "abc";
1003 try testFmt("array: abc\n", "array: {}\n", value);
1004 try testFmt("array: abc\n", "array: {}\n", &value);
1005
1006 var buf: [100]u8 = undefined;
1007 try testFmt(
1008 try bufPrint(buf[0..], "array: [3]u8@{x}\n", @ptrToInt(&value)),
1009 "array: {*}\n",
1010 &value,
1011 );
1012 }
1013 {
1014 const value: []const u8 = "abc";
1015 try testFmt("slice: abc\n", "slice: {}\n", value);
1016 }
1017 {
1018 const value = @intToPtr(*i32, 0xdeadbeef);
1019 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
1020 try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
1021 }
1022 {
1023 const value = @intToPtr(fn () void, 0xdeadbeef);
1024 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
1025 }
1026 {
1027 const value = @intToPtr(fn () void, 0xdeadbeef);
1028 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
1029 }
1030 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1031 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1032 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
1033 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
1034 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1035 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
1036 {
1037 const Struct = struct {
1038 field: u8,
1039 };
1040 const value = Struct{ .field = 42 };
1041 try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", value);
1042 try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", &value);
1043 }
1044 {
1045 const Struct = struct {
1046 a: u0,
1047 b: u1,
1048 };
1049 const value = Struct{ .a = 0, .b = 1 };
1050 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
1051 }
1052 {
1053 const Enum = enum {
1054 One,
1055 Two,
1056 };
1057 const value = Enum.Two;
1058 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
1059 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1060 }
1061 {
1062 var buf1: [32]u8 = undefined;
1063 const value: f32 = 1.34;
1064 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
1065 testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
1066 }
1067 {
1068 var buf1: [32]u8 = undefined;
1069 const value: f32 = 12.34;
1070 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
1071 testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
1072 }
1073 {
1074 var buf1: [32]u8 = undefined;
1075 const value: f64 = -12.34e10;
1076 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1077 testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
1078 }
1079 {
1080 // This fails on release due to a minor rounding difference.
1081 // --release-fast outputs 9.999960000000001e-40 vs. the expected.
1082 // TODO fix this, it should be the same in Debug and ReleaseFast
1083 if (builtin.mode == builtin.Mode.Debug) {
1084 var buf1: [32]u8 = undefined;
1085 const value: f64 = 9.999960e-40;
1086 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1087 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
1088 }
1089 }
1090 {
1091 var buf1: [32]u8 = undefined;
1092 const value: f64 = 1.409706e-42;
1093 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1094 testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));
1095 }
1096 {
1097 var buf1: [32]u8 = undefined;
1098 const value: f64 = @bitCast(f32, u32(814313563));
1099 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1100 testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
1101 }
1102 {
1103 var buf1: [32]u8 = undefined;
1104 const value: f64 = @bitCast(f32, u32(1006632960));
1105 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1106 testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
1107 }
1108 {
1109 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1110 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1111 var buf1: [32]u8 = undefined;
1112 const value: f64 = @bitCast(f32, u32(1203982400));
1113 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1114 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
1115 }
1116 {
1117 var buf1: [32]u8 = undefined;
1118 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
1119 testing.expect(mem.eql(u8, result, "f64: nan\n"));
1120 }
1121 if (builtin.arch != builtin.Arch.arm) {
1122 // negative nan is not defined by IEE 754,
1123 // and ARM thus normalizes it to positive nan
1124 var buf1: [32]u8 = undefined;
1125 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
1126 testing.expect(mem.eql(u8, result, "f64: -nan\n"));
1127 }
1128 {
1129 var buf1: [32]u8 = undefined;
1130 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
1131 testing.expect(mem.eql(u8, result, "f64: inf\n"));
1132 }
1133 {
1134 var buf1: [32]u8 = undefined;
1135 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
1136 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
1137 }
1138 {
1139 var buf1: [64]u8 = undefined;
1140 const value: f64 = 1.52314e+29;
1141 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
1142 testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
1143 }
1144 {
1145 var buf1: [32]u8 = undefined;
1146 const value: f32 = 1.1234;
1147 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
1148 testing.expect(mem.eql(u8, result, "f32: 1.1\n"));
1149 }
1150 {
1151 var buf1: [32]u8 = undefined;
1152 const value: f32 = 1234.567;
1153 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
1154 testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
1155 }
1156 {
1157 var buf1: [32]u8 = undefined;
1158 const value: f32 = -11.1234;
1159 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
1160 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1161 // -11.12339... is rounded back up to -11.1234
1162 testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
1163 }
1164 {
1165 var buf1: [32]u8 = undefined;
1166 const value: f32 = 91.12345;
1167 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
1168 testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
1169 }
1170 {
1171 var buf1: [32]u8 = undefined;
1172 const value: f64 = 91.12345678901235;
1173 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
1174 testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
1175 }
1176 {
1177 var buf1: [32]u8 = undefined;
1178 const value: f64 = 0.0;
1179 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1180 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1181 }
1182 {
1183 var buf1: [32]u8 = undefined;
1184 const value: f64 = 5.700;
1185 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
1186 testing.expect(mem.eql(u8, result, "f64: 6\n"));
1187 }
1188 {
1189 var buf1: [32]u8 = undefined;
1190 const value: f64 = 9.999;
1191 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
1192 testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
1193 }
1194 {
1195 var buf1: [32]u8 = undefined;
1196 const value: f64 = 1.0;
1197 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
1198 testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
1199 }
1200 {
1201 var buf1: [32]u8 = undefined;
1202 const value: f64 = 0.0003;
1203 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
1204 testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
1205 }
1206 {
1207 var buf1: [32]u8 = undefined;
1208 const value: f64 = 1.40130e-45;
1209 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1210 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1211 }
1212 {
1213 var buf1: [32]u8 = undefined;
1214 const value: f64 = 9.999960e-40;
1215 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1216 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1217 }
1218 // libc checks
1219 {
1220 var buf1: [32]u8 = undefined;
1221 const value: f64 = f64(@bitCast(f32, u32(916964781)));
1222 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1223 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1224 }
1225 {
1226 var buf1: [32]u8 = undefined;
1227 const value: f64 = f64(@bitCast(f32, u32(925353389)));
1228 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1229 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1230 }
1231 {
1232 var buf1: [32]u8 = undefined;
1233 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
1234 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1235 testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
1236 }
1237 {
1238 var buf1: [32]u8 = undefined;
1239 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
1240 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1241 testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
1242 }
1243 {
1244 var buf1: [32]u8 = undefined;
1245 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
1246 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1247 testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
1248 }
1249 // libc differences
1250 {
1251 var buf1: [32]u8 = undefined;
1252 // This is 0.015625 exactly according to gdb. We thus round down,
1253 // however glibc rounds up for some reason. This occurs for all
1254 // floats of the form x.yyyy25 on a precision point.
1255 const value: f64 = f64(@bitCast(f32, u32(1015021568)));
1256 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1257 testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));
1258 }
1259 // std-windows-x86_64-Debug-bare test case fails
1260 {
1261 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1262 // also rounds to 630 so I'm inclined to believe libc is not
1263 // optimal here.
1264 var buf1: [32]u8 = undefined;
1265 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
1266 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1267 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1268 }
1269 //custom type format
1270 {
1271 const Vec2 = struct {
1272 const SelfType = @This();
1273 x: f32,
1274 y: f32,
1275
1276 pub fn format(
1277 self: SelfType,
1278 comptime fmt: []const u8,
1279 context: var,
1280 comptime Errors: type,
1281 output: fn (@typeOf(context), []const u8) Errors!void,
1282 ) Errors!void {
1283 switch (fmt.len) {
1284 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1285 1 => switch (fmt[0]) {
1286 //point format
1287 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1288 //dimension format
1289 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1290 else => unreachable,
1291 },
1292 else => unreachable,
1293 }
1294 }
1295 };
1296
1297 var buf1: [32]u8 = undefined;
1298 var value = Vec2{
1299 .x = 10.2,
1300 .y = 2.22,
1301 };
1302 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1303 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
1304
1305 // same thing but not passing a pointer
1306 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1307 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1308 }
1309 //struct format
1310 {
1311 const S = struct {
1312 a: u32,
1313 b: anyerror,
1314 };
1315
1316 const inst = S{
1317 .a = 456,
1318 .b = error.Unused,
1319 };
1320
1321 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1322 }
1323 //union format
1324 {
1325 const TU = union(enum) {
1326 float: f32,
1327 int: u32,
1328 };
1329
1330 const UU = union {
1331 float: f32,
1332 int: u32,
1333 };
1334
1335 const EU = extern union {
1336 float: f32,
1337 int: u32,
1338 };
1339
1340 const tu_inst = TU{ .int = 123 };
1341 const uu_inst = UU{ .int = 456 };
1342 const eu_inst = EU{ .float = 321.123 };
1343
1344 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
1345
1346 var buf: [100]u8 = undefined;
1347 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1348 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
1349
1350 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1351 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1352 }
1353 //enum format
1354 {
1355 const E = enum {
1356 One,
1357 Two,
1358 Three,
1359 };
1360
1361 const inst = E.Two;
1362
1363 try testFmt("E.Two", "{}", inst);
1364 }
1365 //print bytes as hex
1366 {
1367 const some_bytes = "\xCA\xFE\xBA\xBE";
1368 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1369 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1370 //Test Slices
1371 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
1372 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
1373 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1374 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
1375 }
1376}
1377
1378fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
1379 var buf: [100]u8 = undefined;
1380 const result = try bufPrint(buf[0..], template, args);
1381 if (mem.eql(u8, result, expected)) return;
1382
1383 std.debug.warn("\n====== expected this output: =========\n");
1384 std.debug.warn("{}", expected);
1385 std.debug.warn("\n======== instead found this: =========\n");
1386 std.debug.warn("{}", result);
1387 std.debug.warn("\n======================================\n");
1388 return error.TestFailed;
1389}
1390
1391pub fn trim(buf: []const u8) []const u8 {
1392 var start: usize = 0;
1393 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
1394
1395 var end: usize = buf.len;
1396 while (true) {
1397 if (end > start) {
1398 const new_end = end - 1;
1399 if (isWhiteSpace(buf[new_end])) {
1400 end = new_end;
1401 continue;
1402 }
1403 }
1404 break;
1405 }
1406 return buf[start..end];
1407}
1408
1409test "fmt.trim" {
1410 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
1411 testing.expect(mem.eql(u8, "", trim(" ")));
1412 testing.expect(mem.eql(u8, "", trim("")));
1413 testing.expect(mem.eql(u8, "abc", trim(" abc")));
1414 testing.expect(mem.eql(u8, "abc", trim("abc ")));
1415}
1416
1417pub fn isWhiteSpace(byte: u8) bool {
1418 return switch (byte) {
1419 ' ', '\t', '\n', '\r' => true,
1420 else => false,
1421 };
1422}
1423
1424pub fn hexToBytes(out: []u8, input: []const u8) !void {
1425 if (out.len * 2 < input.len)
1426 return error.InvalidLength;
1427
1428 var in_i: usize = 0;
1429 while (in_i != input.len) : (in_i += 2) {
1430 const hi = try charToDigit(input[in_i], 16);
1431 const lo = try charToDigit(input[in_i + 1], 16);
1432 out[in_i / 2] = (hi << 4) | lo;
1433 }
1434}
1435
1436test "fmt.hexToBytes" {
1437 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1438 var pb: [32]u8 = undefined;
1439 try hexToBytes(pb[0..], test_hex_str);
1440 try testFmt(test_hex_str, "{X}", pb);
1441}
std/fmt/errol.zig created+704
...@@ -0,0 +1,704 @@
1const std = @import("../std.zig");
2const enum3 = @import("errol/enum3.zig").enum3;
3const enum3_data = @import("errol/enum3.zig").enum3_data;
4const lookup_table = @import("errol/lookup.zig").lookup_table;
5const HP = @import("errol/lookup.zig").HP;
6const math = std.math;
7const mem = std.mem;
8const assert = std.debug.assert;
9
10pub const FloatDecimal = struct {
11 digits: []u8,
12 exp: i32,
13};
14
15pub const RoundMode = enum {
16 // Round only the fractional portion (e.g. 1234.23 has precision 2)
17 Decimal,
18 // Round the entire whole/fractional portion (e.g. 1.23423e3 has precision 5)
19 Scientific,
20};
21
22/// Round a FloatDecimal as returned by errol3 to the specified fractional precision.
23/// All digits after the specified precision should be considered invalid.
24pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: RoundMode) void {
25 // The round digit refers to the index which we should look at to determine
26 // whether we need to round to match the specified precision.
27 var round_digit: usize = 0;
28
29 switch (mode) {
30 RoundMode.Decimal => {
31 if (float_decimal.exp >= 0) {
32 round_digit = precision + @intCast(usize, float_decimal.exp);
33 } else {
34 // if a small negative exp, then adjust we need to offset by the number
35 // of leading zeros that will occur.
36 const min_exp_required = @intCast(usize, -float_decimal.exp);
37 if (precision > min_exp_required) {
38 round_digit = precision - min_exp_required;
39 }
40 }
41 },
42 RoundMode.Scientific => {
43 round_digit = 1 + precision;
44 },
45 }
46
47 // It suffices to look at just this digit. We don't round and propagate say 0.04999 to 0.05
48 // first, and then to 0.1 in the case of a {.1} single precision.
49
50 // Find the digit which will signify the round point and start rounding backwards.
51 if (round_digit < float_decimal.digits.len and float_decimal.digits[round_digit] - '0' >= 5) {
52 assert(round_digit >= 0);
53
54 var i = round_digit;
55 while (true) {
56 if (i == 0) {
57 // Rounded all the way past the start. This was of the form 9.999...
58 // Slot the new digit in place and increase the exponent.
59 float_decimal.exp += 1;
60
61 // Re-size the buffer to use the reserved leading byte.
62 const one_before = @intToPtr([*]u8, @ptrToInt(&float_decimal.digits[0]) - 1);
63 float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
64 float_decimal.digits[0] = '1';
65 return;
66 }
67
68 i -= 1;
69
70 const new_value = (float_decimal.digits[i] - '0' + 1) % 10;
71 float_decimal.digits[i] = new_value + '0';
72
73 // must continue rounding until non-9
74 if (new_value != 0) {
75 return;
76 }
77 }
78 }
79}
80
81/// Corrected Errol3 double to ASCII conversion.
82pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
83 const bits = @bitCast(u64, value);
84 const i = tableLowerBound(bits);
85 if (i < enum3.len and enum3[i] == bits) {
86 const data = enum3_data[i];
87 const digits = buffer[1 .. data.str.len + 1];
88 mem.copy(u8, digits, data.str);
89 return FloatDecimal{
90 .digits = digits,
91 .exp = data.exp,
92 };
93 }
94
95 return errol3u(value, buffer);
96}
97
98/// Uncorrected Errol3 double to ASCII conversion.
99fn errol3u(val: f64, buffer: []u8) FloatDecimal {
100 // check if in integer or fixed range
101 if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
102 return errolInt(val, buffer);
103 } else if (val >= 16.0 and val < 9.007199254740992e15) {
104 return errolFixed(val, buffer);
105 }
106
107 // normalize the midpoint
108
109 const e = math.frexp(val).exponent;
110 var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103));
111 if (exp < 20) {
112 exp = 20;
113 } else if (@intCast(usize, exp) >= lookup_table.len) {
114 exp = @intCast(i16, lookup_table.len - 1);
115 }
116
117 var mid = lookup_table[@intCast(usize, exp)];
118 mid = hpProd(mid, val);
119 const lten = lookup_table[@intCast(usize, exp)].val;
120
121 exp -= 307;
122
123 var ten: f64 = 1.0;
124
125 while (mid.val > 10.0 or (mid.val == 10.0 and mid.off >= 0.0)) {
126 exp += 1;
127 hpDiv10(&mid);
128 ten /= 10.0;
129 }
130
131 while (mid.val < 1.0 or (mid.val == 1.0 and mid.off < 0.0)) {
132 exp -= 1;
133 hpMul10(&mid);
134 ten *= 10.0;
135 }
136
137 // compute boundaries
138 var high = HP{
139 .val = mid.val,
140 .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
141 };
142 var low = HP{
143 .val = mid.val,
144 .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
145 };
146
147 hpNormalize(&high);
148 hpNormalize(&low);
149
150 // normalized boundaries
151
152 while (high.val > 10.0 or (high.val == 10.0 and high.off >= 0.0)) {
153 exp += 1;
154 hpDiv10(&high);
155 hpDiv10(&low);
156 }
157
158 while (high.val < 1.0 or (high.val == 1.0 and high.off < 0.0)) {
159 exp -= 1;
160 hpMul10(&high);
161 hpMul10(&low);
162 }
163
164 // digit generation
165
166 // We generate digits starting at index 1. If rounding a buffer later then it may be
167 // required to generate a preceding digit in some cases (9.999) in which case we use
168 // the 0-index for this extra digit.
169 var buf_index: usize = 1;
170 while (true) {
171 var hdig = @floatToInt(u8, math.floor(high.val));
172 if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1;
173
174 var ldig = @floatToInt(u8, math.floor(low.val));
175 if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1;
176
177 if (ldig != hdig) break;
178
179 buffer[buf_index] = hdig + '0';
180 buf_index += 1;
181 high.val -= @intToFloat(f64, hdig);
182 low.val -= @intToFloat(f64, ldig);
183 hpMul10(&high);
184 hpMul10(&low);
185 }
186
187 const tmp = (high.val + low.val) / 2.0;
188 var mdig = @floatToInt(u8, math.floor(tmp + 0.5));
189 if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
190
191 buffer[buf_index] = mdig + '0';
192 buf_index += 1;
193
194 return FloatDecimal{
195 .digits = buffer[1..buf_index],
196 .exp = exp,
197 };
198}
199
200fn tableLowerBound(k: u64) usize {
201 var i = enum3.len;
202 var j: usize = 0;
203
204 while (j < enum3.len) {
205 if (enum3[j] < k) {
206 j = 2 * j + 2;
207 } else {
208 i = j;
209 j = 2 * j + 1;
210 }
211 }
212
213 return i;
214}
215
216/// Compute the product of an HP number and a double.
217/// @in: The HP number.
218/// @val: The double.
219/// &returns: The HP number.
220fn hpProd(in: HP, val: f64) HP {
221 var hi: f64 = undefined;
222 var lo: f64 = undefined;
223 split(in.val, &hi, &lo);
224
225 var hi2: f64 = undefined;
226 var lo2: f64 = undefined;
227 split(val, &hi2, &lo2);
228
229 const p = in.val * val;
230 const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
231
232 return HP{
233 .val = p,
234 .off = in.off * val + e,
235 };
236}
237
238/// Split a double into two halves.
239/// @val: The double.
240/// @hi: The high bits.
241/// @lo: The low bits.
242fn split(val: f64, hi: *f64, lo: *f64) void {
243 hi.* = gethi(val);
244 lo.* = val - hi.*;
245}
246
247fn gethi(in: f64) f64 {
248 const bits = @bitCast(u64, in);
249 const new_bits = bits & 0xFFFFFFFFF8000000;
250 return @bitCast(f64, new_bits);
251}
252
253/// Normalize the number by factoring in the error.
254/// @hp: The float pair.
255fn hpNormalize(hp: *HP) void {
256 const val = hp.val;
257 hp.val += hp.off;
258 hp.off += val - hp.val;
259}
260
261/// Divide the high-precision number by ten.
262/// @hp: The high-precision number
263fn hpDiv10(hp: *HP) void {
264 var val = hp.val;
265
266 hp.val /= 10.0;
267 hp.off /= 10.0;
268
269 val -= hp.val * 8.0;
270 val -= hp.val * 2.0;
271
272 hp.off += val / 10.0;
273
274 hpNormalize(hp);
275}
276
277/// Multiply the high-precision number by ten.
278/// @hp: The high-precision number
279fn hpMul10(hp: *HP) void {
280 const val = hp.val;
281
282 hp.val *= 10.0;
283 hp.off *= 10.0;
284
285 var off = hp.val;
286 off -= val * 8.0;
287 off -= val * 2.0;
288
289 hp.off -= off;
290
291 hpNormalize(hp);
292}
293
294/// Integer conversion algorithm, guaranteed correct, optimal, and best.
295/// @val: The val.
296/// @buf: The output buffer.
297/// &return: The exponent.
298fn errolInt(val: f64, buffer: []u8) FloatDecimal {
299 const pow19 = u128(1e19);
300
301 assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
302
303 var mid = @floatToInt(u128, val);
304 var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
305 var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);
306
307 if (@bitCast(u64, val) & 0x1 != 0) {
308 high -= 1;
309 } else {
310 low -= 1;
311 }
312
313 var l64 = @intCast(u64, low % pow19);
314 const lf = @intCast(u64, (low / pow19) % pow19);
315
316 var h64 = @intCast(u64, high % pow19);
317 const hf = @intCast(u64, (high / pow19) % pow19);
318
319 if (lf != hf) {
320 l64 = lf;
321 h64 = hf;
322 mid = mid / (pow19 / 10);
323 }
324
325 var mi: i32 = mismatch10(l64, h64);
326 var x: u64 = 1;
327 {
328 var i: i32 = @boolToInt(lf == hf);
329 while (i < mi) : (i += 1) {
330 x *= 10;
331 }
332 }
333 const m64 = @truncate(u64, @divTrunc(mid, x));
334
335 if (lf != hf) mi += 19;
336
337 var buf_index = u64toa(m64, buffer) - 1;
338
339 if (mi != 0) {
340 buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
341 } else {
342 buf_index += 1;
343 }
344
345 return FloatDecimal{
346 .digits = buffer[0..buf_index],
347 .exp = @intCast(i32, buf_index) + mi,
348 };
349}
350
351/// Fixed point conversion algorithm, guaranteed correct, optimal, and best.
352/// @val: The val.
353/// @buf: The output buffer.
354/// &return: The exponent.
355fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
356 assert((val >= 16.0) and (val < 9.007199254740992e15));
357
358 const u = @floatToInt(u64, val);
359 const n = @intToFloat(f64, u);
360
361 var mid = val - n;
362 var lo = ((fpprev(val) - n) + mid) / 2.0;
363 var hi = ((fpnext(val) - n) + mid) / 2.0;
364
365 var buf_index = u64toa(u, buffer);
366 var exp = @intCast(i32, buf_index);
367 var j = buf_index;
368 buffer[j] = 0;
369
370 if (mid != 0.0) {
371 while (mid != 0.0) {
372 lo *= 10.0;
373 const ldig = @floatToInt(i32, lo);
374 lo -= @intToFloat(f64, ldig);
375
376 mid *= 10.0;
377 const mdig = @floatToInt(i32, mid);
378 mid -= @intToFloat(f64, mdig);
379
380 hi *= 10.0;
381 const hdig = @floatToInt(i32, hi);
382 hi -= @intToFloat(f64, hdig);
383
384 buffer[j] = @intCast(u8, mdig + '0');
385 j += 1;
386
387 if (hdig != ldig or j > 50) break;
388 }
389
390 if (mid > 0.5) {
391 buffer[j - 1] += 1;
392 } else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
393 buffer[j - 1] += 1;
394 }
395 } else {
396 while (buffer[j - 1] == '0') {
397 buffer[j - 1] = 0;
398 j -= 1;
399 }
400 }
401
402 buffer[j] = 0;
403
404 return FloatDecimal{
405 .digits = buffer[0..j],
406 .exp = exp,
407 };
408}
409
410fn fpnext(val: f64) f64 {
411 return @bitCast(f64, @bitCast(u64, val) +% 1);
412}
413
414fn fpprev(val: f64) f64 {
415 return @bitCast(f64, @bitCast(u64, val) -% 1);
416}
417
418pub const c_digits_lut = []u8{
419 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
420 '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
421 '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
422 '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7',
423 '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
424 '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
425 '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8',
426 '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5',
427 '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2',
428 '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
429 '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6',
430 '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
431 '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0',
432 '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7',
433 '9', '8', '9', '9',
434};
435
436fn u64toa(value_param: u64, buffer: []u8) usize {
437 var value = value_param;
438 const kTen8: u64 = 100000000;
439 const kTen9: u64 = kTen8 * 10;
440 const kTen10: u64 = kTen8 * 100;
441 const kTen11: u64 = kTen8 * 1000;
442 const kTen12: u64 = kTen8 * 10000;
443 const kTen13: u64 = kTen8 * 100000;
444 const kTen14: u64 = kTen8 * 1000000;
445 const kTen15: u64 = kTen8 * 10000000;
446 const kTen16: u64 = kTen8 * kTen8;
447
448 var buf_index: usize = 0;
449
450 if (value < kTen8) {
451 const v = @intCast(u32, value);
452 if (v < 10000) {
453 const d1: u32 = (v / 100) << 1;
454 const d2: u32 = (v % 100) << 1;
455
456 if (v >= 1000) {
457 buffer[buf_index] = c_digits_lut[d1];
458 buf_index += 1;
459 }
460 if (v >= 100) {
461 buffer[buf_index] = c_digits_lut[d1 + 1];
462 buf_index += 1;
463 }
464 if (v >= 10) {
465 buffer[buf_index] = c_digits_lut[d2];
466 buf_index += 1;
467 }
468 buffer[buf_index] = c_digits_lut[d2 + 1];
469 buf_index += 1;
470 } else {
471 // value = bbbbcccc
472 const b: u32 = v / 10000;
473 const c: u32 = v % 10000;
474
475 const d1: u32 = (b / 100) << 1;
476 const d2: u32 = (b % 100) << 1;
477
478 const d3: u32 = (c / 100) << 1;
479 const d4: u32 = (c % 100) << 1;
480
481 if (value >= 10000000) {
482 buffer[buf_index] = c_digits_lut[d1];
483 buf_index += 1;
484 }
485 if (value >= 1000000) {
486 buffer[buf_index] = c_digits_lut[d1 + 1];
487 buf_index += 1;
488 }
489 if (value >= 100000) {
490 buffer[buf_index] = c_digits_lut[d2];
491 buf_index += 1;
492 }
493 buffer[buf_index] = c_digits_lut[d2 + 1];
494 buf_index += 1;
495
496 buffer[buf_index] = c_digits_lut[d3];
497 buf_index += 1;
498 buffer[buf_index] = c_digits_lut[d3 + 1];
499 buf_index += 1;
500 buffer[buf_index] = c_digits_lut[d4];
501 buf_index += 1;
502 buffer[buf_index] = c_digits_lut[d4 + 1];
503 buf_index += 1;
504 }
505 } else if (value < kTen16) {
506 const v0: u32 = @intCast(u32, value / kTen8);
507 const v1: u32 = @intCast(u32, value % kTen8);
508
509 const b0: u32 = v0 / 10000;
510 const c0: u32 = v0 % 10000;
511
512 const d1: u32 = (b0 / 100) << 1;
513 const d2: u32 = (b0 % 100) << 1;
514
515 const d3: u32 = (c0 / 100) << 1;
516 const d4: u32 = (c0 % 100) << 1;
517
518 const b1: u32 = v1 / 10000;
519 const c1: u32 = v1 % 10000;
520
521 const d5: u32 = (b1 / 100) << 1;
522 const d6: u32 = (b1 % 100) << 1;
523
524 const d7: u32 = (c1 / 100) << 1;
525 const d8: u32 = (c1 % 100) << 1;
526
527 if (value >= kTen15) {
528 buffer[buf_index] = c_digits_lut[d1];
529 buf_index += 1;
530 }
531 if (value >= kTen14) {
532 buffer[buf_index] = c_digits_lut[d1 + 1];
533 buf_index += 1;
534 }
535 if (value >= kTen13) {
536 buffer[buf_index] = c_digits_lut[d2];
537 buf_index += 1;
538 }
539 if (value >= kTen12) {
540 buffer[buf_index] = c_digits_lut[d2 + 1];
541 buf_index += 1;
542 }
543 if (value >= kTen11) {
544 buffer[buf_index] = c_digits_lut[d3];
545 buf_index += 1;
546 }
547 if (value >= kTen10) {
548 buffer[buf_index] = c_digits_lut[d3 + 1];
549 buf_index += 1;
550 }
551 if (value >= kTen9) {
552 buffer[buf_index] = c_digits_lut[d4];
553 buf_index += 1;
554 }
555 if (value >= kTen8) {
556 buffer[buf_index] = c_digits_lut[d4 + 1];
557 buf_index += 1;
558 }
559
560 buffer[buf_index] = c_digits_lut[d5];
561 buf_index += 1;
562 buffer[buf_index] = c_digits_lut[d5 + 1];
563 buf_index += 1;
564 buffer[buf_index] = c_digits_lut[d6];
565 buf_index += 1;
566 buffer[buf_index] = c_digits_lut[d6 + 1];
567 buf_index += 1;
568 buffer[buf_index] = c_digits_lut[d7];
569 buf_index += 1;
570 buffer[buf_index] = c_digits_lut[d7 + 1];
571 buf_index += 1;
572 buffer[buf_index] = c_digits_lut[d8];
573 buf_index += 1;
574 buffer[buf_index] = c_digits_lut[d8 + 1];
575 buf_index += 1;
576 } else {
577 const a = @intCast(u32, value / kTen16); // 1 to 1844
578 value %= kTen16;
579
580 if (a < 10) {
581 buffer[buf_index] = '0' + @intCast(u8, a);
582 buf_index += 1;
583 } else if (a < 100) {
584 const i: u32 = a << 1;
585 buffer[buf_index] = c_digits_lut[i];
586 buf_index += 1;
587 buffer[buf_index] = c_digits_lut[i + 1];
588 buf_index += 1;
589 } else if (a < 1000) {
590 buffer[buf_index] = '0' + @intCast(u8, a / 100);
591 buf_index += 1;
592
593 const i: u32 = (a % 100) << 1;
594 buffer[buf_index] = c_digits_lut[i];
595 buf_index += 1;
596 buffer[buf_index] = c_digits_lut[i + 1];
597 buf_index += 1;
598 } else {
599 const i: u32 = (a / 100) << 1;
600 const j: u32 = (a % 100) << 1;
601 buffer[buf_index] = c_digits_lut[i];
602 buf_index += 1;
603 buffer[buf_index] = c_digits_lut[i + 1];
604 buf_index += 1;
605 buffer[buf_index] = c_digits_lut[j];
606 buf_index += 1;
607 buffer[buf_index] = c_digits_lut[j + 1];
608 buf_index += 1;
609 }
610
611 const v0 = @intCast(u32, value / kTen8);
612 const v1 = @intCast(u32, value % kTen8);
613
614 const b0: u32 = v0 / 10000;
615 const c0: u32 = v0 % 10000;
616
617 const d1: u32 = (b0 / 100) << 1;
618 const d2: u32 = (b0 % 100) << 1;
619
620 const d3: u32 = (c0 / 100) << 1;
621 const d4: u32 = (c0 % 100) << 1;
622
623 const b1: u32 = v1 / 10000;
624 const c1: u32 = v1 % 10000;
625
626 const d5: u32 = (b1 / 100) << 1;
627 const d6: u32 = (b1 % 100) << 1;
628
629 const d7: u32 = (c1 / 100) << 1;
630 const d8: u32 = (c1 % 100) << 1;
631
632 buffer[buf_index] = c_digits_lut[d1];
633 buf_index += 1;
634 buffer[buf_index] = c_digits_lut[d1 + 1];
635 buf_index += 1;
636 buffer[buf_index] = c_digits_lut[d2];
637 buf_index += 1;
638 buffer[buf_index] = c_digits_lut[d2 + 1];
639 buf_index += 1;
640 buffer[buf_index] = c_digits_lut[d3];
641 buf_index += 1;
642 buffer[buf_index] = c_digits_lut[d3 + 1];
643 buf_index += 1;
644 buffer[buf_index] = c_digits_lut[d4];
645 buf_index += 1;
646 buffer[buf_index] = c_digits_lut[d4 + 1];
647 buf_index += 1;
648 buffer[buf_index] = c_digits_lut[d5];
649 buf_index += 1;
650 buffer[buf_index] = c_digits_lut[d5 + 1];
651 buf_index += 1;
652 buffer[buf_index] = c_digits_lut[d6];
653 buf_index += 1;
654 buffer[buf_index] = c_digits_lut[d6 + 1];
655 buf_index += 1;
656 buffer[buf_index] = c_digits_lut[d7];
657 buf_index += 1;
658 buffer[buf_index] = c_digits_lut[d7 + 1];
659 buf_index += 1;
660 buffer[buf_index] = c_digits_lut[d8];
661 buf_index += 1;
662 buffer[buf_index] = c_digits_lut[d8 + 1];
663 buf_index += 1;
664 }
665
666 return buf_index;
667}
668
669fn fpeint(from: f64) u128 {
670 const bits = @bitCast(u64, from);
671 assert((bits & ((1 << 52) - 1)) == 0);
672
673 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
674}
675
676/// Given two different integers with the same length in terms of the number
677/// of decimal digits, index the digits from the right-most position starting
678/// from zero, find the first index where the digits in the two integers
679/// divergent starting from the highest index.
680/// @a: Integer a.
681/// @b: Integer b.
682/// &returns: An index within [0, 19).
683fn mismatch10(a: u64, b: u64) i32 {
684 const pow10 = 10000000000;
685 const af = a / pow10;
686 const bf = b / pow10;
687
688 var i: i32 = 0;
689 var a_copy = a;
690 var b_copy = b;
691
692 if (af != bf) {
693 i = 10;
694 a_copy = af;
695 b_copy = bf;
696 }
697
698 while (true) : (i += 1) {
699 a_copy /= 10;
700 b_copy /= 10;
701
702 if (a_copy == b_copy) return i;
703 }
704}
std/fmt/errol/index.zig deleted-704
...@@ -1,704 +0,0 @@
1const std = @import("../../index.zig");
2const enum3 = @import("enum3.zig").enum3;
3const enum3_data = @import("enum3.zig").enum3_data;
4const lookup_table = @import("lookup.zig").lookup_table;
5const HP = @import("lookup.zig").HP;
6const math = std.math;
7const mem = std.mem;
8const assert = std.debug.assert;
9
10pub const FloatDecimal = struct {
11 digits: []u8,
12 exp: i32,
13};
14
15pub const RoundMode = enum {
16 // Round only the fractional portion (e.g. 1234.23 has precision 2)
17 Decimal,
18 // Round the entire whole/fractional portion (e.g. 1.23423e3 has precision 5)
19 Scientific,
20};
21
22/// Round a FloatDecimal as returned by errol3 to the specified fractional precision.
23/// All digits after the specified precision should be considered invalid.
24pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: RoundMode) void {
25 // The round digit refers to the index which we should look at to determine
26 // whether we need to round to match the specified precision.
27 var round_digit: usize = 0;
28
29 switch (mode) {
30 RoundMode.Decimal => {
31 if (float_decimal.exp >= 0) {
32 round_digit = precision + @intCast(usize, float_decimal.exp);
33 } else {
34 // if a small negative exp, then adjust we need to offset by the number
35 // of leading zeros that will occur.
36 const min_exp_required = @intCast(usize, -float_decimal.exp);
37 if (precision > min_exp_required) {
38 round_digit = precision - min_exp_required;
39 }
40 }
41 },
42 RoundMode.Scientific => {
43 round_digit = 1 + precision;
44 },
45 }
46
47 // It suffices to look at just this digit. We don't round and propagate say 0.04999 to 0.05
48 // first, and then to 0.1 in the case of a {.1} single precision.
49
50 // Find the digit which will signify the round point and start rounding backwards.
51 if (round_digit < float_decimal.digits.len and float_decimal.digits[round_digit] - '0' >= 5) {
52 assert(round_digit >= 0);
53
54 var i = round_digit;
55 while (true) {
56 if (i == 0) {
57 // Rounded all the way past the start. This was of the form 9.999...
58 // Slot the new digit in place and increase the exponent.
59 float_decimal.exp += 1;
60
61 // Re-size the buffer to use the reserved leading byte.
62 const one_before = @intToPtr([*]u8, @ptrToInt(&float_decimal.digits[0]) - 1);
63 float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
64 float_decimal.digits[0] = '1';
65 return;
66 }
67
68 i -= 1;
69
70 const new_value = (float_decimal.digits[i] - '0' + 1) % 10;
71 float_decimal.digits[i] = new_value + '0';
72
73 // must continue rounding until non-9
74 if (new_value != 0) {
75 return;
76 }
77 }
78 }
79}
80
81/// Corrected Errol3 double to ASCII conversion.
82pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
83 const bits = @bitCast(u64, value);
84 const i = tableLowerBound(bits);
85 if (i < enum3.len and enum3[i] == bits) {
86 const data = enum3_data[i];
87 const digits = buffer[1 .. data.str.len + 1];
88 mem.copy(u8, digits, data.str);
89 return FloatDecimal{
90 .digits = digits,
91 .exp = data.exp,
92 };
93 }
94
95 return errol3u(value, buffer);
96}
97
98/// Uncorrected Errol3 double to ASCII conversion.
99fn errol3u(val: f64, buffer: []u8) FloatDecimal {
100 // check if in integer or fixed range
101 if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
102 return errolInt(val, buffer);
103 } else if (val >= 16.0 and val < 9.007199254740992e15) {
104 return errolFixed(val, buffer);
105 }
106
107 // normalize the midpoint
108
109 const e = math.frexp(val).exponent;
110 var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103));
111 if (exp < 20) {
112 exp = 20;
113 } else if (@intCast(usize, exp) >= lookup_table.len) {
114 exp = @intCast(i16, lookup_table.len - 1);
115 }
116
117 var mid = lookup_table[@intCast(usize, exp)];
118 mid = hpProd(mid, val);
119 const lten = lookup_table[@intCast(usize, exp)].val;
120
121 exp -= 307;
122
123 var ten: f64 = 1.0;
124
125 while (mid.val > 10.0 or (mid.val == 10.0 and mid.off >= 0.0)) {
126 exp += 1;
127 hpDiv10(&mid);
128 ten /= 10.0;
129 }
130
131 while (mid.val < 1.0 or (mid.val == 1.0 and mid.off < 0.0)) {
132 exp -= 1;
133 hpMul10(&mid);
134 ten *= 10.0;
135 }
136
137 // compute boundaries
138 var high = HP{
139 .val = mid.val,
140 .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
141 };
142 var low = HP{
143 .val = mid.val,
144 .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
145 };
146
147 hpNormalize(&high);
148 hpNormalize(&low);
149
150 // normalized boundaries
151
152 while (high.val > 10.0 or (high.val == 10.0 and high.off >= 0.0)) {
153 exp += 1;
154 hpDiv10(&high);
155 hpDiv10(&low);
156 }
157
158 while (high.val < 1.0 or (high.val == 1.0 and high.off < 0.0)) {
159 exp -= 1;
160 hpMul10(&high);
161 hpMul10(&low);
162 }
163
164 // digit generation
165
166 // We generate digits starting at index 1. If rounding a buffer later then it may be
167 // required to generate a preceding digit in some cases (9.999) in which case we use
168 // the 0-index for this extra digit.
169 var buf_index: usize = 1;
170 while (true) {
171 var hdig = @floatToInt(u8, math.floor(high.val));
172 if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1;
173
174 var ldig = @floatToInt(u8, math.floor(low.val));
175 if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1;
176
177 if (ldig != hdig) break;
178
179 buffer[buf_index] = hdig + '0';
180 buf_index += 1;
181 high.val -= @intToFloat(f64, hdig);
182 low.val -= @intToFloat(f64, ldig);
183 hpMul10(&high);
184 hpMul10(&low);
185 }
186
187 const tmp = (high.val + low.val) / 2.0;
188 var mdig = @floatToInt(u8, math.floor(tmp + 0.5));
189 if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
190
191 buffer[buf_index] = mdig + '0';
192 buf_index += 1;
193
194 return FloatDecimal{
195 .digits = buffer[1..buf_index],
196 .exp = exp,
197 };
198}
199
200fn tableLowerBound(k: u64) usize {
201 var i = enum3.len;
202 var j: usize = 0;
203
204 while (j < enum3.len) {
205 if (enum3[j] < k) {
206 j = 2 * j + 2;
207 } else {
208 i = j;
209 j = 2 * j + 1;
210 }
211 }
212
213 return i;
214}
215
216/// Compute the product of an HP number and a double.
217/// @in: The HP number.
218/// @val: The double.
219/// &returns: The HP number.
220fn hpProd(in: HP, val: f64) HP {
221 var hi: f64 = undefined;
222 var lo: f64 = undefined;
223 split(in.val, &hi, &lo);
224
225 var hi2: f64 = undefined;
226 var lo2: f64 = undefined;
227 split(val, &hi2, &lo2);
228
229 const p = in.val * val;
230 const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
231
232 return HP{
233 .val = p,
234 .off = in.off * val + e,
235 };
236}
237
238/// Split a double into two halves.
239/// @val: The double.
240/// @hi: The high bits.
241/// @lo: The low bits.
242fn split(val: f64, hi: *f64, lo: *f64) void {
243 hi.* = gethi(val);
244 lo.* = val - hi.*;
245}
246
247fn gethi(in: f64) f64 {
248 const bits = @bitCast(u64, in);
249 const new_bits = bits & 0xFFFFFFFFF8000000;
250 return @bitCast(f64, new_bits);
251}
252
253/// Normalize the number by factoring in the error.
254/// @hp: The float pair.
255fn hpNormalize(hp: *HP) void {
256 const val = hp.val;
257 hp.val += hp.off;
258 hp.off += val - hp.val;
259}
260
261/// Divide the high-precision number by ten.
262/// @hp: The high-precision number
263fn hpDiv10(hp: *HP) void {
264 var val = hp.val;
265
266 hp.val /= 10.0;
267 hp.off /= 10.0;
268
269 val -= hp.val * 8.0;
270 val -= hp.val * 2.0;
271
272 hp.off += val / 10.0;
273
274 hpNormalize(hp);
275}
276
277/// Multiply the high-precision number by ten.
278/// @hp: The high-precision number
279fn hpMul10(hp: *HP) void {
280 const val = hp.val;
281
282 hp.val *= 10.0;
283 hp.off *= 10.0;
284
285 var off = hp.val;
286 off -= val * 8.0;
287 off -= val * 2.0;
288
289 hp.off -= off;
290
291 hpNormalize(hp);
292}
293
294/// Integer conversion algorithm, guaranteed correct, optimal, and best.
295/// @val: The val.
296/// @buf: The output buffer.
297/// &return: The exponent.
298fn errolInt(val: f64, buffer: []u8) FloatDecimal {
299 const pow19 = u128(1e19);
300
301 assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
302
303 var mid = @floatToInt(u128, val);
304 var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
305 var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);
306
307 if (@bitCast(u64, val) & 0x1 != 0) {
308 high -= 1;
309 } else {
310 low -= 1;
311 }
312
313 var l64 = @intCast(u64, low % pow19);
314 const lf = @intCast(u64, (low / pow19) % pow19);
315
316 var h64 = @intCast(u64, high % pow19);
317 const hf = @intCast(u64, (high / pow19) % pow19);
318
319 if (lf != hf) {
320 l64 = lf;
321 h64 = hf;
322 mid = mid / (pow19 / 10);
323 }
324
325 var mi: i32 = mismatch10(l64, h64);
326 var x: u64 = 1;
327 {
328 var i: i32 = @boolToInt(lf == hf);
329 while (i < mi) : (i += 1) {
330 x *= 10;
331 }
332 }
333 const m64 = @truncate(u64, @divTrunc(mid, x));
334
335 if (lf != hf) mi += 19;
336
337 var buf_index = u64toa(m64, buffer) - 1;
338
339 if (mi != 0) {
340 buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
341 } else {
342 buf_index += 1;
343 }
344
345 return FloatDecimal{
346 .digits = buffer[0..buf_index],
347 .exp = @intCast(i32, buf_index) + mi,
348 };
349}
350
351/// Fixed point conversion algorithm, guaranteed correct, optimal, and best.
352/// @val: The val.
353/// @buf: The output buffer.
354/// &return: The exponent.
355fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
356 assert((val >= 16.0) and (val < 9.007199254740992e15));
357
358 const u = @floatToInt(u64, val);
359 const n = @intToFloat(f64, u);
360
361 var mid = val - n;
362 var lo = ((fpprev(val) - n) + mid) / 2.0;
363 var hi = ((fpnext(val) - n) + mid) / 2.0;
364
365 var buf_index = u64toa(u, buffer);
366 var exp = @intCast(i32, buf_index);
367 var j = buf_index;
368 buffer[j] = 0;
369
370 if (mid != 0.0) {
371 while (mid != 0.0) {
372 lo *= 10.0;
373 const ldig = @floatToInt(i32, lo);
374 lo -= @intToFloat(f64, ldig);
375
376 mid *= 10.0;
377 const mdig = @floatToInt(i32, mid);
378 mid -= @intToFloat(f64, mdig);
379
380 hi *= 10.0;
381 const hdig = @floatToInt(i32, hi);
382 hi -= @intToFloat(f64, hdig);
383
384 buffer[j] = @intCast(u8, mdig + '0');
385 j += 1;
386
387 if (hdig != ldig or j > 50) break;
388 }
389
390 if (mid > 0.5) {
391 buffer[j - 1] += 1;
392 } else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
393 buffer[j - 1] += 1;
394 }
395 } else {
396 while (buffer[j - 1] == '0') {
397 buffer[j - 1] = 0;
398 j -= 1;
399 }
400 }
401
402 buffer[j] = 0;
403
404 return FloatDecimal{
405 .digits = buffer[0..j],
406 .exp = exp,
407 };
408}
409
410fn fpnext(val: f64) f64 {
411 return @bitCast(f64, @bitCast(u64, val) +% 1);
412}
413
414fn fpprev(val: f64) f64 {
415 return @bitCast(f64, @bitCast(u64, val) -% 1);
416}
417
418pub const c_digits_lut = []u8{
419 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
420 '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
421 '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
422 '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7',
423 '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
424 '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
425 '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8',
426 '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5',
427 '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2',
428 '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
429 '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6',
430 '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
431 '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0',
432 '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7',
433 '9', '8', '9', '9',
434};
435
436fn u64toa(value_param: u64, buffer: []u8) usize {
437 var value = value_param;
438 const kTen8: u64 = 100000000;
439 const kTen9: u64 = kTen8 * 10;
440 const kTen10: u64 = kTen8 * 100;
441 const kTen11: u64 = kTen8 * 1000;
442 const kTen12: u64 = kTen8 * 10000;
443 const kTen13: u64 = kTen8 * 100000;
444 const kTen14: u64 = kTen8 * 1000000;
445 const kTen15: u64 = kTen8 * 10000000;
446 const kTen16: u64 = kTen8 * kTen8;
447
448 var buf_index: usize = 0;
449
450 if (value < kTen8) {
451 const v = @intCast(u32, value);
452 if (v < 10000) {
453 const d1: u32 = (v / 100) << 1;
454 const d2: u32 = (v % 100) << 1;
455
456 if (v >= 1000) {
457 buffer[buf_index] = c_digits_lut[d1];
458 buf_index += 1;
459 }
460 if (v >= 100) {
461 buffer[buf_index] = c_digits_lut[d1 + 1];
462 buf_index += 1;
463 }
464 if (v >= 10) {
465 buffer[buf_index] = c_digits_lut[d2];
466 buf_index += 1;
467 }
468 buffer[buf_index] = c_digits_lut[d2 + 1];
469 buf_index += 1;
470 } else {
471 // value = bbbbcccc
472 const b: u32 = v / 10000;
473 const c: u32 = v % 10000;
474
475 const d1: u32 = (b / 100) << 1;
476 const d2: u32 = (b % 100) << 1;
477
478 const d3: u32 = (c / 100) << 1;
479 const d4: u32 = (c % 100) << 1;
480
481 if (value >= 10000000) {
482 buffer[buf_index] = c_digits_lut[d1];
483 buf_index += 1;
484 }
485 if (value >= 1000000) {
486 buffer[buf_index] = c_digits_lut[d1 + 1];
487 buf_index += 1;
488 }
489 if (value >= 100000) {
490 buffer[buf_index] = c_digits_lut[d2];
491 buf_index += 1;
492 }
493 buffer[buf_index] = c_digits_lut[d2 + 1];
494 buf_index += 1;
495
496 buffer[buf_index] = c_digits_lut[d3];
497 buf_index += 1;
498 buffer[buf_index] = c_digits_lut[d3 + 1];
499 buf_index += 1;
500 buffer[buf_index] = c_digits_lut[d4];
501 buf_index += 1;
502 buffer[buf_index] = c_digits_lut[d4 + 1];
503 buf_index += 1;
504 }
505 } else if (value < kTen16) {
506 const v0: u32 = @intCast(u32, value / kTen8);
507 const v1: u32 = @intCast(u32, value % kTen8);
508
509 const b0: u32 = v0 / 10000;
510 const c0: u32 = v0 % 10000;
511
512 const d1: u32 = (b0 / 100) << 1;
513 const d2: u32 = (b0 % 100) << 1;
514
515 const d3: u32 = (c0 / 100) << 1;
516 const d4: u32 = (c0 % 100) << 1;
517
518 const b1: u32 = v1 / 10000;
519 const c1: u32 = v1 % 10000;
520
521 const d5: u32 = (b1 / 100) << 1;
522 const d6: u32 = (b1 % 100) << 1;
523
524 const d7: u32 = (c1 / 100) << 1;
525 const d8: u32 = (c1 % 100) << 1;
526
527 if (value >= kTen15) {
528 buffer[buf_index] = c_digits_lut[d1];
529 buf_index += 1;
530 }
531 if (value >= kTen14) {
532 buffer[buf_index] = c_digits_lut[d1 + 1];
533 buf_index += 1;
534 }
535 if (value >= kTen13) {
536 buffer[buf_index] = c_digits_lut[d2];
537 buf_index += 1;
538 }
539 if (value >= kTen12) {
540 buffer[buf_index] = c_digits_lut[d2 + 1];
541 buf_index += 1;
542 }
543 if (value >= kTen11) {
544 buffer[buf_index] = c_digits_lut[d3];
545 buf_index += 1;
546 }
547 if (value >= kTen10) {
548 buffer[buf_index] = c_digits_lut[d3 + 1];
549 buf_index += 1;
550 }
551 if (value >= kTen9) {
552 buffer[buf_index] = c_digits_lut[d4];
553 buf_index += 1;
554 }
555 if (value >= kTen8) {
556 buffer[buf_index] = c_digits_lut[d4 + 1];
557 buf_index += 1;
558 }
559
560 buffer[buf_index] = c_digits_lut[d5];
561 buf_index += 1;
562 buffer[buf_index] = c_digits_lut[d5 + 1];
563 buf_index += 1;
564 buffer[buf_index] = c_digits_lut[d6];
565 buf_index += 1;
566 buffer[buf_index] = c_digits_lut[d6 + 1];
567 buf_index += 1;
568 buffer[buf_index] = c_digits_lut[d7];
569 buf_index += 1;
570 buffer[buf_index] = c_digits_lut[d7 + 1];
571 buf_index += 1;
572 buffer[buf_index] = c_digits_lut[d8];
573 buf_index += 1;
574 buffer[buf_index] = c_digits_lut[d8 + 1];
575 buf_index += 1;
576 } else {
577 const a = @intCast(u32, value / kTen16); // 1 to 1844
578 value %= kTen16;
579
580 if (a < 10) {
581 buffer[buf_index] = '0' + @intCast(u8, a);
582 buf_index += 1;
583 } else if (a < 100) {
584 const i: u32 = a << 1;
585 buffer[buf_index] = c_digits_lut[i];
586 buf_index += 1;
587 buffer[buf_index] = c_digits_lut[i + 1];
588 buf_index += 1;
589 } else if (a < 1000) {
590 buffer[buf_index] = '0' + @intCast(u8, a / 100);
591 buf_index += 1;
592
593 const i: u32 = (a % 100) << 1;
594 buffer[buf_index] = c_digits_lut[i];
595 buf_index += 1;
596 buffer[buf_index] = c_digits_lut[i + 1];
597 buf_index += 1;
598 } else {
599 const i: u32 = (a / 100) << 1;
600 const j: u32 = (a % 100) << 1;
601 buffer[buf_index] = c_digits_lut[i];
602 buf_index += 1;
603 buffer[buf_index] = c_digits_lut[i + 1];
604 buf_index += 1;
605 buffer[buf_index] = c_digits_lut[j];
606 buf_index += 1;
607 buffer[buf_index] = c_digits_lut[j + 1];
608 buf_index += 1;
609 }
610
611 const v0 = @intCast(u32, value / kTen8);
612 const v1 = @intCast(u32, value % kTen8);
613
614 const b0: u32 = v0 / 10000;
615 const c0: u32 = v0 % 10000;
616
617 const d1: u32 = (b0 / 100) << 1;
618 const d2: u32 = (b0 % 100) << 1;
619
620 const d3: u32 = (c0 / 100) << 1;
621 const d4: u32 = (c0 % 100) << 1;
622
623 const b1: u32 = v1 / 10000;
624 const c1: u32 = v1 % 10000;
625
626 const d5: u32 = (b1 / 100) << 1;
627 const d6: u32 = (b1 % 100) << 1;
628
629 const d7: u32 = (c1 / 100) << 1;
630 const d8: u32 = (c1 % 100) << 1;
631
632 buffer[buf_index] = c_digits_lut[d1];
633 buf_index += 1;
634 buffer[buf_index] = c_digits_lut[d1 + 1];
635 buf_index += 1;
636 buffer[buf_index] = c_digits_lut[d2];
637 buf_index += 1;
638 buffer[buf_index] = c_digits_lut[d2 + 1];
639 buf_index += 1;
640 buffer[buf_index] = c_digits_lut[d3];
641 buf_index += 1;
642 buffer[buf_index] = c_digits_lut[d3 + 1];
643 buf_index += 1;
644 buffer[buf_index] = c_digits_lut[d4];
645 buf_index += 1;
646 buffer[buf_index] = c_digits_lut[d4 + 1];
647 buf_index += 1;
648 buffer[buf_index] = c_digits_lut[d5];
649 buf_index += 1;
650 buffer[buf_index] = c_digits_lut[d5 + 1];
651 buf_index += 1;
652 buffer[buf_index] = c_digits_lut[d6];
653 buf_index += 1;
654 buffer[buf_index] = c_digits_lut[d6 + 1];
655 buf_index += 1;
656 buffer[buf_index] = c_digits_lut[d7];
657 buf_index += 1;
658 buffer[buf_index] = c_digits_lut[d7 + 1];
659 buf_index += 1;
660 buffer[buf_index] = c_digits_lut[d8];
661 buf_index += 1;
662 buffer[buf_index] = c_digits_lut[d8 + 1];
663 buf_index += 1;
664 }
665
666 return buf_index;
667}
668
669fn fpeint(from: f64) u128 {
670 const bits = @bitCast(u64, from);
671 assert((bits & ((1 << 52) - 1)) == 0);
672
673 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
674}
675
676/// Given two different integers with the same length in terms of the number
677/// of decimal digits, index the digits from the right-most position starting
678/// from zero, find the first index where the digits in the two integers
679/// divergent starting from the highest index.
680/// @a: Integer a.
681/// @b: Integer b.
682/// &returns: An index within [0, 19).
683fn mismatch10(a: u64, b: u64) i32 {
684 const pow10 = 10000000000;
685 const af = a / pow10;
686 const bf = b / pow10;
687
688 var i: i32 = 0;
689 var a_copy = a;
690 var b_copy = b;
691
692 if (af != bf) {
693 i = 10;
694 a_copy = af;
695 b_copy = bf;
696 }
697
698 while (true) : (i += 1) {
699 a_copy /= 10;
700 b_copy /= 10;
701
702 if (a_copy == b_copy) return i;
703 }
704}
std/fmt/index.zig deleted-1441
...@@ -1,1441 +0,0 @@
1const std = @import("../index.zig");
2const math = std.math;
3const debug = std.debug;
4const assert = debug.assert;
5const testing = std.testing;
6const mem = std.mem;
7const builtin = @import("builtin");
8const errol = @import("errol/index.zig");
9const lossyCast = std.math.lossyCast;
10
11const max_int_digits = 65;
12
13/// Renders fmt string with args, calling output with slices of bytes.
14/// If `output` returns an error, the error is returned from `format` and
15/// `output` is not called again.
16pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
17 const State = enum {
18 Start,
19 OpenBrace,
20 CloseBrace,
21 FormatString,
22 Pointer,
23 };
24
25 comptime var start_index = 0;
26 comptime var state = State.Start;
27 comptime var next_arg = 0;
28
29 inline for (fmt) |c, i| {
30 switch (state) {
31 State.Start => switch (c) {
32 '{' => {
33 if (start_index < i) {
34 try output(context, fmt[start_index..i]);
35 }
36 start_index = i;
37 state = State.OpenBrace;
38 },
39
40 '}' => {
41 if (start_index < i) {
42 try output(context, fmt[start_index..i]);
43 }
44 state = State.CloseBrace;
45 },
46 else => {},
47 },
48 State.OpenBrace => switch (c) {
49 '{' => {
50 state = State.Start;
51 start_index = i;
52 },
53 '}' => {
54 try formatType(args[next_arg], fmt[0..0], context, Errors, output);
55 next_arg += 1;
56 state = State.Start;
57 start_index = i + 1;
58 },
59 '*' => state = State.Pointer,
60 else => {
61 state = State.FormatString;
62 },
63 },
64 State.CloseBrace => switch (c) {
65 '}' => {
66 state = State.Start;
67 start_index = i;
68 },
69 else => @compileError("Single '}' encountered in format string"),
70 },
71 State.FormatString => switch (c) {
72 '}' => {
73 const s = start_index + 1;
74 try formatType(args[next_arg], fmt[s..i], context, Errors, output);
75 next_arg += 1;
76 state = State.Start;
77 start_index = i + 1;
78 },
79 else => {},
80 },
81 State.Pointer => switch (c) {
82 '}' => {
83 try output(context, @typeName(@typeOf(args[next_arg]).Child));
84 try output(context, "@");
85 try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);
86 next_arg += 1;
87 state = State.Start;
88 start_index = i + 1;
89 },
90 else => @compileError("Unexpected format character after '*'"),
91 },
92 }
93 }
94 comptime {
95 if (args.len != next_arg) {
96 @compileError("Unused arguments");
97 }
98 if (state != State.Start) {
99 @compileError("Incomplete format string: " ++ fmt);
100 }
101 }
102 if (start_index < fmt.len) {
103 try output(context, fmt[start_index..]);
104 }
105}
106
107pub fn formatType(
108 value: var,
109 comptime fmt: []const u8,
110 context: var,
111 comptime Errors: type,
112 output: fn (@typeOf(context), []const u8) Errors!void,
113) Errors!void {
114 const T = @typeOf(value);
115 if (T == anyerror) {
116 try output(context, "error.");
117 return output(context, @errorName(value));
118 }
119 switch (@typeInfo(T)) {
120 builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
121 return formatValue(value, fmt, context, Errors, output);
122 },
123 builtin.TypeId.Void => {
124 return output(context, "void");
125 },
126 builtin.TypeId.Bool => {
127 return output(context, if (value) "true" else "false");
128 },
129 builtin.TypeId.Optional => {
130 if (value) |payload| {
131 return formatType(payload, fmt, context, Errors, output);
132 } else {
133 return output(context, "null");
134 }
135 },
136 builtin.TypeId.ErrorUnion => {
137 if (value) |payload| {
138 return formatType(payload, fmt, context, Errors, output);
139 } else |err| {
140 return formatType(err, fmt, context, Errors, output);
141 }
142 },
143 builtin.TypeId.ErrorSet => {
144 try output(context, "error.");
145 return output(context, @errorName(value));
146 },
147 builtin.TypeId.Promise => {
148 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
149 },
150 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
151 const has_cust_fmt = comptime cf: {
152 const info = @typeInfo(T);
153 const defs = switch (info) {
154 builtin.TypeId.Struct => |s| s.defs,
155 builtin.TypeId.Union => |u| u.defs,
156 builtin.TypeId.Enum => |e| e.defs,
157 else => unreachable,
158 };
159
160 for (defs) |def| {
161 if (mem.eql(u8, def.name, "format")) {
162 break :cf true;
163 }
164 }
165 break :cf false;
166 };
167 if (has_cust_fmt) return value.format(fmt, context, Errors, output);
168
169 try output(context, @typeName(T));
170 switch (comptime @typeId(T)) {
171 builtin.TypeId.Enum => {
172 try output(context, ".");
173 try formatType(@tagName(value), "", context, Errors, output);
174 return;
175 },
176 builtin.TypeId.Struct => {
177 comptime var field_i = 0;
178 inline while (field_i < @memberCount(T)) : (field_i += 1) {
179 if (field_i == 0) {
180 try output(context, "{ .");
181 } else {
182 try output(context, ", .");
183 }
184 try output(context, @memberName(T, field_i));
185 try output(context, " = ");
186 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output);
187 }
188 try output(context, " }");
189 },
190 builtin.TypeId.Union => {
191 const info = @typeInfo(T).Union;
192 if (info.tag_type) |UnionTagType| {
193 try output(context, "{ .");
194 try output(context, @tagName(UnionTagType(value)));
195 try output(context, " = ");
196 inline for (info.fields) |u_field| {
197 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
198 try formatType(@field(value, u_field.name), "", context, Errors, output);
199 }
200 }
201 try output(context, " }");
202 } else {
203 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
204 }
205 },
206 else => unreachable,
207 }
208 return;
209 },
210 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
211 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
212 builtin.TypeId.Array => |info| {
213 if (info.child == u8) {
214 return formatText(value, fmt, context, Errors, output);
215 }
216 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
217 },
218 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
219 return formatType(value.*, fmt, context, Errors, output);
220 },
221 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
222 },
223 builtin.TypeInfo.Pointer.Size.Many => {
224 if (ptr_info.child == u8) {
225 if (fmt.len > 0 and fmt[0] == 's') {
226 const len = std.cstr.len(value);
227 return formatText(value[0..len], fmt, context, Errors, output);
228 }
229 }
230 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
231 },
232 builtin.TypeInfo.Pointer.Size.Slice => {
233 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
234 return formatText(value, fmt, context, Errors, output);
235 }
236 const casted_value = ([]const u8)(value);
237 return output(context, casted_value);
238 },
239 builtin.TypeInfo.Pointer.Size.C => {
240 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
241 },
242 },
243 builtin.TypeId.Array => |info| {
244 if (info.child == u8) {
245 return formatText(value, fmt, context, Errors, output);
246 }
247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
248 },
249 builtin.TypeId.Fn => {
250 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
251 },
252 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
253 }
254}
255
256fn formatValue(
257 value: var,
258 comptime fmt: []const u8,
259 context: var,
260 comptime Errors: type,
261 output: fn (@typeOf(context), []const u8) Errors!void,
262) Errors!void {
263 if (fmt.len > 0) {
264 if (fmt[0] == 'B') {
265 comptime var width: ?usize = null;
266 if (fmt.len > 1) {
267 if (fmt[1] == 'i') {
268 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
269 return formatBytes(value, width, 1024, context, Errors, output);
270 }
271 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
272 }
273 return formatBytes(value, width, 1000, context, Errors, output);
274 }
275 }
276
277 const T = @typeOf(value);
278 switch (@typeId(T)) {
279 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
280 builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
281 builtin.TypeId.ComptimeInt => {
282 const Int = math.IntFittingRange(value, value);
283 return formatIntValue(Int(value), fmt, context, Errors, output);
284 },
285 else => comptime unreachable,
286 }
287}
288
289pub fn formatIntValue(
290 value: var,
291 comptime fmt: []const u8,
292 context: var,
293 comptime Errors: type,
294 output: fn (@typeOf(context), []const u8) Errors!void,
295) Errors!void {
296 comptime var radix = 10;
297 comptime var uppercase = false;
298 comptime var width = 0;
299 if (fmt.len > 0) {
300 switch (fmt[0]) {
301 'c' => {
302 if (@typeOf(value).bit_count <= 8) {
303 if (fmt.len > 1)
304 @compileError("Unknown format character: " ++ []u8{fmt[1]});
305 return formatAsciiChar(u8(value), context, Errors, output);
306 }
307 },
308 'b' => {
309 radix = 2;
310 uppercase = false;
311 width = 0;
312 },
313 'd' => {
314 radix = 10;
315 uppercase = false;
316 width = 0;
317 },
318 'x' => {
319 radix = 16;
320 uppercase = false;
321 width = 0;
322 },
323 'X' => {
324 radix = 16;
325 uppercase = true;
326 width = 0;
327 },
328 else => @compileError("Unknown format character: " ++ []u8{fmt[0]}),
329 }
330 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
331 }
332 return formatInt(value, radix, uppercase, width, context, Errors, output);
333}
334
335fn formatFloatValue(
336 value: var,
337 comptime fmt: []const u8,
338 context: var,
339 comptime Errors: type,
340 output: fn (@typeOf(context), []const u8) Errors!void,
341) Errors!void {
342 comptime var width: ?usize = null;
343 comptime var float_fmt = 'e';
344 if (fmt.len > 0) {
345 float_fmt = fmt[0];
346 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
347 }
348
349 switch (float_fmt) {
350 'e' => try formatFloatScientific(value, width, context, Errors, output),
351 '.' => try formatFloatDecimal(value, width, context, Errors, output),
352 else => @compileError("Unknown format character: " ++ []u8{float_fmt}),
353 }
354}
355
356pub fn formatText(
357 bytes: []const u8,
358 comptime fmt: []const u8,
359 context: var,
360 comptime Errors: type,
361 output: fn (@typeOf(context), []const u8) Errors!void,
362) Errors!void {
363 if (fmt.len > 0) {
364 if (fmt[0] == 's') {
365 comptime var width = 0;
366 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
367 return formatBuf(bytes, width, context, Errors, output);
368 } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {
369 for (bytes) |c| {
370 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
371 }
372 return;
373 } else @compileError("Unknown format character: " ++ []u8{fmt[0]});
374 }
375 return output(context, bytes);
376}
377
378pub fn formatAsciiChar(
379 c: u8,
380 context: var,
381 comptime Errors: type,
382 output: fn (@typeOf(context), []const u8) Errors!void,
383) Errors!void {
384 return output(context, (*[1]u8)(&c)[0..]);
385}
386
387pub fn formatBuf(
388 buf: []const u8,
389 width: usize,
390 context: var,
391 comptime Errors: type,
392 output: fn (@typeOf(context), []const u8) Errors!void,
393) Errors!void {
394 try output(context, buf);
395
396 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
397 const pad_byte: u8 = ' ';
398 while (leftover_padding > 0) : (leftover_padding -= 1) {
399 try output(context, (*[1]u8)(&pad_byte)[0..1]);
400 }
401}
402
403// Print a float in scientific notation to the specified precision. Null uses full precision.
404// It should be the case that every full precision, printed value can be re-parsed back to the
405// same type unambiguously.
406pub fn formatFloatScientific(
407 value: var,
408 maybe_precision: ?usize,
409 context: var,
410 comptime Errors: type,
411 output: fn (@typeOf(context), []const u8) Errors!void,
412) Errors!void {
413 var x = @floatCast(f64, value);
414
415 // Errol doesn't handle these special cases.
416 if (math.signbit(x)) {
417 try output(context, "-");
418 x = -x;
419 }
420
421 if (math.isNan(x)) {
422 return output(context, "nan");
423 }
424 if (math.isPositiveInf(x)) {
425 return output(context, "inf");
426 }
427 if (x == 0.0) {
428 try output(context, "0");
429
430 if (maybe_precision) |precision| {
431 if (precision != 0) {
432 try output(context, ".");
433 var i: usize = 0;
434 while (i < precision) : (i += 1) {
435 try output(context, "0");
436 }
437 }
438 } else {
439 try output(context, ".0");
440 }
441
442 try output(context, "e+00");
443 return;
444 }
445
446 var buffer: [32]u8 = undefined;
447 var float_decimal = errol.errol3(x, buffer[0..]);
448
449 if (maybe_precision) |precision| {
450 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
451
452 try output(context, float_decimal.digits[0..1]);
453
454 // {e0} case prints no `.`
455 if (precision != 0) {
456 try output(context, ".");
457
458 var printed: usize = 0;
459 if (float_decimal.digits.len > 1) {
460 const num_digits = math.min(float_decimal.digits.len, precision + 1);
461 try output(context, float_decimal.digits[1..num_digits]);
462 printed += num_digits - 1;
463 }
464
465 while (printed < precision) : (printed += 1) {
466 try output(context, "0");
467 }
468 }
469 } else {
470 try output(context, float_decimal.digits[0..1]);
471 try output(context, ".");
472 if (float_decimal.digits.len > 1) {
473 const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
474
475 try output(context, float_decimal.digits[1..num_digits]);
476 } else {
477 try output(context, "0");
478 }
479 }
480
481 try output(context, "e");
482 const exp = float_decimal.exp - 1;
483
484 if (exp >= 0) {
485 try output(context, "+");
486 if (exp > -10 and exp < 10) {
487 try output(context, "0");
488 }
489 try formatInt(exp, 10, false, 0, context, Errors, output);
490 } else {
491 try output(context, "-");
492 if (exp > -10 and exp < 10) {
493 try output(context, "0");
494 }
495 try formatInt(-exp, 10, false, 0, context, Errors, output);
496 }
497}
498
499// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
500// By default floats are printed at full precision (no rounding).
501pub fn formatFloatDecimal(
502 value: var,
503 maybe_precision: ?usize,
504 context: var,
505 comptime Errors: type,
506 output: fn (@typeOf(context), []const u8) Errors!void,
507) Errors!void {
508 var x = f64(value);
509
510 // Errol doesn't handle these special cases.
511 if (math.signbit(x)) {
512 try output(context, "-");
513 x = -x;
514 }
515
516 if (math.isNan(x)) {
517 return output(context, "nan");
518 }
519 if (math.isPositiveInf(x)) {
520 return output(context, "inf");
521 }
522 if (x == 0.0) {
523 try output(context, "0");
524
525 if (maybe_precision) |precision| {
526 if (precision != 0) {
527 try output(context, ".");
528 var i: usize = 0;
529 while (i < precision) : (i += 1) {
530 try output(context, "0");
531 }
532 } else {
533 try output(context, ".0");
534 }
535 } else {
536 try output(context, "0");
537 }
538
539 return;
540 }
541
542 // non-special case, use errol3
543 var buffer: [32]u8 = undefined;
544 var float_decimal = errol.errol3(x, buffer[0..]);
545
546 if (maybe_precision) |precision| {
547 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
548
549 // exp < 0 means the leading is always 0 as errol result is normalized.
550 var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
551
552 // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
553 var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
554
555 if (num_digits_whole > 0) {
556 // We may have to zero pad, for instance 1e4 requires zero padding.
557 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
558
559 var i = num_digits_whole_no_pad;
560 while (i < num_digits_whole) : (i += 1) {
561 try output(context, "0");
562 }
563 } else {
564 try output(context, "0");
565 }
566
567 // {.0} special case doesn't want a trailing '.'
568 if (precision == 0) {
569 return;
570 }
571
572 try output(context, ".");
573
574 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
575 var printed: usize = 0;
576
577 // Zero-fill until we reach significant digits or run out of precision.
578 if (float_decimal.exp <= 0) {
579 const zero_digit_count = @intCast(usize, -float_decimal.exp);
580 const zeros_to_print = math.min(zero_digit_count, precision);
581
582 var i: usize = 0;
583 while (i < zeros_to_print) : (i += 1) {
584 try output(context, "0");
585 printed += 1;
586 }
587
588 if (printed >= precision) {
589 return;
590 }
591 }
592
593 // Remaining fractional portion, zero-padding if insufficient.
594 assert(precision >= printed);
595 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
596 try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
597 return;
598 } else {
599 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
600 printed += float_decimal.digits.len - num_digits_whole_no_pad;
601
602 while (printed < precision) : (printed += 1) {
603 try output(context, "0");
604 }
605 }
606 } else {
607 // exp < 0 means the leading is always 0 as errol result is normalized.
608 var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
609
610 // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
611 var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
612
613 if (num_digits_whole > 0) {
614 // We may have to zero pad, for instance 1e4 requires zero padding.
615 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
616
617 var i = num_digits_whole_no_pad;
618 while (i < num_digits_whole) : (i += 1) {
619 try output(context, "0");
620 }
621 } else {
622 try output(context, "0");
623 }
624
625 // Omit `.` if no fractional portion
626 if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
627 return;
628 }
629
630 try output(context, ".");
631
632 // Zero-fill until we reach significant digits or run out of precision.
633 if (float_decimal.exp < 0) {
634 const zero_digit_count = @intCast(usize, -float_decimal.exp);
635
636 var i: usize = 0;
637 while (i < zero_digit_count) : (i += 1) {
638 try output(context, "0");
639 }
640 }
641
642 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
643 }
644}
645
646pub fn formatBytes(
647 value: var,
648 width: ?usize,
649 comptime radix: usize,
650 context: var,
651 comptime Errors: type,
652 output: fn (@typeOf(context), []const u8) Errors!void,
653) Errors!void {
654 if (value == 0) {
655 return output(context, "0B");
656 }
657
658 const mags_si = " kMGTPEZY";
659 const mags_iec = " KMGTPEZY";
660 const magnitude = switch (radix) {
661 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
662 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
663 else => unreachable,
664 };
665 const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
666 const suffix = switch (radix) {
667 1000 => mags_si[magnitude],
668 1024 => mags_iec[magnitude],
669 else => unreachable,
670 };
671
672 try formatFloatDecimal(new_value, width, context, Errors, output);
673
674 if (suffix == ' ') {
675 return output(context, "B");
676 }
677
678 const buf = switch (radix) {
679 1000 => []u8{ suffix, 'B' },
680 1024 => []u8{ suffix, 'i', 'B' },
681 else => unreachable,
682 };
683 return output(context, buf);
684}
685
686pub fn formatInt(
687 value: var,
688 base: u8,
689 uppercase: bool,
690 width: usize,
691 context: var,
692 comptime Errors: type,
693 output: fn (@typeOf(context), []const u8) Errors!void,
694) Errors!void {
695 if (@typeOf(value).is_signed) {
696 return formatIntSigned(value, base, uppercase, width, context, Errors, output);
697 } else {
698 return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
699 }
700}
701
702fn formatIntSigned(
703 value: var,
704 base: u8,
705 uppercase: bool,
706 width: usize,
707 context: var,
708 comptime Errors: type,
709 output: fn (@typeOf(context), []const u8) Errors!void,
710) Errors!void {
711 const uint = @IntType(false, @typeOf(value).bit_count);
712 if (value < 0) {
713 const minus_sign: u8 = '-';
714 try output(context, (*[1]u8)(&minus_sign)[0..]);
715 const new_value = @intCast(uint, -(value + 1)) + 1;
716 const new_width = if (width == 0) 0 else (width - 1);
717 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
718 } else if (width == 0) {
719 return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
720 } else {
721 const plus_sign: u8 = '+';
722 try output(context, (*[1]u8)(&plus_sign)[0..]);
723 const new_value = @intCast(uint, value);
724 const new_width = if (width == 0) 0 else (width - 1);
725 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
726 }
727}
728
729fn formatIntUnsigned(
730 value: var,
731 base: u8,
732 uppercase: bool,
733 width: usize,
734 context: var,
735 comptime Errors: type,
736 output: fn (@typeOf(context), []const u8) Errors!void,
737) Errors!void {
738 // max_int_digits accounts for the minus sign. when printing an unsigned
739 // number we don't need to do that.
740 var buf: [max_int_digits - 1]u8 = undefined;
741 const min_int_bits = comptime math.max(@typeOf(value).bit_count, @typeOf(base).bit_count);
742 const MinInt = @IntType(@typeOf(value).is_signed, min_int_bits);
743 var a: MinInt = value;
744 var index: usize = buf.len;
745
746 while (true) {
747 const digit = a % base;
748 index -= 1;
749 buf[index] = digitToChar(@intCast(u8, digit), uppercase);
750 a /= base;
751 if (a == 0) break;
752 }
753
754 const digits_buf = buf[index..];
755 const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
756
757 if (padding > index) {
758 const zero_byte: u8 = '0';
759 var leftover_padding = padding - index;
760 while (true) {
761 try output(context, (*[1]u8)(&zero_byte)[0..]);
762 leftover_padding -= 1;
763 if (leftover_padding == 0) break;
764 }
765 mem.set(u8, buf[0..index], '0');
766 return output(context, buf);
767 } else {
768 const padded_buf = buf[index - padding ..];
769 mem.set(u8, padded_buf[0..padding], '0');
770 return output(context, padded_buf);
771 }
772}
773
774pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
775 var context = FormatIntBuf{
776 .out_buf = out_buf,
777 .index = 0,
778 };
779 formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
780 return context.index;
781}
782const FormatIntBuf = struct {
783 out_buf: []u8,
784 index: usize,
785};
786fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
787 mem.copy(u8, context.out_buf[context.index..], bytes);
788 context.index += bytes.len;
789}
790
791pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
792 if (!T.is_signed) return parseUnsigned(T, buf, radix);
793 if (buf.len == 0) return T(0);
794 if (buf[0] == '-') {
795 return math.negate(try parseUnsigned(T, buf[1..], radix));
796 } else if (buf[0] == '+') {
797 return parseUnsigned(T, buf[1..], radix);
798 } else {
799 return parseUnsigned(T, buf, radix);
800 }
801}
802
803test "fmt.parseInt" {
804 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
805 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
806 testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
807 testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
808 testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
809 testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
810 testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
811}
812
813const ParseUnsignedError = error{
814 /// The result cannot fit in the type specified
815 Overflow,
816
817 /// The input had a byte that was not a digit
818 InvalidCharacter,
819};
820
821pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
822 var x: T = 0;
823
824 for (buf) |c| {
825 const digit = try charToDigit(c, radix);
826
827 if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
828 x = try math.add(T, x, try math.cast(T, digit));
829 }
830
831 return x;
832}
833
834test "fmt.parseUnsigned" {
835 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
836 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
837 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
838
839 testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
840 testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
841
842 testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
843
844 testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
845 testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
846
847 testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
848 testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
849
850 testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
851
852 // these numbers should fit even though the radix itself doesn't fit in the destination type
853 testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
854 testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
855 testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
856 testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
857 testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
858 testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
859}
860
861pub const parseFloat = @import("parse_float.zig").parseFloat;
862
863test "fmt.parseFloat" {
864 _ = @import("parse_float.zig");
865}
866
867pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
868 const value = switch (c) {
869 '0'...'9' => c - '0',
870 'A'...'Z' => c - 'A' + 10,
871 'a'...'z' => c - 'a' + 10,
872 else => return error.InvalidCharacter,
873 };
874
875 if (value >= radix) return error.InvalidCharacter;
876
877 return value;
878}
879
880fn digitToChar(digit: u8, uppercase: bool) u8 {
881 return switch (digit) {
882 0...9 => digit + '0',
883 10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
884 else => unreachable,
885 };
886}
887
888const BufPrintContext = struct {
889 remaining: []u8,
890};
891
892fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
893 if (context.remaining.len < bytes.len) return error.BufferTooSmall;
894 mem.copy(u8, context.remaining, bytes);
895 context.remaining = context.remaining[bytes.len..];
896}
897
898pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
899 var context = BufPrintContext{ .remaining = buf };
900 try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
901 return buf[0 .. buf.len - context.remaining.len];
902}
903
904pub const AllocPrintError = error{OutOfMemory};
905
906pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) AllocPrintError![]u8 {
907 var size: usize = 0;
908 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
909 const buf = try allocator.alloc(u8, size);
910 return bufPrint(buf, fmt, args) catch |err| switch (err) {
911 error.BufferTooSmall => unreachable, // we just counted the size above
912 };
913}
914
915fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
916 size.* += bytes.len;
917}
918
919test "buf print int" {
920 var buffer: [max_int_digits]u8 = undefined;
921 const buf = buffer[0..];
922 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
923 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
924 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
925 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
926
927 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
928
929 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
930 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
931 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
932
933 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
934 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
935}
936
937fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 {
938 return buf[0..formatIntBuf(buf, value, base, uppercase, width)];
939}
940
941test "parse u64 digit too big" {
942 _ = parseUnsigned(u64, "123a", 10) catch |err| {
943 if (err == error.InvalidCharacter) return;
944 unreachable;
945 };
946 unreachable;
947}
948
949test "parse unsigned comptime" {
950 comptime {
951 testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
952 }
953}
954
955test "fmt.format" {
956 {
957 const value: ?i32 = 1234;
958 try testFmt("optional: 1234\n", "optional: {}\n", value);
959 }
960 {
961 const value: ?i32 = null;
962 try testFmt("optional: null\n", "optional: {}\n", value);
963 }
964 {
965 const value: anyerror!i32 = 1234;
966 try testFmt("error union: 1234\n", "error union: {}\n", value);
967 }
968 {
969 const value: anyerror!i32 = error.InvalidChar;
970 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
971 }
972 {
973 const value: u3 = 0b101;
974 try testFmt("u3: 5\n", "u3: {}\n", value);
975 }
976 {
977 const value: u8 = 'a';
978 try testFmt("u8: a\n", "u8: {c}\n", value);
979 }
980 {
981 const value: u8 = 0b1100;
982 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
983 }
984 {
985 var buf1: [32]u8 = undefined;
986 var context = BufPrintContext{ .remaining = buf1[0..] };
987 try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite);
988 var res = buf1[0 .. buf1.len - context.remaining.len];
989 testing.expect(mem.eql(u8, res, "1234"));
990
991 context = BufPrintContext{ .remaining = buf1[0..] };
992 try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
993 res = buf1[0 .. buf1.len - context.remaining.len];
994 testing.expect(mem.eql(u8, res, "a"));
995
996 context = BufPrintContext{ .remaining = buf1[0..] };
997 try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
998 res = buf1[0 .. buf1.len - context.remaining.len];
999 testing.expect(mem.eql(u8, res, "1100"));
1000 }
1001 {
1002 const value: [3]u8 = "abc";
1003 try testFmt("array: abc\n", "array: {}\n", value);
1004 try testFmt("array: abc\n", "array: {}\n", &value);
1005
1006 var buf: [100]u8 = undefined;
1007 try testFmt(
1008 try bufPrint(buf[0..], "array: [3]u8@{x}\n", @ptrToInt(&value)),
1009 "array: {*}\n",
1010 &value,
1011 );
1012 }
1013 {
1014 const value: []const u8 = "abc";
1015 try testFmt("slice: abc\n", "slice: {}\n", value);
1016 }
1017 {
1018 const value = @intToPtr(*i32, 0xdeadbeef);
1019 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
1020 try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
1021 }
1022 {
1023 const value = @intToPtr(fn () void, 0xdeadbeef);
1024 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
1025 }
1026 {
1027 const value = @intToPtr(fn () void, 0xdeadbeef);
1028 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
1029 }
1030 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1031 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1032 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
1033 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
1034 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1035 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
1036 {
1037 const Struct = struct {
1038 field: u8,
1039 };
1040 const value = Struct{ .field = 42 };
1041 try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", value);
1042 try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", &value);
1043 }
1044 {
1045 const Struct = struct {
1046 a: u0,
1047 b: u1,
1048 };
1049 const value = Struct{ .a = 0, .b = 1 };
1050 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
1051 }
1052 {
1053 const Enum = enum {
1054 One,
1055 Two,
1056 };
1057 const value = Enum.Two;
1058 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
1059 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1060 }
1061 {
1062 var buf1: [32]u8 = undefined;
1063 const value: f32 = 1.34;
1064 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
1065 testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
1066 }
1067 {
1068 var buf1: [32]u8 = undefined;
1069 const value: f32 = 12.34;
1070 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
1071 testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
1072 }
1073 {
1074 var buf1: [32]u8 = undefined;
1075 const value: f64 = -12.34e10;
1076 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1077 testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
1078 }
1079 {
1080 // This fails on release due to a minor rounding difference.
1081 // --release-fast outputs 9.999960000000001e-40 vs. the expected.
1082 // TODO fix this, it should be the same in Debug and ReleaseFast
1083 if (builtin.mode == builtin.Mode.Debug) {
1084 var buf1: [32]u8 = undefined;
1085 const value: f64 = 9.999960e-40;
1086 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1087 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
1088 }
1089 }
1090 {
1091 var buf1: [32]u8 = undefined;
1092 const value: f64 = 1.409706e-42;
1093 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1094 testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));
1095 }
1096 {
1097 var buf1: [32]u8 = undefined;
1098 const value: f64 = @bitCast(f32, u32(814313563));
1099 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1100 testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
1101 }
1102 {
1103 var buf1: [32]u8 = undefined;
1104 const value: f64 = @bitCast(f32, u32(1006632960));
1105 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1106 testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
1107 }
1108 {
1109 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1110 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1111 var buf1: [32]u8 = undefined;
1112 const value: f64 = @bitCast(f32, u32(1203982400));
1113 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1114 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
1115 }
1116 {
1117 var buf1: [32]u8 = undefined;
1118 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
1119 testing.expect(mem.eql(u8, result, "f64: nan\n"));
1120 }
1121 if (builtin.arch != builtin.Arch.arm) {
1122 // negative nan is not defined by IEE 754,
1123 // and ARM thus normalizes it to positive nan
1124 var buf1: [32]u8 = undefined;
1125 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
1126 testing.expect(mem.eql(u8, result, "f64: -nan\n"));
1127 }
1128 {
1129 var buf1: [32]u8 = undefined;
1130 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
1131 testing.expect(mem.eql(u8, result, "f64: inf\n"));
1132 }
1133 {
1134 var buf1: [32]u8 = undefined;
1135 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
1136 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
1137 }
1138 {
1139 var buf1: [64]u8 = undefined;
1140 const value: f64 = 1.52314e+29;
1141 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
1142 testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
1143 }
1144 {
1145 var buf1: [32]u8 = undefined;
1146 const value: f32 = 1.1234;
1147 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
1148 testing.expect(mem.eql(u8, result, "f32: 1.1\n"));
1149 }
1150 {
1151 var buf1: [32]u8 = undefined;
1152 const value: f32 = 1234.567;
1153 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
1154 testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
1155 }
1156 {
1157 var buf1: [32]u8 = undefined;
1158 const value: f32 = -11.1234;
1159 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
1160 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1161 // -11.12339... is rounded back up to -11.1234
1162 testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
1163 }
1164 {
1165 var buf1: [32]u8 = undefined;
1166 const value: f32 = 91.12345;
1167 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
1168 testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
1169 }
1170 {
1171 var buf1: [32]u8 = undefined;
1172 const value: f64 = 91.12345678901235;
1173 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
1174 testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
1175 }
1176 {
1177 var buf1: [32]u8 = undefined;
1178 const value: f64 = 0.0;
1179 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1180 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1181 }
1182 {
1183 var buf1: [32]u8 = undefined;
1184 const value: f64 = 5.700;
1185 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
1186 testing.expect(mem.eql(u8, result, "f64: 6\n"));
1187 }
1188 {
1189 var buf1: [32]u8 = undefined;
1190 const value: f64 = 9.999;
1191 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
1192 testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
1193 }
1194 {
1195 var buf1: [32]u8 = undefined;
1196 const value: f64 = 1.0;
1197 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
1198 testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
1199 }
1200 {
1201 var buf1: [32]u8 = undefined;
1202 const value: f64 = 0.0003;
1203 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
1204 testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
1205 }
1206 {
1207 var buf1: [32]u8 = undefined;
1208 const value: f64 = 1.40130e-45;
1209 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1210 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1211 }
1212 {
1213 var buf1: [32]u8 = undefined;
1214 const value: f64 = 9.999960e-40;
1215 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1216 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1217 }
1218 // libc checks
1219 {
1220 var buf1: [32]u8 = undefined;
1221 const value: f64 = f64(@bitCast(f32, u32(916964781)));
1222 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1223 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1224 }
1225 {
1226 var buf1: [32]u8 = undefined;
1227 const value: f64 = f64(@bitCast(f32, u32(925353389)));
1228 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1229 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1230 }
1231 {
1232 var buf1: [32]u8 = undefined;
1233 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
1234 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1235 testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
1236 }
1237 {
1238 var buf1: [32]u8 = undefined;
1239 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
1240 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1241 testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
1242 }
1243 {
1244 var buf1: [32]u8 = undefined;
1245 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
1246 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1247 testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
1248 }
1249 // libc differences
1250 {
1251 var buf1: [32]u8 = undefined;
1252 // This is 0.015625 exactly according to gdb. We thus round down,
1253 // however glibc rounds up for some reason. This occurs for all
1254 // floats of the form x.yyyy25 on a precision point.
1255 const value: f64 = f64(@bitCast(f32, u32(1015021568)));
1256 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1257 testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));
1258 }
1259 // std-windows-x86_64-Debug-bare test case fails
1260 {
1261 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1262 // also rounds to 630 so I'm inclined to believe libc is not
1263 // optimal here.
1264 var buf1: [32]u8 = undefined;
1265 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
1266 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1267 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1268 }
1269 //custom type format
1270 {
1271 const Vec2 = struct {
1272 const SelfType = @This();
1273 x: f32,
1274 y: f32,
1275
1276 pub fn format(
1277 self: SelfType,
1278 comptime fmt: []const u8,
1279 context: var,
1280 comptime Errors: type,
1281 output: fn (@typeOf(context), []const u8) Errors!void,
1282 ) Errors!void {
1283 switch (fmt.len) {
1284 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1285 1 => switch (fmt[0]) {
1286 //point format
1287 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1288 //dimension format
1289 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1290 else => unreachable,
1291 },
1292 else => unreachable,
1293 }
1294 }
1295 };
1296
1297 var buf1: [32]u8 = undefined;
1298 var value = Vec2{
1299 .x = 10.2,
1300 .y = 2.22,
1301 };
1302 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1303 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
1304
1305 // same thing but not passing a pointer
1306 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1307 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1308 }
1309 //struct format
1310 {
1311 const S = struct {
1312 a: u32,
1313 b: anyerror,
1314 };
1315
1316 const inst = S{
1317 .a = 456,
1318 .b = error.Unused,
1319 };
1320
1321 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1322 }
1323 //union format
1324 {
1325 const TU = union(enum) {
1326 float: f32,
1327 int: u32,
1328 };
1329
1330 const UU = union {
1331 float: f32,
1332 int: u32,
1333 };
1334
1335 const EU = extern union {
1336 float: f32,
1337 int: u32,
1338 };
1339
1340 const tu_inst = TU{ .int = 123 };
1341 const uu_inst = UU{ .int = 456 };
1342 const eu_inst = EU{ .float = 321.123 };
1343
1344 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
1345
1346 var buf: [100]u8 = undefined;
1347 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1348 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
1349
1350 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1351 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1352 }
1353 //enum format
1354 {
1355 const E = enum {
1356 One,
1357 Two,
1358 Three,
1359 };
1360
1361 const inst = E.Two;
1362
1363 try testFmt("E.Two", "{}", inst);
1364 }
1365 //print bytes as hex
1366 {
1367 const some_bytes = "\xCA\xFE\xBA\xBE";
1368 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1369 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1370 //Test Slices
1371 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
1372 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
1373 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1374 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
1375 }
1376}
1377
1378fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
1379 var buf: [100]u8 = undefined;
1380 const result = try bufPrint(buf[0..], template, args);
1381 if (mem.eql(u8, result, expected)) return;
1382
1383 std.debug.warn("\n====== expected this output: =========\n");
1384 std.debug.warn("{}", expected);
1385 std.debug.warn("\n======== instead found this: =========\n");
1386 std.debug.warn("{}", result);
1387 std.debug.warn("\n======================================\n");
1388 return error.TestFailed;
1389}
1390
1391pub fn trim(buf: []const u8) []const u8 {
1392 var start: usize = 0;
1393 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
1394
1395 var end: usize = buf.len;
1396 while (true) {
1397 if (end > start) {
1398 const new_end = end - 1;
1399 if (isWhiteSpace(buf[new_end])) {
1400 end = new_end;
1401 continue;
1402 }
1403 }
1404 break;
1405 }
1406 return buf[start..end];
1407}
1408
1409test "fmt.trim" {
1410 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
1411 testing.expect(mem.eql(u8, "", trim(" ")));
1412 testing.expect(mem.eql(u8, "", trim("")));
1413 testing.expect(mem.eql(u8, "abc", trim(" abc")));
1414 testing.expect(mem.eql(u8, "abc", trim("abc ")));
1415}
1416
1417pub fn isWhiteSpace(byte: u8) bool {
1418 return switch (byte) {
1419 ' ', '\t', '\n', '\r' => true,
1420 else => false,
1421 };
1422}
1423
1424pub fn hexToBytes(out: []u8, input: []const u8) !void {
1425 if (out.len * 2 < input.len)
1426 return error.InvalidLength;
1427
1428 var in_i: usize = 0;
1429 while (in_i != input.len) : (in_i += 2) {
1430 const hi = try charToDigit(input[in_i], 16);
1431 const lo = try charToDigit(input[in_i + 1], 16);
1432 out[in_i / 2] = (hi << 4) | lo;
1433 }
1434}
1435
1436test "fmt.hexToBytes" {
1437 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1438 var pb: [32]u8 = undefined;
1439 try hexToBytes(pb[0..], test_hex_str);
1440 try testFmt(test_hex_str, "{X}", pb);
1441}
std/fmt/parse_float.zig+1-1
...@@ -29,7 +29,7 @@...@@ -29,7 +29,7 @@
29// - Only supports round-to-zero29// - Only supports round-to-zero
30// - Does not handle denormals30// - Does not handle denormals
3131
32const std = @import("../index.zig");32const std = @import("../std.zig");
3333
34const max_digits = 25;34const max_digits = 25;
3535
std/hash.zig created+22
...@@ -0,0 +1,22 @@
1const adler = @import("hash/adler.zig");
2pub const Adler32 = adler.Adler32;
3
4// pub for polynomials + generic crc32 construction
5pub const crc = @import("hash/crc.zig");
6pub const Crc32 = crc.Crc32;
7
8const fnv = @import("hash/fnv.zig");
9pub const Fnv1a_32 = fnv.Fnv1a_32;
10pub const Fnv1a_64 = fnv.Fnv1a_64;
11pub const Fnv1a_128 = fnv.Fnv1a_128;
12
13const siphash = @import("hash/siphash.zig");
14pub const SipHash64 = siphash.SipHash64;
15pub const SipHash128 = siphash.SipHash128;
16
17test "hash" {
18 _ = @import("hash/adler.zig");
19 _ = @import("hash/crc.zig");
20 _ = @import("hash/fnv.zig");
21 _ = @import("hash/siphash.zig");
22}
std/hash/adler.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// https://tools.ietf.org/html/rfc1950#section-93// https://tools.ietf.org/html/rfc1950#section-9
4// https://github.com/madler/zlib/blob/master/adler32.c4// https://github.com/madler/zlib/blob/master/adler32.c
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const testing = std.testing;7const testing = std.testing;
88
9pub const Adler32 = struct {9pub const Adler32 = struct {
std/hash/crc.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is5// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
6// still moderately fast just slow relative to the slicing approach.6// still moderately fast just slow relative to the slicing approach.
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const debug = std.debug;9const debug = std.debug;
10const testing = std.testing;10const testing = std.testing;
1111
std/hash/fnv.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4//4//
5// https://tools.ietf.org/html/draft-eastlake-fnv-145// https://tools.ietf.org/html/draft-eastlake-fnv-14
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const testing = std.testing;8const testing = std.testing;
99
10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);
std/hash/index.zig deleted-22
...@@ -1,22 +0,0 @@
1const adler = @import("adler.zig");
2pub const Adler32 = adler.Adler32;
3
4// pub for polynomials + generic crc32 construction
5pub const crc = @import("crc.zig");
6pub const Crc32 = crc.Crc32;
7
8const fnv = @import("fnv.zig");
9pub const Fnv1a_32 = fnv.Fnv1a_32;
10pub const Fnv1a_64 = fnv.Fnv1a_64;
11pub const Fnv1a_128 = fnv.Fnv1a_128;
12
13const siphash = @import("siphash.zig");
14pub const SipHash64 = siphash.SipHash64;
15pub const SipHash128 = siphash.SipHash128;
16
17test "hash" {
18 _ = @import("adler.zig");
19 _ = @import("crc.zig");
20 _ = @import("fnv.zig");
21 _ = @import("siphash.zig");
22}
std/hash/siphash.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5//5//
6// https://131002.net/siphash/6// https://131002.net/siphash/
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const assert = std.debug.assert;9const assert = std.debug.assert;
10const testing = std.testing;10const testing = std.testing;
11const math = std.math;11const math = std.math;
std/hash_map.zig+1-3
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const testing = std.testing;4const testing = std.testing;
...@@ -486,7 +486,6 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type...@@ -486,7 +486,6 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
486 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng),486 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng),
487 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),487 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),
488488
489 builtin.TypeId.Namespace,
490 builtin.TypeId.BoundFn,489 builtin.TypeId.BoundFn,
491 builtin.TypeId.ComptimeFloat,490 builtin.TypeId.ComptimeFloat,
492 builtin.TypeId.ComptimeInt,491 builtin.TypeId.ComptimeInt,
...@@ -532,7 +531,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {...@@ -532,7 +531,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
532 builtin.TypeId.Float,531 builtin.TypeId.Float,
533 builtin.TypeId.ComptimeFloat,532 builtin.TypeId.ComptimeFloat,
534 builtin.TypeId.ComptimeInt,533 builtin.TypeId.ComptimeInt,
535 builtin.TypeId.Namespace,
536 builtin.TypeId.Promise,534 builtin.TypeId.Promise,
537 builtin.TypeId.Enum,535 builtin.TypeId.Enum,
538 builtin.TypeId.BoundFn,536 builtin.TypeId.BoundFn,
std/heap.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/index.zig deleted-95
...@@ -1,95 +0,0 @@
1pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
2pub const ArrayList = @import("array_list.zig").ArrayList;
3pub const AutoHashMap = @import("hash_map.zig").AutoHashMap;
4pub const BufMap = @import("buf_map.zig").BufMap;
5pub const BufSet = @import("buf_set.zig").BufSet;
6pub const Buffer = @import("buffer.zig").Buffer;
7pub const BufferOutStream = @import("io.zig").BufferOutStream;
8pub const DynLib = @import("dynamic_library.zig").DynLib;
9pub const HashMap = @import("hash_map.zig").HashMap;
10pub const LinkedList = @import("linked_list.zig").LinkedList;
11pub const Mutex = @import("mutex.zig").Mutex;
12pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
13pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
14pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
15pub const SpinLock = @import("spinlock.zig").SpinLock;
16
17pub const atomic = @import("atomic/index.zig");
18pub const base64 = @import("base64.zig");
19pub const build = @import("build.zig");
20pub const c = @import("c/index.zig");
21pub const coff = @import("coff.zig");
22pub const crypto = @import("crypto/index.zig");
23pub const cstr = @import("cstr.zig");
24pub const debug = @import("debug/index.zig");
25pub const dwarf = @import("dwarf.zig");
26pub const elf = @import("elf.zig");
27pub const empty_import = @import("empty.zig");
28pub const event = @import("event.zig");
29pub const fmt = @import("fmt/index.zig");
30pub const hash = @import("hash/index.zig");
31pub const hash_map = @import("hash_map.zig");
32pub const heap = @import("heap.zig");
33pub const io = @import("io.zig");
34pub const json = @import("json.zig");
35pub const lazyInit = @import("lazy_init.zig").lazyInit;
36pub const macho = @import("macho.zig");
37pub const math = @import("math/index.zig");
38pub const mem = @import("mem.zig");
39pub const meta = @import("meta/index.zig");
40pub const net = @import("net.zig");
41pub const os = @import("os/index.zig");
42pub const pdb = @import("pdb.zig");
43pub const rand = @import("rand/index.zig");
44pub const rb = @import("rb.zig");
45pub const sort = @import("sort.zig");
46pub const testing = @import("testing.zig");
47pub const unicode = @import("unicode.zig");
48pub const zig = @import("zig/index.zig");
49
50test "std" {
51 // run tests from these
52 _ = @import("array_list.zig");
53 _ = @import("atomic/index.zig");
54 _ = @import("buf_map.zig");
55 _ = @import("buf_set.zig");
56 _ = @import("buffer.zig");
57 _ = @import("hash_map.zig");
58 _ = @import("linked_list.zig");
59 _ = @import("mutex.zig");
60 _ = @import("statically_initialized_mutex.zig");
61 _ = @import("segmented_list.zig");
62 _ = @import("spinlock.zig");
63
64 _ = @import("base64.zig");
65 _ = @import("build.zig");
66 _ = @import("c/index.zig");
67 _ = @import("coff.zig");
68 _ = @import("crypto/index.zig");
69 _ = @import("cstr.zig");
70 _ = @import("debug/index.zig");
71 _ = @import("dwarf.zig");
72 _ = @import("dynamic_library.zig");
73 _ = @import("elf.zig");
74 _ = @import("empty.zig");
75 _ = @import("event.zig");
76 _ = @import("fmt/index.zig");
77 _ = @import("hash/index.zig");
78 _ = @import("heap.zig");
79 _ = @import("io.zig");
80 _ = @import("json.zig");
81 _ = @import("lazy_init.zig");
82 _ = @import("macho.zig");
83 _ = @import("math/index.zig");
84 _ = @import("mem.zig");
85 _ = @import("meta/index.zig");
86 _ = @import("net.zig");
87 _ = @import("os/index.zig");
88 _ = @import("pdb.zig");
89 _ = @import("priority_queue.zig");
90 _ = @import("rand/index.zig");
91 _ = @import("sort.zig");
92 _ = @import("testing.zig");
93 _ = @import("unicode.zig");
94 _ = @import("zig/index.zig");
95}
std/io.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Os = builtin.Os;3const Os = builtin.Os;
4const c = std.c;4const c = std.c;
std/io/seekable_stream.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const InStream = std.io.InStream;2const InStream = std.io.InStream;
33
4pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {4pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
std/io_test.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const io = std.io;2const io = std.io;
3const meta = std.meta;3const meta = std.meta;
4const trait = std.trait;4const trait = std.trait;
std/json.zig+1-1
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2//2//
3// https://tools.ietf.org/html/rfc82593// https://tools.ietf.org/html/rfc8259
44
5const std = @import("index.zig");5const std = @import("std.zig");
6const debug = std.debug;6const debug = std.debug;
7const testing = std.testing;7const testing = std.testing;
8const mem = std.mem;8const mem = std.mem;
std/json_test.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// Tests are taken from https://github.com/nst/JSONTestSuite3// Tests are taken from https://github.com/nst/JSONTestSuite
4// Read also http://seriot.ch/parsing_json.php for a good overview.4// Read also http://seriot.ch/parsing_json.php for a good overview.
55
6const std = @import("index.zig");6const std = @import("std.zig");
77
8fn ok(comptime s: []const u8) void {8fn ok(comptime s: []const u8) void {
9 std.testing.expect(std.json.validate(s));9 std.testing.expect(std.json.validate(s));
std/lazy_init.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/linked_list.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/math.zig created+797
...@@ -0,0 +1,797 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");
3const TypeId = builtin.TypeId;
4const assert = std.debug.assert;
5const testing = std.testing;
6
7pub const e = 2.71828182845904523536028747135266249775724709369995;
8pub const pi = 3.14159265358979323846264338327950288419716939937510;
9
10// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
11pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001));
12pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000));
13pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
14pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000));
15pub const f128_toint = 1.0 / f128_epsilon;
16
17// float.h details
18pub const f64_true_min = 4.94065645841246544177e-324;
19pub const f64_min = 2.2250738585072014e-308;
20pub const f64_max = 1.79769313486231570815e+308;
21pub const f64_epsilon = 2.22044604925031308085e-16;
22pub const f64_toint = 1.0 / f64_epsilon;
23
24pub const f32_true_min = 1.40129846432481707092e-45;
25pub const f32_min = 1.17549435082228750797e-38;
26pub const f32_max = 3.40282346638528859812e+38;
27pub const f32_epsilon = 1.1920928955078125e-07;
28pub const f32_toint = 1.0 / f32_epsilon;
29
30pub const f16_true_min = 0.000000059604644775390625; // 2**-24
31pub const f16_min = 0.00006103515625; // 2**-14
32pub const f16_max = 65504;
33pub const f16_epsilon = 0.0009765625; // 2**-10
34pub const f16_toint = 1.0 / f16_epsilon;
35
36pub const nan_u16 = u16(0x7C01);
37pub const nan_f16 = @bitCast(f16, nan_u16);
38
39pub const inf_u16 = u16(0x7C00);
40pub const inf_f16 = @bitCast(f16, inf_u16);
41
42pub const nan_u32 = u32(0x7F800001);
43pub const nan_f32 = @bitCast(f32, nan_u32);
44
45pub const inf_u32 = u32(0x7F800000);
46pub const inf_f32 = @bitCast(f32, inf_u32);
47
48pub const nan_u64 = u64(0x7FF << 52) | 1;
49pub const nan_f64 = @bitCast(f64, nan_u64);
50
51pub const inf_u64 = u64(0x7FF << 52);
52pub const inf_f64 = @bitCast(f64, inf_u64);
53
54pub const nan_u128 = u128(0x7fff0000000000000000000000000001);
55pub const nan_f128 = @bitCast(f128, nan_u128);
56
57pub const inf_u128 = u128(0x7fff0000000000000000000000000000);
58pub const inf_f128 = @bitCast(f128, inf_u128);
59
60pub const nan = @import("math/nan.zig").nan;
61pub const snan = @import("math/nan.zig").snan;
62pub const inf = @import("math/inf.zig").inf;
63
64pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
65 assert(@typeId(T) == TypeId.Float);
66 return fabs(x - y) < epsilon;
67}
68
69// TODO: Hide the following in an internal module.
70pub fn forceEval(value: var) void {
71 const T = @typeOf(value);
72 switch (T) {
73 f16 => {
74 var x: f16 = undefined;
75 const p = @ptrCast(*volatile f16, &x);
76 p.* = x;
77 },
78 f32 => {
79 var x: f32 = undefined;
80 const p = @ptrCast(*volatile f32, &x);
81 p.* = x;
82 },
83 f64 => {
84 var x: f64 = undefined;
85 const p = @ptrCast(*volatile f64, &x);
86 p.* = x;
87 },
88 else => {
89 @compileError("forceEval not implemented for " ++ @typeName(T));
90 },
91 }
92}
93
94pub fn raiseInvalid() void {
95 // Raise INVALID fpu exception
96}
97
98pub fn raiseUnderflow() void {
99 // Raise UNDERFLOW fpu exception
100}
101
102pub fn raiseOverflow() void {
103 // Raise OVERFLOW fpu exception
104}
105
106pub fn raiseInexact() void {
107 // Raise INEXACT fpu exception
108}
109
110pub fn raiseDivByZero() void {
111 // Raise INEXACT fpu exception
112}
113
114pub const isNan = @import("math/isnan.zig").isNan;
115pub const isSignalNan = @import("math/isnan.zig").isSignalNan;
116pub const fabs = @import("math/fabs.zig").fabs;
117pub const ceil = @import("math/ceil.zig").ceil;
118pub const floor = @import("math/floor.zig").floor;
119pub const trunc = @import("math/trunc.zig").trunc;
120pub const round = @import("math/round.zig").round;
121pub const frexp = @import("math/frexp.zig").frexp;
122pub const frexp32_result = @import("math/frexp.zig").frexp32_result;
123pub const frexp64_result = @import("math/frexp.zig").frexp64_result;
124pub const modf = @import("math/modf.zig").modf;
125pub const modf32_result = @import("math/modf.zig").modf32_result;
126pub const modf64_result = @import("math/modf.zig").modf64_result;
127pub const copysign = @import("math/copysign.zig").copysign;
128pub const isFinite = @import("math/isfinite.zig").isFinite;
129pub const isInf = @import("math/isinf.zig").isInf;
130pub const isPositiveInf = @import("math/isinf.zig").isPositiveInf;
131pub const isNegativeInf = @import("math/isinf.zig").isNegativeInf;
132pub const isNormal = @import("math/isnormal.zig").isNormal;
133pub const signbit = @import("math/signbit.zig").signbit;
134pub const scalbn = @import("math/scalbn.zig").scalbn;
135pub const pow = @import("math/pow.zig").pow;
136pub const powi = @import("math/powi.zig").powi;
137pub const sqrt = @import("math/sqrt.zig").sqrt;
138pub const cbrt = @import("math/cbrt.zig").cbrt;
139pub const acos = @import("math/acos.zig").acos;
140pub const asin = @import("math/asin.zig").asin;
141pub const atan = @import("math/atan.zig").atan;
142pub const atan2 = @import("math/atan2.zig").atan2;
143pub const hypot = @import("math/hypot.zig").hypot;
144pub const exp = @import("math/exp.zig").exp;
145pub const exp2 = @import("math/exp2.zig").exp2;
146pub const expm1 = @import("math/expm1.zig").expm1;
147pub const ilogb = @import("math/ilogb.zig").ilogb;
148pub const ln = @import("math/ln.zig").ln;
149pub const log = @import("math/log.zig").log;
150pub const log2 = @import("math/log2.zig").log2;
151pub const log10 = @import("math/log10.zig").log10;
152pub const log1p = @import("math/log1p.zig").log1p;
153pub const fma = @import("math/fma.zig").fma;
154pub const asinh = @import("math/asinh.zig").asinh;
155pub const acosh = @import("math/acosh.zig").acosh;
156pub const atanh = @import("math/atanh.zig").atanh;
157pub const sinh = @import("math/sinh.zig").sinh;
158pub const cosh = @import("math/cosh.zig").cosh;
159pub const tanh = @import("math/tanh.zig").tanh;
160pub const cos = @import("math/cos.zig").cos;
161pub const sin = @import("math/sin.zig").sin;
162pub const tan = @import("math/tan.zig").tan;
163
164pub const complex = @import("math/complex.zig");
165pub const Complex = complex.Complex;
166
167pub const big = @import("math/big.zig");
168
169test "math" {
170 _ = @import("math/nan.zig");
171 _ = @import("math/isnan.zig");
172 _ = @import("math/fabs.zig");
173 _ = @import("math/ceil.zig");
174 _ = @import("math/floor.zig");
175 _ = @import("math/trunc.zig");
176 _ = @import("math/round.zig");
177 _ = @import("math/frexp.zig");
178 _ = @import("math/modf.zig");
179 _ = @import("math/copysign.zig");
180 _ = @import("math/isfinite.zig");
181 _ = @import("math/isinf.zig");
182 _ = @import("math/isnormal.zig");
183 _ = @import("math/signbit.zig");
184 _ = @import("math/scalbn.zig");
185 _ = @import("math/pow.zig");
186 _ = @import("math/powi.zig");
187 _ = @import("math/sqrt.zig");
188 _ = @import("math/cbrt.zig");
189 _ = @import("math/acos.zig");
190 _ = @import("math/asin.zig");
191 _ = @import("math/atan.zig");
192 _ = @import("math/atan2.zig");
193 _ = @import("math/hypot.zig");
194 _ = @import("math/exp.zig");
195 _ = @import("math/exp2.zig");
196 _ = @import("math/expm1.zig");
197 _ = @import("math/ilogb.zig");
198 _ = @import("math/ln.zig");
199 _ = @import("math/log.zig");
200 _ = @import("math/log2.zig");
201 _ = @import("math/log10.zig");
202 _ = @import("math/log1p.zig");
203 _ = @import("math/fma.zig");
204 _ = @import("math/asinh.zig");
205 _ = @import("math/acosh.zig");
206 _ = @import("math/atanh.zig");
207 _ = @import("math/sinh.zig");
208 _ = @import("math/cosh.zig");
209 _ = @import("math/tanh.zig");
210 _ = @import("math/sin.zig");
211 _ = @import("math/cos.zig");
212 _ = @import("math/tan.zig");
213
214 _ = @import("math/complex.zig");
215
216 _ = @import("math/big.zig");
217}
218
219pub fn floatMantissaBits(comptime T: type) comptime_int {
220 assert(@typeId(T) == builtin.TypeId.Float);
221
222 return switch (T.bit_count) {
223 16 => 10,
224 32 => 23,
225 64 => 52,
226 80 => 64,
227 128 => 112,
228 else => @compileError("unknown floating point type " ++ @typeName(T)),
229 };
230}
231
232pub fn floatExponentBits(comptime T: type) comptime_int {
233 assert(@typeId(T) == builtin.TypeId.Float);
234
235 return switch (T.bit_count) {
236 16 => 5,
237 32 => 8,
238 64 => 11,
239 80 => 15,
240 128 => 15,
241 else => @compileError("unknown floating point type " ++ @typeName(T)),
242 };
243}
244
245pub fn min(x: var, y: var) @typeOf(x + y) {
246 return if (x < y) x else y;
247}
248
249test "math.min" {
250 testing.expect(min(i32(-1), i32(2)) == -1);
251}
252
253pub fn max(x: var, y: var) @typeOf(x + y) {
254 return if (x > y) x else y;
255}
256
257test "math.max" {
258 testing.expect(max(i32(-1), i32(2)) == 2);
259}
260
261pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
262 var answer: T = undefined;
263 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
264}
265
266pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
267 var answer: T = undefined;
268 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
269}
270
271pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
272 var answer: T = undefined;
273 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
274}
275
276pub fn negate(x: var) !@typeOf(x) {
277 return sub(@typeOf(x), 0, x);
278}
279
280pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
281 var answer: T = undefined;
282 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
283}
284
285/// Shifts left. Overflowed bits are truncated.
286/// A negative shift amount results in a right shift.
287pub fn shl(comptime T: type, a: T, shift_amt: var) T {
288 const abs_shift_amt = absCast(shift_amt);
289 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
290
291 if (@typeOf(shift_amt).is_signed) {
292 if (shift_amt >= 0) {
293 return a << casted_shift_amt;
294 } else {
295 return a >> casted_shift_amt;
296 }
297 }
298
299 return a << casted_shift_amt;
300}
301
302test "math.shl" {
303 testing.expect(shl(u8, 0b11111111, usize(3)) == 0b11111000);
304 testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
305 testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
306 testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);
307}
308
309/// Shifts right. Overflowed bits are truncated.
310/// A negative shift amount results in a lefft shift.
311pub fn shr(comptime T: type, a: T, shift_amt: var) T {
312 const abs_shift_amt = absCast(shift_amt);
313 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
314
315 if (@typeOf(shift_amt).is_signed) {
316 if (shift_amt >= 0) {
317 return a >> casted_shift_amt;
318 } else {
319 return a << casted_shift_amt;
320 }
321 }
322
323 return a >> casted_shift_amt;
324}
325
326test "math.shr" {
327 testing.expect(shr(u8, 0b11111111, usize(3)) == 0b00011111);
328 testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
329 testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
330 testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
331}
332
333/// Rotates right. Only unsigned values can be rotated.
334/// Negative shift values results in shift modulo the bit count.
335pub fn rotr(comptime T: type, x: T, r: var) T {
336 if (T.is_signed) {
337 @compileError("cannot rotate signed integer");
338 } else {
339 const ar = @mod(r, T.bit_count);
340 return shr(T, x, ar) | shl(T, x, T.bit_count - ar);
341 }
342}
343
344test "math.rotr" {
345 testing.expect(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
346 testing.expect(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
347 testing.expect(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
348 testing.expect(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
349 testing.expect(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
350}
351
352/// Rotates left. Only unsigned values can be rotated.
353/// Negative shift values results in shift modulo the bit count.
354pub fn rotl(comptime T: type, x: T, r: var) T {
355 if (T.is_signed) {
356 @compileError("cannot rotate signed integer");
357 } else {
358 const ar = @mod(r, T.bit_count);
359 return shl(T, x, ar) | shr(T, x, T.bit_count - ar);
360 }
361}
362
363test "math.rotl" {
364 testing.expect(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
365 testing.expect(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
366 testing.expect(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
367 testing.expect(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
368 testing.expect(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
369}
370
371pub fn Log2Int(comptime T: type) type {
372 // comptime ceil log2
373 comptime var count = 0;
374 comptime var s = T.bit_count - 1;
375 inline while (s != 0) : (s >>= 1) {
376 count += 1;
377 }
378
379 return @IntType(false, count);
380}
381
382pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
383 assert(from <= to);
384 if (from == 0 and to == 0) {
385 return u0;
386 }
387 const is_signed = from < 0;
388 const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
389 const base = log2(largest_positive_integer);
390 const upper = (1 << base) - 1;
391 var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
392 if (is_signed) {
393 magnitude_bits += 1;
394 }
395 return @IntType(is_signed, magnitude_bits);
396}
397
398test "math.IntFittingRange" {
399 testing.expect(IntFittingRange(0, 0) == u0);
400 testing.expect(IntFittingRange(0, 1) == u1);
401 testing.expect(IntFittingRange(0, 2) == u2);
402 testing.expect(IntFittingRange(0, 3) == u2);
403 testing.expect(IntFittingRange(0, 4) == u3);
404 testing.expect(IntFittingRange(0, 7) == u3);
405 testing.expect(IntFittingRange(0, 8) == u4);
406 testing.expect(IntFittingRange(0, 9) == u4);
407 testing.expect(IntFittingRange(0, 15) == u4);
408 testing.expect(IntFittingRange(0, 16) == u5);
409 testing.expect(IntFittingRange(0, 17) == u5);
410 testing.expect(IntFittingRange(0, 4095) == u12);
411 testing.expect(IntFittingRange(2000, 4095) == u12);
412 testing.expect(IntFittingRange(0, 4096) == u13);
413 testing.expect(IntFittingRange(2000, 4096) == u13);
414 testing.expect(IntFittingRange(0, 4097) == u13);
415 testing.expect(IntFittingRange(2000, 4097) == u13);
416 testing.expect(IntFittingRange(0, 123456789123456798123456789) == u87);
417 testing.expect(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177);
418
419 testing.expect(IntFittingRange(-1, -1) == i1);
420 testing.expect(IntFittingRange(-1, 0) == i1);
421 testing.expect(IntFittingRange(-1, 1) == i2);
422 testing.expect(IntFittingRange(-2, -2) == i2);
423 testing.expect(IntFittingRange(-2, -1) == i2);
424 testing.expect(IntFittingRange(-2, 0) == i2);
425 testing.expect(IntFittingRange(-2, 1) == i2);
426 testing.expect(IntFittingRange(-2, 2) == i3);
427 testing.expect(IntFittingRange(-1, 2) == i3);
428 testing.expect(IntFittingRange(-1, 3) == i3);
429 testing.expect(IntFittingRange(-1, 4) == i4);
430 testing.expect(IntFittingRange(-1, 7) == i4);
431 testing.expect(IntFittingRange(-1, 8) == i5);
432 testing.expect(IntFittingRange(-1, 9) == i5);
433 testing.expect(IntFittingRange(-1, 15) == i5);
434 testing.expect(IntFittingRange(-1, 16) == i6);
435 testing.expect(IntFittingRange(-1, 17) == i6);
436 testing.expect(IntFittingRange(-1, 4095) == i13);
437 testing.expect(IntFittingRange(-4096, 4095) == i13);
438 testing.expect(IntFittingRange(-1, 4096) == i14);
439 testing.expect(IntFittingRange(-4097, 4095) == i14);
440 testing.expect(IntFittingRange(-1, 4097) == i14);
441 testing.expect(IntFittingRange(-1, 123456789123456798123456789) == i88);
442 testing.expect(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178);
443}
444
445test "math overflow functions" {
446 testOverflow();
447 comptime testOverflow();
448}
449
450fn testOverflow() void {
451 testing.expect((mul(i32, 3, 4) catch unreachable) == 12);
452 testing.expect((add(i32, 3, 4) catch unreachable) == 7);
453 testing.expect((sub(i32, 3, 4) catch unreachable) == -1);
454 testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
455}
456
457pub fn absInt(x: var) !@typeOf(x) {
458 const T = @typeOf(x);
459 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
460 comptime assert(T.is_signed); // must pass a signed integer to absInt
461
462 if (x == minInt(@typeOf(x))) {
463 return error.Overflow;
464 } else {
465 @setRuntimeSafety(false);
466 return if (x < 0) -x else x;
467 }
468}
469
470test "math.absInt" {
471 testAbsInt();
472 comptime testAbsInt();
473}
474fn testAbsInt() void {
475 testing.expect((absInt(i32(-10)) catch unreachable) == 10);
476 testing.expect((absInt(i32(10)) catch unreachable) == 10);
477}
478
479pub const absFloat = @import("fabs.zig").fabs;
480
481pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
482 @setRuntimeSafety(false);
483 if (denominator == 0) return error.DivisionByZero;
484 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
485 return @divTrunc(numerator, denominator);
486}
487
488test "math.divTrunc" {
489 testDivTrunc();
490 comptime testDivTrunc();
491}
492fn testDivTrunc() void {
493 testing.expect((divTrunc(i32, 5, 3) catch unreachable) == 1);
494 testing.expect((divTrunc(i32, -5, 3) catch unreachable) == -1);
495 testing.expectError(error.DivisionByZero, divTrunc(i8, -5, 0));
496 testing.expectError(error.Overflow, divTrunc(i8, -128, -1));
497
498 testing.expect((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0);
499 testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);
500}
501
502pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
503 @setRuntimeSafety(false);
504 if (denominator == 0) return error.DivisionByZero;
505 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
506 return @divFloor(numerator, denominator);
507}
508
509test "math.divFloor" {
510 testDivFloor();
511 comptime testDivFloor();
512}
513fn testDivFloor() void {
514 testing.expect((divFloor(i32, 5, 3) catch unreachable) == 1);
515 testing.expect((divFloor(i32, -5, 3) catch unreachable) == -2);
516 testing.expectError(error.DivisionByZero, divFloor(i8, -5, 0));
517 testing.expectError(error.Overflow, divFloor(i8, -128, -1));
518
519 testing.expect((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0);
520 testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);
521}
522
523pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
524 @setRuntimeSafety(false);
525 if (denominator == 0) return error.DivisionByZero;
526 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
527 const result = @divTrunc(numerator, denominator);
528 if (result * denominator != numerator) return error.UnexpectedRemainder;
529 return result;
530}
531
532test "math.divExact" {
533 testDivExact();
534 comptime testDivExact();
535}
536fn testDivExact() void {
537 testing.expect((divExact(i32, 10, 5) catch unreachable) == 2);
538 testing.expect((divExact(i32, -10, 5) catch unreachable) == -2);
539 testing.expectError(error.DivisionByZero, divExact(i8, -5, 0));
540 testing.expectError(error.Overflow, divExact(i8, -128, -1));
541 testing.expectError(error.UnexpectedRemainder, divExact(i32, 5, 2));
542
543 testing.expect((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0);
544 testing.expect((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0);
545 testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0));
546}
547
548pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
549 @setRuntimeSafety(false);
550 if (denominator == 0) return error.DivisionByZero;
551 if (denominator < 0) return error.NegativeDenominator;
552 return @mod(numerator, denominator);
553}
554
555test "math.mod" {
556 testMod();
557 comptime testMod();
558}
559fn testMod() void {
560 testing.expect((mod(i32, -5, 3) catch unreachable) == 1);
561 testing.expect((mod(i32, 5, 3) catch unreachable) == 2);
562 testing.expectError(error.NegativeDenominator, mod(i32, 10, -1));
563 testing.expectError(error.DivisionByZero, mod(i32, 10, 0));
564
565 testing.expect((mod(f32, -5, 3) catch unreachable) == 1);
566 testing.expect((mod(f32, 5, 3) catch unreachable) == 2);
567 testing.expectError(error.NegativeDenominator, mod(f32, 10, -1));
568 testing.expectError(error.DivisionByZero, mod(f32, 10, 0));
569}
570
571pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
572 @setRuntimeSafety(false);
573 if (denominator == 0) return error.DivisionByZero;
574 if (denominator < 0) return error.NegativeDenominator;
575 return @rem(numerator, denominator);
576}
577
578test "math.rem" {
579 testRem();
580 comptime testRem();
581}
582fn testRem() void {
583 testing.expect((rem(i32, -5, 3) catch unreachable) == -2);
584 testing.expect((rem(i32, 5, 3) catch unreachable) == 2);
585 testing.expectError(error.NegativeDenominator, rem(i32, 10, -1));
586 testing.expectError(error.DivisionByZero, rem(i32, 10, 0));
587
588 testing.expect((rem(f32, -5, 3) catch unreachable) == -2);
589 testing.expect((rem(f32, 5, 3) catch unreachable) == 2);
590 testing.expectError(error.NegativeDenominator, rem(f32, 10, -1));
591 testing.expectError(error.DivisionByZero, rem(f32, 10, 0));
592}
593
594/// Returns the absolute value of the integer parameter.
595/// Result is an unsigned integer.
596pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
597 const uint = @IntType(false, @typeOf(x).bit_count);
598 if (x >= 0) return @intCast(uint, x);
599
600 return @intCast(uint, -(x + 1)) + 1;
601}
602
603test "math.absCast" {
604 testing.expect(absCast(i32(-999)) == 999);
605 testing.expect(@typeOf(absCast(i32(-999))) == u32);
606
607 testing.expect(absCast(i32(999)) == 999);
608 testing.expect(@typeOf(absCast(i32(999))) == u32);
609
610 testing.expect(absCast(i32(minInt(i32))) == -minInt(i32));
611 testing.expect(@typeOf(absCast(i32(minInt(i32)))) == u32);
612}
613
614/// Returns the negation of the integer parameter.
615/// Result is a signed integer.
616pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
617 if (@typeOf(x).is_signed) return negate(x);
618
619 const int = @IntType(true, @typeOf(x).bit_count);
620 if (x > -minInt(int)) return error.Overflow;
621
622 if (x == -minInt(int)) return minInt(int);
623
624 return -@intCast(int, x);
625}
626
627test "math.negateCast" {
628 testing.expect((negateCast(u32(999)) catch unreachable) == -999);
629 testing.expect(@typeOf(negateCast(u32(999)) catch unreachable) == i32);
630
631 testing.expect((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32));
632 testing.expect(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32);
633
634 testing.expectError(error.Overflow, negateCast(u32(maxInt(i32) + 10)));
635}
636
637/// Cast an integer to a different integer type. If the value doesn't fit,
638/// return an error.
639pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
640 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
641 comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Int); // must pass an integer
642 if (maxInt(@typeOf(x)) > maxInt(T) and x > maxInt(T)) {
643 return error.Overflow;
644 } else if (minInt(@typeOf(x)) < minInt(T) and x < minInt(T)) {
645 return error.Overflow;
646 } else {
647 return @intCast(T, x);
648 }
649}
650
651test "math.cast" {
652 testing.expectError(error.Overflow, cast(u8, u32(300)));
653 testing.expectError(error.Overflow, cast(i8, i32(-200)));
654 testing.expectError(error.Overflow, cast(u8, i8(-1)));
655 testing.expectError(error.Overflow, cast(u64, i8(-1)));
656
657 testing.expect((try cast(u8, u32(255))) == u8(255));
658 testing.expect(@typeOf(try cast(u8, u32(255))) == u8);
659}
660
661pub const AlignCastError = error{UnalignedMemory};
662
663/// Align cast a pointer but return an error if it's the wrong alignment
664pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alignCast(alignment, ptr)) {
665 const addr = @ptrToInt(ptr);
666 if (addr % alignment != 0) {
667 return error.UnalignedMemory;
668 }
669 return @alignCast(alignment, ptr);
670}
671
672pub fn floorPowerOfTwo(comptime T: type, value: T) T {
673 var x = value;
674
675 comptime var i = 1;
676 inline while (T.bit_count > i) : (i *= 2) {
677 x |= (x >> i);
678 }
679
680 return x - (x >> 1);
681}
682
683test "math.floorPowerOfTwo" {
684 testFloorPowerOfTwo();
685 comptime testFloorPowerOfTwo();
686}
687
688pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
689 assert(x != 0);
690 return @intCast(Log2Int(T), T.bit_count - 1 - @clz(x));
691}
692
693pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
694 assert(x != 0);
695 const log2_val = log2_int(T, x);
696 if (T(1) << log2_val == x)
697 return log2_val;
698 return log2_val + 1;
699}
700
701test "std.math.log2_int_ceil" {
702 testing.expect(log2_int_ceil(u32, 1) == 0);
703 testing.expect(log2_int_ceil(u32, 2) == 1);
704 testing.expect(log2_int_ceil(u32, 3) == 2);
705 testing.expect(log2_int_ceil(u32, 4) == 2);
706 testing.expect(log2_int_ceil(u32, 5) == 3);
707 testing.expect(log2_int_ceil(u32, 6) == 3);
708 testing.expect(log2_int_ceil(u32, 7) == 3);
709 testing.expect(log2_int_ceil(u32, 8) == 3);
710 testing.expect(log2_int_ceil(u32, 9) == 4);
711 testing.expect(log2_int_ceil(u32, 10) == 4);
712}
713
714fn testFloorPowerOfTwo() void {
715 testing.expect(floorPowerOfTwo(u32, 63) == 32);
716 testing.expect(floorPowerOfTwo(u32, 64) == 64);
717 testing.expect(floorPowerOfTwo(u32, 65) == 64);
718 testing.expect(floorPowerOfTwo(u4, 7) == 4);
719 testing.expect(floorPowerOfTwo(u4, 8) == 8);
720 testing.expect(floorPowerOfTwo(u4, 9) == 8);
721}
722
723pub fn lossyCast(comptime T: type, value: var) T {
724 switch (@typeInfo(@typeOf(value))) {
725 builtin.TypeId.Int => return @intToFloat(T, value),
726 builtin.TypeId.Float => return @floatCast(T, value),
727 builtin.TypeId.ComptimeInt => return T(value),
728 builtin.TypeId.ComptimeFloat => return T(value),
729 else => @compileError("bad type"),
730 }
731}
732
733test "math.f64_min" {
734 const f64_min_u64 = 0x0010000000000000;
735 const fmin: f64 = f64_min;
736 testing.expect(@bitCast(u64, fmin) == f64_min_u64);
737}
738
739pub fn maxInt(comptime T: type) comptime_int {
740 const info = @typeInfo(T);
741 const bit_count = info.Int.bits;
742 if (bit_count == 0) return 0;
743 return (1 << (bit_count - @boolToInt(info.Int.is_signed))) - 1;
744}
745
746pub fn minInt(comptime T: type) comptime_int {
747 const info = @typeInfo(T);
748 const bit_count = info.Int.bits;
749 if (!info.Int.is_signed) return 0;
750 if (bit_count == 0) return 0;
751 return -(1 << (bit_count - 1));
752}
753
754test "minInt and maxInt" {
755 testing.expect(maxInt(u0) == 0);
756 testing.expect(maxInt(u1) == 1);
757 testing.expect(maxInt(u8) == 255);
758 testing.expect(maxInt(u16) == 65535);
759 testing.expect(maxInt(u32) == 4294967295);
760 testing.expect(maxInt(u64) == 18446744073709551615);
761 testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
762
763 testing.expect(maxInt(i0) == 0);
764 testing.expect(maxInt(i1) == 0);
765 testing.expect(maxInt(i8) == 127);
766 testing.expect(maxInt(i16) == 32767);
767 testing.expect(maxInt(i32) == 2147483647);
768 testing.expect(maxInt(i63) == 4611686018427387903);
769 testing.expect(maxInt(i64) == 9223372036854775807);
770 testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
771
772 testing.expect(minInt(u0) == 0);
773 testing.expect(minInt(u1) == 0);
774 testing.expect(minInt(u8) == 0);
775 testing.expect(minInt(u16) == 0);
776 testing.expect(minInt(u32) == 0);
777 testing.expect(minInt(u63) == 0);
778 testing.expect(minInt(u64) == 0);
779 testing.expect(minInt(u128) == 0);
780
781 testing.expect(minInt(i0) == 0);
782 testing.expect(minInt(i1) == -1);
783 testing.expect(minInt(i8) == -128);
784 testing.expect(minInt(i16) == -32768);
785 testing.expect(minInt(i32) == -2147483648);
786 testing.expect(minInt(i63) == -4611686018427387904);
787 testing.expect(minInt(i64) == -9223372036854775808);
788 testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
789}
790
791test "max value type" {
792 // If the type of maxInt(i32) was i32 then this implicit cast to
793 // u32 would not work. But since the value is a number literal,
794 // it works fine.
795 const x: u32 = maxInt(i32);
796 testing.expect(x == 2147483647);
797}
std/math/acos.zig+1-1
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2//2//
3// - acos(x) = nan if x < -1 or x > 13// - acos(x) = nan if x < -1 or x > 1
44
5const std = @import("../index.zig");5const std = @import("../std.zig");
6const math = std.math;6const math = std.math;
7const expect = std.testing.expect;7const expect = std.testing.expect;
88
std/math/acosh.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - acosh(nan) = nan4// - acosh(nan) = nan
55
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
1010
std/math/asin.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// - asin(+-0) = +-03// - asin(+-0) = +-0
4// - asin(x) = nan if x < -1 or x > 14// - asin(x) = nan if x < -1 or x > 1
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const math = std.math;7const math = std.math;
8const expect = std.testing.expect;8const expect = std.testing.expect;
99
std/math/asinh.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - asinh(+-inf) = +-inf4// - asinh(+-inf) = +-inf
5// - asinh(nan) = nan5// - asinh(nan) = nan
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
10const maxInt = std.math.maxInt;10const maxInt = std.math.maxInt;
std/math/atan.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// - atan(+-0) = +-03// - atan(+-0) = +-0
4// - atan(+-inf) = +-pi/24// - atan(+-inf) = +-pi/2
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const math = std.math;7const math = std.math;
8const expect = std.testing.expect;8const expect = std.testing.expect;
99
std/math/atan2.zig+1-1
...@@ -18,7 +18,7 @@...@@ -18,7 +18,7 @@
18// atan2(+inf, x) = +pi/218// atan2(+inf, x) = +pi/2
19// atan2(-inf, x) = -pi/219// atan2(-inf, x) = -pi/2
2020
21const std = @import("../index.zig");21const std = @import("../std.zig");
22const math = std.math;22const math = std.math;
23const expect = std.testing.expect;23const expect = std.testing.expect;
2424
std/math/atanh.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - atanh(x) = nan if |x| > 1 with signal4// - atanh(x) = nan if |x| > 1 with signal
5// - atanh(nan) = nan5// - atanh(nan) = nan
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
10const maxInt = std.math.maxInt;10const maxInt = std.math.maxInt;
std/math/big.zig created+5
...@@ -0,0 +1,5 @@
1pub use @import("big/int.zig");
2
3test "math.big" {
4 _ = @import("big/int.zig");
5}
std/math/big/index.zig deleted-5
...@@ -1,5 +0,0 @@
1pub use @import("int.zig");
2
3test "math.big" {
4 _ = @import("int.zig");
5}
std/math/big/int.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const debug = std.debug;3const debug = std.debug;
4const testing = std.testing;4const testing = std.testing;
std/math/cbrt.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - cbrt(+-inf) = +-inf4// - cbrt(+-inf) = +-inf
5// - cbrt(nan) = nan5// - cbrt(nan) = nan
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
1010
std/math/ceil.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - ceil(nan) = nan5// - ceil(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
1111
std/math/complex.zig created+171
...@@ -0,0 +1,171 @@
1const std = @import("../std.zig");
2const testing = std.testing;
3const math = std.math;
4
5pub const abs = @import("complex/abs.zig").abs;
6pub const acosh = @import("complex/acosh.zig").acosh;
7pub const acos = @import("complex/acos.zig").acos;
8pub const arg = @import("complex/arg.zig").arg;
9pub const asinh = @import("complex/asinh.zig").asinh;
10pub const asin = @import("complex/asin.zig").asin;
11pub const atanh = @import("complex/atanh.zig").atanh;
12pub const atan = @import("complex/atan.zig").atan;
13pub const conj = @import("complex/conj.zig").conj;
14pub const cosh = @import("complex/cosh.zig").cosh;
15pub const cos = @import("complex/cos.zig").cos;
16pub const exp = @import("complex/exp.zig").exp;
17pub const log = @import("complex/log.zig").log;
18pub const pow = @import("complex/pow.zig").pow;
19pub const proj = @import("complex/proj.zig").proj;
20pub const sinh = @import("complex/sinh.zig").sinh;
21pub const sin = @import("complex/sin.zig").sin;
22pub const sqrt = @import("complex/sqrt.zig").sqrt;
23pub const tanh = @import("complex/tanh.zig").tanh;
24pub const tan = @import("complex/tan.zig").tan;
25
26pub fn Complex(comptime T: type) type {
27 return struct {
28 const Self = @This();
29
30 re: T,
31 im: T,
32
33 pub fn new(re: T, im: T) Self {
34 return Self{
35 .re = re,
36 .im = im,
37 };
38 }
39
40 pub fn add(self: Self, other: Self) Self {
41 return Self{
42 .re = self.re + other.re,
43 .im = self.im + other.im,
44 };
45 }
46
47 pub fn sub(self: Self, other: Self) Self {
48 return Self{
49 .re = self.re - other.re,
50 .im = self.im - other.im,
51 };
52 }
53
54 pub fn mul(self: Self, other: Self) Self {
55 return Self{
56 .re = self.re * other.re - self.im * other.im,
57 .im = self.im * other.re + self.re * other.im,
58 };
59 }
60
61 pub fn div(self: Self, other: Self) Self {
62 const re_num = self.re * other.re + self.im * other.im;
63 const im_num = self.im * other.re - self.re * other.im;
64 const den = other.re * other.re + other.im * other.im;
65
66 return Self{
67 .re = re_num / den,
68 .im = im_num / den,
69 };
70 }
71
72 pub fn conjugate(self: Self) Self {
73 return Self{
74 .re = self.re,
75 .im = -self.im,
76 };
77 }
78
79 pub fn reciprocal(self: Self) Self {
80 const m = self.re * self.re + self.im * self.im;
81 return Self{
82 .re = self.re / m,
83 .im = -self.im / m,
84 };
85 }
86
87 pub fn magnitude(self: Self) T {
88 return math.sqrt(self.re * self.re + self.im * self.im);
89 }
90 };
91}
92
93const epsilon = 0.0001;
94
95test "complex.add" {
96 const a = Complex(f32).new(5, 3);
97 const b = Complex(f32).new(2, 7);
98 const c = a.add(b);
99
100 testing.expect(c.re == 7 and c.im == 10);
101}
102
103test "complex.sub" {
104 const a = Complex(f32).new(5, 3);
105 const b = Complex(f32).new(2, 7);
106 const c = a.sub(b);
107
108 testing.expect(c.re == 3 and c.im == -4);
109}
110
111test "complex.mul" {
112 const a = Complex(f32).new(5, 3);
113 const b = Complex(f32).new(2, 7);
114 const c = a.mul(b);
115
116 testing.expect(c.re == -11 and c.im == 41);
117}
118
119test "complex.div" {
120 const a = Complex(f32).new(5, 3);
121 const b = Complex(f32).new(2, 7);
122 const c = a.div(b);
123
124 testing.expect(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and
125 math.approxEq(f32, c.im, f32(-29) / 53, epsilon));
126}
127
128test "complex.conjugate" {
129 const a = Complex(f32).new(5, 3);
130 const c = a.conjugate();
131
132 testing.expect(c.re == 5 and c.im == -3);
133}
134
135test "complex.reciprocal" {
136 const a = Complex(f32).new(5, 3);
137 const c = a.reciprocal();
138
139 testing.expect(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and
140 math.approxEq(f32, c.im, f32(-3) / 34, epsilon));
141}
142
143test "complex.magnitude" {
144 const a = Complex(f32).new(5, 3);
145 const c = a.magnitude();
146
147 testing.expect(math.approxEq(f32, c, 5.83095, epsilon));
148}
149
150test "complex.cmath" {
151 _ = @import("complex/abs.zig");
152 _ = @import("complex/acosh.zig");
153 _ = @import("complex/acos.zig");
154 _ = @import("complex/arg.zig");
155 _ = @import("complex/asinh.zig");
156 _ = @import("complex/asin.zig");
157 _ = @import("complex/atanh.zig");
158 _ = @import("complex/atan.zig");
159 _ = @import("complex/conj.zig");
160 _ = @import("complex/cosh.zig");
161 _ = @import("complex/cos.zig");
162 _ = @import("complex/exp.zig");
163 _ = @import("complex/log.zig");
164 _ = @import("complex/pow.zig");
165 _ = @import("complex/proj.zig");
166 _ = @import("complex/sinh.zig");
167 _ = @import("complex/sin.zig");
168 _ = @import("complex/sqrt.zig");
169 _ = @import("complex/tanh.zig");
170 _ = @import("complex/tan.zig");
171}
std/math/complex/abs.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/acos.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/acosh.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/arg.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/asin.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/asinh.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/atan.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/atanh.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/conj.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/cos.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/cosh.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/exp.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/index.zig deleted-171
...@@ -1,171 +0,0 @@
1const std = @import("../../index.zig");
2const testing = std.testing;
3const math = std.math;
4
5pub const abs = @import("abs.zig").abs;
6pub const acosh = @import("acosh.zig").acosh;
7pub const acos = @import("acos.zig").acos;
8pub const arg = @import("arg.zig").arg;
9pub const asinh = @import("asinh.zig").asinh;
10pub const asin = @import("asin.zig").asin;
11pub const atanh = @import("atanh.zig").atanh;
12pub const atan = @import("atan.zig").atan;
13pub const conj = @import("conj.zig").conj;
14pub const cosh = @import("cosh.zig").cosh;
15pub const cos = @import("cos.zig").cos;
16pub const exp = @import("exp.zig").exp;
17pub const log = @import("log.zig").log;
18pub const pow = @import("pow.zig").pow;
19pub const proj = @import("proj.zig").proj;
20pub const sinh = @import("sinh.zig").sinh;
21pub const sin = @import("sin.zig").sin;
22pub const sqrt = @import("sqrt.zig").sqrt;
23pub const tanh = @import("tanh.zig").tanh;
24pub const tan = @import("tan.zig").tan;
25
26pub fn Complex(comptime T: type) type {
27 return struct {
28 const Self = @This();
29
30 re: T,
31 im: T,
32
33 pub fn new(re: T, im: T) Self {
34 return Self{
35 .re = re,
36 .im = im,
37 };
38 }
39
40 pub fn add(self: Self, other: Self) Self {
41 return Self{
42 .re = self.re + other.re,
43 .im = self.im + other.im,
44 };
45 }
46
47 pub fn sub(self: Self, other: Self) Self {
48 return Self{
49 .re = self.re - other.re,
50 .im = self.im - other.im,
51 };
52 }
53
54 pub fn mul(self: Self, other: Self) Self {
55 return Self{
56 .re = self.re * other.re - self.im * other.im,
57 .im = self.im * other.re + self.re * other.im,
58 };
59 }
60
61 pub fn div(self: Self, other: Self) Self {
62 const re_num = self.re * other.re + self.im * other.im;
63 const im_num = self.im * other.re - self.re * other.im;
64 const den = other.re * other.re + other.im * other.im;
65
66 return Self{
67 .re = re_num / den,
68 .im = im_num / den,
69 };
70 }
71
72 pub fn conjugate(self: Self) Self {
73 return Self{
74 .re = self.re,
75 .im = -self.im,
76 };
77 }
78
79 pub fn reciprocal(self: Self) Self {
80 const m = self.re * self.re + self.im * self.im;
81 return Self{
82 .re = self.re / m,
83 .im = -self.im / m,
84 };
85 }
86
87 pub fn magnitude(self: Self) T {
88 return math.sqrt(self.re * self.re + self.im * self.im);
89 }
90 };
91}
92
93const epsilon = 0.0001;
94
95test "complex.add" {
96 const a = Complex(f32).new(5, 3);
97 const b = Complex(f32).new(2, 7);
98 const c = a.add(b);
99
100 testing.expect(c.re == 7 and c.im == 10);
101}
102
103test "complex.sub" {
104 const a = Complex(f32).new(5, 3);
105 const b = Complex(f32).new(2, 7);
106 const c = a.sub(b);
107
108 testing.expect(c.re == 3 and c.im == -4);
109}
110
111test "complex.mul" {
112 const a = Complex(f32).new(5, 3);
113 const b = Complex(f32).new(2, 7);
114 const c = a.mul(b);
115
116 testing.expect(c.re == -11 and c.im == 41);
117}
118
119test "complex.div" {
120 const a = Complex(f32).new(5, 3);
121 const b = Complex(f32).new(2, 7);
122 const c = a.div(b);
123
124 testing.expect(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and
125 math.approxEq(f32, c.im, f32(-29) / 53, epsilon));
126}
127
128test "complex.conjugate" {
129 const a = Complex(f32).new(5, 3);
130 const c = a.conjugate();
131
132 testing.expect(c.re == 5 and c.im == -3);
133}
134
135test "complex.reciprocal" {
136 const a = Complex(f32).new(5, 3);
137 const c = a.reciprocal();
138
139 testing.expect(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and
140 math.approxEq(f32, c.im, f32(-3) / 34, epsilon));
141}
142
143test "complex.magnitude" {
144 const a = Complex(f32).new(5, 3);
145 const c = a.magnitude();
146
147 testing.expect(math.approxEq(f32, c, 5.83095, epsilon));
148}
149
150test "complex.cmath" {
151 _ = @import("abs.zig");
152 _ = @import("acosh.zig");
153 _ = @import("acos.zig");
154 _ = @import("arg.zig");
155 _ = @import("asinh.zig");
156 _ = @import("asin.zig");
157 _ = @import("atanh.zig");
158 _ = @import("atan.zig");
159 _ = @import("conj.zig");
160 _ = @import("cosh.zig");
161 _ = @import("cos.zig");
162 _ = @import("exp.zig");
163 _ = @import("log.zig");
164 _ = @import("pow.zig");
165 _ = @import("proj.zig");
166 _ = @import("sinh.zig");
167 _ = @import("sin.zig");
168 _ = @import("sqrt.zig");
169 _ = @import("tanh.zig");
170 _ = @import("tan.zig");
171}
std/math/complex/ldexp.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const debug = std.debug;2const debug = std.debug;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/log.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/pow.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/proj.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/sin.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/sinh.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/sqrt.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/tan.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/complex/tanh.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const testing = std.testing;2const testing = std.testing;
3const math = std.math;3const math = std.math;
4const cmath = math.complex;4const cmath = math.complex;
std/math/copysign.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
std/math/cos.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - cos(nan) = nan4// - cos(nan) = nan
55
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
1010
std/math/cosh.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - cosh(nan) = nan5// - cosh(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expo2 = @import("expo2.zig").expo2;10const expo2 = @import("expo2.zig").expo2;
11const expect = std.testing.expect;11const expect = std.testing.expect;
std/math/exp.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// - exp(+inf) = +inf3// - exp(+inf) = +inf
4// - exp(nan) = nan4// - exp(nan) = nan
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const math = std.math;7const math = std.math;
8const assert = std.debug.assert;8const assert = std.debug.assert;
9const builtin = @import("builtin");9const builtin = @import("builtin");
std/math/exp2.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// - exp2(+inf) = +inf3// - exp2(+inf) = +inf
4// - exp2(nan) = nan4// - exp2(nan) = nan
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const math = std.math;7const math = std.math;
8const expect = std.testing.expect;8const expect = std.testing.expect;
99
std/math/expm1.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - expm1(nan) = nan5// - expm1(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
1111
std/math/expo2.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const math = @import("index.zig");1const math = @import("../math.zig");
22
3pub fn expo2(x: var) @typeOf(x) {3pub fn expo2(x: var) @typeOf(x) {
4 const T = @typeOf(x);4 const T = @typeOf(x);
std/math/fabs.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// - fabs(+-inf) = +inf3// - fabs(+-inf) = +inf
4// - fabs(nan) = nan4// - fabs(nan) = nan
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const math = std.math;7const math = std.math;
8const expect = std.testing.expect;8const expect = std.testing.expect;
9const maxInt = std.math.maxInt;9const maxInt = std.math.maxInt;
std/math/floor.zig+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const expect = std.testing.expect;8const expect = std.testing.expect;
9const std = @import("../index.zig");9const std = @import("../std.zig");
10const math = std.math;10const math = std.math;
1111
12pub fn floor(x: var) @typeOf(x) {12pub fn floor(x: var) @typeOf(x) {
std/math/fma.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
std/math/frexp.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - frexp(+-inf) = +-inf, 04// - frexp(+-inf) = +-inf, 0
5// - frexp(nan) = nan, undefined5// - frexp(nan) = nan, undefined
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
1010
std/math/hypot.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - hypot(nan, y) = nan5// - hypot(nan, y) = nan
6// - hypot(x, nan) = nan6// - hypot(x, nan) = nan
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const maxInt = std.math.maxInt;11const maxInt = std.math.maxInt;
std/math/ilogb.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - ilogb(0) = maxInt(i32)4// - ilogb(0) = maxInt(i32)
5// - ilogb(nan) = maxInt(i32)5// - ilogb(nan) = maxInt(i32)
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
10const maxInt = std.math.maxInt;10const maxInt = std.math.maxInt;
std/math/index.zig deleted-797
...@@ -1,797 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("../index.zig");
3const TypeId = builtin.TypeId;
4const assert = std.debug.assert;
5const testing = std.testing;
6
7pub const e = 2.71828182845904523536028747135266249775724709369995;
8pub const pi = 3.14159265358979323846264338327950288419716939937510;
9
10// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
11pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001));
12pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000));
13pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
14pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000));
15pub const f128_toint = 1.0 / f128_epsilon;
16
17// float.h details
18pub const f64_true_min = 4.94065645841246544177e-324;
19pub const f64_min = 2.2250738585072014e-308;
20pub const f64_max = 1.79769313486231570815e+308;
21pub const f64_epsilon = 2.22044604925031308085e-16;
22pub const f64_toint = 1.0 / f64_epsilon;
23
24pub const f32_true_min = 1.40129846432481707092e-45;
25pub const f32_min = 1.17549435082228750797e-38;
26pub const f32_max = 3.40282346638528859812e+38;
27pub const f32_epsilon = 1.1920928955078125e-07;
28pub const f32_toint = 1.0 / f32_epsilon;
29
30pub const f16_true_min = 0.000000059604644775390625; // 2**-24
31pub const f16_min = 0.00006103515625; // 2**-14
32pub const f16_max = 65504;
33pub const f16_epsilon = 0.0009765625; // 2**-10
34pub const f16_toint = 1.0 / f16_epsilon;
35
36pub const nan_u16 = u16(0x7C01);
37pub const nan_f16 = @bitCast(f16, nan_u16);
38
39pub const inf_u16 = u16(0x7C00);
40pub const inf_f16 = @bitCast(f16, inf_u16);
41
42pub const nan_u32 = u32(0x7F800001);
43pub const nan_f32 = @bitCast(f32, nan_u32);
44
45pub const inf_u32 = u32(0x7F800000);
46pub const inf_f32 = @bitCast(f32, inf_u32);
47
48pub const nan_u64 = u64(0x7FF << 52) | 1;
49pub const nan_f64 = @bitCast(f64, nan_u64);
50
51pub const inf_u64 = u64(0x7FF << 52);
52pub const inf_f64 = @bitCast(f64, inf_u64);
53
54pub const nan_u128 = u128(0x7fff0000000000000000000000000001);
55pub const nan_f128 = @bitCast(f128, nan_u128);
56
57pub const inf_u128 = u128(0x7fff0000000000000000000000000000);
58pub const inf_f128 = @bitCast(f128, inf_u128);
59
60pub const nan = @import("nan.zig").nan;
61pub const snan = @import("nan.zig").snan;
62pub const inf = @import("inf.zig").inf;
63
64pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
65 assert(@typeId(T) == TypeId.Float);
66 return fabs(x - y) < epsilon;
67}
68
69// TODO: Hide the following in an internal module.
70pub fn forceEval(value: var) void {
71 const T = @typeOf(value);
72 switch (T) {
73 f16 => {
74 var x: f16 = undefined;
75 const p = @ptrCast(*volatile f16, &x);
76 p.* = x;
77 },
78 f32 => {
79 var x: f32 = undefined;
80 const p = @ptrCast(*volatile f32, &x);
81 p.* = x;
82 },
83 f64 => {
84 var x: f64 = undefined;
85 const p = @ptrCast(*volatile f64, &x);
86 p.* = x;
87 },
88 else => {
89 @compileError("forceEval not implemented for " ++ @typeName(T));
90 },
91 }
92}
93
94pub fn raiseInvalid() void {
95 // Raise INVALID fpu exception
96}
97
98pub fn raiseUnderflow() void {
99 // Raise UNDERFLOW fpu exception
100}
101
102pub fn raiseOverflow() void {
103 // Raise OVERFLOW fpu exception
104}
105
106pub fn raiseInexact() void {
107 // Raise INEXACT fpu exception
108}
109
110pub fn raiseDivByZero() void {
111 // Raise INEXACT fpu exception
112}
113
114pub const isNan = @import("isnan.zig").isNan;
115pub const isSignalNan = @import("isnan.zig").isSignalNan;
116pub const fabs = @import("fabs.zig").fabs;
117pub const ceil = @import("ceil.zig").ceil;
118pub const floor = @import("floor.zig").floor;
119pub const trunc = @import("trunc.zig").trunc;
120pub const round = @import("round.zig").round;
121pub const frexp = @import("frexp.zig").frexp;
122pub const frexp32_result = @import("frexp.zig").frexp32_result;
123pub const frexp64_result = @import("frexp.zig").frexp64_result;
124pub const modf = @import("modf.zig").modf;
125pub const modf32_result = @import("modf.zig").modf32_result;
126pub const modf64_result = @import("modf.zig").modf64_result;
127pub const copysign = @import("copysign.zig").copysign;
128pub const isFinite = @import("isfinite.zig").isFinite;
129pub const isInf = @import("isinf.zig").isInf;
130pub const isPositiveInf = @import("isinf.zig").isPositiveInf;
131pub const isNegativeInf = @import("isinf.zig").isNegativeInf;
132pub const isNormal = @import("isnormal.zig").isNormal;
133pub const signbit = @import("signbit.zig").signbit;
134pub const scalbn = @import("scalbn.zig").scalbn;
135pub const pow = @import("pow.zig").pow;
136pub const powi = @import("powi.zig").powi;
137pub const sqrt = @import("sqrt.zig").sqrt;
138pub const cbrt = @import("cbrt.zig").cbrt;
139pub const acos = @import("acos.zig").acos;
140pub const asin = @import("asin.zig").asin;
141pub const atan = @import("atan.zig").atan;
142pub const atan2 = @import("atan2.zig").atan2;
143pub const hypot = @import("hypot.zig").hypot;
144pub const exp = @import("exp.zig").exp;
145pub const exp2 = @import("exp2.zig").exp2;
146pub const expm1 = @import("expm1.zig").expm1;
147pub const ilogb = @import("ilogb.zig").ilogb;
148pub const ln = @import("ln.zig").ln;
149pub const log = @import("log.zig").log;
150pub const log2 = @import("log2.zig").log2;
151pub const log10 = @import("log10.zig").log10;
152pub const log1p = @import("log1p.zig").log1p;
153pub const fma = @import("fma.zig").fma;
154pub const asinh = @import("asinh.zig").asinh;
155pub const acosh = @import("acosh.zig").acosh;
156pub const atanh = @import("atanh.zig").atanh;
157pub const sinh = @import("sinh.zig").sinh;
158pub const cosh = @import("cosh.zig").cosh;
159pub const tanh = @import("tanh.zig").tanh;
160pub const cos = @import("cos.zig").cos;
161pub const sin = @import("sin.zig").sin;
162pub const tan = @import("tan.zig").tan;
163
164pub const complex = @import("complex/index.zig");
165pub const Complex = complex.Complex;
166
167pub const big = @import("big/index.zig");
168
169test "math" {
170 _ = @import("nan.zig");
171 _ = @import("isnan.zig");
172 _ = @import("fabs.zig");
173 _ = @import("ceil.zig");
174 _ = @import("floor.zig");
175 _ = @import("trunc.zig");
176 _ = @import("round.zig");
177 _ = @import("frexp.zig");
178 _ = @import("modf.zig");
179 _ = @import("copysign.zig");
180 _ = @import("isfinite.zig");
181 _ = @import("isinf.zig");
182 _ = @import("isnormal.zig");
183 _ = @import("signbit.zig");
184 _ = @import("scalbn.zig");
185 _ = @import("pow.zig");
186 _ = @import("powi.zig");
187 _ = @import("sqrt.zig");
188 _ = @import("cbrt.zig");
189 _ = @import("acos.zig");
190 _ = @import("asin.zig");
191 _ = @import("atan.zig");
192 _ = @import("atan2.zig");
193 _ = @import("hypot.zig");
194 _ = @import("exp.zig");
195 _ = @import("exp2.zig");
196 _ = @import("expm1.zig");
197 _ = @import("ilogb.zig");
198 _ = @import("ln.zig");
199 _ = @import("log.zig");
200 _ = @import("log2.zig");
201 _ = @import("log10.zig");
202 _ = @import("log1p.zig");
203 _ = @import("fma.zig");
204 _ = @import("asinh.zig");
205 _ = @import("acosh.zig");
206 _ = @import("atanh.zig");
207 _ = @import("sinh.zig");
208 _ = @import("cosh.zig");
209 _ = @import("tanh.zig");
210 _ = @import("sin.zig");
211 _ = @import("cos.zig");
212 _ = @import("tan.zig");
213
214 _ = @import("complex/index.zig");
215
216 _ = @import("big/index.zig");
217}
218
219pub fn floatMantissaBits(comptime T: type) comptime_int {
220 assert(@typeId(T) == builtin.TypeId.Float);
221
222 return switch (T.bit_count) {
223 16 => 10,
224 32 => 23,
225 64 => 52,
226 80 => 64,
227 128 => 112,
228 else => @compileError("unknown floating point type " ++ @typeName(T)),
229 };
230}
231
232pub fn floatExponentBits(comptime T: type) comptime_int {
233 assert(@typeId(T) == builtin.TypeId.Float);
234
235 return switch (T.bit_count) {
236 16 => 5,
237 32 => 8,
238 64 => 11,
239 80 => 15,
240 128 => 15,
241 else => @compileError("unknown floating point type " ++ @typeName(T)),
242 };
243}
244
245pub fn min(x: var, y: var) @typeOf(x + y) {
246 return if (x < y) x else y;
247}
248
249test "math.min" {
250 testing.expect(min(i32(-1), i32(2)) == -1);
251}
252
253pub fn max(x: var, y: var) @typeOf(x + y) {
254 return if (x > y) x else y;
255}
256
257test "math.max" {
258 testing.expect(max(i32(-1), i32(2)) == 2);
259}
260
261pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
262 var answer: T = undefined;
263 return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
264}
265
266pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
267 var answer: T = undefined;
268 return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
269}
270
271pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
272 var answer: T = undefined;
273 return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
274}
275
276pub fn negate(x: var) !@typeOf(x) {
277 return sub(@typeOf(x), 0, x);
278}
279
280pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
281 var answer: T = undefined;
282 return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
283}
284
285/// Shifts left. Overflowed bits are truncated.
286/// A negative shift amount results in a right shift.
287pub fn shl(comptime T: type, a: T, shift_amt: var) T {
288 const abs_shift_amt = absCast(shift_amt);
289 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
290
291 if (@typeOf(shift_amt).is_signed) {
292 if (shift_amt >= 0) {
293 return a << casted_shift_amt;
294 } else {
295 return a >> casted_shift_amt;
296 }
297 }
298
299 return a << casted_shift_amt;
300}
301
302test "math.shl" {
303 testing.expect(shl(u8, 0b11111111, usize(3)) == 0b11111000);
304 testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
305 testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
306 testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);
307}
308
309/// Shifts right. Overflowed bits are truncated.
310/// A negative shift amount results in a lefft shift.
311pub fn shr(comptime T: type, a: T, shift_amt: var) T {
312 const abs_shift_amt = absCast(shift_amt);
313 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
314
315 if (@typeOf(shift_amt).is_signed) {
316 if (shift_amt >= 0) {
317 return a >> casted_shift_amt;
318 } else {
319 return a << casted_shift_amt;
320 }
321 }
322
323 return a >> casted_shift_amt;
324}
325
326test "math.shr" {
327 testing.expect(shr(u8, 0b11111111, usize(3)) == 0b00011111);
328 testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
329 testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
330 testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
331}
332
333/// Rotates right. Only unsigned values can be rotated.
334/// Negative shift values results in shift modulo the bit count.
335pub fn rotr(comptime T: type, x: T, r: var) T {
336 if (T.is_signed) {
337 @compileError("cannot rotate signed integer");
338 } else {
339 const ar = @mod(r, T.bit_count);
340 return shr(T, x, ar) | shl(T, x, T.bit_count - ar);
341 }
342}
343
344test "math.rotr" {
345 testing.expect(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
346 testing.expect(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
347 testing.expect(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
348 testing.expect(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
349 testing.expect(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
350}
351
352/// Rotates left. Only unsigned values can be rotated.
353/// Negative shift values results in shift modulo the bit count.
354pub fn rotl(comptime T: type, x: T, r: var) T {
355 if (T.is_signed) {
356 @compileError("cannot rotate signed integer");
357 } else {
358 const ar = @mod(r, T.bit_count);
359 return shl(T, x, ar) | shr(T, x, T.bit_count - ar);
360 }
361}
362
363test "math.rotl" {
364 testing.expect(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
365 testing.expect(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
366 testing.expect(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
367 testing.expect(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
368 testing.expect(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
369}
370
371pub fn Log2Int(comptime T: type) type {
372 // comptime ceil log2
373 comptime var count = 0;
374 comptime var s = T.bit_count - 1;
375 inline while (s != 0) : (s >>= 1) {
376 count += 1;
377 }
378
379 return @IntType(false, count);
380}
381
382pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
383 assert(from <= to);
384 if (from == 0 and to == 0) {
385 return u0;
386 }
387 const is_signed = from < 0;
388 const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
389 const base = log2(largest_positive_integer);
390 const upper = (1 << base) - 1;
391 var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
392 if (is_signed) {
393 magnitude_bits += 1;
394 }
395 return @IntType(is_signed, magnitude_bits);
396}
397
398test "math.IntFittingRange" {
399 testing.expect(IntFittingRange(0, 0) == u0);
400 testing.expect(IntFittingRange(0, 1) == u1);
401 testing.expect(IntFittingRange(0, 2) == u2);
402 testing.expect(IntFittingRange(0, 3) == u2);
403 testing.expect(IntFittingRange(0, 4) == u3);
404 testing.expect(IntFittingRange(0, 7) == u3);
405 testing.expect(IntFittingRange(0, 8) == u4);
406 testing.expect(IntFittingRange(0, 9) == u4);
407 testing.expect(IntFittingRange(0, 15) == u4);
408 testing.expect(IntFittingRange(0, 16) == u5);
409 testing.expect(IntFittingRange(0, 17) == u5);
410 testing.expect(IntFittingRange(0, 4095) == u12);
411 testing.expect(IntFittingRange(2000, 4095) == u12);
412 testing.expect(IntFittingRange(0, 4096) == u13);
413 testing.expect(IntFittingRange(2000, 4096) == u13);
414 testing.expect(IntFittingRange(0, 4097) == u13);
415 testing.expect(IntFittingRange(2000, 4097) == u13);
416 testing.expect(IntFittingRange(0, 123456789123456798123456789) == u87);
417 testing.expect(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177);
418
419 testing.expect(IntFittingRange(-1, -1) == i1);
420 testing.expect(IntFittingRange(-1, 0) == i1);
421 testing.expect(IntFittingRange(-1, 1) == i2);
422 testing.expect(IntFittingRange(-2, -2) == i2);
423 testing.expect(IntFittingRange(-2, -1) == i2);
424 testing.expect(IntFittingRange(-2, 0) == i2);
425 testing.expect(IntFittingRange(-2, 1) == i2);
426 testing.expect(IntFittingRange(-2, 2) == i3);
427 testing.expect(IntFittingRange(-1, 2) == i3);
428 testing.expect(IntFittingRange(-1, 3) == i3);
429 testing.expect(IntFittingRange(-1, 4) == i4);
430 testing.expect(IntFittingRange(-1, 7) == i4);
431 testing.expect(IntFittingRange(-1, 8) == i5);
432 testing.expect(IntFittingRange(-1, 9) == i5);
433 testing.expect(IntFittingRange(-1, 15) == i5);
434 testing.expect(IntFittingRange(-1, 16) == i6);
435 testing.expect(IntFittingRange(-1, 17) == i6);
436 testing.expect(IntFittingRange(-1, 4095) == i13);
437 testing.expect(IntFittingRange(-4096, 4095) == i13);
438 testing.expect(IntFittingRange(-1, 4096) == i14);
439 testing.expect(IntFittingRange(-4097, 4095) == i14);
440 testing.expect(IntFittingRange(-1, 4097) == i14);
441 testing.expect(IntFittingRange(-1, 123456789123456798123456789) == i88);
442 testing.expect(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178);
443}
444
445test "math overflow functions" {
446 testOverflow();
447 comptime testOverflow();
448}
449
450fn testOverflow() void {
451 testing.expect((mul(i32, 3, 4) catch unreachable) == 12);
452 testing.expect((add(i32, 3, 4) catch unreachable) == 7);
453 testing.expect((sub(i32, 3, 4) catch unreachable) == -1);
454 testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
455}
456
457pub fn absInt(x: var) !@typeOf(x) {
458 const T = @typeOf(x);
459 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
460 comptime assert(T.is_signed); // must pass a signed integer to absInt
461
462 if (x == minInt(@typeOf(x))) {
463 return error.Overflow;
464 } else {
465 @setRuntimeSafety(false);
466 return if (x < 0) -x else x;
467 }
468}
469
470test "math.absInt" {
471 testAbsInt();
472 comptime testAbsInt();
473}
474fn testAbsInt() void {
475 testing.expect((absInt(i32(-10)) catch unreachable) == 10);
476 testing.expect((absInt(i32(10)) catch unreachable) == 10);
477}
478
479pub const absFloat = @import("fabs.zig").fabs;
480
481pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
482 @setRuntimeSafety(false);
483 if (denominator == 0) return error.DivisionByZero;
484 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
485 return @divTrunc(numerator, denominator);
486}
487
488test "math.divTrunc" {
489 testDivTrunc();
490 comptime testDivTrunc();
491}
492fn testDivTrunc() void {
493 testing.expect((divTrunc(i32, 5, 3) catch unreachable) == 1);
494 testing.expect((divTrunc(i32, -5, 3) catch unreachable) == -1);
495 testing.expectError(error.DivisionByZero, divTrunc(i8, -5, 0));
496 testing.expectError(error.Overflow, divTrunc(i8, -128, -1));
497
498 testing.expect((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0);
499 testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);
500}
501
502pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
503 @setRuntimeSafety(false);
504 if (denominator == 0) return error.DivisionByZero;
505 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
506 return @divFloor(numerator, denominator);
507}
508
509test "math.divFloor" {
510 testDivFloor();
511 comptime testDivFloor();
512}
513fn testDivFloor() void {
514 testing.expect((divFloor(i32, 5, 3) catch unreachable) == 1);
515 testing.expect((divFloor(i32, -5, 3) catch unreachable) == -2);
516 testing.expectError(error.DivisionByZero, divFloor(i8, -5, 0));
517 testing.expectError(error.Overflow, divFloor(i8, -128, -1));
518
519 testing.expect((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0);
520 testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);
521}
522
523pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
524 @setRuntimeSafety(false);
525 if (denominator == 0) return error.DivisionByZero;
526 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
527 const result = @divTrunc(numerator, denominator);
528 if (result * denominator != numerator) return error.UnexpectedRemainder;
529 return result;
530}
531
532test "math.divExact" {
533 testDivExact();
534 comptime testDivExact();
535}
536fn testDivExact() void {
537 testing.expect((divExact(i32, 10, 5) catch unreachable) == 2);
538 testing.expect((divExact(i32, -10, 5) catch unreachable) == -2);
539 testing.expectError(error.DivisionByZero, divExact(i8, -5, 0));
540 testing.expectError(error.Overflow, divExact(i8, -128, -1));
541 testing.expectError(error.UnexpectedRemainder, divExact(i32, 5, 2));
542
543 testing.expect((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0);
544 testing.expect((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0);
545 testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0));
546}
547
548pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
549 @setRuntimeSafety(false);
550 if (denominator == 0) return error.DivisionByZero;
551 if (denominator < 0) return error.NegativeDenominator;
552 return @mod(numerator, denominator);
553}
554
555test "math.mod" {
556 testMod();
557 comptime testMod();
558}
559fn testMod() void {
560 testing.expect((mod(i32, -5, 3) catch unreachable) == 1);
561 testing.expect((mod(i32, 5, 3) catch unreachable) == 2);
562 testing.expectError(error.NegativeDenominator, mod(i32, 10, -1));
563 testing.expectError(error.DivisionByZero, mod(i32, 10, 0));
564
565 testing.expect((mod(f32, -5, 3) catch unreachable) == 1);
566 testing.expect((mod(f32, 5, 3) catch unreachable) == 2);
567 testing.expectError(error.NegativeDenominator, mod(f32, 10, -1));
568 testing.expectError(error.DivisionByZero, mod(f32, 10, 0));
569}
570
571pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
572 @setRuntimeSafety(false);
573 if (denominator == 0) return error.DivisionByZero;
574 if (denominator < 0) return error.NegativeDenominator;
575 return @rem(numerator, denominator);
576}
577
578test "math.rem" {
579 testRem();
580 comptime testRem();
581}
582fn testRem() void {
583 testing.expect((rem(i32, -5, 3) catch unreachable) == -2);
584 testing.expect((rem(i32, 5, 3) catch unreachable) == 2);
585 testing.expectError(error.NegativeDenominator, rem(i32, 10, -1));
586 testing.expectError(error.DivisionByZero, rem(i32, 10, 0));
587
588 testing.expect((rem(f32, -5, 3) catch unreachable) == -2);
589 testing.expect((rem(f32, 5, 3) catch unreachable) == 2);
590 testing.expectError(error.NegativeDenominator, rem(f32, 10, -1));
591 testing.expectError(error.DivisionByZero, rem(f32, 10, 0));
592}
593
594/// Returns the absolute value of the integer parameter.
595/// Result is an unsigned integer.
596pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
597 const uint = @IntType(false, @typeOf(x).bit_count);
598 if (x >= 0) return @intCast(uint, x);
599
600 return @intCast(uint, -(x + 1)) + 1;
601}
602
603test "math.absCast" {
604 testing.expect(absCast(i32(-999)) == 999);
605 testing.expect(@typeOf(absCast(i32(-999))) == u32);
606
607 testing.expect(absCast(i32(999)) == 999);
608 testing.expect(@typeOf(absCast(i32(999))) == u32);
609
610 testing.expect(absCast(i32(minInt(i32))) == -minInt(i32));
611 testing.expect(@typeOf(absCast(i32(minInt(i32)))) == u32);
612}
613
614/// Returns the negation of the integer parameter.
615/// Result is a signed integer.
616pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
617 if (@typeOf(x).is_signed) return negate(x);
618
619 const int = @IntType(true, @typeOf(x).bit_count);
620 if (x > -minInt(int)) return error.Overflow;
621
622 if (x == -minInt(int)) return minInt(int);
623
624 return -@intCast(int, x);
625}
626
627test "math.negateCast" {
628 testing.expect((negateCast(u32(999)) catch unreachable) == -999);
629 testing.expect(@typeOf(negateCast(u32(999)) catch unreachable) == i32);
630
631 testing.expect((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32));
632 testing.expect(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32);
633
634 testing.expectError(error.Overflow, negateCast(u32(maxInt(i32) + 10)));
635}
636
637/// Cast an integer to a different integer type. If the value doesn't fit,
638/// return an error.
639pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
640 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
641 comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Int); // must pass an integer
642 if (maxInt(@typeOf(x)) > maxInt(T) and x > maxInt(T)) {
643 return error.Overflow;
644 } else if (minInt(@typeOf(x)) < minInt(T) and x < minInt(T)) {
645 return error.Overflow;
646 } else {
647 return @intCast(T, x);
648 }
649}
650
651test "math.cast" {
652 testing.expectError(error.Overflow, cast(u8, u32(300)));
653 testing.expectError(error.Overflow, cast(i8, i32(-200)));
654 testing.expectError(error.Overflow, cast(u8, i8(-1)));
655 testing.expectError(error.Overflow, cast(u64, i8(-1)));
656
657 testing.expect((try cast(u8, u32(255))) == u8(255));
658 testing.expect(@typeOf(try cast(u8, u32(255))) == u8);
659}
660
661pub const AlignCastError = error{UnalignedMemory};
662
663/// Align cast a pointer but return an error if it's the wrong alignment
664pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alignCast(alignment, ptr)) {
665 const addr = @ptrToInt(ptr);
666 if (addr % alignment != 0) {
667 return error.UnalignedMemory;
668 }
669 return @alignCast(alignment, ptr);
670}
671
672pub fn floorPowerOfTwo(comptime T: type, value: T) T {
673 var x = value;
674
675 comptime var i = 1;
676 inline while (T.bit_count > i) : (i *= 2) {
677 x |= (x >> i);
678 }
679
680 return x - (x >> 1);
681}
682
683test "math.floorPowerOfTwo" {
684 testFloorPowerOfTwo();
685 comptime testFloorPowerOfTwo();
686}
687
688pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
689 assert(x != 0);
690 return @intCast(Log2Int(T), T.bit_count - 1 - @clz(x));
691}
692
693pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
694 assert(x != 0);
695 const log2_val = log2_int(T, x);
696 if (T(1) << log2_val == x)
697 return log2_val;
698 return log2_val + 1;
699}
700
701test "std.math.log2_int_ceil" {
702 testing.expect(log2_int_ceil(u32, 1) == 0);
703 testing.expect(log2_int_ceil(u32, 2) == 1);
704 testing.expect(log2_int_ceil(u32, 3) == 2);
705 testing.expect(log2_int_ceil(u32, 4) == 2);
706 testing.expect(log2_int_ceil(u32, 5) == 3);
707 testing.expect(log2_int_ceil(u32, 6) == 3);
708 testing.expect(log2_int_ceil(u32, 7) == 3);
709 testing.expect(log2_int_ceil(u32, 8) == 3);
710 testing.expect(log2_int_ceil(u32, 9) == 4);
711 testing.expect(log2_int_ceil(u32, 10) == 4);
712}
713
714fn testFloorPowerOfTwo() void {
715 testing.expect(floorPowerOfTwo(u32, 63) == 32);
716 testing.expect(floorPowerOfTwo(u32, 64) == 64);
717 testing.expect(floorPowerOfTwo(u32, 65) == 64);
718 testing.expect(floorPowerOfTwo(u4, 7) == 4);
719 testing.expect(floorPowerOfTwo(u4, 8) == 8);
720 testing.expect(floorPowerOfTwo(u4, 9) == 8);
721}
722
723pub fn lossyCast(comptime T: type, value: var) T {
724 switch (@typeInfo(@typeOf(value))) {
725 builtin.TypeId.Int => return @intToFloat(T, value),
726 builtin.TypeId.Float => return @floatCast(T, value),
727 builtin.TypeId.ComptimeInt => return T(value),
728 builtin.TypeId.ComptimeFloat => return T(value),
729 else => @compileError("bad type"),
730 }
731}
732
733test "math.f64_min" {
734 const f64_min_u64 = 0x0010000000000000;
735 const fmin: f64 = f64_min;
736 testing.expect(@bitCast(u64, fmin) == f64_min_u64);
737}
738
739pub fn maxInt(comptime T: type) comptime_int {
740 const info = @typeInfo(T);
741 const bit_count = comptime_int(info.Int.bits); // TODO #1683
742 if (bit_count == 0) return 0;
743 return (1 << (bit_count - @boolToInt(info.Int.is_signed))) - 1;
744}
745
746pub fn minInt(comptime T: type) comptime_int {
747 const info = @typeInfo(T);
748 const bit_count = comptime_int(info.Int.bits); // TODO #1683
749 if (!info.Int.is_signed) return 0;
750 if (bit_count == 0) return 0;
751 return -(1 << (bit_count - 1));
752}
753
754test "minInt and maxInt" {
755 testing.expect(maxInt(u0) == 0);
756 testing.expect(maxInt(u1) == 1);
757 testing.expect(maxInt(u8) == 255);
758 testing.expect(maxInt(u16) == 65535);
759 testing.expect(maxInt(u32) == 4294967295);
760 testing.expect(maxInt(u64) == 18446744073709551615);
761 testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
762
763 testing.expect(maxInt(i0) == 0);
764 testing.expect(maxInt(i1) == 0);
765 testing.expect(maxInt(i8) == 127);
766 testing.expect(maxInt(i16) == 32767);
767 testing.expect(maxInt(i32) == 2147483647);
768 testing.expect(maxInt(i63) == 4611686018427387903);
769 testing.expect(maxInt(i64) == 9223372036854775807);
770 testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
771
772 testing.expect(minInt(u0) == 0);
773 testing.expect(minInt(u1) == 0);
774 testing.expect(minInt(u8) == 0);
775 testing.expect(minInt(u16) == 0);
776 testing.expect(minInt(u32) == 0);
777 testing.expect(minInt(u63) == 0);
778 testing.expect(minInt(u64) == 0);
779 testing.expect(minInt(u128) == 0);
780
781 testing.expect(minInt(i0) == 0);
782 testing.expect(minInt(i1) == -1);
783 testing.expect(minInt(i8) == -128);
784 testing.expect(minInt(i16) == -32768);
785 testing.expect(minInt(i32) == -2147483648);
786 testing.expect(minInt(i63) == -4611686018427387904);
787 testing.expect(minInt(i64) == -9223372036854775808);
788 testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
789}
790
791test "max value type" {
792 // If the type of maxInt(i32) was i32 then this implicit cast to
793 // u32 would not work. But since the value is a number literal,
794 // it works fine.
795 const x: u32 = maxInt(i32);
796 testing.expect(x == 2147483647);
797}
std/math/inf.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
33
4pub fn inf(comptime T: type) T {4pub fn inf(comptime T: type) T {
std/math/isfinite.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
std/math/isinf.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
std/math/isnan.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
std/math/isnormal.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
std/math/ln.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - ln(x) = nan if x < 05// - ln(x) = nan if x < 0
6// - ln(nan) = nan6// - ln(nan) = nan
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const builtin = @import("builtin");11const builtin = @import("builtin");
std/math/log.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const TypeId = builtin.TypeId;4const TypeId = builtin.TypeId;
std/math/log10.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - log10(x) = nan if x < 05// - log10(x) = nan if x < 0
6// - log10(nan) = nan6// - log10(nan) = nan
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const testing = std.testing;10const testing = std.testing;
11const builtin = @import("builtin");11const builtin = @import("builtin");
std/math/log1p.zig+1-1
...@@ -7,7 +7,7 @@...@@ -7,7 +7,7 @@
7// - log1p(nan) = nan7// - log1p(nan) = nan
88
9const builtin = @import("builtin");9const builtin = @import("builtin");
10const std = @import("../index.zig");10const std = @import("../std.zig");
11const math = std.math;11const math = std.math;
12const expect = std.testing.expect;12const expect = std.testing.expect;
1313
std/math/log2.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - log2(x) = nan if x < 05// - log2(x) = nan if x < 0
6// - log2(nan) = nan6// - log2(nan) = nan
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const builtin = @import("builtin");11const builtin = @import("builtin");
std/math/modf.zig+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3// - modf(+-inf) = +-inf, nan3// - modf(+-inf) = +-inf, nan
4// - modf(nan) = nan, nan4// - modf(nan) = nan, nan
55
6const std = @import("../index.zig");6const std = @import("../std.zig");
7const math = std.math;7const math = std.math;
8const expect = std.testing.expect;8const expect = std.testing.expect;
9const maxInt = std.math.maxInt;9const maxInt = std.math.maxInt;
std/math/nan.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const math = @import("index.zig");1const math = @import("../math.zig");
22
3pub fn nan(comptime T: type) T {3pub fn nan(comptime T: type) T {
4 return switch (T) {4 return switch (T) {
std/math/pow.zig+1-1
...@@ -22,7 +22,7 @@...@@ -22,7 +22,7 @@
22// pow(x, y) = nan for finite x < 0 and finite non-integer y22// pow(x, y) = nan for finite x < 0 and finite non-integer y
2323
24const builtin = @import("builtin");24const builtin = @import("builtin");
25const std = @import("../index.zig");25const std = @import("../std.zig");
26const math = std.math;26const math = std.math;
27const expect = std.testing.expect;27const expect = std.testing.expect;
2828
std/math/powi.zig+1-1
...@@ -9,7 +9,7 @@...@@ -9,7 +9,7 @@
9// powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 09// powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 0
1010
11const builtin = @import("builtin");11const builtin = @import("builtin");
12const std = @import("../index.zig");12const std = @import("../std.zig");
13const math = std.math;13const math = std.math;
14const assert = std.debug.assert;14const assert = std.debug.assert;
15const testing = std.testing;15const testing = std.testing;
std/math/round.zig+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const expect = std.testing.expect;8const expect = std.testing.expect;
9const std = @import("../index.zig");9const std = @import("../std.zig");
10const math = std.math;10const math = std.math;
1111
12pub fn round(x: var) @typeOf(x) {12pub fn round(x: var) @typeOf(x) {
std/math/scalbn.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
std/math/signbit.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const math = std.math;2const math = std.math;
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
std/math/sin.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - sin(nan) = nan5// - sin(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
1111
std/math/sinh.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - sinh(nan) = nan5// - sinh(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const expo2 = @import("expo2.zig").expo2;11const expo2 = @import("expo2.zig").expo2;
std/math/sqrt.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - sqrt(x) = nan if x < 05// - sqrt(x) = nan if x < 0
6// - sqrt(nan) = nan6// - sqrt(nan) = nan
77
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const builtin = @import("builtin");11const builtin = @import("builtin");
std/math/tan.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - tan(nan) = nan5// - tan(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
1111
std/math/tanh.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// - sinh(nan) = nan5// - sinh(nan) = nan
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const std = @import("../index.zig");8const std = @import("../std.zig");
9const math = std.math;9const math = std.math;
10const expect = std.testing.expect;10const expect = std.testing.expect;
11const expo2 = @import("expo2.zig").expo2;11const expo2 = @import("expo2.zig").expo2;
std/math/trunc.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4// - trunc(+-inf) = +-inf4// - trunc(+-inf) = +-inf
5// - trunc(nan) = nan5// - trunc(nan) = nan
66
7const std = @import("../index.zig");7const std = @import("../std.zig");
8const math = std.math;8const math = std.math;
9const expect = std.testing.expect;9const expect = std.testing.expect;
10const maxInt = std.math.maxInt;10const maxInt = std.math.maxInt;
std/mem.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const math = std.math;4const math = std.math;
std/meta.zig created+569
...@@ -0,0 +1,569 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");
3const debug = std.debug;
4const mem = std.mem;
5const math = std.math;
6const testing = std.testing;
7
8pub const trait = @import("meta/trait.zig");
9
10const TypeId = builtin.TypeId;
11const TypeInfo = builtin.TypeInfo;
12
13pub fn tagName(v: var) []const u8 {
14 const T = @typeOf(v);
15 switch (@typeInfo(T)) {
16 TypeId.Enum => |info| {
17 const Tag = info.tag_type;
18 inline for (info.fields) |field| {
19 if (field.value == @enumToInt(v)) return field.name;
20 }
21
22 unreachable;
23 },
24 TypeId.Union => |info| {
25 const UnionTag = if (info.tag_type) |UT| UT else @compileError("union is untagged");
26 const Tag = @typeInfo(UnionTag).Enum.tag_type;
27 inline for (info.fields) |field| {
28 if (field.enum_field.?.value == @enumToInt(UnionTag(v)))
29 return field.name;
30 }
31
32 unreachable;
33 },
34 TypeId.ErrorSet => |info| {
35 inline for (info.errors) |err| {
36 if (err.value == @errorToInt(v)) return err.name;
37 }
38
39 unreachable;
40 },
41 else => @compileError("expected enum, error set or union type, found '" ++ @typeName(T) ++ "'"),
42 }
43}
44
45test "std.meta.tagName" {
46 const E1 = enum {
47 A,
48 B,
49 };
50 const E2 = enum(u8) {
51 C = 33,
52 D,
53 };
54 const U1 = union(enum) {
55 G: u8,
56 H: u16,
57 };
58 const U2 = union(E2) {
59 C: u8,
60 D: u16,
61 };
62
63 var u1g = U1{ .G = 0 };
64 var u1h = U1{ .H = 0 };
65 var u2a = U2{ .C = 0 };
66 var u2b = U2{ .D = 0 };
67
68 testing.expect(mem.eql(u8, tagName(E1.A), "A"));
69 testing.expect(mem.eql(u8, tagName(E1.B), "B"));
70 testing.expect(mem.eql(u8, tagName(E2.C), "C"));
71 testing.expect(mem.eql(u8, tagName(E2.D), "D"));
72 testing.expect(mem.eql(u8, tagName(error.E), "E"));
73 testing.expect(mem.eql(u8, tagName(error.F), "F"));
74 testing.expect(mem.eql(u8, tagName(u1g), "G"));
75 testing.expect(mem.eql(u8, tagName(u1h), "H"));
76 testing.expect(mem.eql(u8, tagName(u2a), "C"));
77 testing.expect(mem.eql(u8, tagName(u2b), "D"));
78}
79
80pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
81 inline for (@typeInfo(T).Enum.fields) |enumField| {
82 if (std.mem.eql(u8, str, enumField.name)) {
83 return @field(T, enumField.name);
84 }
85 }
86 return null;
87}
88
89test "std.meta.stringToEnum" {
90 const E1 = enum {
91 A,
92 B,
93 };
94 testing.expect(E1.A == stringToEnum(E1, "A").?);
95 testing.expect(E1.B == stringToEnum(E1, "B").?);
96 testing.expect(null == stringToEnum(E1, "C"));
97}
98
99pub fn bitCount(comptime T: type) comptime_int {
100 return switch (@typeInfo(T)) {
101 TypeId.Int => |info| info.bits,
102 TypeId.Float => |info| info.bits,
103 else => @compileError("Expected int or float type, found '" ++ @typeName(T) ++ "'"),
104 };
105}
106
107test "std.meta.bitCount" {
108 testing.expect(bitCount(u8) == 8);
109 testing.expect(bitCount(f32) == 32);
110}
111
112pub fn alignment(comptime T: type) comptime_int {
113 //@alignOf works on non-pointer types
114 const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T;
115 return @typeInfo(P).Pointer.alignment;
116}
117
118test "std.meta.alignment" {
119 testing.expect(alignment(u8) == 1);
120 testing.expect(alignment(*align(1) u8) == 1);
121 testing.expect(alignment(*align(2) u8) == 2);
122 testing.expect(alignment([]align(1) u8) == 1);
123 testing.expect(alignment([]align(2) u8) == 2);
124}
125
126pub fn Child(comptime T: type) type {
127 return switch (@typeInfo(T)) {
128 TypeId.Array => |info| info.child,
129 TypeId.Pointer => |info| info.child,
130 TypeId.Optional => |info| info.child,
131 TypeId.Promise => |info| if (info.child) |child| child else null,
132 else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
133 };
134}
135
136test "std.meta.Child" {
137 testing.expect(Child([1]u8) == u8);
138 testing.expect(Child(*u8) == u8);
139 testing.expect(Child([]u8) == u8);
140 testing.expect(Child(?u8) == u8);
141 testing.expect(Child(promise->u8) == u8);
142}
143
144pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
145 return switch (@typeInfo(T)) {
146 TypeId.Struct => |info| info.layout,
147 TypeId.Enum => |info| info.layout,
148 TypeId.Union => |info| info.layout,
149 else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
150 };
151}
152
153test "std.meta.containerLayout" {
154 const E1 = enum {
155 A,
156 };
157 const E2 = packed enum {
158 A,
159 };
160 const E3 = extern enum {
161 A,
162 };
163 const S1 = struct {};
164 const S2 = packed struct {};
165 const S3 = extern struct {};
166 const U1 = union {
167 a: u8,
168 };
169 const U2 = packed union {
170 a: u8,
171 };
172 const U3 = extern union {
173 a: u8,
174 };
175
176 testing.expect(containerLayout(E1) == TypeInfo.ContainerLayout.Auto);
177 testing.expect(containerLayout(E2) == TypeInfo.ContainerLayout.Packed);
178 testing.expect(containerLayout(E3) == TypeInfo.ContainerLayout.Extern);
179 testing.expect(containerLayout(S1) == TypeInfo.ContainerLayout.Auto);
180 testing.expect(containerLayout(S2) == TypeInfo.ContainerLayout.Packed);
181 testing.expect(containerLayout(S3) == TypeInfo.ContainerLayout.Extern);
182 testing.expect(containerLayout(U1) == TypeInfo.ContainerLayout.Auto);
183 testing.expect(containerLayout(U2) == TypeInfo.ContainerLayout.Packed);
184 testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern);
185}
186
187pub fn definitions(comptime T: type) []TypeInfo.Definition {
188 return switch (@typeInfo(T)) {
189 TypeId.Struct => |info| info.defs,
190 TypeId.Enum => |info| info.defs,
191 TypeId.Union => |info| info.defs,
192 else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
193 };
194}
195
196test "std.meta.definitions" {
197 const E1 = enum {
198 A,
199
200 fn a() void {}
201 };
202 const S1 = struct {
203 fn a() void {}
204 };
205 const U1 = union {
206 a: u8,
207
208 fn a() void {}
209 };
210
211 const defs = comptime [][]TypeInfo.Definition{
212 definitions(E1),
213 definitions(S1),
214 definitions(U1),
215 };
216
217 inline for (defs) |def| {
218 testing.expect(def.len == 1);
219 testing.expect(comptime mem.eql(u8, def[0].name, "a"));
220 }
221}
222
223pub fn definitionInfo(comptime T: type, comptime def_name: []const u8) TypeInfo.Definition {
224 inline for (comptime definitions(T)) |def| {
225 if (comptime mem.eql(u8, def.name, def_name))
226 return def;
227 }
228
229 @compileError("'" ++ @typeName(T) ++ "' has no definition '" ++ def_name ++ "'");
230}
231
232test "std.meta.definitionInfo" {
233 const E1 = enum {
234 A,
235
236 fn a() void {}
237 };
238 const S1 = struct {
239 fn a() void {}
240 };
241 const U1 = union {
242 a: u8,
243
244 fn a() void {}
245 };
246
247 const infos = comptime []TypeInfo.Definition{
248 definitionInfo(E1, "a"),
249 definitionInfo(S1, "a"),
250 definitionInfo(U1, "a"),
251 };
252
253 inline for (infos) |info| {
254 testing.expect(comptime mem.eql(u8, info.name, "a"));
255 testing.expect(!info.is_pub);
256 }
257}
258
259pub fn fields(comptime T: type) switch (@typeInfo(T)) {
260 TypeId.Struct => []TypeInfo.StructField,
261 TypeId.Union => []TypeInfo.UnionField,
262 TypeId.ErrorSet => []TypeInfo.Error,
263 TypeId.Enum => []TypeInfo.EnumField,
264 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
265} {
266 return switch (@typeInfo(T)) {
267 TypeId.Struct => |info| info.fields,
268 TypeId.Union => |info| info.fields,
269 TypeId.Enum => |info| info.fields,
270 TypeId.ErrorSet => |info| info.errors,
271 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
272 };
273}
274
275test "std.meta.fields" {
276 const E1 = enum {
277 A,
278 };
279 const E2 = error{A};
280 const S1 = struct {
281 a: u8,
282 };
283 const U1 = union {
284 a: u8,
285 };
286
287 const e1f = comptime fields(E1);
288 const e2f = comptime fields(E2);
289 const sf = comptime fields(S1);
290 const uf = comptime fields(U1);
291
292 testing.expect(e1f.len == 1);
293 testing.expect(e2f.len == 1);
294 testing.expect(sf.len == 1);
295 testing.expect(uf.len == 1);
296 testing.expect(mem.eql(u8, e1f[0].name, "A"));
297 testing.expect(mem.eql(u8, e2f[0].name, "A"));
298 testing.expect(mem.eql(u8, sf[0].name, "a"));
299 testing.expect(mem.eql(u8, uf[0].name, "a"));
300 testing.expect(comptime sf[0].field_type == u8);
301 testing.expect(comptime uf[0].field_type == u8);
302}
303
304pub fn fieldInfo(comptime T: type, comptime field_name: []const u8) switch (@typeInfo(T)) {
305 TypeId.Struct => TypeInfo.StructField,
306 TypeId.Union => TypeInfo.UnionField,
307 TypeId.ErrorSet => TypeInfo.Error,
308 TypeId.Enum => TypeInfo.EnumField,
309 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
310} {
311 inline for (comptime fields(T)) |field| {
312 if (comptime mem.eql(u8, field.name, field_name))
313 return field;
314 }
315
316 @compileError("'" ++ @typeName(T) ++ "' has no field '" ++ field_name ++ "'");
317}
318
319test "std.meta.fieldInfo" {
320 const E1 = enum {
321 A,
322 };
323 const E2 = error{A};
324 const S1 = struct {
325 a: u8,
326 };
327 const U1 = union {
328 a: u8,
329 };
330
331 const e1f = comptime fieldInfo(E1, "A");
332 const e2f = comptime fieldInfo(E2, "A");
333 const sf = comptime fieldInfo(S1, "a");
334 const uf = comptime fieldInfo(U1, "a");
335
336 testing.expect(mem.eql(u8, e1f.name, "A"));
337 testing.expect(mem.eql(u8, e2f.name, "A"));
338 testing.expect(mem.eql(u8, sf.name, "a"));
339 testing.expect(mem.eql(u8, uf.name, "a"));
340 testing.expect(comptime sf.field_type == u8);
341 testing.expect(comptime uf.field_type == u8);
342}
343
344pub fn TagType(comptime T: type) type {
345 return switch (@typeInfo(T)) {
346 TypeId.Enum => |info| info.tag_type,
347 TypeId.Union => |info| if (info.tag_type) |Tag| Tag else null,
348 else => @compileError("expected enum or union type, found '" ++ @typeName(T) ++ "'"),
349 };
350}
351
352test "std.meta.TagType" {
353 const E = enum(u8) {
354 C = 33,
355 D,
356 };
357 const U = union(E) {
358 C: u8,
359 D: u16,
360 };
361
362 testing.expect(TagType(E) == u8);
363 testing.expect(TagType(U) == E);
364}
365
366///Returns the active tag of a tagged union
367pub fn activeTag(u: var) @TagType(@typeOf(u)) {
368 const T = @typeOf(u);
369 return @TagType(T)(u);
370}
371
372test "std.meta.activeTag" {
373 const UE = enum {
374 Int,
375 Float,
376 };
377
378 const U = union(UE) {
379 Int: u32,
380 Float: f32,
381 };
382
383 var u = U{ .Int = 32 };
384 testing.expect(activeTag(u) == UE.Int);
385
386 u = U{ .Float = 112.9876 };
387 testing.expect(activeTag(u) == UE.Float);
388}
389
390///Given a tagged union type, and an enum, return the type of the union
391/// field corresponding to the enum tag.
392pub fn TagPayloadType(comptime U: type, tag: var) type {
393 const Tag = @typeOf(tag);
394 testing.expect(trait.is(builtin.TypeId.Union)(U));
395 testing.expect(trait.is(builtin.TypeId.Enum)(Tag));
396
397 const info = @typeInfo(U).Union;
398
399 inline for (info.fields) |field_info| {
400 if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
401 }
402 unreachable;
403}
404
405test "std.meta.TagPayloadType" {
406 const Event = union(enum) {
407 Moved: struct {
408 from: i32,
409 to: i32,
410 },
411 };
412 const MovedEvent = TagPayloadType(Event, Event.Moved);
413 var e: Event = undefined;
414 testing.expect(MovedEvent == @typeOf(e.Moved));
415}
416
417///Compares two of any type for equality. Containers are compared on a field-by-field basis,
418/// where possible. Pointers are not followed.
419pub fn eql(a: var, b: @typeOf(a)) bool {
420 const T = @typeOf(a);
421
422 switch (@typeId(T)) {
423 builtin.TypeId.Struct => {
424 const info = @typeInfo(T).Struct;
425
426 inline for (info.fields) |field_info| {
427 if (!eql(@field(a, field_info.name), @field(b, field_info.name))) return false;
428 }
429 return true;
430 },
431 builtin.TypeId.ErrorUnion => {
432 if (a) |a_p| {
433 if (b) |b_p| return eql(a_p, b_p) else |_| return false;
434 } else |a_e| {
435 if (b) |_| return false else |b_e| return a_e == b_e;
436 }
437 },
438 builtin.TypeId.Union => {
439 const info = @typeInfo(T).Union;
440
441 if (info.tag_type) |_| {
442 const tag_a = activeTag(a);
443 const tag_b = activeTag(b);
444 if (tag_a != tag_b) return false;
445
446 inline for (info.fields) |field_info| {
447 const enum_field = field_info.enum_field.?;
448 if (enum_field.value == @enumToInt(tag_a)) {
449 return eql(@field(a, enum_field.name), @field(b, enum_field.name));
450 }
451 }
452 return false;
453 }
454
455 @compileError("cannot compare untagged union type " ++ @typeName(T));
456 },
457 builtin.TypeId.Array => {
458 if (a.len != b.len) return false;
459 for (a) |e, i|
460 if (!eql(e, b[i])) return false;
461 return true;
462 },
463 builtin.TypeId.Pointer => {
464 const info = @typeInfo(T).Pointer;
465 switch (info.size) {
466 builtin.TypeInfo.Pointer.Size.One,
467 builtin.TypeInfo.Pointer.Size.Many,
468 builtin.TypeInfo.Pointer.Size.C,
469 => return a == b,
470 builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
471 }
472 },
473 builtin.TypeId.Optional => {
474 if (a == null and b == null) return true;
475 if (a == null or b == null) return false;
476 return eql(a.?, b.?);
477 },
478 else => return a == b,
479 }
480}
481
482test "std.meta.eql" {
483 const S = struct {
484 a: u32,
485 b: f64,
486 c: [5]u8,
487 };
488
489 const U = union(enum) {
490 s: S,
491 f: ?f32,
492 };
493
494 const s_1 = S{
495 .a = 134,
496 .b = 123.3,
497 .c = "12345",
498 };
499
500 const s_2 = S{
501 .a = 1,
502 .b = 123.3,
503 .c = "54321",
504 };
505
506 const s_3 = S{
507 .a = 134,
508 .b = 123.3,
509 .c = "12345",
510 };
511
512 const u_1 = U{ .f = 24 };
513 const u_2 = U{ .s = s_1 };
514 const u_3 = U{ .f = 24 };
515
516 testing.expect(eql(s_1, s_3));
517 testing.expect(eql(&s_1, &s_1));
518 testing.expect(!eql(&s_1, &s_3));
519 testing.expect(eql(u_1, u_3));
520 testing.expect(!eql(u_1, u_2));
521
522 var a1 = "abcdef";
523 var a2 = "abcdef";
524 var a3 = "ghijkl";
525
526 testing.expect(eql(a1, a2));
527 testing.expect(!eql(a1, a3));
528 testing.expect(!eql(a1[0..], a2[0..]));
529
530 const EU = struct {
531 fn tst(err: bool) !u8 {
532 if (err) return error.Error;
533 return u8(5);
534 }
535 };
536
537 testing.expect(eql(EU.tst(true), EU.tst(true)));
538 testing.expect(eql(EU.tst(false), EU.tst(false)));
539 testing.expect(!eql(EU.tst(false), EU.tst(true)));
540}
541
542test "intToEnum with error return" {
543 const E1 = enum {
544 A,
545 };
546 const E2 = enum {
547 A,
548 B,
549 };
550
551 var zero: u8 = 0;
552 var one: u16 = 1;
553 testing.expect(intToEnum(E1, zero) catch unreachable == E1.A);
554 testing.expect(intToEnum(E2, one) catch unreachable == E2.B);
555 testing.expectError(error.InvalidEnumTag, intToEnum(E1, one));
556}
557
558pub const IntToEnumError = error{InvalidEnumTag};
559
560pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag {
561 comptime var i = 0;
562 inline while (i != @memberCount(Tag)) : (i += 1) {
563 const this_tag_value = @field(Tag, @memberName(Tag, i));
564 if (tag_int == @enumToInt(this_tag_value)) {
565 return this_tag_value;
566 }
567 }
568 return error.InvalidEnumTag;
569}
std/meta/index.zig deleted-569
...@@ -1,569 +0,0 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const debug = std.debug;
4const mem = std.mem;
5const math = std.math;
6const testing = std.testing;
7
8pub const trait = @import("trait.zig");
9
10const TypeId = builtin.TypeId;
11const TypeInfo = builtin.TypeInfo;
12
13pub fn tagName(v: var) []const u8 {
14 const T = @typeOf(v);
15 switch (@typeInfo(T)) {
16 TypeId.Enum => |info| {
17 const Tag = info.tag_type;
18 inline for (info.fields) |field| {
19 if (field.value == @enumToInt(v)) return field.name;
20 }
21
22 unreachable;
23 },
24 TypeId.Union => |info| {
25 const UnionTag = if (info.tag_type) |UT| UT else @compileError("union is untagged");
26 const Tag = @typeInfo(UnionTag).Enum.tag_type;
27 inline for (info.fields) |field| {
28 if (field.enum_field.?.value == @enumToInt(UnionTag(v)))
29 return field.name;
30 }
31
32 unreachable;
33 },
34 TypeId.ErrorSet => |info| {
35 inline for (info.errors) |err| {
36 if (err.value == @errorToInt(v)) return err.name;
37 }
38
39 unreachable;
40 },
41 else => @compileError("expected enum, error set or union type, found '" ++ @typeName(T) ++ "'"),
42 }
43}
44
45test "std.meta.tagName" {
46 const E1 = enum {
47 A,
48 B,
49 };
50 const E2 = enum(u8) {
51 C = 33,
52 D,
53 };
54 const U1 = union(enum) {
55 G: u8,
56 H: u16,
57 };
58 const U2 = union(E2) {
59 C: u8,
60 D: u16,
61 };
62
63 var u1g = U1{ .G = 0 };
64 var u1h = U1{ .H = 0 };
65 var u2a = U2{ .C = 0 };
66 var u2b = U2{ .D = 0 };
67
68 testing.expect(mem.eql(u8, tagName(E1.A), "A"));
69 testing.expect(mem.eql(u8, tagName(E1.B), "B"));
70 testing.expect(mem.eql(u8, tagName(E2.C), "C"));
71 testing.expect(mem.eql(u8, tagName(E2.D), "D"));
72 testing.expect(mem.eql(u8, tagName(error.E), "E"));
73 testing.expect(mem.eql(u8, tagName(error.F), "F"));
74 testing.expect(mem.eql(u8, tagName(u1g), "G"));
75 testing.expect(mem.eql(u8, tagName(u1h), "H"));
76 testing.expect(mem.eql(u8, tagName(u2a), "C"));
77 testing.expect(mem.eql(u8, tagName(u2b), "D"));
78}
79
80pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
81 inline for (@typeInfo(T).Enum.fields) |enumField| {
82 if (std.mem.eql(u8, str, enumField.name)) {
83 return @field(T, enumField.name);
84 }
85 }
86 return null;
87}
88
89test "std.meta.stringToEnum" {
90 const E1 = enum {
91 A,
92 B,
93 };
94 testing.expect(E1.A == stringToEnum(E1, "A").?);
95 testing.expect(E1.B == stringToEnum(E1, "B").?);
96 testing.expect(null == stringToEnum(E1, "C"));
97}
98
99pub fn bitCount(comptime T: type) comptime_int {
100 return switch (@typeInfo(T)) {
101 TypeId.Int => |info| info.bits,
102 TypeId.Float => |info| info.bits,
103 else => @compileError("Expected int or float type, found '" ++ @typeName(T) ++ "'"),
104 };
105}
106
107test "std.meta.bitCount" {
108 testing.expect(bitCount(u8) == 8);
109 testing.expect(bitCount(f32) == 32);
110}
111
112pub fn alignment(comptime T: type) comptime_int {
113 //@alignOf works on non-pointer types
114 const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T;
115 return @typeInfo(P).Pointer.alignment;
116}
117
118test "std.meta.alignment" {
119 testing.expect(alignment(u8) == 1);
120 testing.expect(alignment(*align(1) u8) == 1);
121 testing.expect(alignment(*align(2) u8) == 2);
122 testing.expect(alignment([]align(1) u8) == 1);
123 testing.expect(alignment([]align(2) u8) == 2);
124}
125
126pub fn Child(comptime T: type) type {
127 return switch (@typeInfo(T)) {
128 TypeId.Array => |info| info.child,
129 TypeId.Pointer => |info| info.child,
130 TypeId.Optional => |info| info.child,
131 TypeId.Promise => |info| if (info.child) |child| child else null,
132 else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
133 };
134}
135
136test "std.meta.Child" {
137 testing.expect(Child([1]u8) == u8);
138 testing.expect(Child(*u8) == u8);
139 testing.expect(Child([]u8) == u8);
140 testing.expect(Child(?u8) == u8);
141 testing.expect(Child(promise->u8) == u8);
142}
143
144pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
145 return switch (@typeInfo(T)) {
146 TypeId.Struct => |info| info.layout,
147 TypeId.Enum => |info| info.layout,
148 TypeId.Union => |info| info.layout,
149 else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
150 };
151}
152
153test "std.meta.containerLayout" {
154 const E1 = enum {
155 A,
156 };
157 const E2 = packed enum {
158 A,
159 };
160 const E3 = extern enum {
161 A,
162 };
163 const S1 = struct {};
164 const S2 = packed struct {};
165 const S3 = extern struct {};
166 const U1 = union {
167 a: u8,
168 };
169 const U2 = packed union {
170 a: u8,
171 };
172 const U3 = extern union {
173 a: u8,
174 };
175
176 testing.expect(containerLayout(E1) == TypeInfo.ContainerLayout.Auto);
177 testing.expect(containerLayout(E2) == TypeInfo.ContainerLayout.Packed);
178 testing.expect(containerLayout(E3) == TypeInfo.ContainerLayout.Extern);
179 testing.expect(containerLayout(S1) == TypeInfo.ContainerLayout.Auto);
180 testing.expect(containerLayout(S2) == TypeInfo.ContainerLayout.Packed);
181 testing.expect(containerLayout(S3) == TypeInfo.ContainerLayout.Extern);
182 testing.expect(containerLayout(U1) == TypeInfo.ContainerLayout.Auto);
183 testing.expect(containerLayout(U2) == TypeInfo.ContainerLayout.Packed);
184 testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern);
185}
186
187pub fn definitions(comptime T: type) []TypeInfo.Definition {
188 return switch (@typeInfo(T)) {
189 TypeId.Struct => |info| info.defs,
190 TypeId.Enum => |info| info.defs,
191 TypeId.Union => |info| info.defs,
192 else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
193 };
194}
195
196test "std.meta.definitions" {
197 const E1 = enum {
198 A,
199
200 fn a() void {}
201 };
202 const S1 = struct {
203 fn a() void {}
204 };
205 const U1 = union {
206 a: u8,
207
208 fn a() void {}
209 };
210
211 const defs = comptime [][]TypeInfo.Definition{
212 definitions(E1),
213 definitions(S1),
214 definitions(U1),
215 };
216
217 inline for (defs) |def| {
218 testing.expect(def.len == 1);
219 testing.expect(comptime mem.eql(u8, def[0].name, "a"));
220 }
221}
222
223pub fn definitionInfo(comptime T: type, comptime def_name: []const u8) TypeInfo.Definition {
224 inline for (comptime definitions(T)) |def| {
225 if (comptime mem.eql(u8, def.name, def_name))
226 return def;
227 }
228
229 @compileError("'" ++ @typeName(T) ++ "' has no definition '" ++ def_name ++ "'");
230}
231
232test "std.meta.definitionInfo" {
233 const E1 = enum {
234 A,
235
236 fn a() void {}
237 };
238 const S1 = struct {
239 fn a() void {}
240 };
241 const U1 = union {
242 a: u8,
243
244 fn a() void {}
245 };
246
247 const infos = comptime []TypeInfo.Definition{
248 definitionInfo(E1, "a"),
249 definitionInfo(S1, "a"),
250 definitionInfo(U1, "a"),
251 };
252
253 inline for (infos) |info| {
254 testing.expect(comptime mem.eql(u8, info.name, "a"));
255 testing.expect(!info.is_pub);
256 }
257}
258
259pub fn fields(comptime T: type) switch (@typeInfo(T)) {
260 TypeId.Struct => []TypeInfo.StructField,
261 TypeId.Union => []TypeInfo.UnionField,
262 TypeId.ErrorSet => []TypeInfo.Error,
263 TypeId.Enum => []TypeInfo.EnumField,
264 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
265} {
266 return switch (@typeInfo(T)) {
267 TypeId.Struct => |info| info.fields,
268 TypeId.Union => |info| info.fields,
269 TypeId.Enum => |info| info.fields,
270 TypeId.ErrorSet => |info| info.errors,
271 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
272 };
273}
274
275test "std.meta.fields" {
276 const E1 = enum {
277 A,
278 };
279 const E2 = error{A};
280 const S1 = struct {
281 a: u8,
282 };
283 const U1 = union {
284 a: u8,
285 };
286
287 const e1f = comptime fields(E1);
288 const e2f = comptime fields(E2);
289 const sf = comptime fields(S1);
290 const uf = comptime fields(U1);
291
292 testing.expect(e1f.len == 1);
293 testing.expect(e2f.len == 1);
294 testing.expect(sf.len == 1);
295 testing.expect(uf.len == 1);
296 testing.expect(mem.eql(u8, e1f[0].name, "A"));
297 testing.expect(mem.eql(u8, e2f[0].name, "A"));
298 testing.expect(mem.eql(u8, sf[0].name, "a"));
299 testing.expect(mem.eql(u8, uf[0].name, "a"));
300 testing.expect(comptime sf[0].field_type == u8);
301 testing.expect(comptime uf[0].field_type == u8);
302}
303
304pub fn fieldInfo(comptime T: type, comptime field_name: []const u8) switch (@typeInfo(T)) {
305 TypeId.Struct => TypeInfo.StructField,
306 TypeId.Union => TypeInfo.UnionField,
307 TypeId.ErrorSet => TypeInfo.Error,
308 TypeId.Enum => TypeInfo.EnumField,
309 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
310} {
311 inline for (comptime fields(T)) |field| {
312 if (comptime mem.eql(u8, field.name, field_name))
313 return field;
314 }
315
316 @compileError("'" ++ @typeName(T) ++ "' has no field '" ++ field_name ++ "'");
317}
318
319test "std.meta.fieldInfo" {
320 const E1 = enum {
321 A,
322 };
323 const E2 = error{A};
324 const S1 = struct {
325 a: u8,
326 };
327 const U1 = union {
328 a: u8,
329 };
330
331 const e1f = comptime fieldInfo(E1, "A");
332 const e2f = comptime fieldInfo(E2, "A");
333 const sf = comptime fieldInfo(S1, "a");
334 const uf = comptime fieldInfo(U1, "a");
335
336 testing.expect(mem.eql(u8, e1f.name, "A"));
337 testing.expect(mem.eql(u8, e2f.name, "A"));
338 testing.expect(mem.eql(u8, sf.name, "a"));
339 testing.expect(mem.eql(u8, uf.name, "a"));
340 testing.expect(comptime sf.field_type == u8);
341 testing.expect(comptime uf.field_type == u8);
342}
343
344pub fn TagType(comptime T: type) type {
345 return switch (@typeInfo(T)) {
346 TypeId.Enum => |info| info.tag_type,
347 TypeId.Union => |info| if (info.tag_type) |Tag| Tag else null,
348 else => @compileError("expected enum or union type, found '" ++ @typeName(T) ++ "'"),
349 };
350}
351
352test "std.meta.TagType" {
353 const E = enum(u8) {
354 C = 33,
355 D,
356 };
357 const U = union(E) {
358 C: u8,
359 D: u16,
360 };
361
362 testing.expect(TagType(E) == u8);
363 testing.expect(TagType(U) == E);
364}
365
366///Returns the active tag of a tagged union
367pub fn activeTag(u: var) @TagType(@typeOf(u)) {
368 const T = @typeOf(u);
369 return @TagType(T)(u);
370}
371
372test "std.meta.activeTag" {
373 const UE = enum {
374 Int,
375 Float,
376 };
377
378 const U = union(UE) {
379 Int: u32,
380 Float: f32,
381 };
382
383 var u = U{ .Int = 32 };
384 testing.expect(activeTag(u) == UE.Int);
385
386 u = U{ .Float = 112.9876 };
387 testing.expect(activeTag(u) == UE.Float);
388}
389
390///Given a tagged union type, and an enum, return the type of the union
391/// field corresponding to the enum tag.
392pub fn TagPayloadType(comptime U: type, tag: var) type {
393 const Tag = @typeOf(tag);
394 testing.expect(trait.is(builtin.TypeId.Union)(U));
395 testing.expect(trait.is(builtin.TypeId.Enum)(Tag));
396
397 const info = @typeInfo(U).Union;
398
399 inline for (info.fields) |field_info| {
400 if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
401 }
402 unreachable;
403}
404
405test "std.meta.TagPayloadType" {
406 const Event = union(enum) {
407 Moved: struct {
408 from: i32,
409 to: i32,
410 },
411 };
412 const MovedEvent = TagPayloadType(Event, Event.Moved);
413 var e: Event = undefined;
414 testing.expect(MovedEvent == @typeOf(e.Moved));
415}
416
417///Compares two of any type for equality. Containers are compared on a field-by-field basis,
418/// where possible. Pointers are not followed.
419pub fn eql(a: var, b: @typeOf(a)) bool {
420 const T = @typeOf(a);
421
422 switch (@typeId(T)) {
423 builtin.TypeId.Struct => {
424 const info = @typeInfo(T).Struct;
425
426 inline for (info.fields) |field_info| {
427 if (!eql(@field(a, field_info.name), @field(b, field_info.name))) return false;
428 }
429 return true;
430 },
431 builtin.TypeId.ErrorUnion => {
432 if (a) |a_p| {
433 if (b) |b_p| return eql(a_p, b_p) else |_| return false;
434 } else |a_e| {
435 if (b) |_| return false else |b_e| return a_e == b_e;
436 }
437 },
438 builtin.TypeId.Union => {
439 const info = @typeInfo(T).Union;
440
441 if (info.tag_type) |_| {
442 const tag_a = activeTag(a);
443 const tag_b = activeTag(b);
444 if (tag_a != tag_b) return false;
445
446 inline for (info.fields) |field_info| {
447 const enum_field = field_info.enum_field.?;
448 if (enum_field.value == @enumToInt(tag_a)) {
449 return eql(@field(a, enum_field.name), @field(b, enum_field.name));
450 }
451 }
452 return false;
453 }
454
455 @compileError("cannot compare untagged union type " ++ @typeName(T));
456 },
457 builtin.TypeId.Array => {
458 if (a.len != b.len) return false;
459 for (a) |e, i|
460 if (!eql(e, b[i])) return false;
461 return true;
462 },
463 builtin.TypeId.Pointer => {
464 const info = @typeInfo(T).Pointer;
465 switch (info.size) {
466 builtin.TypeInfo.Pointer.Size.One,
467 builtin.TypeInfo.Pointer.Size.Many,
468 builtin.TypeInfo.Pointer.Size.C,
469 => return a == b,
470 builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
471 }
472 },
473 builtin.TypeId.Optional => {
474 if (a == null and b == null) return true;
475 if (a == null or b == null) return false;
476 return eql(a.?, b.?);
477 },
478 else => return a == b,
479 }
480}
481
482test "std.meta.eql" {
483 const S = struct {
484 a: u32,
485 b: f64,
486 c: [5]u8,
487 };
488
489 const U = union(enum) {
490 s: S,
491 f: ?f32,
492 };
493
494 const s_1 = S{
495 .a = 134,
496 .b = 123.3,
497 .c = "12345",
498 };
499
500 const s_2 = S{
501 .a = 1,
502 .b = 123.3,
503 .c = "54321",
504 };
505
506 const s_3 = S{
507 .a = 134,
508 .b = 123.3,
509 .c = "12345",
510 };
511
512 const u_1 = U{ .f = 24 };
513 const u_2 = U{ .s = s_1 };
514 const u_3 = U{ .f = 24 };
515
516 testing.expect(eql(s_1, s_3));
517 testing.expect(eql(&s_1, &s_1));
518 testing.expect(!eql(&s_1, &s_3));
519 testing.expect(eql(u_1, u_3));
520 testing.expect(!eql(u_1, u_2));
521
522 var a1 = "abcdef";
523 var a2 = "abcdef";
524 var a3 = "ghijkl";
525
526 testing.expect(eql(a1, a2));
527 testing.expect(!eql(a1, a3));
528 testing.expect(!eql(a1[0..], a2[0..]));
529
530 const EU = struct {
531 fn tst(err: bool) !u8 {
532 if (err) return error.Error;
533 return u8(5);
534 }
535 };
536
537 testing.expect(eql(EU.tst(true), EU.tst(true)));
538 testing.expect(eql(EU.tst(false), EU.tst(false)));
539 testing.expect(!eql(EU.tst(false), EU.tst(true)));
540}
541
542test "intToEnum with error return" {
543 const E1 = enum {
544 A,
545 };
546 const E2 = enum {
547 A,
548 B,
549 };
550
551 var zero: u8 = 0;
552 var one: u16 = 1;
553 testing.expect(intToEnum(E1, zero) catch unreachable == E1.A);
554 testing.expect(intToEnum(E2, one) catch unreachable == E2.B);
555 testing.expectError(error.InvalidEnumTag, intToEnum(E1, one));
556}
557
558pub const IntToEnumError = error{InvalidEnumTag};
559
560pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag {
561 comptime var i = 0;
562 inline while (i != @memberCount(Tag)) : (i += 1) {
563 const this_tag_value = @field(Tag, @memberName(Tag, i));
564 if (tag_int == @enumToInt(this_tag_value)) {
565 return this_tag_value;
566 }
567 }
568 return error.InvalidEnumTag;
569}
std/meta/trait.zig+2-2
...@@ -1,11 +1,11 @@...@@ -1,11 +1,11 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const mem = std.mem;3const mem = std.mem;
4const debug = std.debug;4const debug = std.debug;
5const testing = std.testing;5const testing = std.testing;
6const warn = debug.warn;6const warn = debug.warn;
77
8const meta = @import("index.zig");8const meta = @import("../meta.zig");
99
10//This is necessary if we want to return generic functions directly because of how the10//This is necessary if we want to return generic functions directly because of how the
11// the type erasure works. see: #137511// the type erasure works. see: #1375
std/mutex.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;3const AtomicOrder = builtin.AtomicOrder;
4const AtomicRmwOp = builtin.AtomicRmwOp;4const AtomicRmwOp = builtin.AtomicRmwOp;
std/net.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const net = @This();4const net = @This();
std/os.zig created+3432
...@@ -0,0 +1,3432 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;
5const is_posix = switch (builtin.os) {
6 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
7 else => false,
8};
9const os = @This();
10
11comptime {
12 assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir
13}
14
15test "std.os" {
16 _ = @import("os/child_process.zig");
17 _ = @import("os/darwin.zig");
18 _ = @import("os/darwin/errno.zig");
19 _ = @import("os/get_user_id.zig");
20 _ = @import("os/linux.zig");
21 _ = @import("os/path.zig");
22 _ = @import("os/test.zig");
23 _ = @import("os/time.zig");
24 _ = @import("os/windows.zig");
25 _ = @import("os/uefi.zig");
26 _ = @import("os/get_app_data_dir.zig");
27}
28
29pub const windows = @import("os/windows.zig");
30pub const darwin = @import("os/darwin.zig");
31pub const linux = @import("os/linux.zig");
32pub const freebsd = @import("os/freebsd.zig");
33pub const netbsd = @import("os/netbsd.zig");
34pub const zen = @import("os/zen.zig");
35pub const uefi = @import("os/uefi.zig");
36
37pub const posix = switch (builtin.os) {
38 Os.linux => linux,
39 Os.macosx, Os.ios => darwin,
40 Os.freebsd => freebsd,
41 Os.netbsd => netbsd,
42 Os.zen => zen,
43 else => @compileError("Unsupported OS"),
44};
45
46pub const net = @import("net.zig");
47
48pub const ChildProcess = @import("os/child_process.zig").ChildProcess;
49pub const path = @import("os/path.zig");
50pub const File = @import("os/file.zig").File;
51pub const time = @import("os/time.zig");
52
53pub const page_size = 4 * 1024;
54pub const MAX_PATH_BYTES = switch (builtin.os) {
55 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
56 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
57 // If it would require 4 UTF-8 bytes, then there would be a surrogate
58 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
59 // +1 for the null byte at the end, which can be encoded in 1 byte.
60 Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
61 else => @compileError("Unsupported OS"),
62};
63
64pub const UserInfo = @import("os/get_user_id.zig").UserInfo;
65pub const getUserInfo = @import("os/get_user_id.zig").getUserInfo;
66
67const windows_util = @import("os/windows/util.zig");
68pub const windowsWaitSingle = windows_util.windowsWaitSingle;
69pub const windowsWrite = windows_util.windowsWrite;
70pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
71pub const windowsOpen = windows_util.windowsOpen;
72pub const windowsOpenW = windows_util.windowsOpenW;
73pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
74
75pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;
76pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;
77
78pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;
79pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;
80
81pub const WindowsWaitResult = windows_util.WindowsWaitResult;
82pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;
83
84pub const WindowsWaitError = windows_util.WaitError;
85pub const WindowsOpenError = windows_util.OpenError;
86pub const WindowsWriteError = windows_util.WriteError;
87pub const WindowsReadError = windows_util.ReadError;
88
89pub const FileHandle = if (is_windows) windows.HANDLE else i32;
90
91pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir;
92pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError;
93
94const debug = std.debug;
95const assert = debug.assert;
96const testing = std.testing;
97
98const c = std.c;
99
100const mem = std.mem;
101const Allocator = mem.Allocator;
102
103const BufMap = std.BufMap;
104const cstr = std.cstr;
105
106const io = std.io;
107const base64 = std.base64;
108const ArrayList = std.ArrayList;
109const Buffer = std.Buffer;
110const math = std.math;
111
112/// Fills `buf` with random bytes. If linking against libc, this calls the
113/// appropriate OS-specific library call. Otherwise it uses the zig standard
114/// library implementation.
115pub fn getRandomBytes(buf: []u8) !void {
116 switch (builtin.os) {
117 Os.linux => while (true) {
118 // TODO check libc version and potentially call c.getrandom.
119 // See #397
120 const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
121 switch (errno) {
122 0 => return,
123 posix.EINVAL => unreachable,
124 posix.EFAULT => unreachable,
125 posix.EINTR => continue,
126 posix.ENOSYS => return getRandomBytesDevURandom(buf),
127 else => return unexpectedErrorPosix(errno),
128 }
129 },
130 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
131 Os.windows => {
132 // Call RtlGenRandom() instead of CryptGetRandom() on Windows
133 // https://github.com/rust-lang-nursery/rand/issues/111
134 // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
135 if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
136 const err = windows.GetLastError();
137 return switch (err) {
138 else => unexpectedErrorWindows(err),
139 };
140 }
141 },
142 Os.zen => {
143 const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
144 var i: usize = 0;
145 while (i < buf.len) : (i += 1) {
146 if (i > randomness.len) return error.Unknown;
147 buf[i] = randomness[i];
148 }
149 },
150 else => @compileError("Unsupported OS"),
151 }
152}
153
154fn getRandomBytesDevURandom(buf: []u8) !void {
155 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
156 defer close(fd);
157
158 const stream = &File.openHandle(fd).inStream().stream;
159 stream.readNoEof(buf) catch |err| switch (err) {
160 error.EndOfStream => unreachable,
161 error.OperationAborted => unreachable,
162 error.BrokenPipe => unreachable,
163 error.Unexpected => return error.Unexpected,
164 error.InputOutput => return error.Unexpected,
165 error.SystemResources => return error.Unexpected,
166 error.IsDir => unreachable,
167 };
168}
169
170test "os.getRandomBytes" {
171 var buf_a: [50]u8 = undefined;
172 var buf_b: [50]u8 = undefined;
173 // Call Twice
174 try getRandomBytes(buf_a[0..]);
175 try getRandomBytes(buf_b[0..]);
176
177 // Check if random (not 100% conclusive)
178 testing.expect(!mem.eql(u8, buf_a, buf_b));
179}
180
181/// Raises a signal in the current kernel thread, ending its execution.
182/// If linking against libc, this calls the abort() libc function. Otherwise
183/// it uses the zig standard library implementation.
184pub fn abort() noreturn {
185 @setCold(true);
186 if (builtin.link_libc) {
187 c.abort();
188 }
189 switch (builtin.os) {
190 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
191 _ = posix.raise(posix.SIGABRT);
192 _ = posix.raise(posix.SIGKILL);
193 while (true) {}
194 },
195 Os.windows => {
196 if (builtin.mode == builtin.Mode.Debug) {
197 @breakpoint();
198 }
199 windows.ExitProcess(3);
200 },
201 Os.uefi => {
202 // TODO there's gotta be a better thing to do here than loop forever
203 while (true) {}
204 },
205 else => @compileError("Unsupported OS"),
206 }
207}
208
209/// Exits the program cleanly with the specified status code.
210pub fn exit(status: u8) noreturn {
211 @setCold(true);
212 if (builtin.link_libc) {
213 c.exit(status);
214 }
215 switch (builtin.os) {
216 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
217 posix.exit(status);
218 },
219 Os.windows => {
220 windows.ExitProcess(status);
221 },
222 else => @compileError("Unsupported OS"),
223 }
224}
225
226/// When a file descriptor is closed on linux, it pops the first
227/// node from this queue and resumes it.
228/// Async functions which get the EMFILE error code can suspend,
229/// putting their coroutine handle into this list.
230/// TODO make this an atomic linked list
231pub var emfile_promise_queue = std.LinkedList(promise).init();
232
233/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
234pub fn close(handle: FileHandle) void {
235 if (is_windows) {
236 windows_util.windowsClose(handle);
237 } else {
238 while (true) {
239 const err = posix.getErrno(posix.close(handle));
240 switch (err) {
241 posix.EINTR => continue,
242 else => {
243 if (emfile_promise_queue.popFirst()) |p| resume p.data;
244 return;
245 },
246 }
247 }
248 }
249}
250
251pub const PosixReadError = error{
252 InputOutput,
253 SystemResources,
254 IsDir,
255 Unexpected,
256};
257
258/// Returns the number of bytes that were read, which can be less than
259/// buf.len. If 0 bytes were read, that means EOF.
260pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
261 // Linux can return EINVAL when read amount is > 0x7ffff000
262 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
263 const max_buf_len = 0x7ffff000;
264
265 var index: usize = 0;
266 while (index < buf.len) {
267 const want_to_read = math.min(buf.len - index, usize(max_buf_len));
268 const rc = posix.read(fd, buf.ptr + index, want_to_read);
269 const err = posix.getErrno(rc);
270 switch (err) {
271 0 => {
272 index += rc;
273 if (rc == want_to_read) continue;
274 // Read returned less than buf.len.
275 return index;
276 },
277 posix.EINTR => continue,
278 posix.EINVAL => unreachable,
279 posix.EFAULT => unreachable,
280 posix.EAGAIN => unreachable,
281 posix.EBADF => unreachable, // always a race condition
282 posix.EIO => return error.InputOutput,
283 posix.EISDIR => return error.IsDir,
284 posix.ENOBUFS => return error.SystemResources,
285 posix.ENOMEM => return error.SystemResources,
286 else => return unexpectedErrorPosix(err),
287 }
288 }
289 return index;
290}
291
292/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
293pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
294 switch (builtin.os) {
295 builtin.Os.macosx => {
296 // Darwin does not have preadv but it does have pread.
297 var off: usize = 0;
298 var iov_i: usize = 0;
299 var inner_off: usize = 0;
300 while (true) {
301 const v = iov[iov_i];
302 const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
303 const err = darwin.getErrno(rc);
304 switch (err) {
305 0 => {
306 off += rc;
307 inner_off += rc;
308 if (inner_off == v.iov_len) {
309 iov_i += 1;
310 inner_off = 0;
311 if (iov_i == count) {
312 return off;
313 }
314 }
315 if (rc == 0) return off; // EOF
316 continue;
317 },
318 posix.EINTR => continue,
319 posix.EINVAL => unreachable,
320 posix.EFAULT => unreachable,
321 posix.ESPIPE => unreachable, // fd is not seekable
322 posix.EAGAIN => unreachable, // this function is not for non blocking
323 posix.EBADF => unreachable, // always a race condition
324 posix.EIO => return error.InputOutput,
325 posix.EISDIR => return error.IsDir,
326 posix.ENOBUFS => return error.SystemResources,
327 posix.ENOMEM => return error.SystemResources,
328 else => return unexpectedErrorPosix(err),
329 }
330 }
331 },
332 builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
333 const rc = posix.preadv(fd, iov, count, offset);
334 const err = posix.getErrno(rc);
335 switch (err) {
336 0 => return rc,
337 posix.EINTR => continue,
338 posix.EINVAL => unreachable,
339 posix.EFAULT => unreachable,
340 posix.EAGAIN => unreachable, // don't call this function for non blocking
341 posix.EBADF => unreachable, // always a race condition
342 posix.EIO => return error.InputOutput,
343 posix.EISDIR => return error.IsDir,
344 posix.ENOBUFS => return error.SystemResources,
345 posix.ENOMEM => return error.SystemResources,
346 else => return unexpectedErrorPosix(err),
347 }
348 },
349 else => @compileError("Unsupported OS"),
350 }
351}
352
353pub const PosixWriteError = error{
354 DiskQuota,
355 FileTooBig,
356 InputOutput,
357 NoSpaceLeft,
358 AccessDenied,
359 BrokenPipe,
360
361 /// See https://github.com/ziglang/zig/issues/1396
362 Unexpected,
363};
364
365/// Calls POSIX write, and keeps trying if it gets interrupted.
366pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
367 // Linux can return EINVAL when write amount is > 0x7ffff000
368 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
369 const max_bytes_len = 0x7ffff000;
370
371 var index: usize = 0;
372 while (index < bytes.len) {
373 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
374 const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
375 const write_err = posix.getErrno(rc);
376 switch (write_err) {
377 0 => {
378 index += rc;
379 continue;
380 },
381 posix.EINTR => continue,
382 posix.EINVAL => unreachable,
383 posix.EFAULT => unreachable,
384 posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
385 posix.EBADF => unreachable, // always a race condition
386 posix.EDESTADDRREQ => unreachable, // connect was never called
387 posix.EDQUOT => return PosixWriteError.DiskQuota,
388 posix.EFBIG => return PosixWriteError.FileTooBig,
389 posix.EIO => return PosixWriteError.InputOutput,
390 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
391 posix.EPERM => return PosixWriteError.AccessDenied,
392 posix.EPIPE => return PosixWriteError.BrokenPipe,
393 else => return unexpectedErrorPosix(write_err),
394 }
395 }
396}
397
398pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
399 switch (builtin.os) {
400 builtin.Os.macosx => {
401 // Darwin does not have pwritev but it does have pwrite.
402 var off: usize = 0;
403 var iov_i: usize = 0;
404 var inner_off: usize = 0;
405 while (true) {
406 const v = iov[iov_i];
407 const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
408 const err = darwin.getErrno(rc);
409 switch (err) {
410 0 => {
411 off += rc;
412 inner_off += rc;
413 if (inner_off == v.iov_len) {
414 iov_i += 1;
415 inner_off = 0;
416 if (iov_i == count) {
417 return;
418 }
419 }
420 continue;
421 },
422 posix.EINTR => continue,
423 posix.ESPIPE => unreachable, // fd is not seekable
424 posix.EINVAL => unreachable,
425 posix.EFAULT => unreachable,
426 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
427 posix.EBADF => unreachable, // always a race condition
428 posix.EDESTADDRREQ => unreachable, // connect was never called
429 posix.EDQUOT => return PosixWriteError.DiskQuota,
430 posix.EFBIG => return PosixWriteError.FileTooBig,
431 posix.EIO => return PosixWriteError.InputOutput,
432 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
433 posix.EPERM => return PosixWriteError.AccessDenied,
434 posix.EPIPE => return PosixWriteError.BrokenPipe,
435 else => return unexpectedErrorPosix(err),
436 }
437 }
438 },
439 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
440 const rc = posix.pwritev(fd, iov, count, offset);
441 const err = posix.getErrno(rc);
442 switch (err) {
443 0 => return,
444 posix.EINTR => continue,
445 posix.EINVAL => unreachable,
446 posix.EFAULT => unreachable,
447 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
448 posix.EBADF => unreachable, // always a race condition
449 posix.EDESTADDRREQ => unreachable, // connect was never called
450 posix.EDQUOT => return PosixWriteError.DiskQuota,
451 posix.EFBIG => return PosixWriteError.FileTooBig,
452 posix.EIO => return PosixWriteError.InputOutput,
453 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
454 posix.EPERM => return PosixWriteError.AccessDenied,
455 posix.EPIPE => return PosixWriteError.BrokenPipe,
456 else => return unexpectedErrorPosix(err),
457 }
458 },
459 else => @compileError("Unsupported OS"),
460 }
461}
462
463pub const PosixOpenError = error{
464 AccessDenied,
465 FileTooBig,
466 IsDir,
467 SymLinkLoop,
468 ProcessFdQuotaExceeded,
469 NameTooLong,
470 SystemFdQuotaExceeded,
471 NoDevice,
472 FileNotFound,
473 SystemResources,
474 NoSpaceLeft,
475 NotDir,
476 PathAlreadyExists,
477 DeviceBusy,
478
479 /// See https://github.com/ziglang/zig/issues/1396
480 Unexpected,
481};
482
483/// ::file_path needs to be copied in memory to add a null terminating byte.
484/// Calls POSIX open, keeps trying if it gets interrupted, and translates
485/// the return value into zig errors.
486pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
487 const file_path_c = try toPosixPath(file_path);
488 return posixOpenC(&file_path_c, flags, perm);
489}
490
491// TODO https://github.com/ziglang/zig/issues/265
492pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
493 while (true) {
494 const result = posix.open(file_path, flags, perm);
495 const err = posix.getErrno(result);
496 if (err > 0) {
497 switch (err) {
498 posix.EINTR => continue,
499
500 posix.EFAULT => unreachable,
501 posix.EINVAL => unreachable,
502 posix.EACCES => return PosixOpenError.AccessDenied,
503 posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
504 posix.EISDIR => return PosixOpenError.IsDir,
505 posix.ELOOP => return PosixOpenError.SymLinkLoop,
506 posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
507 posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
508 posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
509 posix.ENODEV => return PosixOpenError.NoDevice,
510 posix.ENOENT => return PosixOpenError.FileNotFound,
511 posix.ENOMEM => return PosixOpenError.SystemResources,
512 posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
513 posix.ENOTDIR => return PosixOpenError.NotDir,
514 posix.EPERM => return PosixOpenError.AccessDenied,
515 posix.EEXIST => return PosixOpenError.PathAlreadyExists,
516 posix.EBUSY => return PosixOpenError.DeviceBusy,
517 else => return unexpectedErrorPosix(err),
518 }
519 }
520 return @intCast(i32, result);
521 }
522}
523
524/// Used to convert a slice to a null terminated slice on the stack.
525/// TODO well defined copy elision
526pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
527 var path_with_null: [posix.PATH_MAX]u8 = undefined;
528 if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
529 mem.copy(u8, path_with_null[0..], file_path);
530 path_with_null[file_path.len] = 0;
531 return path_with_null;
532}
533
534pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
535 while (true) {
536 const err = posix.getErrno(posix.dup2(old_fd, new_fd));
537 if (err > 0) {
538 return switch (err) {
539 posix.EBUSY, posix.EINTR => continue,
540 posix.EMFILE => error.ProcessFdQuotaExceeded,
541 posix.EINVAL => unreachable,
542 else => unexpectedErrorPosix(err),
543 };
544 }
545 return;
546 }
547}
548
549pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
550 const envp_count = env_map.count();
551 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
552 mem.set(?[*]u8, envp_buf, null);
553 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
554 {
555 var it = env_map.iterator();
556 var i: usize = 0;
557 while (it.next()) |pair| : (i += 1) {
558 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
559 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
560 env_buf[pair.key.len] = '=';
561 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
562 env_buf[env_buf.len - 1] = 0;
563
564 envp_buf[i] = env_buf.ptr;
565 }
566 assert(i == envp_count);
567 }
568 assert(envp_buf[envp_count] == null);
569 return envp_buf;
570}
571
572pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
573 for (envp_buf) |env| {
574 const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
575 allocator.free(env_buf);
576 }
577 allocator.free(envp_buf);
578}
579
580/// This function must allocate memory to add a null terminating bytes on path and each arg.
581/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
582/// pointers after the args and after the environment variables.
583/// `argv[0]` is the executable path.
584/// This function also uses the PATH environment variable to get the full path to the executable.
585pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
586 const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
587 mem.set(?[*]u8, argv_buf, null);
588 defer {
589 for (argv_buf) |arg| {
590 const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
591 allocator.free(arg_buf);
592 }
593 allocator.free(argv_buf);
594 }
595 for (argv) |arg, i| {
596 const arg_buf = try allocator.alloc(u8, arg.len + 1);
597 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
598 arg_buf[arg.len] = 0;
599
600 argv_buf[i] = arg_buf.ptr;
601 }
602 argv_buf[argv.len] = null;
603
604 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
605 defer freeNullDelimitedEnvMap(allocator, envp_buf);
606
607 const exe_path = argv[0];
608 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
609 return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
610 }
611
612 const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
613 // PATH.len because it is >= the largest search_path
614 // +1 for the / to join the search path and exe_path
615 // +1 for the null terminating byte
616 const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
617 defer allocator.free(path_buf);
618 var it = mem.tokenize(PATH, ":");
619 var seen_eacces = false;
620 var err: usize = undefined;
621 while (it.next()) |search_path| {
622 mem.copy(u8, path_buf, search_path);
623 path_buf[search_path.len] = '/';
624 mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
625 path_buf[search_path.len + exe_path.len + 1] = 0;
626 err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
627 assert(err > 0);
628 if (err == posix.EACCES) {
629 seen_eacces = true;
630 } else if (err != posix.ENOENT) {
631 return posixExecveErrnoToErr(err);
632 }
633 }
634 if (seen_eacces) {
635 err = posix.EACCES;
636 }
637 return posixExecveErrnoToErr(err);
638}
639
640pub const PosixExecveError = error{
641 SystemResources,
642 AccessDenied,
643 InvalidExe,
644 FileSystem,
645 IsDir,
646 FileNotFound,
647 NotDir,
648 FileBusy,
649
650 /// See https://github.com/ziglang/zig/issues/1396
651 Unexpected,
652};
653
654fn posixExecveErrnoToErr(err: usize) PosixExecveError {
655 assert(err > 0);
656 switch (err) {
657 posix.EFAULT => unreachable,
658 posix.E2BIG => return error.SystemResources,
659 posix.EMFILE => return error.SystemResources,
660 posix.ENAMETOOLONG => return error.SystemResources,
661 posix.ENFILE => return error.SystemResources,
662 posix.ENOMEM => return error.SystemResources,
663 posix.EACCES => return error.AccessDenied,
664 posix.EPERM => return error.AccessDenied,
665 posix.EINVAL => return error.InvalidExe,
666 posix.ENOEXEC => return error.InvalidExe,
667 posix.EIO => return error.FileSystem,
668 posix.ELOOP => return error.FileSystem,
669 posix.EISDIR => return error.IsDir,
670 posix.ENOENT => return error.FileNotFound,
671 posix.ENOTDIR => return error.NotDir,
672 posix.ETXTBSY => return error.FileBusy,
673 else => return unexpectedErrorPosix(err),
674 }
675}
676
677pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
678pub var posix_environ_raw: [][*]u8 = undefined;
679
680/// See std.elf for the constants.
681pub fn linuxGetAuxVal(index: usize) usize {
682 if (builtin.link_libc) {
683 return usize(std.c.getauxval(index));
684 } else if (linux_elf_aux_maybe) |auxv| {
685 var i: usize = 0;
686 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
687 if (auxv[i].a_type == index)
688 return auxv[i].a_un.a_val;
689 }
690 }
691 return 0;
692}
693
694pub fn getBaseAddress() usize {
695 switch (builtin.os) {
696 builtin.Os.linux => {
697 const base = linuxGetAuxVal(std.elf.AT_BASE);
698 if (base != 0) {
699 return base;
700 }
701 const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
702 return phdr - @sizeOf(std.elf.Ehdr);
703 },
704 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
705 return @ptrToInt(&std.c._mh_execute_header);
706 },
707 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
708 else => @compileError("Unsupported OS"),
709 }
710}
711
712/// Caller must free result when done.
713/// TODO make this go through libc when we have it
714pub fn getEnvMap(allocator: *Allocator) !BufMap {
715 var result = BufMap.init(allocator);
716 errdefer result.deinit();
717
718 if (is_windows) {
719 const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
720 defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
721
722 var i: usize = 0;
723 while (true) {
724 if (ptr[i] == 0) return result;
725
726 const key_start = i;
727
728 while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
729 const key_w = ptr[key_start..i];
730 const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
731 errdefer allocator.free(key);
732
733 if (ptr[i] == '=') i += 1;
734
735 const value_start = i;
736 while (ptr[i] != 0) : (i += 1) {}
737 const value_w = ptr[value_start..i];
738 const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
739 errdefer allocator.free(value);
740
741 i += 1; // skip over null byte
742
743 try result.setMove(key, value);
744 }
745 } else {
746 for (posix_environ_raw) |ptr| {
747 var line_i: usize = 0;
748 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
749 const key = ptr[0..line_i];
750
751 var end_i: usize = line_i;
752 while (ptr[end_i] != 0) : (end_i += 1) {}
753 const value = ptr[line_i + 1 .. end_i];
754
755 try result.set(key, value);
756 }
757 return result;
758 }
759}
760
761test "os.getEnvMap" {
762 var env = try getEnvMap(std.debug.global_allocator);
763 defer env.deinit();
764}
765
766/// TODO make this go through libc when we have it
767pub fn getEnvPosix(key: []const u8) ?[]const u8 {
768 for (posix_environ_raw) |ptr| {
769 var line_i: usize = 0;
770 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
771 const this_key = ptr[0..line_i];
772 if (!mem.eql(u8, key, this_key)) continue;
773
774 var end_i: usize = line_i;
775 while (ptr[end_i] != 0) : (end_i += 1) {}
776 const this_value = ptr[line_i + 1 .. end_i];
777
778 return this_value;
779 }
780 return null;
781}
782
783pub const GetEnvVarOwnedError = error{
784 OutOfMemory,
785 EnvironmentVariableNotFound,
786
787 /// See https://github.com/ziglang/zig/issues/1774
788 InvalidUtf8,
789};
790
791/// Caller must free returned memory.
792/// TODO make this go through libc when we have it
793pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
794 if (is_windows) {
795 const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
796 defer allocator.free(key_with_null);
797
798 var buf = try allocator.alloc(u16, 256);
799 defer allocator.free(buf);
800
801 while (true) {
802 const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
803 const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
804
805 if (result == 0) {
806 const err = windows.GetLastError();
807 return switch (err) {
808 windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
809 else => {
810 _ = unexpectedErrorWindows(err);
811 return error.EnvironmentVariableNotFound;
812 },
813 };
814 }
815
816 if (result > buf.len) {
817 buf = try allocator.realloc(u16, buf, result);
818 continue;
819 }
820
821 return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
822 error.DanglingSurrogateHalf => return error.InvalidUtf8,
823 error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
824 error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
825 error.OutOfMemory => return error.OutOfMemory,
826 };
827 }
828 } else {
829 const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
830 return mem.dupe(allocator, u8, result);
831 }
832}
833
834test "os.getEnvVarOwned" {
835 var ga = debug.global_allocator;
836 testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
837}
838
839/// Caller must free the returned memory.
840pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
841 var buf: [MAX_PATH_BYTES]u8 = undefined;
842 return mem.dupe(allocator, u8, try getCwd(&buf));
843}
844
845pub const GetCwdError = error{Unexpected};
846
847/// The result is a slice of out_buffer.
848pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
849 switch (builtin.os) {
850 Os.windows => {
851 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
852 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
853 const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
854 const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
855 if (result == 0) {
856 const err = windows.GetLastError();
857 switch (err) {
858 else => return unexpectedErrorWindows(err),
859 }
860 }
861 assert(result <= utf16le_buf.len);
862 const utf16le_slice = utf16le_buf[0..result];
863 // Trust that Windows gives us valid UTF-16LE.
864 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
865 return out_buffer[0..end_index];
866 },
867 else => {
868 const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
869 switch (err) {
870 0 => return cstr.toSlice(out_buffer),
871 posix.ERANGE => unreachable,
872 else => return unexpectedErrorPosix(err),
873 }
874 },
875 }
876}
877
878test "os.getCwd" {
879 // at least call it so it gets compiled
880 _ = getCwdAlloc(debug.global_allocator);
881 var buf: [MAX_PATH_BYTES]u8 = undefined;
882 _ = getCwd(&buf);
883}
884
885pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
886
887/// TODO add a symLinkC variant
888pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
889 if (is_windows) {
890 return symLinkWindows(existing_path, new_path);
891 } else {
892 return symLinkPosix(existing_path, new_path);
893 }
894}
895
896pub const WindowsSymLinkError = error{
897 NameTooLong,
898 InvalidUtf8,
899 BadPathName,
900
901 /// See https://github.com/ziglang/zig/issues/1396
902 Unexpected,
903};
904
905pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
906 if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
907 const err = windows.GetLastError();
908 switch (err) {
909 else => return unexpectedErrorWindows(err),
910 }
911 }
912}
913
914pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
915 const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
916 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
917 return symLinkW(&existing_path_w, &new_path_w);
918}
919
920pub const PosixSymLinkError = error{
921 AccessDenied,
922 DiskQuota,
923 PathAlreadyExists,
924 FileSystem,
925 SymLinkLoop,
926 NameTooLong,
927 FileNotFound,
928 SystemResources,
929 NoSpaceLeft,
930 ReadOnlyFileSystem,
931 NotDir,
932
933 /// See https://github.com/ziglang/zig/issues/1396
934 Unexpected,
935};
936
937pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
938 const err = posix.getErrno(posix.symlink(existing_path, new_path));
939 switch (err) {
940 0 => return,
941 posix.EFAULT => unreachable,
942 posix.EINVAL => unreachable,
943 posix.EACCES => return error.AccessDenied,
944 posix.EPERM => return error.AccessDenied,
945 posix.EDQUOT => return error.DiskQuota,
946 posix.EEXIST => return error.PathAlreadyExists,
947 posix.EIO => return error.FileSystem,
948 posix.ELOOP => return error.SymLinkLoop,
949 posix.ENAMETOOLONG => return error.NameTooLong,
950 posix.ENOENT => return error.FileNotFound,
951 posix.ENOTDIR => return error.NotDir,
952 posix.ENOMEM => return error.SystemResources,
953 posix.ENOSPC => return error.NoSpaceLeft,
954 posix.EROFS => return error.ReadOnlyFileSystem,
955 else => return unexpectedErrorPosix(err),
956 }
957}
958
959pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
960 const existing_path_c = try toPosixPath(existing_path);
961 const new_path_c = try toPosixPath(new_path);
962 return symLinkPosixC(&existing_path_c, &new_path_c);
963}
964
965// here we replace the standard +/ with -_ so that it can be used in a file name
966const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
967
968/// TODO remove the allocator requirement from this API
969pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
970 if (symLink(existing_path, new_path)) {
971 return;
972 } else |err| switch (err) {
973 error.PathAlreadyExists => {},
974 else => return err, // TODO zig should know this set does not include PathAlreadyExists
975 }
976
977 const dirname = os.path.dirname(new_path) orelse ".";
978
979 var rand_buf: [12]u8 = undefined;
980 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
981 defer allocator.free(tmp_path);
982 mem.copy(u8, tmp_path[0..], dirname);
983 tmp_path[dirname.len] = os.path.sep;
984 while (true) {
985 try getRandomBytes(rand_buf[0..]);
986 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
987
988 if (symLink(existing_path, tmp_path)) {
989 return rename(tmp_path, new_path);
990 } else |err| switch (err) {
991 error.PathAlreadyExists => continue,
992 else => return err, // TODO zig should know this set does not include PathAlreadyExists
993 }
994 }
995}
996
997pub const DeleteFileError = error{
998 FileNotFound,
999 AccessDenied,
1000 FileBusy,
1001 FileSystem,
1002 IsDir,
1003 SymLinkLoop,
1004 NameTooLong,
1005 NotDir,
1006 SystemResources,
1007 ReadOnlyFileSystem,
1008
1009 /// On Windows, file paths must be valid Unicode.
1010 InvalidUtf8,
1011
1012 /// On Windows, file paths cannot contain these characters:
1013 /// '/', '*', '?', '"', '<', '>', '|'
1014 BadPathName,
1015
1016 /// See https://github.com/ziglang/zig/issues/1396
1017 Unexpected,
1018};
1019
1020pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
1021 if (builtin.os == Os.windows) {
1022 const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
1023 return deleteFileW(&file_path_w);
1024 } else {
1025 const file_path_c = try toPosixPath(file_path);
1026 return deleteFileC(&file_path_c);
1027 }
1028}
1029
1030pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
1031 if (windows.DeleteFileW(file_path) == 0) {
1032 const err = windows.GetLastError();
1033 switch (err) {
1034 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1035 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
1036 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1037 windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
1038 else => return unexpectedErrorWindows(err),
1039 }
1040 }
1041}
1042
1043pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
1044 if (is_windows) {
1045 const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
1046 return deleteFileW(&file_path_w);
1047 } else {
1048 const err = posix.getErrno(posix.unlink(file_path));
1049 switch (err) {
1050 0 => return,
1051 posix.EACCES => return error.AccessDenied,
1052 posix.EPERM => return error.AccessDenied,
1053 posix.EBUSY => return error.FileBusy,
1054 posix.EFAULT => unreachable,
1055 posix.EINVAL => unreachable,
1056 posix.EIO => return error.FileSystem,
1057 posix.EISDIR => return error.IsDir,
1058 posix.ELOOP => return error.SymLinkLoop,
1059 posix.ENAMETOOLONG => return error.NameTooLong,
1060 posix.ENOENT => return error.FileNotFound,
1061 posix.ENOTDIR => return error.NotDir,
1062 posix.ENOMEM => return error.SystemResources,
1063 posix.EROFS => return error.ReadOnlyFileSystem,
1064 else => return unexpectedErrorPosix(err),
1065 }
1066 }
1067}
1068
1069/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
1070/// merged and readily available,
1071/// there is a possibility of power loss or application termination leaving temporary files present
1072/// in the same directory as dest_path.
1073/// Destination file will have the same mode as the source file.
1074pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
1075 var in_file = try os.File.openRead(source_path);
1076 defer in_file.close();
1077
1078 const mode = try in_file.mode();
1079
1080 var atomic_file = try AtomicFile.init(dest_path, mode);
1081 defer atomic_file.deinit();
1082
1083 var buf: [page_size]u8 = undefined;
1084 while (true) {
1085 const amt = try in_file.readFull(buf[0..]);
1086 try atomic_file.file.write(buf[0..amt]);
1087 if (amt != buf.len) {
1088 return atomic_file.finish();
1089 }
1090 }
1091}
1092
1093/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
1094/// merged and readily available,
1095/// there is a possibility of power loss or application termination leaving temporary files present
1096pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
1097 var in_file = try os.File.openRead(source_path);
1098 defer in_file.close();
1099
1100 var atomic_file = try AtomicFile.init(dest_path, mode);
1101 defer atomic_file.deinit();
1102
1103 var buf: [page_size]u8 = undefined;
1104 while (true) {
1105 const amt = try in_file.read(buf[0..]);
1106 try atomic_file.file.write(buf[0..amt]);
1107 if (amt != buf.len) {
1108 return atomic_file.finish();
1109 }
1110 }
1111}
1112
1113pub const AtomicFile = struct {
1114 file: os.File,
1115 tmp_path_buf: [MAX_PATH_BYTES]u8,
1116 dest_path: []const u8,
1117 finished: bool,
1118
1119 const InitError = os.File.OpenError;
1120
1121 /// dest_path must remain valid for the lifetime of AtomicFile
1122 /// call finish to atomically replace dest_path with contents
1123 /// TODO once we have null terminated pointers, use the
1124 /// openWriteNoClobberN function
1125 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
1126 const dirname = os.path.dirname(dest_path);
1127 var rand_buf: [12]u8 = undefined;
1128 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
1129 const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
1130 const tmp_path_len = dirname_component_len + encoded_rand_len;
1131 var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
1132 if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
1133
1134 if (dirname) |dir| {
1135 mem.copy(u8, tmp_path_buf[0..], dir);
1136 tmp_path_buf[dir.len] = os.path.sep;
1137 }
1138
1139 tmp_path_buf[tmp_path_len] = 0;
1140
1141 while (true) {
1142 try getRandomBytes(rand_buf[0..]);
1143 b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
1144
1145 const file = os.File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
1146 error.PathAlreadyExists => continue,
1147 // TODO zig should figure out that this error set does not include PathAlreadyExists since
1148 // it is handled in the above switch
1149 else => return err,
1150 };
1151
1152 return AtomicFile{
1153 .file = file,
1154 .tmp_path_buf = tmp_path_buf,
1155 .dest_path = dest_path,
1156 .finished = false,
1157 };
1158 }
1159 }
1160
1161 /// always call deinit, even after successful finish()
1162 pub fn deinit(self: *AtomicFile) void {
1163 if (!self.finished) {
1164 self.file.close();
1165 deleteFileC(&self.tmp_path_buf) catch {};
1166 self.finished = true;
1167 }
1168 }
1169
1170 pub fn finish(self: *AtomicFile) !void {
1171 assert(!self.finished);
1172 self.file.close();
1173 self.finished = true;
1174 if (is_posix) {
1175 const dest_path_c = try toPosixPath(self.dest_path);
1176 return renameC(&self.tmp_path_buf, &dest_path_c);
1177 } else if (is_windows) {
1178 const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
1179 const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
1180 return renameW(&tmp_path_w, &dest_path_w);
1181 } else {
1182 @compileError("Unsupported OS");
1183 }
1184 }
1185};
1186
1187pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
1188 if (is_windows) {
1189 const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
1190 const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
1191 return renameW(&old_path_w, &new_path_w);
1192 } else {
1193 const err = posix.getErrno(posix.rename(old_path, new_path));
1194 switch (err) {
1195 0 => return,
1196 posix.EACCES => return error.AccessDenied,
1197 posix.EPERM => return error.AccessDenied,
1198 posix.EBUSY => return error.FileBusy,
1199 posix.EDQUOT => return error.DiskQuota,
1200 posix.EFAULT => unreachable,
1201 posix.EINVAL => unreachable,
1202 posix.EISDIR => return error.IsDir,
1203 posix.ELOOP => return error.SymLinkLoop,
1204 posix.EMLINK => return error.LinkQuotaExceeded,
1205 posix.ENAMETOOLONG => return error.NameTooLong,
1206 posix.ENOENT => return error.FileNotFound,
1207 posix.ENOTDIR => return error.NotDir,
1208 posix.ENOMEM => return error.SystemResources,
1209 posix.ENOSPC => return error.NoSpaceLeft,
1210 posix.EEXIST => return error.PathAlreadyExists,
1211 posix.ENOTEMPTY => return error.PathAlreadyExists,
1212 posix.EROFS => return error.ReadOnlyFileSystem,
1213 posix.EXDEV => return error.RenameAcrossMountPoints,
1214 else => return unexpectedErrorPosix(err),
1215 }
1216 }
1217}
1218
1219pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
1220 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
1221 if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
1222 const err = windows.GetLastError();
1223 switch (err) {
1224 else => return unexpectedErrorWindows(err),
1225 }
1226 }
1227}
1228
1229pub fn rename(old_path: []const u8, new_path: []const u8) !void {
1230 if (is_windows) {
1231 const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
1232 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
1233 return renameW(&old_path_w, &new_path_w);
1234 } else {
1235 const old_path_c = try toPosixPath(old_path);
1236 const new_path_c = try toPosixPath(new_path);
1237 return renameC(&old_path_c, &new_path_c);
1238 }
1239}
1240
1241pub fn makeDir(dir_path: []const u8) !void {
1242 if (is_windows) {
1243 return makeDirWindows(dir_path);
1244 } else {
1245 return makeDirPosix(dir_path);
1246 }
1247}
1248
1249pub fn makeDirWindows(dir_path: []const u8) !void {
1250 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1251
1252 if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
1253 const err = windows.GetLastError();
1254 return switch (err) {
1255 windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
1256 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1257 else => unexpectedErrorWindows(err),
1258 };
1259 }
1260}
1261
1262pub fn makeDirPosixC(dir_path: [*]const u8) !void {
1263 const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
1264 switch (err) {
1265 0 => return,
1266 posix.EACCES => return error.AccessDenied,
1267 posix.EPERM => return error.AccessDenied,
1268 posix.EDQUOT => return error.DiskQuota,
1269 posix.EEXIST => return error.PathAlreadyExists,
1270 posix.EFAULT => unreachable,
1271 posix.ELOOP => return error.SymLinkLoop,
1272 posix.EMLINK => return error.LinkQuotaExceeded,
1273 posix.ENAMETOOLONG => return error.NameTooLong,
1274 posix.ENOENT => return error.FileNotFound,
1275 posix.ENOMEM => return error.SystemResources,
1276 posix.ENOSPC => return error.NoSpaceLeft,
1277 posix.ENOTDIR => return error.NotDir,
1278 posix.EROFS => return error.ReadOnlyFileSystem,
1279 else => return unexpectedErrorPosix(err),
1280 }
1281}
1282
1283pub fn makeDirPosix(dir_path: []const u8) !void {
1284 const dir_path_c = try toPosixPath(dir_path);
1285 return makeDirPosixC(&dir_path_c);
1286}
1287
1288/// Calls makeDir recursively to make an entire path. Returns success if the path
1289/// already exists and is a directory.
1290/// TODO determine if we can remove the allocator requirement from this function
1291pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
1292 const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
1293 defer allocator.free(resolved_path);
1294
1295 var end_index: usize = resolved_path.len;
1296 while (true) {
1297 makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
1298 error.PathAlreadyExists => {
1299 // TODO stat the file and return an error if it's not a directory
1300 // this is important because otherwise a dangling symlink
1301 // could cause an infinite loop
1302 if (end_index == resolved_path.len) return;
1303 },
1304 error.FileNotFound => {
1305 // march end_index backward until next path component
1306 while (true) {
1307 end_index -= 1;
1308 if (os.path.isSep(resolved_path[end_index])) break;
1309 }
1310 continue;
1311 },
1312 else => return err,
1313 };
1314 if (end_index == resolved_path.len) return;
1315 // march end_index forward until next path component
1316 while (true) {
1317 end_index += 1;
1318 if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
1319 }
1320 }
1321}
1322
1323pub const DeleteDirError = error{
1324 AccessDenied,
1325 FileBusy,
1326 SymLinkLoop,
1327 NameTooLong,
1328 FileNotFound,
1329 SystemResources,
1330 NotDir,
1331 DirNotEmpty,
1332 ReadOnlyFileSystem,
1333 InvalidUtf8,
1334 BadPathName,
1335
1336 /// See https://github.com/ziglang/zig/issues/1396
1337 Unexpected,
1338};
1339
1340pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
1341 switch (builtin.os) {
1342 Os.windows => {
1343 const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
1344 return deleteDirW(&dir_path_w);
1345 },
1346 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1347 const err = posix.getErrno(posix.rmdir(dir_path));
1348 switch (err) {
1349 0 => return,
1350 posix.EACCES => return error.AccessDenied,
1351 posix.EPERM => return error.AccessDenied,
1352 posix.EBUSY => return error.FileBusy,
1353 posix.EFAULT => unreachable,
1354 posix.EINVAL => unreachable,
1355 posix.ELOOP => return error.SymLinkLoop,
1356 posix.ENAMETOOLONG => return error.NameTooLong,
1357 posix.ENOENT => return error.FileNotFound,
1358 posix.ENOMEM => return error.SystemResources,
1359 posix.ENOTDIR => return error.NotDir,
1360 posix.EEXIST => return error.DirNotEmpty,
1361 posix.ENOTEMPTY => return error.DirNotEmpty,
1362 posix.EROFS => return error.ReadOnlyFileSystem,
1363 else => return unexpectedErrorPosix(err),
1364 }
1365 },
1366 else => @compileError("unimplemented"),
1367 }
1368}
1369
1370pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
1371 if (windows.RemoveDirectoryW(dir_path_w) == 0) {
1372 const err = windows.GetLastError();
1373 switch (err) {
1374 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1375 windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
1376 else => return unexpectedErrorWindows(err),
1377 }
1378 }
1379}
1380
1381/// Returns ::error.DirNotEmpty if the directory is not empty.
1382/// To delete a directory recursively, see ::deleteTree
1383pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
1384 switch (builtin.os) {
1385 Os.windows => {
1386 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1387 return deleteDirW(&dir_path_w);
1388 },
1389 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1390 const dir_path_c = try toPosixPath(dir_path);
1391 return deleteDirC(&dir_path_c);
1392 },
1393 else => @compileError("unimplemented"),
1394 }
1395}
1396
1397/// Whether ::full_path describes a symlink, file, or directory, this function
1398/// removes it. If it cannot be removed because it is a non-empty directory,
1399/// this function recursively removes its entries and then tries again.
1400const DeleteTreeError = error{
1401 OutOfMemory,
1402 AccessDenied,
1403 FileTooBig,
1404 IsDir,
1405 SymLinkLoop,
1406 ProcessFdQuotaExceeded,
1407 NameTooLong,
1408 SystemFdQuotaExceeded,
1409 NoDevice,
1410 SystemResources,
1411 NoSpaceLeft,
1412 PathAlreadyExists,
1413 ReadOnlyFileSystem,
1414 NotDir,
1415 FileNotFound,
1416 FileSystem,
1417 FileBusy,
1418 DirNotEmpty,
1419 DeviceBusy,
1420
1421 /// On Windows, file paths must be valid Unicode.
1422 InvalidUtf8,
1423
1424 /// On Windows, file paths cannot contain these characters:
1425 /// '/', '*', '?', '"', '<', '>', '|'
1426 BadPathName,
1427
1428 /// See https://github.com/ziglang/zig/issues/1396
1429 Unexpected,
1430};
1431
1432/// TODO determine if we can remove the allocator requirement
1433pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
1434 start_over: while (true) {
1435 var got_access_denied = false;
1436 // First, try deleting the item as a file. This way we don't follow sym links.
1437 if (deleteFile(full_path)) {
1438 return;
1439 } else |err| switch (err) {
1440 error.FileNotFound => return,
1441 error.IsDir => {},
1442 error.AccessDenied => got_access_denied = true,
1443
1444 error.InvalidUtf8,
1445 error.SymLinkLoop,
1446 error.NameTooLong,
1447 error.SystemResources,
1448 error.ReadOnlyFileSystem,
1449 error.NotDir,
1450 error.FileSystem,
1451 error.FileBusy,
1452 error.BadPathName,
1453 error.Unexpected,
1454 => return err,
1455 }
1456 {
1457 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
1458 error.NotDir => {
1459 if (got_access_denied) {
1460 return error.AccessDenied;
1461 }
1462 continue :start_over;
1463 },
1464
1465 error.OutOfMemory,
1466 error.AccessDenied,
1467 error.FileTooBig,
1468 error.IsDir,
1469 error.SymLinkLoop,
1470 error.ProcessFdQuotaExceeded,
1471 error.NameTooLong,
1472 error.SystemFdQuotaExceeded,
1473 error.NoDevice,
1474 error.FileNotFound,
1475 error.SystemResources,
1476 error.NoSpaceLeft,
1477 error.PathAlreadyExists,
1478 error.Unexpected,
1479 error.InvalidUtf8,
1480 error.BadPathName,
1481 error.DeviceBusy,
1482 => return err,
1483 };
1484 defer dir.close();
1485
1486 var full_entry_buf = ArrayList(u8).init(allocator);
1487 defer full_entry_buf.deinit();
1488
1489 while (try dir.next()) |entry| {
1490 try full_entry_buf.resize(full_path.len + entry.name.len + 1);
1491 const full_entry_path = full_entry_buf.toSlice();
1492 mem.copy(u8, full_entry_path, full_path);
1493 full_entry_path[full_path.len] = path.sep;
1494 mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
1495
1496 try deleteTree(allocator, full_entry_path);
1497 }
1498 }
1499 return deleteDir(full_path);
1500 }
1501}
1502
1503pub const Dir = struct {
1504 handle: Handle,
1505 allocator: *Allocator,
1506
1507 pub const Handle = switch (builtin.os) {
1508 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
1509 fd: i32,
1510 seek: i64,
1511 buf: []u8,
1512 index: usize,
1513 end_index: usize,
1514 },
1515 Os.linux => struct {
1516 fd: i32,
1517 buf: []u8,
1518 index: usize,
1519 end_index: usize,
1520 },
1521 Os.windows => struct {
1522 handle: windows.HANDLE,
1523 find_file_data: windows.WIN32_FIND_DATAW,
1524 first: bool,
1525 name_data: [256]u8,
1526 },
1527 else => @compileError("unimplemented"),
1528 };
1529
1530 pub const Entry = struct {
1531 name: []const u8,
1532 kind: Kind,
1533
1534 pub const Kind = enum {
1535 BlockDevice,
1536 CharacterDevice,
1537 Directory,
1538 NamedPipe,
1539 SymLink,
1540 File,
1541 UnixDomainSocket,
1542 Whiteout,
1543 Unknown,
1544 };
1545 };
1546
1547 pub const OpenError = error{
1548 FileNotFound,
1549 NotDir,
1550 AccessDenied,
1551 FileTooBig,
1552 IsDir,
1553 SymLinkLoop,
1554 ProcessFdQuotaExceeded,
1555 NameTooLong,
1556 SystemFdQuotaExceeded,
1557 NoDevice,
1558 SystemResources,
1559 NoSpaceLeft,
1560 PathAlreadyExists,
1561 OutOfMemory,
1562 InvalidUtf8,
1563 BadPathName,
1564 DeviceBusy,
1565
1566 /// See https://github.com/ziglang/zig/issues/1396
1567 Unexpected,
1568 };
1569
1570 /// TODO remove the allocator requirement from this API
1571 pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
1572 return Dir{
1573 .allocator = allocator,
1574 .handle = switch (builtin.os) {
1575 Os.windows => blk: {
1576 var find_file_data: windows.WIN32_FIND_DATAW = undefined;
1577 const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
1578 break :blk Handle{
1579 .handle = handle,
1580 .find_file_data = find_file_data, // TODO guaranteed copy elision
1581 .first = true,
1582 .name_data = undefined,
1583 };
1584 },
1585 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
1586 .fd = try posixOpen(
1587 dir_path,
1588 posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
1589 0,
1590 ),
1591 .seek = 0,
1592 .index = 0,
1593 .end_index = 0,
1594 .buf = []u8{},
1595 },
1596 Os.linux => Handle{
1597 .fd = try posixOpen(
1598 dir_path,
1599 posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
1600 0,
1601 ),
1602 .index = 0,
1603 .end_index = 0,
1604 .buf = []u8{},
1605 },
1606 else => @compileError("unimplemented"),
1607 },
1608 };
1609 }
1610
1611 pub fn close(self: *Dir) void {
1612 switch (builtin.os) {
1613 Os.windows => {
1614 _ = windows.FindClose(self.handle.handle);
1615 },
1616 Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
1617 self.allocator.free(self.handle.buf);
1618 os.close(self.handle.fd);
1619 },
1620 else => @compileError("unimplemented"),
1621 }
1622 }
1623
1624 /// Memory such as file names referenced in this returned entry becomes invalid
1625 /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
1626 pub fn next(self: *Dir) !?Entry {
1627 switch (builtin.os) {
1628 Os.linux => return self.nextLinux(),
1629 Os.macosx, Os.ios => return self.nextDarwin(),
1630 Os.windows => return self.nextWindows(),
1631 Os.freebsd => return self.nextFreebsd(),
1632 Os.netbsd => return self.nextFreebsd(),
1633 else => @compileError("unimplemented"),
1634 }
1635 }
1636
1637 fn nextDarwin(self: *Dir) !?Entry {
1638 start_over: while (true) {
1639 if (self.handle.index >= self.handle.end_index) {
1640 if (self.handle.buf.len == 0) {
1641 self.handle.buf = try self.allocator.alloc(u8, page_size);
1642 }
1643
1644 while (true) {
1645 const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
1646 const err = posix.getErrno(result);
1647 if (err > 0) {
1648 switch (err) {
1649 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1650 posix.EINVAL => {
1651 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
1652 continue;
1653 },
1654 else => return unexpectedErrorPosix(err),
1655 }
1656 }
1657 if (result == 0) return null;
1658 self.handle.index = 0;
1659 self.handle.end_index = result;
1660 break;
1661 }
1662 }
1663 const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1664 const next_index = self.handle.index + darwin_entry.d_reclen;
1665 self.handle.index = next_index;
1666
1667 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
1668
1669 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1670 continue :start_over;
1671 }
1672
1673 const entry_kind = switch (darwin_entry.d_type) {
1674 posix.DT_BLK => Entry.Kind.BlockDevice,
1675 posix.DT_CHR => Entry.Kind.CharacterDevice,
1676 posix.DT_DIR => Entry.Kind.Directory,
1677 posix.DT_FIFO => Entry.Kind.NamedPipe,
1678 posix.DT_LNK => Entry.Kind.SymLink,
1679 posix.DT_REG => Entry.Kind.File,
1680 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1681 posix.DT_WHT => Entry.Kind.Whiteout,
1682 else => Entry.Kind.Unknown,
1683 };
1684 return Entry{
1685 .name = name,
1686 .kind = entry_kind,
1687 };
1688 }
1689 }
1690
1691 fn nextWindows(self: *Dir) !?Entry {
1692 while (true) {
1693 if (self.handle.first) {
1694 self.handle.first = false;
1695 } else {
1696 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
1697 return null;
1698 }
1699 const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
1700 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
1701 continue;
1702 // Trust that Windows gives us valid UTF-16LE
1703 const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
1704 const name_utf8 = self.handle.name_data[0..name_utf8_len];
1705 const kind = blk: {
1706 const attrs = self.handle.find_file_data.dwFileAttributes;
1707 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
1708 if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
1709 if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
1710 break :blk Entry.Kind.Unknown;
1711 };
1712 return Entry{
1713 .name = name_utf8,
1714 .kind = kind,
1715 };
1716 }
1717 }
1718
1719 fn nextLinux(self: *Dir) !?Entry {
1720 start_over: while (true) {
1721 if (self.handle.index >= self.handle.end_index) {
1722 if (self.handle.buf.len == 0) {
1723 self.handle.buf = try self.allocator.alloc(u8, page_size);
1724 }
1725
1726 while (true) {
1727 const result = posix.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
1728 const err = posix.getErrno(result);
1729 if (err > 0) {
1730 switch (err) {
1731 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1732 posix.EINVAL => {
1733 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
1734 continue;
1735 },
1736 else => return unexpectedErrorPosix(err),
1737 }
1738 }
1739 if (result == 0) return null;
1740 self.handle.index = 0;
1741 self.handle.end_index = result;
1742 break;
1743 }
1744 }
1745 const linux_entry = @ptrCast(*align(1) posix.dirent64, &self.handle.buf[self.handle.index]);
1746 const next_index = self.handle.index + linux_entry.d_reclen;
1747 self.handle.index = next_index;
1748
1749 const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
1750
1751 // skip . and .. entries
1752 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1753 continue :start_over;
1754 }
1755
1756 const entry_kind = switch (linux_entry.d_type) {
1757 posix.DT_BLK => Entry.Kind.BlockDevice,
1758 posix.DT_CHR => Entry.Kind.CharacterDevice,
1759 posix.DT_DIR => Entry.Kind.Directory,
1760 posix.DT_FIFO => Entry.Kind.NamedPipe,
1761 posix.DT_LNK => Entry.Kind.SymLink,
1762 posix.DT_REG => Entry.Kind.File,
1763 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1764 else => Entry.Kind.Unknown,
1765 };
1766 return Entry{
1767 .name = name,
1768 .kind = entry_kind,
1769 };
1770 }
1771 }
1772
1773 fn nextFreebsd(self: *Dir) !?Entry {
1774 start_over: while (true) {
1775 if (self.handle.index >= self.handle.end_index) {
1776 if (self.handle.buf.len == 0) {
1777 self.handle.buf = try self.allocator.alloc(u8, page_size);
1778 }
1779
1780 while (true) {
1781 const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
1782 const err = posix.getErrno(result);
1783 if (err > 0) {
1784 switch (err) {
1785 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1786 posix.EINVAL => {
1787 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
1788 continue;
1789 },
1790 else => return unexpectedErrorPosix(err),
1791 }
1792 }
1793 if (result == 0) return null;
1794 self.handle.index = 0;
1795 self.handle.end_index = result;
1796 break;
1797 }
1798 }
1799 const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1800 const next_index = self.handle.index + freebsd_entry.d_reclen;
1801 self.handle.index = next_index;
1802
1803 const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
1804
1805 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1806 continue :start_over;
1807 }
1808
1809 const entry_kind = switch (freebsd_entry.d_type) {
1810 posix.DT_BLK => Entry.Kind.BlockDevice,
1811 posix.DT_CHR => Entry.Kind.CharacterDevice,
1812 posix.DT_DIR => Entry.Kind.Directory,
1813 posix.DT_FIFO => Entry.Kind.NamedPipe,
1814 posix.DT_LNK => Entry.Kind.SymLink,
1815 posix.DT_REG => Entry.Kind.File,
1816 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1817 posix.DT_WHT => Entry.Kind.Whiteout,
1818 else => Entry.Kind.Unknown,
1819 };
1820 return Entry{
1821 .name = name,
1822 .kind = entry_kind,
1823 };
1824 }
1825 }
1826};
1827
1828pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
1829 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
1830 defer allocator.free(path_buf);
1831
1832 mem.copy(u8, path_buf, dir_path);
1833 path_buf[dir_path.len] = 0;
1834
1835 const err = posix.getErrno(posix.chdir(path_buf.ptr));
1836 if (err > 0) {
1837 return switch (err) {
1838 posix.EACCES => error.AccessDenied,
1839 posix.EFAULT => unreachable,
1840 posix.EIO => error.FileSystem,
1841 posix.ELOOP => error.SymLinkLoop,
1842 posix.ENAMETOOLONG => error.NameTooLong,
1843 posix.ENOENT => error.FileNotFound,
1844 posix.ENOMEM => error.SystemResources,
1845 posix.ENOTDIR => error.NotDir,
1846 else => unexpectedErrorPosix(err),
1847 };
1848 }
1849}
1850
1851/// Read value of a symbolic link.
1852/// The return value is a slice of out_buffer.
1853pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
1854 const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
1855 const err = posix.getErrno(rc);
1856 switch (err) {
1857 0 => return out_buffer[0..rc],
1858 posix.EACCES => return error.AccessDenied,
1859 posix.EFAULT => unreachable,
1860 posix.EINVAL => unreachable,
1861 posix.EIO => return error.FileSystem,
1862 posix.ELOOP => return error.SymLinkLoop,
1863 posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
1864 posix.ENOENT => return error.FileNotFound,
1865 posix.ENOMEM => return error.SystemResources,
1866 posix.ENOTDIR => return error.NotDir,
1867 else => return unexpectedErrorPosix(err),
1868 }
1869}
1870
1871/// Read value of a symbolic link.
1872/// The return value is a slice of out_buffer.
1873pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
1874 const file_path_c = try toPosixPath(file_path);
1875 return readLinkC(out_buffer, &file_path_c);
1876}
1877
1878pub fn posix_setuid(uid: u32) !void {
1879 const err = posix.getErrno(posix.setuid(uid));
1880 if (err == 0) return;
1881 return switch (err) {
1882 posix.EAGAIN => error.ResourceLimitReached,
1883 posix.EINVAL => error.InvalidUserId,
1884 posix.EPERM => error.PermissionDenied,
1885 else => unexpectedErrorPosix(err),
1886 };
1887}
1888
1889pub fn posix_setreuid(ruid: u32, euid: u32) !void {
1890 const err = posix.getErrno(posix.setreuid(ruid, euid));
1891 if (err == 0) return;
1892 return switch (err) {
1893 posix.EAGAIN => error.ResourceLimitReached,
1894 posix.EINVAL => error.InvalidUserId,
1895 posix.EPERM => error.PermissionDenied,
1896 else => unexpectedErrorPosix(err),
1897 };
1898}
1899
1900pub fn posix_setgid(gid: u32) !void {
1901 const err = posix.getErrno(posix.setgid(gid));
1902 if (err == 0) return;
1903 return switch (err) {
1904 posix.EAGAIN => error.ResourceLimitReached,
1905 posix.EINVAL => error.InvalidUserId,
1906 posix.EPERM => error.PermissionDenied,
1907 else => unexpectedErrorPosix(err),
1908 };
1909}
1910
1911pub fn posix_setregid(rgid: u32, egid: u32) !void {
1912 const err = posix.getErrno(posix.setregid(rgid, egid));
1913 if (err == 0) return;
1914 return switch (err) {
1915 posix.EAGAIN => error.ResourceLimitReached,
1916 posix.EINVAL => error.InvalidUserId,
1917 posix.EPERM => error.PermissionDenied,
1918 else => unexpectedErrorPosix(err),
1919 };
1920}
1921
1922pub const WindowsGetStdHandleErrs = error{
1923 NoStdHandles,
1924
1925 /// See https://github.com/ziglang/zig/issues/1396
1926 Unexpected,
1927};
1928
1929pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
1930 if (windows.GetStdHandle(handle_id)) |handle| {
1931 if (handle == windows.INVALID_HANDLE_VALUE) {
1932 const err = windows.GetLastError();
1933 return switch (err) {
1934 else => os.unexpectedErrorWindows(err),
1935 };
1936 }
1937 return handle;
1938 } else {
1939 return error.NoStdHandles;
1940 }
1941}
1942
1943pub const ArgIteratorPosix = struct {
1944 index: usize,
1945 count: usize,
1946
1947 pub fn init() ArgIteratorPosix {
1948 return ArgIteratorPosix{
1949 .index = 0,
1950 .count = raw.len,
1951 };
1952 }
1953
1954 pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
1955 if (self.index == self.count) return null;
1956
1957 const s = raw[self.index];
1958 self.index += 1;
1959 return cstr.toSlice(s);
1960 }
1961
1962 pub fn skip(self: *ArgIteratorPosix) bool {
1963 if (self.index == self.count) return false;
1964
1965 self.index += 1;
1966 return true;
1967 }
1968
1969 /// This is marked as public but actually it's only meant to be used
1970 /// internally by zig's startup code.
1971 pub var raw: [][*]u8 = undefined;
1972};
1973
1974pub const ArgIteratorWindows = struct {
1975 index: usize,
1976 cmd_line: [*]const u8,
1977 in_quote: bool,
1978 quote_count: usize,
1979 seen_quote_count: usize,
1980
1981 pub const NextError = error{OutOfMemory};
1982
1983 pub fn init() ArgIteratorWindows {
1984 return initWithCmdLine(windows.GetCommandLineA());
1985 }
1986
1987 pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
1988 return ArgIteratorWindows{
1989 .index = 0,
1990 .cmd_line = cmd_line,
1991 .in_quote = false,
1992 .quote_count = countQuotes(cmd_line),
1993 .seen_quote_count = 0,
1994 };
1995 }
1996
1997 /// You must free the returned memory when done.
1998 pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
1999 // march forward over whitespace
2000 while (true) : (self.index += 1) {
2001 const byte = self.cmd_line[self.index];
2002 switch (byte) {
2003 0 => return null,
2004 ' ', '\t' => continue,
2005 else => break,
2006 }
2007 }
2008
2009 return self.internalNext(allocator);
2010 }
2011
2012 pub fn skip(self: *ArgIteratorWindows) bool {
2013 // march forward over whitespace
2014 while (true) : (self.index += 1) {
2015 const byte = self.cmd_line[self.index];
2016 switch (byte) {
2017 0 => return false,
2018 ' ', '\t' => continue,
2019 else => break,
2020 }
2021 }
2022
2023 var backslash_count: usize = 0;
2024 while (true) : (self.index += 1) {
2025 const byte = self.cmd_line[self.index];
2026 switch (byte) {
2027 0 => return true,
2028 '"' => {
2029 const quote_is_real = backslash_count % 2 == 0;
2030 if (quote_is_real) {
2031 self.seen_quote_count += 1;
2032 }
2033 },
2034 '\\' => {
2035 backslash_count += 1;
2036 },
2037 ' ', '\t' => {
2038 if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
2039 return true;
2040 }
2041 backslash_count = 0;
2042 },
2043 else => {
2044 backslash_count = 0;
2045 continue;
2046 },
2047 }
2048 }
2049 }
2050
2051 fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
2052 var buf = try Buffer.initSize(allocator, 0);
2053 defer buf.deinit();
2054
2055 var backslash_count: usize = 0;
2056 while (true) : (self.index += 1) {
2057 const byte = self.cmd_line[self.index];
2058 switch (byte) {
2059 0 => return buf.toOwnedSlice(),
2060 '"' => {
2061 const quote_is_real = backslash_count % 2 == 0;
2062 try self.emitBackslashes(&buf, backslash_count / 2);
2063 backslash_count = 0;
2064
2065 if (quote_is_real) {
2066 self.seen_quote_count += 1;
2067 if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
2068 try buf.appendByte('"');
2069 }
2070 } else {
2071 try buf.appendByte('"');
2072 }
2073 },
2074 '\\' => {
2075 backslash_count += 1;
2076 },
2077 ' ', '\t' => {
2078 try self.emitBackslashes(&buf, backslash_count);
2079 backslash_count = 0;
2080 if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
2081 try buf.appendByte(byte);
2082 } else {
2083 return buf.toOwnedSlice();
2084 }
2085 },
2086 else => {
2087 try self.emitBackslashes(&buf, backslash_count);
2088 backslash_count = 0;
2089 try buf.appendByte(byte);
2090 },
2091 }
2092 }
2093 }
2094
2095 fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
2096 var i: usize = 0;
2097 while (i < emit_count) : (i += 1) {
2098 try buf.appendByte('\\');
2099 }
2100 }
2101
2102 fn countQuotes(cmd_line: [*]const u8) usize {
2103 var result: usize = 0;
2104 var backslash_count: usize = 0;
2105 var index: usize = 0;
2106 while (true) : (index += 1) {
2107 const byte = cmd_line[index];
2108 switch (byte) {
2109 0 => return result,
2110 '\\' => backslash_count += 1,
2111 '"' => {
2112 result += 1 - (backslash_count % 2);
2113 backslash_count = 0;
2114 },
2115 else => {
2116 backslash_count = 0;
2117 },
2118 }
2119 }
2120 }
2121};
2122
2123pub const ArgIterator = struct {
2124 const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
2125
2126 inner: InnerType,
2127
2128 pub fn init() ArgIterator {
2129 return ArgIterator{ .inner = InnerType.init() };
2130 }
2131
2132 pub const NextError = ArgIteratorWindows.NextError;
2133
2134 /// You must free the returned memory when done.
2135 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
2136 if (builtin.os == Os.windows) {
2137 return self.inner.next(allocator);
2138 } else {
2139 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
2140 }
2141 }
2142
2143 /// If you only are targeting posix you can call this and not need an allocator.
2144 pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
2145 return self.inner.next();
2146 }
2147
2148 /// Parse past 1 argument without capturing it.
2149 /// Returns `true` if skipped an arg, `false` if we are at the end.
2150 pub fn skip(self: *ArgIterator) bool {
2151 return self.inner.skip();
2152 }
2153};
2154
2155pub fn args() ArgIterator {
2156 return ArgIterator.init();
2157}
2158
2159/// Caller must call argsFree on result.
2160pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
2161 // TODO refactor to only make 1 allocation.
2162 var it = args();
2163 var contents = try Buffer.initSize(allocator, 0);
2164 defer contents.deinit();
2165
2166 var slice_list = ArrayList(usize).init(allocator);
2167 defer slice_list.deinit();
2168
2169 while (it.next(allocator)) |arg_or_err| {
2170 const arg = try arg_or_err;
2171 defer allocator.free(arg);
2172 try contents.append(arg);
2173 try slice_list.append(arg.len);
2174 }
2175
2176 const contents_slice = contents.toSliceConst();
2177 const slice_sizes = slice_list.toSliceConst();
2178 const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
2179 const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
2180 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
2181 errdefer allocator.free(buf);
2182
2183 const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
2184 const result_contents = buf[slice_list_bytes..];
2185 mem.copy(u8, result_contents, contents_slice);
2186
2187 var contents_index: usize = 0;
2188 for (slice_sizes) |len, i| {
2189 const new_index = contents_index + len;
2190 result_slice_list[i] = result_contents[contents_index..new_index];
2191 contents_index = new_index;
2192 }
2193
2194 return result_slice_list;
2195}
2196
2197pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
2198 var total_bytes: usize = 0;
2199 for (args_alloc) |arg| {
2200 total_bytes += @sizeOf([]u8) + arg.len;
2201 }
2202 const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
2203 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
2204 return allocator.free(aligned_allocated_buf);
2205}
2206
2207test "windows arg parsing" {
2208 testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
2209 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
2210 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
2211 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
2212 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
2213 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
2214
2215 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
2216 ".\\..\\zig-cache\\build",
2217 "bin\\zig.exe",
2218 ".\\..",
2219 ".\\..\\zig-cache",
2220 "--help",
2221 });
2222}
2223
2224fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
2225 var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
2226 for (expected_args) |expected_arg| {
2227 const arg = it.next(debug.global_allocator).? catch unreachable;
2228 testing.expectEqualSlices(u8, expected_arg, arg);
2229 }
2230 testing.expect(it.next(debug.global_allocator) == null);
2231}
2232
2233// TODO make this a build variable that you can set
2234const unexpected_error_tracing = false;
2235const UnexpectedError = error{
2236 /// The Operating System returned an undocumented error code.
2237 Unexpected,
2238};
2239
2240/// Call this when you made a syscall or something that sets errno
2241/// and you get an unexpected error.
2242pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2243 if (unexpected_error_tracing) {
2244 debug.warn("unexpected errno: {}\n", errno);
2245 debug.dumpCurrentStackTrace(null);
2246 }
2247 return error.Unexpected;
2248}
2249
2250/// Call this when you made a windows DLL call or something that does SetLastError
2251/// and you get an unexpected error.
2252pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2253 if (unexpected_error_tracing) {
2254 debug.warn("unexpected GetLastError(): {}\n", err);
2255 @breakpoint();
2256 debug.dumpCurrentStackTrace(null);
2257 }
2258 return error.Unexpected;
2259}
2260
2261pub fn openSelfExe() !os.File {
2262 switch (builtin.os) {
2263 Os.linux => return os.File.openReadC(c"/proc/self/exe"),
2264 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
2265 var buf: [MAX_PATH_BYTES]u8 = undefined;
2266 const self_exe_path = try selfExePath(&buf);
2267 buf[self_exe_path.len] = 0;
2268 return os.File.openReadC(self_exe_path.ptr);
2269 },
2270 Os.windows => {
2271 var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2272 const wide_slice = try selfExePathW(&buf);
2273 return os.File.openReadW(wide_slice.ptr);
2274 },
2275 else => @compileError("Unsupported OS"),
2276 }
2277}
2278
2279test "openSelfExe" {
2280 switch (builtin.os) {
2281 Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
2282 else => return error.SkipZigTest, // Unsupported OS.
2283 }
2284}
2285
2286pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
2287 const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
2288 const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
2289 assert(rc <= out_buffer.len);
2290 if (rc == 0) {
2291 const err = windows.GetLastError();
2292 switch (err) {
2293 else => return unexpectedErrorWindows(err),
2294 }
2295 }
2296 return out_buffer[0..rc];
2297}
2298
2299/// Get the path to the current executable.
2300/// If you only need the directory, use selfExeDirPath.
2301/// If you only want an open file handle, use openSelfExe.
2302/// This function may return an error if the current executable
2303/// was deleted after spawning.
2304/// Returned value is a slice of out_buffer.
2305///
2306/// On Linux, depends on procfs being mounted. If the currently executing binary has
2307/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
2308/// TODO make the return type of this a null terminated pointer
2309pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
2310 switch (builtin.os) {
2311 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
2312 Os.freebsd => {
2313 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
2314 var out_len: usize = out_buffer.len;
2315 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
2316
2317 if (err == 0) return mem.toSlice(u8, out_buffer);
2318
2319 return switch (err) {
2320 posix.EFAULT => error.BadAdress,
2321 posix.EPERM => error.PermissionDenied,
2322 else => unexpectedErrorPosix(err),
2323 };
2324 },
2325 Os.netbsd => {
2326 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
2327 var out_len: usize = out_buffer.len;
2328 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
2329
2330 if (err == 0) return mem.toSlice(u8, out_buffer);
2331
2332 return switch (err) {
2333 posix.EFAULT => error.BadAdress,
2334 posix.EPERM => error.PermissionDenied,
2335 else => unexpectedErrorPosix(err),
2336 };
2337 },
2338 Os.windows => {
2339 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2340 const utf16le_slice = try selfExePathW(&utf16le_buf);
2341 // Trust that Windows gives us valid UTF-16LE.
2342 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
2343 return out_buffer[0..end_index];
2344 },
2345 Os.macosx, Os.ios => {
2346 var u32_len: u32 = @intCast(u32, out_buffer.len); // TODO shouldn't need this cast
2347 const rc = c._NSGetExecutablePath(out_buffer, &u32_len);
2348 if (rc != 0) return error.NameTooLong;
2349 return mem.toSlice(u8, out_buffer);
2350 },
2351 else => @compileError("Unsupported OS"),
2352 }
2353}
2354
2355/// `selfExeDirPath` except allocates the result on the heap.
2356/// Caller owns returned memory.
2357pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
2358 var buf: [MAX_PATH_BYTES]u8 = undefined;
2359 return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
2360}
2361
2362/// Get the directory path that contains the current executable.
2363/// Returned value is a slice of out_buffer.
2364pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
2365 switch (builtin.os) {
2366 Os.linux => {
2367 // If the currently executing binary has been deleted,
2368 // the file path looks something like `/a/b/c/exe (deleted)`
2369 // This path cannot be opened, but it's valid for determining the directory
2370 // the executable was in when it was run.
2371 const full_exe_path = try readLinkC(out_buffer, c"/proc/self/exe");
2372 // Assume that /proc/self/exe has an absolute path, and therefore dirname
2373 // will not return null.
2374 return path.dirname(full_exe_path).?;
2375 },
2376 Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
2377 const self_exe_path = try selfExePath(out_buffer);
2378 // Assume that the OS APIs return absolute paths, and therefore dirname
2379 // will not return null.
2380 return path.dirname(self_exe_path).?;
2381 },
2382 else => @compileError("Unsupported OS"),
2383 }
2384}
2385
2386pub fn isTty(handle: FileHandle) bool {
2387 if (is_windows) {
2388 return windows_util.windowsIsTty(handle);
2389 } else {
2390 if (builtin.link_libc) {
2391 return c.isatty(handle) != 0;
2392 } else {
2393 return posix.isatty(handle);
2394 }
2395 }
2396}
2397
2398pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
2399 if (is_windows) {
2400 return windows_util.windowsIsCygwinPty(handle);
2401 } else {
2402 if (builtin.link_libc) {
2403 return c.isatty(handle) != 0;
2404 } else {
2405 return posix.isatty(handle);
2406 }
2407 }
2408}
2409
2410pub const PosixSocketError = error{
2411 /// Permission to create a socket of the specified type and/or
2412 /// pro‐tocol is denied.
2413 PermissionDenied,
2414
2415 /// The implementation does not support the specified address family.
2416 AddressFamilyNotSupported,
2417
2418 /// Unknown protocol, or protocol family not available.
2419 ProtocolFamilyNotAvailable,
2420
2421 /// The per-process limit on the number of open file descriptors has been reached.
2422 ProcessFdQuotaExceeded,
2423
2424 /// The system-wide limit on the total number of open files has been reached.
2425 SystemFdQuotaExceeded,
2426
2427 /// Insufficient memory is available. The socket cannot be created until sufficient
2428 /// resources are freed.
2429 SystemResources,
2430
2431 /// The protocol type or the specified protocol is not supported within this domain.
2432 ProtocolNotSupported,
2433};
2434
2435pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
2436 const rc = posix.socket(domain, socket_type, protocol);
2437 const err = posix.getErrno(rc);
2438 switch (err) {
2439 0 => return @intCast(i32, rc),
2440 posix.EACCES => return PosixSocketError.PermissionDenied,
2441 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
2442 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
2443 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
2444 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
2445 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
2446 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
2447 else => return unexpectedErrorPosix(err),
2448 }
2449}
2450
2451pub const PosixBindError = error{
2452 /// The address is protected, and the user is not the superuser.
2453 /// For UNIX domain sockets: Search permission is denied on a component
2454 /// of the path prefix.
2455 AccessDenied,
2456
2457 /// The given address is already in use, or in the case of Internet domain sockets,
2458 /// The port number was specified as zero in the socket
2459 /// address structure, but, upon attempting to bind to an ephemeral port, it was
2460 /// determined that all port numbers in the ephemeral port range are currently in
2461 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
2462 AddressInUse,
2463
2464 /// A nonexistent interface was requested or the requested address was not local.
2465 AddressNotAvailable,
2466
2467 /// Too many symbolic links were encountered in resolving addr.
2468 SymLinkLoop,
2469
2470 /// addr is too long.
2471 NameTooLong,
2472
2473 /// A component in the directory prefix of the socket pathname does not exist.
2474 FileNotFound,
2475
2476 /// Insufficient kernel memory was available.
2477 SystemResources,
2478
2479 /// A component of the path prefix is not a directory.
2480 NotDir,
2481
2482 /// The socket inode would reside on a read-only filesystem.
2483 ReadOnlyFileSystem,
2484
2485 /// See https://github.com/ziglang/zig/issues/1396
2486 Unexpected,
2487};
2488
2489/// addr is `&const T` where T is one of the sockaddr
2490pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
2491 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
2492 const err = posix.getErrno(rc);
2493 switch (err) {
2494 0 => return,
2495 posix.EACCES => return PosixBindError.AccessDenied,
2496 posix.EADDRINUSE => return PosixBindError.AddressInUse,
2497 posix.EBADF => unreachable, // always a race condition if this error is returned
2498 posix.EINVAL => unreachable,
2499 posix.ENOTSOCK => unreachable,
2500 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
2501 posix.EFAULT => unreachable,
2502 posix.ELOOP => return PosixBindError.SymLinkLoop,
2503 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
2504 posix.ENOENT => return PosixBindError.FileNotFound,
2505 posix.ENOMEM => return PosixBindError.SystemResources,
2506 posix.ENOTDIR => return PosixBindError.NotDir,
2507 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
2508 else => return unexpectedErrorPosix(err),
2509 }
2510}
2511
2512const PosixListenError = error{
2513 /// Another socket is already listening on the same port.
2514 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2515 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
2516 /// was determined that all port numbers in the ephemeral port range are currently in
2517 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2518 AddressInUse,
2519
2520 /// The file descriptor sockfd does not refer to a socket.
2521 FileDescriptorNotASocket,
2522
2523 /// The socket is not of a type that supports the listen() operation.
2524 OperationNotSupported,
2525
2526 /// See https://github.com/ziglang/zig/issues/1396
2527 Unexpected,
2528};
2529
2530pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2531 const rc = posix.listen(sockfd, backlog);
2532 const err = posix.getErrno(rc);
2533 switch (err) {
2534 0 => return,
2535 posix.EADDRINUSE => return PosixListenError.AddressInUse,
2536 posix.EBADF => unreachable,
2537 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
2538 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
2539 else => return unexpectedErrorPosix(err),
2540 }
2541}
2542
2543pub const PosixAcceptError = error{
2544 ConnectionAborted,
2545
2546 /// The per-process limit on the number of open file descriptors has been reached.
2547 ProcessFdQuotaExceeded,
2548
2549 /// The system-wide limit on the total number of open files has been reached.
2550 SystemFdQuotaExceeded,
2551
2552 /// Not enough free memory. This often means that the memory allocation is limited
2553 /// by the socket buffer limits, not by the system memory.
2554 SystemResources,
2555
2556 /// The file descriptor sockfd does not refer to a socket.
2557 FileDescriptorNotASocket,
2558
2559 /// The referenced socket is not of type SOCK_STREAM.
2560 OperationNotSupported,
2561
2562 ProtocolFailure,
2563
2564 /// Firewall rules forbid connection.
2565 BlockedByFirewall,
2566
2567 /// See https://github.com/ziglang/zig/issues/1396
2568 Unexpected,
2569};
2570
2571pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2572 while (true) {
2573 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2574 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2575 const err = posix.getErrno(rc);
2576 switch (err) {
2577 0 => return @intCast(i32, rc),
2578 posix.EINTR => continue,
2579 else => return unexpectedErrorPosix(err),
2580
2581 posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
2582 posix.EBADF => unreachable, // always a race condition
2583 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2584 posix.EFAULT => unreachable,
2585 posix.EINVAL => unreachable,
2586 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2587 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2588 posix.ENOBUFS => return PosixAcceptError.SystemResources,
2589 posix.ENOMEM => return PosixAcceptError.SystemResources,
2590 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2591 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2592 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2593 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2594 }
2595 }
2596}
2597
2598/// Returns -1 if would block.
2599pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2600 while (true) {
2601 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2602 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2603 const err = posix.getErrno(rc);
2604 switch (err) {
2605 0 => return @intCast(i32, rc),
2606 posix.EINTR => continue,
2607 else => return unexpectedErrorPosix(err),
2608
2609 posix.EAGAIN => return -1,
2610 posix.EBADF => unreachable, // always a race condition
2611 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2612 posix.EFAULT => unreachable,
2613 posix.EINVAL => unreachable,
2614 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2615 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2616 posix.ENOBUFS => return PosixAcceptError.SystemResources,
2617 posix.ENOMEM => return PosixAcceptError.SystemResources,
2618 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2619 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2620 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2621 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2622 }
2623 }
2624}
2625
2626pub const LinuxEpollCreateError = error{
2627 /// The per-user limit on the number of epoll instances imposed by
2628 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2629 /// details.
2630 /// Or, The per-process limit on the number of open file descriptors has been reached.
2631 ProcessFdQuotaExceeded,
2632
2633 /// The system-wide limit on the total number of open files has been reached.
2634 SystemFdQuotaExceeded,
2635
2636 /// There was insufficient memory to create the kernel object.
2637 SystemResources,
2638
2639 /// See https://github.com/ziglang/zig/issues/1396
2640 Unexpected,
2641};
2642
2643pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2644 const rc = posix.epoll_create1(flags);
2645 const err = posix.getErrno(rc);
2646 switch (err) {
2647 0 => return @intCast(i32, rc),
2648 else => return unexpectedErrorPosix(err),
2649
2650 posix.EINVAL => unreachable,
2651 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
2652 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
2653 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
2654 }
2655}
2656
2657pub const LinuxEpollCtlError = error{
2658 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2659 /// with this epoll instance.
2660 FileDescriptorAlreadyPresentInSet,
2661
2662 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
2663 /// circular loop of epoll instances monitoring one another.
2664 OperationCausesCircularLoop,
2665
2666 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
2667 /// instance.
2668 FileDescriptorNotRegistered,
2669
2670 /// There was insufficient memory to handle the requested op control operation.
2671 SystemResources,
2672
2673 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
2674 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
2675 /// See epoll(7) for further details.
2676 UserResourceLimitReached,
2677
2678 /// The target file fd does not support epoll. This error can occur if fd refers to,
2679 /// for example, a regular file or a directory.
2680 FileDescriptorIncompatibleWithEpoll,
2681
2682 /// See https://github.com/ziglang/zig/issues/1396
2683 Unexpected,
2684};
2685
2686pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
2687 const rc = posix.epoll_ctl(epfd, op, fd, event);
2688 const err = posix.getErrno(rc);
2689 switch (err) {
2690 0 => return,
2691 else => return unexpectedErrorPosix(err),
2692
2693 posix.EBADF => unreachable, // always a race condition if this happens
2694 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
2695 posix.EINVAL => unreachable,
2696 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
2697 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
2698 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
2699 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
2700 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
2701 }
2702}
2703
2704pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2705 while (true) {
2706 const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
2707 const err = posix.getErrno(rc);
2708 switch (err) {
2709 0 => return rc,
2710 posix.EINTR => continue,
2711 posix.EBADF => unreachable,
2712 posix.EFAULT => unreachable,
2713 posix.EINVAL => unreachable,
2714 else => unreachable,
2715 }
2716 }
2717}
2718
2719pub const LinuxEventFdError = error{
2720 InvalidFlagValue,
2721 SystemResources,
2722 ProcessFdQuotaExceeded,
2723 SystemFdQuotaExceeded,
2724
2725 /// See https://github.com/ziglang/zig/issues/1396
2726 Unexpected,
2727};
2728
2729pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
2730 const rc = posix.eventfd(initval, flags);
2731 const err = posix.getErrno(rc);
2732 switch (err) {
2733 0 => return @intCast(i32, rc),
2734 else => return unexpectedErrorPosix(err),
2735
2736 posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
2737 posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
2738 posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
2739 posix.ENODEV => return LinuxEventFdError.SystemResources,
2740 posix.ENOMEM => return LinuxEventFdError.SystemResources,
2741 }
2742}
2743
2744pub const PosixGetSockNameError = error{
2745 /// Insufficient resources were available in the system to perform the operation.
2746 SystemResources,
2747
2748 /// See https://github.com/ziglang/zig/issues/1396
2749 Unexpected,
2750};
2751
2752pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2753 var addr: posix.sockaddr = undefined;
2754 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
2755 const rc = posix.getsockname(sockfd, &addr, &addrlen);
2756 const err = posix.getErrno(rc);
2757 switch (err) {
2758 0 => return addr,
2759 else => return unexpectedErrorPosix(err),
2760
2761 posix.EBADF => unreachable,
2762 posix.EFAULT => unreachable,
2763 posix.EINVAL => unreachable,
2764 posix.ENOTSOCK => unreachable,
2765 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2766 }
2767}
2768
2769pub const PosixConnectError = error{
2770 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2771 /// file, or search permission is denied for one of the directories in the path prefix.
2772 /// or
2773 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2774 /// the connection request failed because of a local firewall rule.
2775 PermissionDenied,
2776
2777 /// Local address is already in use.
2778 AddressInUse,
2779
2780 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2781 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2782 /// in the ephemeral port range are currently in use. See the discussion of
2783 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2784 AddressNotAvailable,
2785
2786 /// The passed address didn't have the correct address family in its sa_family field.
2787 AddressFamilyNotSupported,
2788
2789 /// Insufficient entries in the routing cache.
2790 SystemResources,
2791
2792 /// A connect() on a stream socket found no one listening on the remote address.
2793 ConnectionRefused,
2794
2795 /// Network is unreachable.
2796 NetworkUnreachable,
2797
2798 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2799 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2800 ConnectionTimedOut,
2801
2802 /// See https://github.com/ziglang/zig/issues/1396
2803 Unexpected,
2804};
2805
2806pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
2807 while (true) {
2808 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2809 const err = posix.getErrno(rc);
2810 switch (err) {
2811 0 => return,
2812 else => return unexpectedErrorPosix(err),
2813
2814 posix.EACCES => return PosixConnectError.PermissionDenied,
2815 posix.EPERM => return PosixConnectError.PermissionDenied,
2816 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2817 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2818 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2819 posix.EAGAIN => return PosixConnectError.SystemResources,
2820 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2821 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2822 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2823 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2824 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2825 posix.EINTR => continue,
2826 posix.EISCONN => unreachable, // The socket is already connected.
2827 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2828 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2829 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2830 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2831 }
2832 }
2833}
2834
2835/// Same as posixConnect except it is for blocking socket file descriptors.
2836/// It expects to receive EINPROGRESS.
2837pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
2838 while (true) {
2839 const rc = posix.connect(sockfd, sockaddr, len);
2840 const err = posix.getErrno(rc);
2841 switch (err) {
2842 0, posix.EINPROGRESS => return,
2843 else => return unexpectedErrorPosix(err),
2844
2845 posix.EACCES => return PosixConnectError.PermissionDenied,
2846 posix.EPERM => return PosixConnectError.PermissionDenied,
2847 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2848 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2849 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2850 posix.EAGAIN => return PosixConnectError.SystemResources,
2851 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2852 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2853 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2854 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2855 posix.EINTR => continue,
2856 posix.EISCONN => unreachable, // The socket is already connected.
2857 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2858 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2859 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2860 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2861 }
2862 }
2863}
2864
2865pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2866 var err_code: i32 = undefined;
2867 var size: u32 = @sizeOf(i32);
2868 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
2869 assert(size == 4);
2870 const err = posix.getErrno(rc);
2871 switch (err) {
2872 0 => switch (err_code) {
2873 0 => return,
2874 else => return unexpectedErrorPosix(err),
2875
2876 posix.EACCES => return PosixConnectError.PermissionDenied,
2877 posix.EPERM => return PosixConnectError.PermissionDenied,
2878 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2879 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2880 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2881 posix.EAGAIN => return PosixConnectError.SystemResources,
2882 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2883 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2884 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2885 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2886 posix.EISCONN => unreachable, // The socket is already connected.
2887 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2888 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2889 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2890 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2891 },
2892 else => return unexpectedErrorPosix(err),
2893 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2894 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2895 posix.EINVAL => unreachable,
2896 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2897 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2898 }
2899}
2900
2901pub const Thread = struct {
2902 data: Data,
2903
2904 pub const use_pthreads = is_posix and builtin.link_libc;
2905
2906 /// Represents a kernel thread handle.
2907 /// May be an integer or a pointer depending on the platform.
2908 /// On Linux and POSIX, this is the same as Id.
2909 pub const Handle = if (use_pthreads)
2910 c.pthread_t
2911 else switch (builtin.os) {
2912 builtin.Os.linux => i32,
2913 builtin.Os.windows => windows.HANDLE,
2914 else => @compileError("Unsupported OS"),
2915 };
2916
2917 /// Represents a unique ID per thread.
2918 /// May be an integer or pointer depending on the platform.
2919 /// On Linux and POSIX, this is the same as Handle.
2920 pub const Id = switch (builtin.os) {
2921 builtin.Os.windows => windows.DWORD,
2922 else => Handle,
2923 };
2924
2925 pub const Data = if (use_pthreads)
2926 struct {
2927 handle: Thread.Handle,
2928 mmap_addr: usize,
2929 mmap_len: usize,
2930 }
2931 else switch (builtin.os) {
2932 builtin.Os.linux => struct {
2933 handle: Thread.Handle,
2934 mmap_addr: usize,
2935 mmap_len: usize,
2936 tls_end_addr: usize,
2937 },
2938 builtin.Os.windows => struct {
2939 handle: Thread.Handle,
2940 alloc_start: *c_void,
2941 heap_handle: windows.HANDLE,
2942 },
2943 else => @compileError("Unsupported OS"),
2944 };
2945
2946 /// Returns the ID of the calling thread.
2947 /// Makes a syscall every time the function is called.
2948 /// On Linux and POSIX, this Id is the same as a Handle.
2949 pub fn getCurrentId() Id {
2950 if (use_pthreads) {
2951 return c.pthread_self();
2952 } else
2953 return switch (builtin.os) {
2954 builtin.Os.linux => linux.gettid(),
2955 builtin.Os.windows => windows.GetCurrentThreadId(),
2956 else => @compileError("Unsupported OS"),
2957 };
2958 }
2959
2960 /// Returns the handle of this thread.
2961 /// On Linux and POSIX, this is the same as Id.
2962 pub fn handle(self: Thread) Handle {
2963 return self.data.handle;
2964 }
2965
2966 pub fn wait(self: *const Thread) void {
2967 if (use_pthreads) {
2968 const err = c.pthread_join(self.data.handle, null);
2969 switch (err) {
2970 0 => {},
2971 posix.EINVAL => unreachable,
2972 posix.ESRCH => unreachable,
2973 posix.EDEADLK => unreachable,
2974 else => unreachable,
2975 }
2976 assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
2977 } else switch (builtin.os) {
2978 builtin.Os.linux => {
2979 while (true) {
2980 const pid_value = @atomicLoad(i32, &self.data.handle, builtin.AtomicOrder.SeqCst);
2981 if (pid_value == 0) break;
2982 const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null);
2983 switch (linux.getErrno(rc)) {
2984 0 => continue,
2985 posix.EINTR => continue,
2986 posix.EAGAIN => continue,
2987 else => unreachable,
2988 }
2989 }
2990 assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
2991 },
2992 builtin.Os.windows => {
2993 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
2994 assert(windows.CloseHandle(self.data.handle) != 0);
2995 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
2996 },
2997 else => @compileError("Unsupported OS"),
2998 }
2999 }
3000};
3001
3002pub const SpawnThreadError = error{
3003 /// A system-imposed limit on the number of threads was encountered.
3004 /// There are a number of limits that may trigger this error:
3005 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
3006 /// which limits the number of processes and threads for a real
3007 /// user ID, was reached;
3008 /// * the kernel's system-wide limit on the number of processes and
3009 /// threads, /proc/sys/kernel/threads-max, was reached (see
3010 /// proc(5));
3011 /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
3012 /// reached (see proc(5)); or
3013 /// * the PID limit (pids.max) imposed by the cgroup "process num‐
3014 /// ber" (PIDs) controller was reached.
3015 ThreadQuotaExceeded,
3016
3017 /// The kernel cannot allocate sufficient memory to allocate a task structure
3018 /// for the child, or to copy those parts of the caller's context that need to
3019 /// be copied.
3020 SystemResources,
3021
3022 /// Not enough userland memory to spawn the thread.
3023 OutOfMemory,
3024
3025 /// See https://github.com/ziglang/zig/issues/1396
3026 Unexpected,
3027};
3028
3029pub var linux_tls_phdr: ?*std.elf.Phdr = null;
3030pub var linux_tls_img_src: [*]const u8 = undefined; // defined if linux_tls_phdr is
3031
3032/// caller must call wait on the returned thread
3033/// fn startFn(@typeOf(context)) T
3034/// where T is u8, noreturn, void, or !void
3035/// caller must call wait on the returned thread
3036pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
3037 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
3038 // TODO compile-time call graph analysis to determine stack upper bound
3039 // https://github.com/ziglang/zig/issues/157
3040 const default_stack_size = 8 * 1024 * 1024;
3041
3042 const Context = @typeOf(context);
3043 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
3044
3045 if (builtin.os == builtin.Os.windows) {
3046 const WinThread = struct {
3047 const OuterContext = struct {
3048 thread: Thread,
3049 inner: Context,
3050 };
3051 extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
3052 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
3053 switch (@typeId(@typeOf(startFn).ReturnType)) {
3054 builtin.TypeId.Int => {
3055 return startFn(arg);
3056 },
3057 builtin.TypeId.Void => {
3058 startFn(arg);
3059 return 0;
3060 },
3061 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
3062 }
3063 }
3064 };
3065
3066 const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
3067 const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
3068 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
3069 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
3070 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
3071 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
3072 outer_context.* = WinThread.OuterContext{
3073 .thread = Thread{
3074 .data = Thread.Data{
3075 .heap_handle = heap_handle,
3076 .alloc_start = bytes_ptr,
3077 .handle = undefined,
3078 },
3079 },
3080 .inner = context,
3081 };
3082
3083 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
3084 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
3085 const err = windows.GetLastError();
3086 return switch (err) {
3087 else => os.unexpectedErrorWindows(err),
3088 };
3089 };
3090 return &outer_context.thread;
3091 }
3092
3093 const MainFuncs = struct {
3094 extern fn linuxThreadMain(ctx_addr: usize) u8 {
3095 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
3096
3097 switch (@typeId(@typeOf(startFn).ReturnType)) {
3098 builtin.TypeId.Int => {
3099 return startFn(arg);
3100 },
3101 builtin.TypeId.Void => {
3102 startFn(arg);
3103 return 0;
3104 },
3105 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
3106 }
3107 }
3108 extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
3109 if (@sizeOf(Context) == 0) {
3110 _ = startFn({});
3111 return null;
3112 } else {
3113 _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
3114 return null;
3115 }
3116 }
3117 };
3118
3119 const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
3120
3121 var stack_end_offset: usize = undefined;
3122 var thread_start_offset: usize = undefined;
3123 var context_start_offset: usize = undefined;
3124 var tls_start_offset: usize = undefined;
3125 const mmap_len = blk: {
3126 // First in memory will be the stack, which grows downwards.
3127 var l: usize = mem.alignForward(default_stack_size, os.page_size);
3128 stack_end_offset = l;
3129 // Above the stack, so that it can be in the same mmap call, put the Thread object.
3130 l = mem.alignForward(l, @alignOf(Thread));
3131 thread_start_offset = l;
3132 l += @sizeOf(Thread);
3133 // Next, the Context object.
3134 if (@sizeOf(Context) != 0) {
3135 l = mem.alignForward(l, @alignOf(Context));
3136 context_start_offset = l;
3137 l += @sizeOf(Context);
3138 }
3139 // Finally, the Thread Local Storage, if any.
3140 if (!Thread.use_pthreads) {
3141 if (linux_tls_phdr) |tls_phdr| {
3142 l = mem.alignForward(l, tls_phdr.p_align);
3143 tls_start_offset = l;
3144 l += tls_phdr.p_memsz;
3145 }
3146 }
3147 break :blk l;
3148 };
3149 const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
3150 if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
3151 errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
3152
3153 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
3154 thread_ptr.data.mmap_addr = mmap_addr;
3155 thread_ptr.data.mmap_len = mmap_len;
3156
3157 var arg: usize = undefined;
3158 if (@sizeOf(Context) != 0) {
3159 arg = mmap_addr + context_start_offset;
3160 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
3161 context_ptr.* = context;
3162 }
3163
3164 if (Thread.use_pthreads) {
3165 // use pthreads
3166 var attr: c.pthread_attr_t = undefined;
3167 if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
3168 defer assert(c.pthread_attr_destroy(&attr) == 0);
3169
3170 assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
3171
3172 const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
3173 switch (err) {
3174 0 => return thread_ptr,
3175 posix.EAGAIN => return SpawnThreadError.SystemResources,
3176 posix.EPERM => unreachable,
3177 posix.EINVAL => unreachable,
3178 else => return unexpectedErrorPosix(@intCast(usize, err)),
3179 }
3180 } else if (builtin.os == builtin.Os.linux) {
3181 var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
3182 posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
3183 posix.CLONE_DETACHED;
3184 var newtls: usize = undefined;
3185 if (linux_tls_phdr) |tls_phdr| {
3186 @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz);
3187 thread_ptr.data.tls_end_addr = mmap_addr + mmap_len;
3188 newtls = @ptrToInt(&thread_ptr.data.tls_end_addr);
3189 flags |= posix.CLONE_SETTLS;
3190 }
3191 const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
3192 const err = posix.getErrno(rc);
3193 switch (err) {
3194 0 => return thread_ptr,
3195 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
3196 posix.EINVAL => unreachable,
3197 posix.ENOMEM => return SpawnThreadError.SystemResources,
3198 posix.ENOSPC => unreachable,
3199 posix.EPERM => unreachable,
3200 posix.EUSERS => unreachable,
3201 else => return unexpectedErrorPosix(err),
3202 }
3203 } else {
3204 @compileError("Unsupported OS");
3205 }
3206}
3207
3208pub fn posixWait(pid: i32) i32 {
3209 var status: i32 = undefined;
3210 while (true) {
3211 const err = posix.getErrno(posix.waitpid(pid, &status, 0));
3212 switch (err) {
3213 0 => return status,
3214 posix.EINTR => continue,
3215 posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
3216 posix.EINVAL => unreachable, // The options argument was invalid
3217 else => unreachable,
3218 }
3219 }
3220}
3221
3222pub fn posixFStat(fd: i32) !posix.Stat {
3223 var stat: posix.Stat = undefined;
3224 const err = posix.getErrno(posix.fstat(fd, &stat));
3225 if (err > 0) {
3226 return switch (err) {
3227 // We do not make this an error code because if you get EBADF it's always a bug,
3228 // since the fd could have been reused.
3229 posix.EBADF => unreachable,
3230 posix.ENOMEM => error.SystemResources,
3231 else => os.unexpectedErrorPosix(err),
3232 };
3233 }
3234
3235 return stat;
3236}
3237
3238pub const CpuCountError = error{
3239 OutOfMemory,
3240 PermissionDenied,
3241
3242 /// See https://github.com/ziglang/zig/issues/1396
3243 Unexpected,
3244};
3245
3246pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
3247 switch (builtin.os) {
3248 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
3249 var count: c_int = undefined;
3250 var count_len: usize = @sizeOf(c_int);
3251 const rc = posix.sysctlbyname(switch (builtin.os) {
3252 builtin.Os.macosx => c"hw.logicalcpu",
3253 else => c"hw.ncpu",
3254 }, @ptrCast(*c_void, &count), &count_len, null, 0);
3255 const err = posix.getErrno(rc);
3256 switch (err) {
3257 0 => return @intCast(usize, count),
3258 posix.EFAULT => unreachable,
3259 posix.EINVAL => unreachable,
3260 posix.ENOMEM => return CpuCountError.OutOfMemory,
3261 posix.ENOTDIR => unreachable,
3262 posix.EISDIR => unreachable,
3263 posix.ENOENT => unreachable,
3264 posix.EPERM => unreachable,
3265 else => return os.unexpectedErrorPosix(err),
3266 }
3267 },
3268 builtin.Os.linux => {
3269 const usize_count = 16;
3270 const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
3271
3272 var set = try allocator.alloc(usize, usize_count);
3273 defer allocator.free(set);
3274
3275 while (true) {
3276 const rc = posix.sched_getaffinity(0, set);
3277 const err = posix.getErrno(rc);
3278 switch (err) {
3279 0 => {
3280 if (rc < set.len * @sizeOf(usize)) {
3281 const result = set[0 .. rc / @sizeOf(usize)];
3282 var sum: usize = 0;
3283 for (result) |x| {
3284 sum += @popCount(x);
3285 }
3286 return sum;
3287 } else {
3288 set = try allocator.realloc(usize, set, set.len * 2);
3289 continue;
3290 }
3291 },
3292 posix.EFAULT => unreachable,
3293 posix.EINVAL => unreachable,
3294 posix.EPERM => return CpuCountError.PermissionDenied,
3295 posix.ESRCH => unreachable,
3296 else => return os.unexpectedErrorPosix(err),
3297 }
3298 }
3299 },
3300 builtin.Os.windows => {
3301 var system_info: windows.SYSTEM_INFO = undefined;
3302 windows.GetSystemInfo(&system_info);
3303 return @intCast(usize, system_info.dwNumberOfProcessors);
3304 },
3305 else => @compileError("unsupported OS"),
3306 }
3307}
3308
3309pub const BsdKQueueError = error{
3310 /// The per-process limit on the number of open file descriptors has been reached.
3311 ProcessFdQuotaExceeded,
3312
3313 /// The system-wide limit on the total number of open files has been reached.
3314 SystemFdQuotaExceeded,
3315
3316 /// See https://github.com/ziglang/zig/issues/1396
3317 Unexpected,
3318};
3319
3320pub fn bsdKQueue() BsdKQueueError!i32 {
3321 const rc = posix.kqueue();
3322 const err = posix.getErrno(rc);
3323 switch (err) {
3324 0 => return @intCast(i32, rc),
3325 posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
3326 posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
3327 else => return unexpectedErrorPosix(err),
3328 }
3329}
3330
3331pub const BsdKEventError = error{
3332 /// The process does not have permission to register a filter.
3333 AccessDenied,
3334
3335 /// The event could not be found to be modified or deleted.
3336 EventNotFound,
3337
3338 /// No memory was available to register the event.
3339 SystemResources,
3340
3341 /// The specified process to attach to does not exist.
3342 ProcessNotFound,
3343};
3344
3345pub fn bsdKEvent(
3346 kq: i32,
3347 changelist: []const posix.Kevent,
3348 eventlist: []posix.Kevent,
3349 timeout: ?*const posix.timespec,
3350) BsdKEventError!usize {
3351 while (true) {
3352 const rc = posix.kevent(kq, changelist, eventlist, timeout);
3353 const err = posix.getErrno(rc);
3354 switch (err) {
3355 0 => return rc,
3356 posix.EACCES => return BsdKEventError.AccessDenied,
3357 posix.EFAULT => unreachable,
3358 posix.EBADF => unreachable,
3359 posix.EINTR => continue,
3360 posix.EINVAL => unreachable,
3361 posix.ENOENT => return BsdKEventError.EventNotFound,
3362 posix.ENOMEM => return BsdKEventError.SystemResources,
3363 posix.ESRCH => return BsdKEventError.ProcessNotFound,
3364 else => unreachable,
3365 }
3366 }
3367}
3368
3369pub fn linuxINotifyInit1(flags: u32) !i32 {
3370 const rc = linux.inotify_init1(flags);
3371 const err = posix.getErrno(rc);
3372 switch (err) {
3373 0 => return @intCast(i32, rc),
3374 posix.EINVAL => unreachable,
3375 posix.EMFILE => return error.ProcessFdQuotaExceeded,
3376 posix.ENFILE => return error.SystemFdQuotaExceeded,
3377 posix.ENOMEM => return error.SystemResources,
3378 else => return unexpectedErrorPosix(err),
3379 }
3380}
3381
3382pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
3383 const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
3384 const err = posix.getErrno(rc);
3385 switch (err) {
3386 0 => return @intCast(i32, rc),
3387 posix.EACCES => return error.AccessDenied,
3388 posix.EBADF => unreachable,
3389 posix.EFAULT => unreachable,
3390 posix.EINVAL => unreachable,
3391 posix.ENAMETOOLONG => return error.NameTooLong,
3392 posix.ENOENT => return error.FileNotFound,
3393 posix.ENOMEM => return error.SystemResources,
3394 posix.ENOSPC => return error.UserResourceLimitReached,
3395 else => return unexpectedErrorPosix(err),
3396 }
3397}
3398
3399pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
3400 const rc = linux.inotify_rm_watch(inotify_fd, wd);
3401 const err = posix.getErrno(rc);
3402 switch (err) {
3403 0 => return rc,
3404 posix.EBADF => unreachable,
3405 posix.EINVAL => unreachable,
3406 else => unreachable,
3407 }
3408}
3409
3410pub const MProtectError = error{
3411 AccessDenied,
3412 OutOfMemory,
3413 Unexpected,
3414};
3415
3416/// address and length must be page-aligned
3417pub fn posixMProtect(address: usize, length: usize, protection: u32) MProtectError!void {
3418 const negative_page_size = @bitCast(usize, -isize(page_size));
3419 const aligned_address = address & negative_page_size;
3420 const aligned_end = (address + length + page_size - 1) & negative_page_size;
3421 assert(address == aligned_address);
3422 assert(length == aligned_end - aligned_address);
3423 const rc = posix.mprotect(address, length, protection);
3424 const err = posix.getErrno(rc);
3425 switch (err) {
3426 0 => return,
3427 posix.EINVAL => unreachable,
3428 posix.EACCES => return error.AccessDenied,
3429 posix.ENOMEM => return error.OutOfMemory,
3430 else => return unexpectedErrorPosix(err),
3431 }
3432}
std/os/child_process.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const cstr = std.cstr;2const cstr = std.cstr;
3const unicode = std.unicode;3const unicode = std.unicode;
4const io = std.io;4const io = std.io;
std/os/darwin.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const c = std.c;2const c = std.c;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
std/os/file.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const os = std.os;3const os = std.os;
4const io = std.io;4const io = std.io;
std/os/freebsd.zig created+845
...@@ -0,0 +1,845 @@
1const builtin = @import("builtin");
2
3pub use @import("freebsd/errno.zig");
4
5const std = @import("../std.zig");
6const c = std.c;
7
8const assert = std.debug.assert;
9const maxInt = std.math.maxInt;
10pub const Kevent = c.Kevent;
11
12pub const CTL_KERN = 1;
13pub const CTL_DEBUG = 5;
14
15pub const KERN_PROC = 14; // struct: process entries
16pub const KERN_PROC_PATHNAME = 12; // path to executable
17
18pub const PATH_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const PROT_NONE = 0;
25pub const PROT_READ = 1;
26pub const PROT_WRITE = 2;
27pub const PROT_EXEC = 4;
28
29pub const CLOCK_REALTIME = 0;
30pub const CLOCK_VIRTUAL = 1;
31pub const CLOCK_PROF = 2;
32pub const CLOCK_MONOTONIC = 4;
33pub const CLOCK_UPTIME = 5;
34pub const CLOCK_UPTIME_PRECISE = 7;
35pub const CLOCK_UPTIME_FAST = 8;
36pub const CLOCK_REALTIME_PRECISE = 9;
37pub const CLOCK_REALTIME_FAST = 10;
38pub const CLOCK_MONOTONIC_PRECISE = 11;
39pub const CLOCK_MONOTONIC_FAST = 12;
40pub const CLOCK_SECOND = 13;
41pub const CLOCK_THREAD_CPUTIME_ID = 14;
42pub const CLOCK_PROCESS_CPUTIME_ID = 15;
43
44pub const MAP_FAILED = maxInt(usize);
45pub const MAP_SHARED = 0x0001;
46pub const MAP_PRIVATE = 0x0002;
47pub const MAP_FIXED = 0x0010;
48pub const MAP_STACK = 0x0400;
49pub const MAP_NOSYNC = 0x0800;
50pub const MAP_ANON = 0x1000;
51pub const MAP_ANONYMOUS = MAP_ANON;
52pub const MAP_FILE = 0;
53pub const MAP_NORESERVE = 0;
54
55pub const MAP_GUARD = 0x00002000;
56pub const MAP_EXCL = 0x00004000;
57pub const MAP_NOCORE = 0x00020000;
58pub const MAP_PREFAULT_READ = 0x00040000;
59pub const MAP_32BIT = 0x00080000;
60
61pub const WNOHANG = 1;
62pub const WUNTRACED = 2;
63pub const WSTOPPED = WUNTRACED;
64pub const WCONTINUED = 4;
65pub const WNOWAIT = 8;
66pub const WEXITED = 16;
67pub const WTRAPPED = 32;
68
69pub const SA_ONSTACK = 0x0001;
70pub const SA_RESTART = 0x0002;
71pub const SA_RESETHAND = 0x0004;
72pub const SA_NOCLDSTOP = 0x0008;
73pub const SA_NODEFER = 0x0010;
74pub const SA_NOCLDWAIT = 0x0020;
75pub const SA_SIGINFO = 0x0040;
76
77pub const SIGHUP = 1;
78pub const SIGINT = 2;
79pub const SIGQUIT = 3;
80pub const SIGILL = 4;
81pub const SIGTRAP = 5;
82pub const SIGABRT = 6;
83pub const SIGIOT = SIGABRT;
84pub const SIGEMT = 7;
85pub const SIGFPE = 8;
86pub const SIGKILL = 9;
87pub const SIGBUS = 10;
88pub const SIGSEGV = 11;
89pub const SIGSYS = 12;
90pub const SIGPIPE = 13;
91pub const SIGALRM = 14;
92pub const SIGTERM = 15;
93pub const SIGURG = 16;
94pub const SIGSTOP = 17;
95pub const SIGTSTP = 18;
96pub const SIGCONT = 19;
97pub const SIGCHLD = 20;
98pub const SIGTTIN = 21;
99pub const SIGTTOU = 22;
100pub const SIGIO = 23;
101pub const SIGXCPU = 24;
102pub const SIGXFSZ = 25;
103pub const SIGVTALRM = 26;
104pub const SIGPROF = 27;
105pub const SIGWINCH = 28;
106pub const SIGINFO = 29;
107pub const SIGUSR1 = 30;
108pub const SIGUSR2 = 31;
109pub const SIGTHR = 32;
110pub const SIGLWP = SIGTHR;
111pub const SIGLIBRT = 33;
112
113pub const SIGRTMIN = 65;
114pub const SIGRTMAX = 126;
115
116// access function
117pub const F_OK = 0; // test for existence of file
118pub const X_OK = 1; // test for execute or search permission
119pub const W_OK = 2; // test for write permission
120pub const R_OK = 4; // test for read permission
121
122pub const O_RDONLY = 0x0000;
123pub const O_WRONLY = 0x0001;
124pub const O_RDWR = 0x0002;
125pub const O_ACCMODE = 0x0003;
126
127pub const O_CREAT = 0x0200;
128pub const O_EXCL = 0x0800;
129pub const O_NOCTTY = 0x8000;
130pub const O_TRUNC = 0x0400;
131pub const O_APPEND = 0x0008;
132pub const O_NONBLOCK = 0x0004;
133pub const O_DSYNC = 0o10000;
134pub const O_SYNC = 0x0080;
135pub const O_RSYNC = 0o4010000;
136pub const O_DIRECTORY = 0o200000;
137pub const O_NOFOLLOW = 0x0100;
138pub const O_CLOEXEC = 0x00100000;
139
140pub const O_ASYNC = 0x0040;
141pub const O_DIRECT = 0x00010000;
142pub const O_LARGEFILE = 0;
143pub const O_NOATIME = 0o1000000;
144pub const O_PATH = 0o10000000;
145pub const O_TMPFILE = 0o20200000;
146pub const O_NDELAY = O_NONBLOCK;
147
148pub const F_DUPFD = 0;
149pub const F_GETFD = 1;
150pub const F_SETFD = 2;
151pub const F_GETFL = 3;
152pub const F_SETFL = 4;
153
154pub const F_SETOWN = 8;
155pub const F_GETOWN = 9;
156pub const F_SETSIG = 10;
157pub const F_GETSIG = 11;
158
159pub const F_GETLK = 5;
160pub const F_SETLK = 6;
161pub const F_SETLKW = 7;
162
163pub const F_SETOWN_EX = 15;
164pub const F_GETOWN_EX = 16;
165
166pub const F_GETOWNER_UIDS = 17;
167
168pub const SEEK_SET = 0;
169pub const SEEK_CUR = 1;
170pub const SEEK_END = 2;
171
172pub const SIG_BLOCK = 1;
173pub const SIG_UNBLOCK = 2;
174pub const SIG_SETMASK = 3;
175
176pub const SOCK_STREAM = 1;
177pub const SOCK_DGRAM = 2;
178pub const SOCK_RAW = 3;
179pub const SOCK_RDM = 4;
180pub const SOCK_SEQPACKET = 5;
181
182pub const SOCK_CLOEXEC = 0x10000000;
183pub const SOCK_NONBLOCK = 0x20000000;
184
185pub const PROTO_ip = 0o000;
186pub const PROTO_icmp = 0o001;
187pub const PROTO_igmp = 0o002;
188pub const PROTO_ggp = 0o003;
189pub const PROTO_ipencap = 0o004;
190pub const PROTO_st = 0o005;
191pub const PROTO_tcp = 0o006;
192pub const PROTO_egp = 0o010;
193pub const PROTO_pup = 0o014;
194pub const PROTO_udp = 0o021;
195pub const PROTO_hmp = 0o024;
196pub const PROTO_xns_idp = 0o026;
197pub const PROTO_rdp = 0o033;
198pub const PROTO_iso_tp4 = 0o035;
199pub const PROTO_xtp = 0o044;
200pub const PROTO_ddp = 0o045;
201pub const PROTO_idpr_cmtp = 0o046;
202pub const PROTO_ipv6 = 0o051;
203pub const PROTO_ipv6_route = 0o053;
204pub const PROTO_ipv6_frag = 0o054;
205pub const PROTO_idrp = 0o055;
206pub const PROTO_rsvp = 0o056;
207pub const PROTO_gre = 0o057;
208pub const PROTO_esp = 0o062;
209pub const PROTO_ah = 0o063;
210pub const PROTO_skip = 0o071;
211pub const PROTO_ipv6_icmp = 0o072;
212pub const PROTO_ipv6_nonxt = 0o073;
213pub const PROTO_ipv6_opts = 0o074;
214pub const PROTO_rspf = 0o111;
215pub const PROTO_vmtp = 0o121;
216pub const PROTO_ospf = 0o131;
217pub const PROTO_ipip = 0o136;
218pub const PROTO_encap = 0o142;
219pub const PROTO_pim = 0o147;
220pub const PROTO_raw = 0o377;
221
222pub const PF_UNSPEC = 0;
223pub const PF_LOCAL = 1;
224pub const PF_UNIX = PF_LOCAL;
225pub const PF_FILE = PF_LOCAL;
226pub const PF_INET = 2;
227pub const PF_AX25 = 3;
228pub const PF_IPX = 4;
229pub const PF_APPLETALK = 5;
230pub const PF_NETROM = 6;
231pub const PF_BRIDGE = 7;
232pub const PF_ATMPVC = 8;
233pub const PF_X25 = 9;
234pub const PF_INET6 = 10;
235pub const PF_ROSE = 11;
236pub const PF_DECnet = 12;
237pub const PF_NETBEUI = 13;
238pub const PF_SECURITY = 14;
239pub const PF_KEY = 15;
240pub const PF_NETLINK = 16;
241pub const PF_ROUTE = PF_NETLINK;
242pub const PF_PACKET = 17;
243pub const PF_ASH = 18;
244pub const PF_ECONET = 19;
245pub const PF_ATMSVC = 20;
246pub const PF_RDS = 21;
247pub const PF_SNA = 22;
248pub const PF_IRDA = 23;
249pub const PF_PPPOX = 24;
250pub const PF_WANPIPE = 25;
251pub const PF_LLC = 26;
252pub const PF_IB = 27;
253pub const PF_MPLS = 28;
254pub const PF_CAN = 29;
255pub const PF_TIPC = 30;
256pub const PF_BLUETOOTH = 31;
257pub const PF_IUCV = 32;
258pub const PF_RXRPC = 33;
259pub const PF_ISDN = 34;
260pub const PF_PHONET = 35;
261pub const PF_IEEE802154 = 36;
262pub const PF_CAIF = 37;
263pub const PF_ALG = 38;
264pub const PF_NFC = 39;
265pub const PF_VSOCK = 40;
266pub const PF_MAX = 41;
267
268pub const AF_UNSPEC = PF_UNSPEC;
269pub const AF_LOCAL = PF_LOCAL;
270pub const AF_UNIX = AF_LOCAL;
271pub const AF_FILE = AF_LOCAL;
272pub const AF_INET = PF_INET;
273pub const AF_AX25 = PF_AX25;
274pub const AF_IPX = PF_IPX;
275pub const AF_APPLETALK = PF_APPLETALK;
276pub const AF_NETROM = PF_NETROM;
277pub const AF_BRIDGE = PF_BRIDGE;
278pub const AF_ATMPVC = PF_ATMPVC;
279pub const AF_X25 = PF_X25;
280pub const AF_INET6 = PF_INET6;
281pub const AF_ROSE = PF_ROSE;
282pub const AF_DECnet = PF_DECnet;
283pub const AF_NETBEUI = PF_NETBEUI;
284pub const AF_SECURITY = PF_SECURITY;
285pub const AF_KEY = PF_KEY;
286pub const AF_NETLINK = PF_NETLINK;
287pub const AF_ROUTE = PF_ROUTE;
288pub const AF_PACKET = PF_PACKET;
289pub const AF_ASH = PF_ASH;
290pub const AF_ECONET = PF_ECONET;
291pub const AF_ATMSVC = PF_ATMSVC;
292pub const AF_RDS = PF_RDS;
293pub const AF_SNA = PF_SNA;
294pub const AF_IRDA = PF_IRDA;
295pub const AF_PPPOX = PF_PPPOX;
296pub const AF_WANPIPE = PF_WANPIPE;
297pub const AF_LLC = PF_LLC;
298pub const AF_IB = PF_IB;
299pub const AF_MPLS = PF_MPLS;
300pub const AF_CAN = PF_CAN;
301pub const AF_TIPC = PF_TIPC;
302pub const AF_BLUETOOTH = PF_BLUETOOTH;
303pub const AF_IUCV = PF_IUCV;
304pub const AF_RXRPC = PF_RXRPC;
305pub const AF_ISDN = PF_ISDN;
306pub const AF_PHONET = PF_PHONET;
307pub const AF_IEEE802154 = PF_IEEE802154;
308pub const AF_CAIF = PF_CAIF;
309pub const AF_ALG = PF_ALG;
310pub const AF_NFC = PF_NFC;
311pub const AF_VSOCK = PF_VSOCK;
312pub const AF_MAX = PF_MAX;
313
314pub const DT_UNKNOWN = 0;
315pub const DT_FIFO = 1;
316pub const DT_CHR = 2;
317pub const DT_DIR = 4;
318pub const DT_BLK = 6;
319pub const DT_REG = 8;
320pub const DT_LNK = 10;
321pub const DT_SOCK = 12;
322pub const DT_WHT = 14;
323
324/// add event to kq (implies enable)
325pub const EV_ADD = 0x0001;
326
327/// delete event from kq
328pub const EV_DELETE = 0x0002;
329
330/// enable event
331pub const EV_ENABLE = 0x0004;
332
333/// disable event (not reported)
334pub const EV_DISABLE = 0x0008;
335
336/// only report one occurrence
337pub const EV_ONESHOT = 0x0010;
338
339/// clear event state after reporting
340pub const EV_CLEAR = 0x0020;
341
342/// force immediate event output
343/// ... with or without EV_ERROR
344/// ... use KEVENT_FLAG_ERROR_EVENTS
345/// on syscalls supporting flags
346pub const EV_RECEIPT = 0x0040;
347
348/// disable event after reporting
349pub const EV_DISPATCH = 0x0080;
350
351pub const EVFILT_READ = -1;
352pub const EVFILT_WRITE = -2;
353
354/// attached to aio requests
355pub const EVFILT_AIO = -3;
356
357/// attached to vnodes
358pub const EVFILT_VNODE = -4;
359
360/// attached to struct proc
361pub const EVFILT_PROC = -5;
362
363/// attached to struct proc
364pub const EVFILT_SIGNAL = -6;
365
366/// timers
367pub const EVFILT_TIMER = -7;
368
369/// Process descriptors
370pub const EVFILT_PROCDESC = -8;
371
372/// Filesystem events
373pub const EVFILT_FS = -9;
374
375pub const EVFILT_LIO = -10;
376
377/// User events
378pub const EVFILT_USER = -11;
379
380/// Sendfile events
381pub const EVFILT_SENDFILE = -12;
382
383pub const EVFILT_EMPTY = -13;
384
385/// On input, NOTE_TRIGGER causes the event to be triggered for output.
386pub const NOTE_TRIGGER = 0x01000000;
387
388/// ignore input fflags
389pub const NOTE_FFNOP = 0x00000000;
390
391/// and fflags
392pub const NOTE_FFAND = 0x40000000;
393
394/// or fflags
395pub const NOTE_FFOR = 0x80000000;
396
397/// copy fflags
398pub const NOTE_FFCOPY = 0xc0000000;
399
400/// mask for operations
401pub const NOTE_FFCTRLMASK = 0xc0000000;
402pub const NOTE_FFLAGSMASK = 0x00ffffff;
403
404/// low water mark
405pub const NOTE_LOWAT = 0x00000001;
406
407/// behave like poll()
408pub const NOTE_FILE_POLL = 0x00000002;
409
410/// vnode was removed
411pub const NOTE_DELETE = 0x00000001;
412
413/// data contents changed
414pub const NOTE_WRITE = 0x00000002;
415
416/// size increased
417pub const NOTE_EXTEND = 0x00000004;
418
419/// attributes changed
420pub const NOTE_ATTRIB = 0x00000008;
421
422/// link count changed
423pub const NOTE_LINK = 0x00000010;
424
425/// vnode was renamed
426pub const NOTE_RENAME = 0x00000020;
427
428/// vnode access was revoked
429pub const NOTE_REVOKE = 0x00000040;
430
431/// vnode was opened
432pub const NOTE_OPEN = 0x00000080;
433
434/// file closed, fd did not allow write
435pub const NOTE_CLOSE = 0x00000100;
436
437/// file closed, fd did allow write
438pub const NOTE_CLOSE_WRITE = 0x00000200;
439
440/// file was read
441pub const NOTE_READ = 0x00000400;
442
443/// process exited
444pub const NOTE_EXIT = 0x80000000;
445
446/// process forked
447pub const NOTE_FORK = 0x40000000;
448
449/// process exec'd
450pub const NOTE_EXEC = 0x20000000;
451
452/// mask for signal & exit status
453pub const NOTE_PDATAMASK = 0x000fffff;
454pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
455
456/// data is seconds
457pub const NOTE_SECONDS = 0x00000001;
458
459/// data is milliseconds
460pub const NOTE_MSECONDS = 0x00000002;
461
462/// data is microseconds
463pub const NOTE_USECONDS = 0x00000004;
464
465/// data is nanoseconds
466pub const NOTE_NSECONDS = 0x00000008;
467
468/// timeout is absolute
469pub const NOTE_ABSTIME = 0x00000010;
470
471pub const TCGETS = 0x5401;
472pub const TCSETS = 0x5402;
473pub const TCSETSW = 0x5403;
474pub const TCSETSF = 0x5404;
475pub const TCGETA = 0x5405;
476pub const TCSETA = 0x5406;
477pub const TCSETAW = 0x5407;
478pub const TCSETAF = 0x5408;
479pub const TCSBRK = 0x5409;
480pub const TCXONC = 0x540A;
481pub const TCFLSH = 0x540B;
482pub const TIOCEXCL = 0x540C;
483pub const TIOCNXCL = 0x540D;
484pub const TIOCSCTTY = 0x540E;
485pub const TIOCGPGRP = 0x540F;
486pub const TIOCSPGRP = 0x5410;
487pub const TIOCOUTQ = 0x5411;
488pub const TIOCSTI = 0x5412;
489pub const TIOCGWINSZ = 0x5413;
490pub const TIOCSWINSZ = 0x5414;
491pub const TIOCMGET = 0x5415;
492pub const TIOCMBIS = 0x5416;
493pub const TIOCMBIC = 0x5417;
494pub const TIOCMSET = 0x5418;
495pub const TIOCGSOFTCAR = 0x5419;
496pub const TIOCSSOFTCAR = 0x541A;
497pub const FIONREAD = 0x541B;
498pub const TIOCINQ = FIONREAD;
499pub const TIOCLINUX = 0x541C;
500pub const TIOCCONS = 0x541D;
501pub const TIOCGSERIAL = 0x541E;
502pub const TIOCSSERIAL = 0x541F;
503pub const TIOCPKT = 0x5420;
504pub const FIONBIO = 0x5421;
505pub const TIOCNOTTY = 0x5422;
506pub const TIOCSETD = 0x5423;
507pub const TIOCGETD = 0x5424;
508pub const TCSBRKP = 0x5425;
509pub const TIOCSBRK = 0x5427;
510pub const TIOCCBRK = 0x5428;
511pub const TIOCGSID = 0x5429;
512pub const TIOCGRS485 = 0x542E;
513pub const TIOCSRS485 = 0x542F;
514pub const TIOCGPTN = 0x80045430;
515pub const TIOCSPTLCK = 0x40045431;
516pub const TIOCGDEV = 0x80045432;
517pub const TCGETX = 0x5432;
518pub const TCSETX = 0x5433;
519pub const TCSETXF = 0x5434;
520pub const TCSETXW = 0x5435;
521pub const TIOCSIG = 0x40045436;
522pub const TIOCVHANGUP = 0x5437;
523pub const TIOCGPKT = 0x80045438;
524pub const TIOCGPTLCK = 0x80045439;
525pub const TIOCGEXCL = 0x80045440;
526
527pub const sockaddr = c.sockaddr;
528pub const sockaddr_in = c.sockaddr_in;
529pub const sockaddr_in6 = c.sockaddr_in6;
530
531fn unsigned(s: i32) u32 {
532 return @bitCast(u32, s);
533}
534fn signed(s: u32) i32 {
535 return @bitCast(i32, s);
536}
537pub fn WEXITSTATUS(s: i32) i32 {
538 return signed((unsigned(s) & 0xff00) >> 8);
539}
540pub fn WTERMSIG(s: i32) i32 {
541 return signed(unsigned(s) & 0x7f);
542}
543pub fn WSTOPSIG(s: i32) i32 {
544 return WEXITSTATUS(s);
545}
546pub fn WIFEXITED(s: i32) bool {
547 return WTERMSIG(s) == 0;
548}
549pub fn WIFSTOPPED(s: i32) bool {
550 return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
551}
552pub fn WIFSIGNALED(s: i32) bool {
553 return (unsigned(s) & 0xffff) -% 1 < 0xff;
554}
555
556pub const winsize = extern struct {
557 ws_row: u16,
558 ws_col: u16,
559 ws_xpixel: u16,
560 ws_ypixel: u16,
561};
562
563/// Get the errno from a syscall return value, or 0 for no error.
564pub fn getErrno(r: usize) usize {
565 const signed_r = @bitCast(isize, r);
566 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
567}
568
569pub fn dup2(old: i32, new: i32) usize {
570 return errnoWrap(c.dup2(old, new));
571}
572
573pub fn chdir(path: [*]const u8) usize {
574 return errnoWrap(c.chdir(path));
575}
576
577pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
578 return errnoWrap(c.execve(path, argv, envp));
579}
580
581pub fn fork() usize {
582 return errnoWrap(c.fork());
583}
584
585pub fn access(path: [*]const u8, mode: u32) usize {
586 return errnoWrap(c.access(path, mode));
587}
588
589pub fn getcwd(buf: [*]u8, size: usize) usize {
590 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
591}
592
593pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
594 return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
595}
596
597pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
598 return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
599}
600
601pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
602 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
603}
604
605pub fn isatty(fd: i32) bool {
606 return c.isatty(fd) != 0;
607}
608
609pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
610 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
611}
612
613pub fn mkdir(path: [*]const u8, mode: u32) usize {
614 return errnoWrap(c.mkdir(path, mode));
615}
616
617pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
618 const ptr_result = c.mmap(
619 @ptrCast(?*c_void, address),
620 length,
621 @bitCast(c_int, @intCast(c_uint, prot)),
622 @bitCast(c_int, c_uint(flags)),
623 fd,
624 offset,
625 );
626 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
627 return errnoWrap(isize_result);
628}
629
630pub fn munmap(address: usize, length: usize) usize {
631 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
632}
633
634pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
635 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
636}
637
638pub fn rmdir(path: [*]const u8) usize {
639 return errnoWrap(c.rmdir(path));
640}
641
642pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
643 return errnoWrap(c.symlink(existing, new));
644}
645
646pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
647 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
648}
649
650pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
651 return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
652}
653
654pub fn pipe(fd: *[2]i32) usize {
655 return pipe2(fd, 0);
656}
657
658pub fn pipe2(fd: *[2]i32, flags: u32) usize {
659 comptime assert(i32.bit_count == c_int.bit_count);
660 return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
661}
662
663pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
664 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
665}
666
667pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
668 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
669}
670
671pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
672 return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
673}
674
675pub fn rename(old: [*]const u8, new: [*]const u8) usize {
676 return errnoWrap(c.rename(old, new));
677}
678
679pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
680 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
681}
682
683pub fn create(path: [*]const u8, perm: usize) usize {
684 return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
685}
686
687pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
688 return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
689}
690
691pub fn close(fd: i32) usize {
692 return errnoWrap(c.close(fd));
693}
694
695pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
696 return errnoWrap(c.lseek(fd, offset, whence));
697}
698
699pub fn exit(code: i32) noreturn {
700 c.exit(code);
701}
702
703pub fn kill(pid: i32, sig: i32) usize {
704 return errnoWrap(c.kill(pid, sig));
705}
706
707pub fn unlink(path: [*]const u8) usize {
708 return errnoWrap(c.unlink(path));
709}
710
711pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
712 comptime assert(i32.bit_count == c_int.bit_count);
713 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
714}
715
716pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
717 return errnoWrap(c.nanosleep(req, rem));
718}
719
720pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
721 return errnoWrap(c.clock_gettime(clk_id, tp));
722}
723
724pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
725 return errnoWrap(c.clock_getres(clk_id, tp));
726}
727
728pub fn setuid(uid: u32) usize {
729 return errnoWrap(c.setuid(uid));
730}
731
732pub fn setgid(gid: u32) usize {
733 return errnoWrap(c.setgid(gid));
734}
735
736pub fn setreuid(ruid: u32, euid: u32) usize {
737 return errnoWrap(c.setreuid(ruid, euid));
738}
739
740pub fn setregid(rgid: u32, egid: u32) usize {
741 return errnoWrap(c.setregid(rgid, egid));
742}
743
744const NSIG = 32;
745
746pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
747pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
748pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
749
750/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
751pub const Sigaction = extern struct {
752 /// signal handler
753 __sigaction_u: extern union {
754 __sa_handler: extern fn (i32) void,
755 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
756 },
757
758 /// see signal options
759 sa_flags: u32,
760
761 /// signal mask to apply
762 sa_mask: sigset_t,
763};
764
765pub const _SIG_WORDS = 4;
766pub const _SIG_MAXSIG = 128;
767
768pub inline fn _SIG_IDX(sig: usize) usize {
769 return sig - 1;
770}
771pub inline fn _SIG_WORD(sig: usize) usize {
772 return_SIG_IDX(sig) >> 5;
773}
774pub inline fn _SIG_BIT(sig: usize) usize {
775 return 1 << (_SIG_IDX(sig) & 31);
776}
777pub inline fn _SIG_VALID(sig: usize) usize {
778 return sig <= _SIG_MAXSIG and sig > 0;
779}
780
781pub const sigset_t = extern struct {
782 __bits: [_SIG_WORDS]u32,
783};
784
785pub fn raise(sig: i32) usize {
786 return errnoWrap(c.raise(sig));
787}
788
789pub const Stat = c.Stat;
790pub const dirent = c.dirent;
791pub const timespec = c.timespec;
792
793pub fn fstat(fd: i32, buf: *c.Stat) usize {
794 return errnoWrap(c.fstat(fd, buf));
795}
796pub const iovec = extern struct {
797 iov_base: [*]u8,
798 iov_len: usize,
799};
800
801pub const iovec_const = extern struct {
802 iov_base: [*]const u8,
803 iov_len: usize,
804};
805
806// TODO avoid libc dependency
807pub fn kqueue() usize {
808 return errnoWrap(c.kqueue());
809}
810
811// TODO avoid libc dependency
812pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
813 return errnoWrap(c.kevent(
814 kq,
815 changelist.ptr,
816 @intCast(c_int, changelist.len),
817 eventlist.ptr,
818 @intCast(c_int, eventlist.len),
819 timeout,
820 ));
821}
822
823// TODO avoid libc dependency
824pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
825 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
826}
827
828// TODO avoid libc dependency
829pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
830 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
831}
832
833// TODO avoid libc dependency
834pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
835 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
836}
837
838// TODO avoid libc dependency
839
840/// Takes the return value from a syscall and formats it back in the way
841/// that the kernel represents it to libc. Errno was a mistake, let's make
842/// it go away forever.
843fn errnoWrap(value: isize) usize {
844 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
845}
std/os/freebsd/index.zig deleted-846
...@@ -1,846 +0,0 @@
1const builtin = @import("builtin");
2
3pub use @import("errno.zig");
4
5const std = @import("../../index.zig");
6const c = std.c;
7
8const assert = std.debug.assert;
9const maxInt = std.math.maxInt;
10pub const Kevent = c.Kevent;
11
12pub const CTL_KERN = 1;
13pub const CTL_DEBUG = 5;
14
15pub const KERN_PROC = 14; // struct: process entries
16pub const KERN_PROC_PATHNAME = 12; // path to executable
17
18pub const PATH_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const PROT_NONE = 0;
25pub const PROT_READ = 1;
26pub const PROT_WRITE = 2;
27pub const PROT_EXEC = 4;
28
29pub const CLOCK_REALTIME = 0;
30pub const CLOCK_VIRTUAL = 1;
31pub const CLOCK_PROF = 2;
32pub const CLOCK_MONOTONIC = 4;
33pub const CLOCK_UPTIME = 5;
34pub const CLOCK_UPTIME_PRECISE = 7;
35pub const CLOCK_UPTIME_FAST = 8;
36pub const CLOCK_REALTIME_PRECISE = 9;
37pub const CLOCK_REALTIME_FAST = 10;
38pub const CLOCK_MONOTONIC_PRECISE = 11;
39pub const CLOCK_MONOTONIC_FAST = 12;
40pub const CLOCK_SECOND = 13;
41pub const CLOCK_THREAD_CPUTIME_ID = 14;
42pub const CLOCK_PROCESS_CPUTIME_ID = 15;
43
44pub const MAP_FAILED = maxInt(usize);
45pub const MAP_SHARED = 0x0001;
46pub const MAP_PRIVATE = 0x0002;
47pub const MAP_FIXED = 0x0010;
48pub const MAP_STACK = 0x0400;
49pub const MAP_NOSYNC = 0x0800;
50pub const MAP_ANON = 0x1000;
51pub const MAP_ANONYMOUS = MAP_ANON;
52pub const MAP_FILE = 0;
53pub const MAP_NORESERVE = 0;
54
55pub const MAP_GUARD = 0x00002000;
56pub const MAP_EXCL = 0x00004000;
57pub const MAP_NOCORE = 0x00020000;
58pub const MAP_PREFAULT_READ = 0x00040000;
59pub const MAP_32BIT = 0x00080000;
60
61pub const WNOHANG = 1;
62pub const WUNTRACED = 2;
63pub const WSTOPPED = WUNTRACED;
64pub const WCONTINUED = 4;
65pub const WNOWAIT = 8;
66pub const WEXITED = 16;
67pub const WTRAPPED = 32;
68
69pub const SA_ONSTACK = 0x0001;
70pub const SA_RESTART = 0x0002;
71pub const SA_RESETHAND = 0x0004;
72pub const SA_NOCLDSTOP = 0x0008;
73pub const SA_NODEFER = 0x0010;
74pub const SA_NOCLDWAIT = 0x0020;
75pub const SA_SIGINFO = 0x0040;
76
77pub const SIGHUP = 1;
78pub const SIGINT = 2;
79pub const SIGQUIT = 3;
80pub const SIGILL = 4;
81pub const SIGTRAP = 5;
82pub const SIGABRT = 6;
83pub const SIGIOT = SIGABRT;
84pub const SIGEMT = 7;
85pub const SIGFPE = 8;
86pub const SIGKILL = 9;
87pub const SIGBUS = 10;
88pub const SIGSEGV = 11;
89pub const SIGSYS = 12;
90pub const SIGPIPE = 13;
91pub const SIGALRM = 14;
92pub const SIGTERM = 15;
93pub const SIGURG = 16;
94pub const SIGSTOP = 17;
95pub const SIGTSTP = 18;
96pub const SIGCONT = 19;
97pub const SIGCHLD = 20;
98pub const SIGTTIN = 21;
99pub const SIGTTOU = 22;
100pub const SIGIO = 23;
101pub const SIGXCPU = 24;
102pub const SIGXFSZ = 25;
103pub const SIGVTALRM = 26;
104pub const SIGPROF = 27;
105pub const SIGWINCH = 28;
106pub const SIGINFO = 29;
107pub const SIGUSR1 = 30;
108pub const SIGUSR2 = 31;
109pub const SIGTHR = 32;
110pub const SIGLWP = SIGTHR;
111pub const SIGLIBRT = 33;
112
113pub const SIGRTMIN = 65;
114pub const SIGRTMAX = 126;
115
116// access function
117pub const F_OK = 0; // test for existence of file
118pub const X_OK = 1; // test for execute or search permission
119pub const W_OK = 2; // test for write permission
120pub const R_OK = 4; // test for read permission
121
122
123pub const O_RDONLY = 0x0000;
124pub const O_WRONLY = 0x0001;
125pub const O_RDWR = 0x0002;
126pub const O_ACCMODE = 0x0003;
127
128pub const O_CREAT = 0x0200;
129pub const O_EXCL = 0x0800;
130pub const O_NOCTTY = 0x8000;
131pub const O_TRUNC = 0x0400;
132pub const O_APPEND = 0x0008;
133pub const O_NONBLOCK = 0x0004;
134pub const O_DSYNC = 0o10000;
135pub const O_SYNC = 0x0080;
136pub const O_RSYNC = 0o4010000;
137pub const O_DIRECTORY = 0o200000;
138pub const O_NOFOLLOW = 0x0100;
139pub const O_CLOEXEC = 0x00100000;
140
141pub const O_ASYNC = 0x0040;
142pub const O_DIRECT = 0x00010000;
143pub const O_LARGEFILE = 0;
144pub const O_NOATIME = 0o1000000;
145pub const O_PATH = 0o10000000;
146pub const O_TMPFILE = 0o20200000;
147pub const O_NDELAY = O_NONBLOCK;
148
149pub const F_DUPFD = 0;
150pub const F_GETFD = 1;
151pub const F_SETFD = 2;
152pub const F_GETFL = 3;
153pub const F_SETFL = 4;
154
155pub const F_SETOWN = 8;
156pub const F_GETOWN = 9;
157pub const F_SETSIG = 10;
158pub const F_GETSIG = 11;
159
160pub const F_GETLK = 5;
161pub const F_SETLK = 6;
162pub const F_SETLKW = 7;
163
164pub const F_SETOWN_EX = 15;
165pub const F_GETOWN_EX = 16;
166
167pub const F_GETOWNER_UIDS = 17;
168
169pub const SEEK_SET = 0;
170pub const SEEK_CUR = 1;
171pub const SEEK_END = 2;
172
173pub const SIG_BLOCK = 1;
174pub const SIG_UNBLOCK = 2;
175pub const SIG_SETMASK = 3;
176
177pub const SOCK_STREAM = 1;
178pub const SOCK_DGRAM = 2;
179pub const SOCK_RAW = 3;
180pub const SOCK_RDM = 4;
181pub const SOCK_SEQPACKET = 5;
182
183pub const SOCK_CLOEXEC = 0x10000000;
184pub const SOCK_NONBLOCK = 0x20000000;
185
186pub const PROTO_ip = 0o000;
187pub const PROTO_icmp = 0o001;
188pub const PROTO_igmp = 0o002;
189pub const PROTO_ggp = 0o003;
190pub const PROTO_ipencap = 0o004;
191pub const PROTO_st = 0o005;
192pub const PROTO_tcp = 0o006;
193pub const PROTO_egp = 0o010;
194pub const PROTO_pup = 0o014;
195pub const PROTO_udp = 0o021;
196pub const PROTO_hmp = 0o024;
197pub const PROTO_xns_idp = 0o026;
198pub const PROTO_rdp = 0o033;
199pub const PROTO_iso_tp4 = 0o035;
200pub const PROTO_xtp = 0o044;
201pub const PROTO_ddp = 0o045;
202pub const PROTO_idpr_cmtp = 0o046;
203pub const PROTO_ipv6 = 0o051;
204pub const PROTO_ipv6_route = 0o053;
205pub const PROTO_ipv6_frag = 0o054;
206pub const PROTO_idrp = 0o055;
207pub const PROTO_rsvp = 0o056;
208pub const PROTO_gre = 0o057;
209pub const PROTO_esp = 0o062;
210pub const PROTO_ah = 0o063;
211pub const PROTO_skip = 0o071;
212pub const PROTO_ipv6_icmp = 0o072;
213pub const PROTO_ipv6_nonxt = 0o073;
214pub const PROTO_ipv6_opts = 0o074;
215pub const PROTO_rspf = 0o111;
216pub const PROTO_vmtp = 0o121;
217pub const PROTO_ospf = 0o131;
218pub const PROTO_ipip = 0o136;
219pub const PROTO_encap = 0o142;
220pub const PROTO_pim = 0o147;
221pub const PROTO_raw = 0o377;
222
223pub const PF_UNSPEC = 0;
224pub const PF_LOCAL = 1;
225pub const PF_UNIX = PF_LOCAL;
226pub const PF_FILE = PF_LOCAL;
227pub const PF_INET = 2;
228pub const PF_AX25 = 3;
229pub const PF_IPX = 4;
230pub const PF_APPLETALK = 5;
231pub const PF_NETROM = 6;
232pub const PF_BRIDGE = 7;
233pub const PF_ATMPVC = 8;
234pub const PF_X25 = 9;
235pub const PF_INET6 = 10;
236pub const PF_ROSE = 11;
237pub const PF_DECnet = 12;
238pub const PF_NETBEUI = 13;
239pub const PF_SECURITY = 14;
240pub const PF_KEY = 15;
241pub const PF_NETLINK = 16;
242pub const PF_ROUTE = PF_NETLINK;
243pub const PF_PACKET = 17;
244pub const PF_ASH = 18;
245pub const PF_ECONET = 19;
246pub const PF_ATMSVC = 20;
247pub const PF_RDS = 21;
248pub const PF_SNA = 22;
249pub const PF_IRDA = 23;
250pub const PF_PPPOX = 24;
251pub const PF_WANPIPE = 25;
252pub const PF_LLC = 26;
253pub const PF_IB = 27;
254pub const PF_MPLS = 28;
255pub const PF_CAN = 29;
256pub const PF_TIPC = 30;
257pub const PF_BLUETOOTH = 31;
258pub const PF_IUCV = 32;
259pub const PF_RXRPC = 33;
260pub const PF_ISDN = 34;
261pub const PF_PHONET = 35;
262pub const PF_IEEE802154 = 36;
263pub const PF_CAIF = 37;
264pub const PF_ALG = 38;
265pub const PF_NFC = 39;
266pub const PF_VSOCK = 40;
267pub const PF_MAX = 41;
268
269pub const AF_UNSPEC = PF_UNSPEC;
270pub const AF_LOCAL = PF_LOCAL;
271pub const AF_UNIX = AF_LOCAL;
272pub const AF_FILE = AF_LOCAL;
273pub const AF_INET = PF_INET;
274pub const AF_AX25 = PF_AX25;
275pub const AF_IPX = PF_IPX;
276pub const AF_APPLETALK = PF_APPLETALK;
277pub const AF_NETROM = PF_NETROM;
278pub const AF_BRIDGE = PF_BRIDGE;
279pub const AF_ATMPVC = PF_ATMPVC;
280pub const AF_X25 = PF_X25;
281pub const AF_INET6 = PF_INET6;
282pub const AF_ROSE = PF_ROSE;
283pub const AF_DECnet = PF_DECnet;
284pub const AF_NETBEUI = PF_NETBEUI;
285pub const AF_SECURITY = PF_SECURITY;
286pub const AF_KEY = PF_KEY;
287pub const AF_NETLINK = PF_NETLINK;
288pub const AF_ROUTE = PF_ROUTE;
289pub const AF_PACKET = PF_PACKET;
290pub const AF_ASH = PF_ASH;
291pub const AF_ECONET = PF_ECONET;
292pub const AF_ATMSVC = PF_ATMSVC;
293pub const AF_RDS = PF_RDS;
294pub const AF_SNA = PF_SNA;
295pub const AF_IRDA = PF_IRDA;
296pub const AF_PPPOX = PF_PPPOX;
297pub const AF_WANPIPE = PF_WANPIPE;
298pub const AF_LLC = PF_LLC;
299pub const AF_IB = PF_IB;
300pub const AF_MPLS = PF_MPLS;
301pub const AF_CAN = PF_CAN;
302pub const AF_TIPC = PF_TIPC;
303pub const AF_BLUETOOTH = PF_BLUETOOTH;
304pub const AF_IUCV = PF_IUCV;
305pub const AF_RXRPC = PF_RXRPC;
306pub const AF_ISDN = PF_ISDN;
307pub const AF_PHONET = PF_PHONET;
308pub const AF_IEEE802154 = PF_IEEE802154;
309pub const AF_CAIF = PF_CAIF;
310pub const AF_ALG = PF_ALG;
311pub const AF_NFC = PF_NFC;
312pub const AF_VSOCK = PF_VSOCK;
313pub const AF_MAX = PF_MAX;
314
315pub const DT_UNKNOWN = 0;
316pub const DT_FIFO = 1;
317pub const DT_CHR = 2;
318pub const DT_DIR = 4;
319pub const DT_BLK = 6;
320pub const DT_REG = 8;
321pub const DT_LNK = 10;
322pub const DT_SOCK = 12;
323pub const DT_WHT = 14;
324
325/// add event to kq (implies enable)
326pub const EV_ADD = 0x0001;
327
328/// delete event from kq
329pub const EV_DELETE = 0x0002;
330
331/// enable event
332pub const EV_ENABLE = 0x0004;
333
334/// disable event (not reported)
335pub const EV_DISABLE = 0x0008;
336
337/// only report one occurrence
338pub const EV_ONESHOT = 0x0010;
339
340/// clear event state after reporting
341pub const EV_CLEAR = 0x0020;
342
343/// force immediate event output
344/// ... with or without EV_ERROR
345/// ... use KEVENT_FLAG_ERROR_EVENTS
346/// on syscalls supporting flags
347pub const EV_RECEIPT = 0x0040;
348
349/// disable event after reporting
350pub const EV_DISPATCH = 0x0080;
351
352pub const EVFILT_READ = -1;
353pub const EVFILT_WRITE = -2;
354
355/// attached to aio requests
356pub const EVFILT_AIO = -3;
357
358/// attached to vnodes
359pub const EVFILT_VNODE = -4;
360
361/// attached to struct proc
362pub const EVFILT_PROC = -5;
363
364/// attached to struct proc
365pub const EVFILT_SIGNAL = -6;
366
367/// timers
368pub const EVFILT_TIMER = -7;
369
370/// Process descriptors
371pub const EVFILT_PROCDESC = -8;
372
373/// Filesystem events
374pub const EVFILT_FS = -9;
375
376pub const EVFILT_LIO = -10;
377
378/// User events
379pub const EVFILT_USER = -11;
380
381/// Sendfile events
382pub const EVFILT_SENDFILE = -12;
383
384pub const EVFILT_EMPTY = -13;
385
386/// On input, NOTE_TRIGGER causes the event to be triggered for output.
387pub const NOTE_TRIGGER = 0x01000000;
388
389/// ignore input fflags
390pub const NOTE_FFNOP = 0x00000000;
391
392/// and fflags
393pub const NOTE_FFAND = 0x40000000;
394
395/// or fflags
396pub const NOTE_FFOR = 0x80000000;
397
398/// copy fflags
399pub const NOTE_FFCOPY = 0xc0000000;
400
401/// mask for operations
402pub const NOTE_FFCTRLMASK = 0xc0000000;
403pub const NOTE_FFLAGSMASK = 0x00ffffff;
404
405/// low water mark
406pub const NOTE_LOWAT = 0x00000001;
407
408/// behave like poll()
409pub const NOTE_FILE_POLL = 0x00000002;
410
411/// vnode was removed
412pub const NOTE_DELETE = 0x00000001;
413
414/// data contents changed
415pub const NOTE_WRITE = 0x00000002;
416
417/// size increased
418pub const NOTE_EXTEND = 0x00000004;
419
420/// attributes changed
421pub const NOTE_ATTRIB = 0x00000008;
422
423/// link count changed
424pub const NOTE_LINK = 0x00000010;
425
426/// vnode was renamed
427pub const NOTE_RENAME = 0x00000020;
428
429/// vnode access was revoked
430pub const NOTE_REVOKE = 0x00000040;
431
432/// vnode was opened
433pub const NOTE_OPEN = 0x00000080;
434
435/// file closed, fd did not allow write
436pub const NOTE_CLOSE = 0x00000100;
437
438/// file closed, fd did allow write
439pub const NOTE_CLOSE_WRITE = 0x00000200;
440
441/// file was read
442pub const NOTE_READ = 0x00000400;
443
444/// process exited
445pub const NOTE_EXIT = 0x80000000;
446
447/// process forked
448pub const NOTE_FORK = 0x40000000;
449
450/// process exec'd
451pub const NOTE_EXEC = 0x20000000;
452
453/// mask for signal & exit status
454pub const NOTE_PDATAMASK = 0x000fffff;
455pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
456
457/// data is seconds
458pub const NOTE_SECONDS = 0x00000001;
459
460/// data is milliseconds
461pub const NOTE_MSECONDS = 0x00000002;
462
463/// data is microseconds
464pub const NOTE_USECONDS = 0x00000004;
465
466/// data is nanoseconds
467pub const NOTE_NSECONDS = 0x00000008;
468
469/// timeout is absolute
470pub const NOTE_ABSTIME = 0x00000010;
471
472pub const TCGETS = 0x5401;
473pub const TCSETS = 0x5402;
474pub const TCSETSW = 0x5403;
475pub const TCSETSF = 0x5404;
476pub const TCGETA = 0x5405;
477pub const TCSETA = 0x5406;
478pub const TCSETAW = 0x5407;
479pub const TCSETAF = 0x5408;
480pub const TCSBRK = 0x5409;
481pub const TCXONC = 0x540A;
482pub const TCFLSH = 0x540B;
483pub const TIOCEXCL = 0x540C;
484pub const TIOCNXCL = 0x540D;
485pub const TIOCSCTTY = 0x540E;
486pub const TIOCGPGRP = 0x540F;
487pub const TIOCSPGRP = 0x5410;
488pub const TIOCOUTQ = 0x5411;
489pub const TIOCSTI = 0x5412;
490pub const TIOCGWINSZ = 0x5413;
491pub const TIOCSWINSZ = 0x5414;
492pub const TIOCMGET = 0x5415;
493pub const TIOCMBIS = 0x5416;
494pub const TIOCMBIC = 0x5417;
495pub const TIOCMSET = 0x5418;
496pub const TIOCGSOFTCAR = 0x5419;
497pub const TIOCSSOFTCAR = 0x541A;
498pub const FIONREAD = 0x541B;
499pub const TIOCINQ = FIONREAD;
500pub const TIOCLINUX = 0x541C;
501pub const TIOCCONS = 0x541D;
502pub const TIOCGSERIAL = 0x541E;
503pub const TIOCSSERIAL = 0x541F;
504pub const TIOCPKT = 0x5420;
505pub const FIONBIO = 0x5421;
506pub const TIOCNOTTY = 0x5422;
507pub const TIOCSETD = 0x5423;
508pub const TIOCGETD = 0x5424;
509pub const TCSBRKP = 0x5425;
510pub const TIOCSBRK = 0x5427;
511pub const TIOCCBRK = 0x5428;
512pub const TIOCGSID = 0x5429;
513pub const TIOCGRS485 = 0x542E;
514pub const TIOCSRS485 = 0x542F;
515pub const TIOCGPTN = 0x80045430;
516pub const TIOCSPTLCK = 0x40045431;
517pub const TIOCGDEV = 0x80045432;
518pub const TCGETX = 0x5432;
519pub const TCSETX = 0x5433;
520pub const TCSETXF = 0x5434;
521pub const TCSETXW = 0x5435;
522pub const TIOCSIG = 0x40045436;
523pub const TIOCVHANGUP = 0x5437;
524pub const TIOCGPKT = 0x80045438;
525pub const TIOCGPTLCK = 0x80045439;
526pub const TIOCGEXCL = 0x80045440;
527
528pub const sockaddr = c.sockaddr;
529pub const sockaddr_in = c.sockaddr_in;
530pub const sockaddr_in6 = c.sockaddr_in6;
531
532fn unsigned(s: i32) u32 {
533 return @bitCast(u32, s);
534}
535fn signed(s: u32) i32 {
536 return @bitCast(i32, s);
537}
538pub fn WEXITSTATUS(s: i32) i32 {
539 return signed((unsigned(s) & 0xff00) >> 8);
540}
541pub fn WTERMSIG(s: i32) i32 {
542 return signed(unsigned(s) & 0x7f);
543}
544pub fn WSTOPSIG(s: i32) i32 {
545 return WEXITSTATUS(s);
546}
547pub fn WIFEXITED(s: i32) bool {
548 return WTERMSIG(s) == 0;
549}
550pub fn WIFSTOPPED(s: i32) bool {
551 return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
552}
553pub fn WIFSIGNALED(s: i32) bool {
554 return (unsigned(s) & 0xffff) -% 1 < 0xff;
555}
556
557pub const winsize = extern struct {
558 ws_row: u16,
559 ws_col: u16,
560 ws_xpixel: u16,
561 ws_ypixel: u16,
562};
563
564/// Get the errno from a syscall return value, or 0 for no error.
565pub fn getErrno(r: usize) usize {
566 const signed_r = @bitCast(isize, r);
567 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
568}
569
570pub fn dup2(old: i32, new: i32) usize {
571 return errnoWrap(c.dup2(old, new));
572}
573
574pub fn chdir(path: [*]const u8) usize {
575 return errnoWrap(c.chdir(path));
576}
577
578pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
579 return errnoWrap(c.execve(path, argv, envp));
580}
581
582pub fn fork() usize {
583 return errnoWrap(c.fork());
584}
585
586pub fn access(path: [*]const u8, mode: u32) usize {
587 return errnoWrap(c.access(path, mode));
588}
589
590pub fn getcwd(buf: [*]u8, size: usize) usize {
591 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
592}
593
594pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
595 return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
596}
597
598pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
599 return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
600}
601
602pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
603 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
604}
605
606pub fn isatty(fd: i32) bool {
607 return c.isatty(fd) != 0;
608}
609
610pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
611 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
612}
613
614pub fn mkdir(path: [*]const u8, mode: u32) usize {
615 return errnoWrap(c.mkdir(path, mode));
616}
617
618pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
619 const ptr_result = c.mmap(
620 @ptrCast(?*c_void, address),
621 length,
622 @bitCast(c_int, @intCast(c_uint, prot)),
623 @bitCast(c_int, c_uint(flags)),
624 fd,
625 offset,
626 );
627 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
628 return errnoWrap(isize_result);
629}
630
631pub fn munmap(address: usize, length: usize) usize {
632 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
633}
634
635pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
636 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
637}
638
639pub fn rmdir(path: [*]const u8) usize {
640 return errnoWrap(c.rmdir(path));
641}
642
643pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
644 return errnoWrap(c.symlink(existing, new));
645}
646
647pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
648 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
649}
650
651pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
652 return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
653}
654
655pub fn pipe(fd: *[2]i32) usize {
656 return pipe2(fd, 0);
657}
658
659pub fn pipe2(fd: *[2]i32, flags: u32) usize {
660 comptime assert(i32.bit_count == c_int.bit_count);
661 return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
662}
663
664pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
665 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
666}
667
668pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
669 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
670}
671
672pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
673 return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
674}
675
676pub fn rename(old: [*]const u8, new: [*]const u8) usize {
677 return errnoWrap(c.rename(old, new));
678}
679
680pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
681 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
682}
683
684pub fn create(path: [*]const u8, perm: usize) usize {
685 return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
686}
687
688pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
689 return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
690}
691
692pub fn close(fd: i32) usize {
693 return errnoWrap(c.close(fd));
694}
695
696pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
697 return errnoWrap(c.lseek(fd, offset, whence));
698}
699
700pub fn exit(code: i32) noreturn {
701 c.exit(code);
702}
703
704pub fn kill(pid: i32, sig: i32) usize {
705 return errnoWrap(c.kill(pid, sig));
706}
707
708pub fn unlink(path: [*]const u8) usize {
709 return errnoWrap(c.unlink(path));
710}
711
712pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
713 comptime assert(i32.bit_count == c_int.bit_count);
714 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
715}
716
717pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
718 return errnoWrap(c.nanosleep(req, rem));
719}
720
721pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
722 return errnoWrap(c.clock_gettime(clk_id, tp));
723}
724
725pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
726 return errnoWrap(c.clock_getres(clk_id, tp));
727}
728
729pub fn setuid(uid: u32) usize {
730 return errnoWrap(c.setuid(uid));
731}
732
733pub fn setgid(gid: u32) usize {
734 return errnoWrap(c.setgid(gid));
735}
736
737pub fn setreuid(ruid: u32, euid: u32) usize {
738 return errnoWrap(c.setreuid(ruid, euid));
739}
740
741pub fn setregid(rgid: u32, egid: u32) usize {
742 return errnoWrap(c.setregid(rgid, egid));
743}
744
745const NSIG = 32;
746
747pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
748pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
749pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
750
751/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
752pub const Sigaction = extern struct {
753 /// signal handler
754 __sigaction_u: extern union {
755 __sa_handler: extern fn (i32) void,
756 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
757 },
758
759 /// see signal options
760 sa_flags: u32,
761
762 /// signal mask to apply
763 sa_mask: sigset_t,
764};
765
766pub const _SIG_WORDS = 4;
767pub const _SIG_MAXSIG = 128;
768
769pub inline fn _SIG_IDX(sig: usize) usize {
770 return sig - 1;
771}
772pub inline fn _SIG_WORD(sig: usize) usize {
773 return_SIG_IDX(sig) >> 5;
774}
775pub inline fn _SIG_BIT(sig: usize) usize {
776 return 1 << (_SIG_IDX(sig) & 31);
777}
778pub inline fn _SIG_VALID(sig: usize) usize {
779 return sig <= _SIG_MAXSIG and sig > 0;
780}
781
782pub const sigset_t = extern struct {
783 __bits: [_SIG_WORDS]u32,
784};
785
786pub fn raise(sig: i32) usize {
787 return errnoWrap(c.raise(sig));
788}
789
790pub const Stat = c.Stat;
791pub const dirent = c.dirent;
792pub const timespec = c.timespec;
793
794pub fn fstat(fd: i32, buf: *c.Stat) usize {
795 return errnoWrap(c.fstat(fd, buf));
796}
797pub const iovec = extern struct {
798 iov_base: [*]u8,
799 iov_len: usize,
800};
801
802pub const iovec_const = extern struct {
803 iov_base: [*]const u8,
804 iov_len: usize,
805};
806
807// TODO avoid libc dependency
808pub fn kqueue() usize {
809 return errnoWrap(c.kqueue());
810}
811
812// TODO avoid libc dependency
813pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
814 return errnoWrap(c.kevent(
815 kq,
816 changelist.ptr,
817 @intCast(c_int, changelist.len),
818 eventlist.ptr,
819 @intCast(c_int, eventlist.len),
820 timeout,
821 ));
822}
823
824// TODO avoid libc dependency
825pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
826 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
827}
828
829// TODO avoid libc dependency
830pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
831 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
832}
833
834// TODO avoid libc dependency
835pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
836 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
837}
838
839// TODO avoid libc dependency
840
841/// Takes the return value from a syscall and formats it back in the way
842/// that the kernel represents it to libc. Errno was a mistake, let's make
843/// it go away forever.
844fn errnoWrap(value: isize) usize {
845 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
846}
std/os/get_app_data_dir.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const unicode = std.unicode;3const unicode = std.unicode;
4const mem = std.mem;4const mem = std.mem;
std/os/get_user_id.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const Os = builtin.Os;2const Os = builtin.Os;
3const os = @import("index.zig");3const os = @import("../os.zig");
4const io = @import("../io.zig");4const io = @import("../io.zig");
55
6pub const UserInfo = struct {6pub const UserInfo = struct {
std/os/index.zig deleted-3408
...@@ -1,3408 +0,0 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;
5const is_posix = switch (builtin.os) {
6 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
7 else => false,
8};
9const os = @This();
10
11comptime {
12 assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir
13}
14
15test "std.os" {
16 _ = @import("child_process.zig");
17 _ = @import("darwin.zig");
18 _ = @import("darwin/errno.zig");
19 _ = @import("get_user_id.zig");
20 _ = @import("linux/index.zig");
21 _ = @import("path.zig");
22 _ = @import("test.zig");
23 _ = @import("time.zig");
24 _ = @import("windows/index.zig");
25 _ = @import("uefi.zig");
26 _ = @import("get_app_data_dir.zig");
27}
28
29pub const windows = @import("windows/index.zig");
30pub const darwin = @import("darwin.zig");
31pub const linux = @import("linux/index.zig");
32pub const freebsd = @import("freebsd/index.zig");
33pub const netbsd = @import("netbsd/index.zig");
34pub const zen = @import("zen.zig");
35pub const uefi = @import("uefi.zig");
36
37pub const posix = switch (builtin.os) {
38 Os.linux => linux,
39 Os.macosx, Os.ios => darwin,
40 Os.freebsd => freebsd,
41 Os.netbsd => netbsd,
42 Os.zen => zen,
43 else => @compileError("Unsupported OS"),
44};
45
46pub const net = @import("net.zig");
47
48pub const ChildProcess = @import("child_process.zig").ChildProcess;
49pub const path = @import("path.zig");
50pub const File = @import("file.zig").File;
51pub const time = @import("time.zig");
52
53pub const page_size = 4 * 1024;
54pub const MAX_PATH_BYTES = switch (builtin.os) {
55 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
56 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
57 // If it would require 4 UTF-8 bytes, then there would be a surrogate
58 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
59 // +1 for the null byte at the end, which can be encoded in 1 byte.
60 Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
61 else => @compileError("Unsupported OS"),
62};
63
64pub const UserInfo = @import("get_user_id.zig").UserInfo;
65pub const getUserInfo = @import("get_user_id.zig").getUserInfo;
66
67const windows_util = @import("windows/util.zig");
68pub const windowsWaitSingle = windows_util.windowsWaitSingle;
69pub const windowsWrite = windows_util.windowsWrite;
70pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
71pub const windowsOpen = windows_util.windowsOpen;
72pub const windowsOpenW = windows_util.windowsOpenW;
73pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
74
75pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;
76pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;
77
78pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;
79pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;
80
81pub const WindowsWaitResult = windows_util.WindowsWaitResult;
82pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;
83
84pub const WindowsWaitError = windows_util.WaitError;
85pub const WindowsOpenError = windows_util.OpenError;
86pub const WindowsWriteError = windows_util.WriteError;
87pub const WindowsReadError = windows_util.ReadError;
88
89pub const FileHandle = if (is_windows) windows.HANDLE else i32;
90
91pub const getAppDataDir = @import("get_app_data_dir.zig").getAppDataDir;
92pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirError;
93
94const debug = std.debug;
95const assert = debug.assert;
96const testing = std.testing;
97
98const c = std.c;
99
100const mem = std.mem;
101const Allocator = mem.Allocator;
102
103const BufMap = std.BufMap;
104const cstr = std.cstr;
105
106const io = std.io;
107const base64 = std.base64;
108const ArrayList = std.ArrayList;
109const Buffer = std.Buffer;
110const math = std.math;
111
112/// Fills `buf` with random bytes. If linking against libc, this calls the
113/// appropriate OS-specific library call. Otherwise it uses the zig standard
114/// library implementation.
115pub fn getRandomBytes(buf: []u8) !void {
116 switch (builtin.os) {
117 Os.linux => while (true) {
118 // TODO check libc version and potentially call c.getrandom.
119 // See #397
120 const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
121 switch (errno) {
122 0 => return,
123 posix.EINVAL => unreachable,
124 posix.EFAULT => unreachable,
125 posix.EINTR => continue,
126 posix.ENOSYS => return getRandomBytesDevURandom(buf),
127 else => return unexpectedErrorPosix(errno),
128 }
129 },
130 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
131 Os.windows => {
132 // Call RtlGenRandom() instead of CryptGetRandom() on Windows
133 // https://github.com/rust-lang-nursery/rand/issues/111
134 // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
135 if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
136 const err = windows.GetLastError();
137 return switch (err) {
138 else => unexpectedErrorWindows(err),
139 };
140 }
141 },
142 Os.zen => {
143 const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
144 var i: usize = 0;
145 while (i < buf.len) : (i += 1) {
146 if (i > randomness.len) return error.Unknown;
147 buf[i] = randomness[i];
148 }
149 },
150 else => @compileError("Unsupported OS"),
151 }
152}
153
154fn getRandomBytesDevURandom(buf: []u8) !void {
155 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
156 defer close(fd);
157
158 const stream = &File.openHandle(fd).inStream().stream;
159 stream.readNoEof(buf) catch |err| switch (err) {
160 error.EndOfStream => unreachable,
161 error.OperationAborted => unreachable,
162 error.BrokenPipe => unreachable,
163 error.Unexpected => return error.Unexpected,
164 error.InputOutput => return error.Unexpected,
165 error.SystemResources => return error.Unexpected,
166 error.IsDir => unreachable,
167 };
168}
169
170test "os.getRandomBytes" {
171 var buf_a: [50]u8 = undefined;
172 var buf_b: [50]u8 = undefined;
173 // Call Twice
174 try getRandomBytes(buf_a[0..]);
175 try getRandomBytes(buf_b[0..]);
176
177 // Check if random (not 100% conclusive)
178 testing.expect(!mem.eql(u8, buf_a, buf_b));
179}
180
181/// Raises a signal in the current kernel thread, ending its execution.
182/// If linking against libc, this calls the abort() libc function. Otherwise
183/// it uses the zig standard library implementation.
184pub fn abort() noreturn {
185 @setCold(true);
186 if (builtin.link_libc) {
187 c.abort();
188 }
189 switch (builtin.os) {
190 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
191 _ = posix.raise(posix.SIGABRT);
192 _ = posix.raise(posix.SIGKILL);
193 while (true) {}
194 },
195 Os.windows => {
196 if (builtin.mode == builtin.Mode.Debug) {
197 @breakpoint();
198 }
199 windows.ExitProcess(3);
200 },
201 Os.uefi => {
202 // TODO there's gotta be a better thing to do here than loop forever
203 while (true) {}
204 },
205 else => @compileError("Unsupported OS"),
206 }
207}
208
209/// Exits the program cleanly with the specified status code.
210pub fn exit(status: u8) noreturn {
211 @setCold(true);
212 if (builtin.link_libc) {
213 c.exit(status);
214 }
215 switch (builtin.os) {
216 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
217 posix.exit(status);
218 },
219 Os.windows => {
220 windows.ExitProcess(status);
221 },
222 else => @compileError("Unsupported OS"),
223 }
224}
225
226/// When a file descriptor is closed on linux, it pops the first
227/// node from this queue and resumes it.
228/// Async functions which get the EMFILE error code can suspend,
229/// putting their coroutine handle into this list.
230/// TODO make this an atomic linked list
231pub var emfile_promise_queue = std.LinkedList(promise).init();
232
233/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
234pub fn close(handle: FileHandle) void {
235 if (is_windows) {
236 windows_util.windowsClose(handle);
237 } else {
238 while (true) {
239 const err = posix.getErrno(posix.close(handle));
240 switch (err) {
241 posix.EINTR => continue,
242 else => {
243 if (emfile_promise_queue.popFirst()) |p| resume p.data;
244 return;
245 },
246 }
247 }
248 }
249}
250
251pub const PosixReadError = error{
252 InputOutput,
253 SystemResources,
254 IsDir,
255 Unexpected,
256};
257
258/// Returns the number of bytes that were read, which can be less than
259/// buf.len. If 0 bytes were read, that means EOF.
260pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
261 // Linux can return EINVAL when read amount is > 0x7ffff000
262 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
263 const max_buf_len = 0x7ffff000;
264
265 var index: usize = 0;
266 while (index < buf.len) {
267 const want_to_read = math.min(buf.len - index, usize(max_buf_len));
268 const rc = posix.read(fd, buf.ptr + index, want_to_read);
269 const err = posix.getErrno(rc);
270 switch (err) {
271 0 => {
272 index += rc;
273 if (rc == want_to_read) continue;
274 // Read returned less than buf.len.
275 return index;
276 },
277 posix.EINTR => continue,
278 posix.EINVAL => unreachable,
279 posix.EFAULT => unreachable,
280 posix.EAGAIN => unreachable,
281 posix.EBADF => unreachable, // always a race condition
282 posix.EIO => return error.InputOutput,
283 posix.EISDIR => return error.IsDir,
284 posix.ENOBUFS => return error.SystemResources,
285 posix.ENOMEM => return error.SystemResources,
286 else => return unexpectedErrorPosix(err),
287 }
288 }
289 return index;
290}
291
292/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
293pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
294 switch (builtin.os) {
295 builtin.Os.macosx => {
296 // Darwin does not have preadv but it does have pread.
297 var off: usize = 0;
298 var iov_i: usize = 0;
299 var inner_off: usize = 0;
300 while (true) {
301 const v = iov[iov_i];
302 const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
303 const err = darwin.getErrno(rc);
304 switch (err) {
305 0 => {
306 off += rc;
307 inner_off += rc;
308 if (inner_off == v.iov_len) {
309 iov_i += 1;
310 inner_off = 0;
311 if (iov_i == count) {
312 return off;
313 }
314 }
315 if (rc == 0) return off; // EOF
316 continue;
317 },
318 posix.EINTR => continue,
319 posix.EINVAL => unreachable,
320 posix.EFAULT => unreachable,
321 posix.ESPIPE => unreachable, // fd is not seekable
322 posix.EAGAIN => unreachable, // this function is not for non blocking
323 posix.EBADF => unreachable, // always a race condition
324 posix.EIO => return error.InputOutput,
325 posix.EISDIR => return error.IsDir,
326 posix.ENOBUFS => return error.SystemResources,
327 posix.ENOMEM => return error.SystemResources,
328 else => return unexpectedErrorPosix(err),
329 }
330 }
331 },
332 builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
333 const rc = posix.preadv(fd, iov, count, offset);
334 const err = posix.getErrno(rc);
335 switch (err) {
336 0 => return rc,
337 posix.EINTR => continue,
338 posix.EINVAL => unreachable,
339 posix.EFAULT => unreachable,
340 posix.EAGAIN => unreachable, // don't call this function for non blocking
341 posix.EBADF => unreachable, // always a race condition
342 posix.EIO => return error.InputOutput,
343 posix.EISDIR => return error.IsDir,
344 posix.ENOBUFS => return error.SystemResources,
345 posix.ENOMEM => return error.SystemResources,
346 else => return unexpectedErrorPosix(err),
347 }
348 },
349 else => @compileError("Unsupported OS"),
350 }
351}
352
353pub const PosixWriteError = error{
354 DiskQuota,
355 FileTooBig,
356 InputOutput,
357 NoSpaceLeft,
358 AccessDenied,
359 BrokenPipe,
360
361 /// See https://github.com/ziglang/zig/issues/1396
362 Unexpected,
363};
364
365/// Calls POSIX write, and keeps trying if it gets interrupted.
366pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
367 // Linux can return EINVAL when write amount is > 0x7ffff000
368 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
369 const max_bytes_len = 0x7ffff000;
370
371 var index: usize = 0;
372 while (index < bytes.len) {
373 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
374 const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
375 const write_err = posix.getErrno(rc);
376 switch (write_err) {
377 0 => {
378 index += rc;
379 continue;
380 },
381 posix.EINTR => continue,
382 posix.EINVAL => unreachable,
383 posix.EFAULT => unreachable,
384 posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
385 posix.EBADF => unreachable, // always a race condition
386 posix.EDESTADDRREQ => unreachable, // connect was never called
387 posix.EDQUOT => return PosixWriteError.DiskQuota,
388 posix.EFBIG => return PosixWriteError.FileTooBig,
389 posix.EIO => return PosixWriteError.InputOutput,
390 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
391 posix.EPERM => return PosixWriteError.AccessDenied,
392 posix.EPIPE => return PosixWriteError.BrokenPipe,
393 else => return unexpectedErrorPosix(write_err),
394 }
395 }
396}
397
398pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
399 switch (builtin.os) {
400 builtin.Os.macosx => {
401 // Darwin does not have pwritev but it does have pwrite.
402 var off: usize = 0;
403 var iov_i: usize = 0;
404 var inner_off: usize = 0;
405 while (true) {
406 const v = iov[iov_i];
407 const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
408 const err = darwin.getErrno(rc);
409 switch (err) {
410 0 => {
411 off += rc;
412 inner_off += rc;
413 if (inner_off == v.iov_len) {
414 iov_i += 1;
415 inner_off = 0;
416 if (iov_i == count) {
417 return;
418 }
419 }
420 continue;
421 },
422 posix.EINTR => continue,
423 posix.ESPIPE => unreachable, // fd is not seekable
424 posix.EINVAL => unreachable,
425 posix.EFAULT => unreachable,
426 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
427 posix.EBADF => unreachable, // always a race condition
428 posix.EDESTADDRREQ => unreachable, // connect was never called
429 posix.EDQUOT => return PosixWriteError.DiskQuota,
430 posix.EFBIG => return PosixWriteError.FileTooBig,
431 posix.EIO => return PosixWriteError.InputOutput,
432 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
433 posix.EPERM => return PosixWriteError.AccessDenied,
434 posix.EPIPE => return PosixWriteError.BrokenPipe,
435 else => return unexpectedErrorPosix(err),
436 }
437 }
438 },
439 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
440 const rc = posix.pwritev(fd, iov, count, offset);
441 const err = posix.getErrno(rc);
442 switch (err) {
443 0 => return,
444 posix.EINTR => continue,
445 posix.EINVAL => unreachable,
446 posix.EFAULT => unreachable,
447 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
448 posix.EBADF => unreachable, // always a race condition
449 posix.EDESTADDRREQ => unreachable, // connect was never called
450 posix.EDQUOT => return PosixWriteError.DiskQuota,
451 posix.EFBIG => return PosixWriteError.FileTooBig,
452 posix.EIO => return PosixWriteError.InputOutput,
453 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
454 posix.EPERM => return PosixWriteError.AccessDenied,
455 posix.EPIPE => return PosixWriteError.BrokenPipe,
456 else => return unexpectedErrorPosix(err),
457 }
458 },
459 else => @compileError("Unsupported OS"),
460 }
461}
462
463pub const PosixOpenError = error{
464 AccessDenied,
465 FileTooBig,
466 IsDir,
467 SymLinkLoop,
468 ProcessFdQuotaExceeded,
469 NameTooLong,
470 SystemFdQuotaExceeded,
471 NoDevice,
472 FileNotFound,
473 SystemResources,
474 NoSpaceLeft,
475 NotDir,
476 PathAlreadyExists,
477 DeviceBusy,
478
479 /// See https://github.com/ziglang/zig/issues/1396
480 Unexpected,
481};
482
483/// ::file_path needs to be copied in memory to add a null terminating byte.
484/// Calls POSIX open, keeps trying if it gets interrupted, and translates
485/// the return value into zig errors.
486pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
487 const file_path_c = try toPosixPath(file_path);
488 return posixOpenC(&file_path_c, flags, perm);
489}
490
491// TODO https://github.com/ziglang/zig/issues/265
492pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
493 while (true) {
494 const result = posix.open(file_path, flags, perm);
495 const err = posix.getErrno(result);
496 if (err > 0) {
497 switch (err) {
498 posix.EINTR => continue,
499
500 posix.EFAULT => unreachable,
501 posix.EINVAL => unreachable,
502 posix.EACCES => return PosixOpenError.AccessDenied,
503 posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
504 posix.EISDIR => return PosixOpenError.IsDir,
505 posix.ELOOP => return PosixOpenError.SymLinkLoop,
506 posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
507 posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
508 posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
509 posix.ENODEV => return PosixOpenError.NoDevice,
510 posix.ENOENT => return PosixOpenError.FileNotFound,
511 posix.ENOMEM => return PosixOpenError.SystemResources,
512 posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
513 posix.ENOTDIR => return PosixOpenError.NotDir,
514 posix.EPERM => return PosixOpenError.AccessDenied,
515 posix.EEXIST => return PosixOpenError.PathAlreadyExists,
516 posix.EBUSY => return PosixOpenError.DeviceBusy,
517 else => return unexpectedErrorPosix(err),
518 }
519 }
520 return @intCast(i32, result);
521 }
522}
523
524/// Used to convert a slice to a null terminated slice on the stack.
525/// TODO well defined copy elision
526pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
527 var path_with_null: [posix.PATH_MAX]u8 = undefined;
528 if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
529 mem.copy(u8, path_with_null[0..], file_path);
530 path_with_null[file_path.len] = 0;
531 return path_with_null;
532}
533
534pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
535 while (true) {
536 const err = posix.getErrno(posix.dup2(old_fd, new_fd));
537 if (err > 0) {
538 return switch (err) {
539 posix.EBUSY, posix.EINTR => continue,
540 posix.EMFILE => error.ProcessFdQuotaExceeded,
541 posix.EINVAL => unreachable,
542 else => unexpectedErrorPosix(err),
543 };
544 }
545 return;
546 }
547}
548
549pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
550 const envp_count = env_map.count();
551 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
552 mem.set(?[*]u8, envp_buf, null);
553 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
554 {
555 var it = env_map.iterator();
556 var i: usize = 0;
557 while (it.next()) |pair| : (i += 1) {
558 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
559 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
560 env_buf[pair.key.len] = '=';
561 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
562 env_buf[env_buf.len - 1] = 0;
563
564 envp_buf[i] = env_buf.ptr;
565 }
566 assert(i == envp_count);
567 }
568 assert(envp_buf[envp_count] == null);
569 return envp_buf;
570}
571
572pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
573 for (envp_buf) |env| {
574 const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
575 allocator.free(env_buf);
576 }
577 allocator.free(envp_buf);
578}
579
580/// This function must allocate memory to add a null terminating bytes on path and each arg.
581/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
582/// pointers after the args and after the environment variables.
583/// `argv[0]` is the executable path.
584/// This function also uses the PATH environment variable to get the full path to the executable.
585pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
586 const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
587 mem.set(?[*]u8, argv_buf, null);
588 defer {
589 for (argv_buf) |arg| {
590 const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
591 allocator.free(arg_buf);
592 }
593 allocator.free(argv_buf);
594 }
595 for (argv) |arg, i| {
596 const arg_buf = try allocator.alloc(u8, arg.len + 1);
597 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
598 arg_buf[arg.len] = 0;
599
600 argv_buf[i] = arg_buf.ptr;
601 }
602 argv_buf[argv.len] = null;
603
604 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
605 defer freeNullDelimitedEnvMap(allocator, envp_buf);
606
607 const exe_path = argv[0];
608 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
609 return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
610 }
611
612 const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
613 // PATH.len because it is >= the largest search_path
614 // +1 for the / to join the search path and exe_path
615 // +1 for the null terminating byte
616 const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
617 defer allocator.free(path_buf);
618 var it = mem.tokenize(PATH, ":");
619 var seen_eacces = false;
620 var err: usize = undefined;
621 while (it.next()) |search_path| {
622 mem.copy(u8, path_buf, search_path);
623 path_buf[search_path.len] = '/';
624 mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
625 path_buf[search_path.len + exe_path.len + 1] = 0;
626 err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
627 assert(err > 0);
628 if (err == posix.EACCES) {
629 seen_eacces = true;
630 } else if (err != posix.ENOENT) {
631 return posixExecveErrnoToErr(err);
632 }
633 }
634 if (seen_eacces) {
635 err = posix.EACCES;
636 }
637 return posixExecveErrnoToErr(err);
638}
639
640pub const PosixExecveError = error{
641 SystemResources,
642 AccessDenied,
643 InvalidExe,
644 FileSystem,
645 IsDir,
646 FileNotFound,
647 NotDir,
648 FileBusy,
649
650 /// See https://github.com/ziglang/zig/issues/1396
651 Unexpected,
652};
653
654fn posixExecveErrnoToErr(err: usize) PosixExecveError {
655 assert(err > 0);
656 switch (err) {
657 posix.EFAULT => unreachable,
658 posix.E2BIG => return error.SystemResources,
659 posix.EMFILE => return error.SystemResources,
660 posix.ENAMETOOLONG => return error.SystemResources,
661 posix.ENFILE => return error.SystemResources,
662 posix.ENOMEM => return error.SystemResources,
663 posix.EACCES => return error.AccessDenied,
664 posix.EPERM => return error.AccessDenied,
665 posix.EINVAL => return error.InvalidExe,
666 posix.ENOEXEC => return error.InvalidExe,
667 posix.EIO => return error.FileSystem,
668 posix.ELOOP => return error.FileSystem,
669 posix.EISDIR => return error.IsDir,
670 posix.ENOENT => return error.FileNotFound,
671 posix.ENOTDIR => return error.NotDir,
672 posix.ETXTBSY => return error.FileBusy,
673 else => return unexpectedErrorPosix(err),
674 }
675}
676
677pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
678pub var posix_environ_raw: [][*]u8 = undefined;
679
680/// See std.elf for the constants.
681pub fn linuxGetAuxVal(index: usize) usize {
682 if (builtin.link_libc) {
683 return usize(std.c.getauxval(index));
684 } else if (linux_elf_aux_maybe) |auxv| {
685 var i: usize = 0;
686 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
687 if (auxv[i].a_type == index)
688 return auxv[i].a_un.a_val;
689 }
690 }
691 return 0;
692}
693
694pub fn getBaseAddress() usize {
695 switch (builtin.os) {
696 builtin.Os.linux => {
697 const base = linuxGetAuxVal(std.elf.AT_BASE);
698 if (base != 0) {
699 return base;
700 }
701 const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
702 return phdr - @sizeOf(std.elf.Ehdr);
703 },
704 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
705 return @ptrToInt(&std.c._mh_execute_header);
706 },
707 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
708 else => @compileError("Unsupported OS"),
709 }
710}
711
712/// Caller must free result when done.
713/// TODO make this go through libc when we have it
714pub fn getEnvMap(allocator: *Allocator) !BufMap {
715 var result = BufMap.init(allocator);
716 errdefer result.deinit();
717
718 if (is_windows) {
719 const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
720 defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
721
722 var i: usize = 0;
723 while (true) {
724 if (ptr[i] == 0) return result;
725
726 const key_start = i;
727
728 while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
729 const key_w = ptr[key_start..i];
730 const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
731 errdefer allocator.free(key);
732
733 if (ptr[i] == '=') i += 1;
734
735 const value_start = i;
736 while (ptr[i] != 0) : (i += 1) {}
737 const value_w = ptr[value_start..i];
738 const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
739 errdefer allocator.free(value);
740
741 i += 1; // skip over null byte
742
743 try result.setMove(key, value);
744 }
745 } else {
746 for (posix_environ_raw) |ptr| {
747 var line_i: usize = 0;
748 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
749 const key = ptr[0..line_i];
750
751 var end_i: usize = line_i;
752 while (ptr[end_i] != 0) : (end_i += 1) {}
753 const value = ptr[line_i + 1 .. end_i];
754
755 try result.set(key, value);
756 }
757 return result;
758 }
759}
760
761test "os.getEnvMap" {
762 var env = try getEnvMap(std.debug.global_allocator);
763 defer env.deinit();
764}
765
766/// TODO make this go through libc when we have it
767pub fn getEnvPosix(key: []const u8) ?[]const u8 {
768 for (posix_environ_raw) |ptr| {
769 var line_i: usize = 0;
770 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
771 const this_key = ptr[0..line_i];
772 if (!mem.eql(u8, key, this_key)) continue;
773
774 var end_i: usize = line_i;
775 while (ptr[end_i] != 0) : (end_i += 1) {}
776 const this_value = ptr[line_i + 1 .. end_i];
777
778 return this_value;
779 }
780 return null;
781}
782
783pub const GetEnvVarOwnedError = error{
784 OutOfMemory,
785 EnvironmentVariableNotFound,
786
787 /// See https://github.com/ziglang/zig/issues/1774
788 InvalidUtf8,
789};
790
791/// Caller must free returned memory.
792/// TODO make this go through libc when we have it
793pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
794 if (is_windows) {
795 const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
796 defer allocator.free(key_with_null);
797
798 var buf = try allocator.alloc(u16, 256);
799 defer allocator.free(buf);
800
801 while (true) {
802 const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
803 const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
804
805 if (result == 0) {
806 const err = windows.GetLastError();
807 return switch (err) {
808 windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
809 else => {
810 _ = unexpectedErrorWindows(err);
811 return error.EnvironmentVariableNotFound;
812 },
813 };
814 }
815
816 if (result > buf.len) {
817 buf = try allocator.realloc(u16, buf, result);
818 continue;
819 }
820
821 return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
822 error.DanglingSurrogateHalf => return error.InvalidUtf8,
823 error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
824 error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
825 error.OutOfMemory => return error.OutOfMemory,
826 };
827 }
828 } else {
829 const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
830 return mem.dupe(allocator, u8, result);
831 }
832}
833
834test "os.getEnvVarOwned" {
835 var ga = debug.global_allocator;
836 testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
837}
838
839/// Caller must free the returned memory.
840pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
841 var buf: [MAX_PATH_BYTES]u8 = undefined;
842 return mem.dupe(allocator, u8, try getCwd(&buf));
843}
844
845pub const GetCwdError = error{Unexpected};
846
847/// The result is a slice of out_buffer.
848pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
849 switch (builtin.os) {
850 Os.windows => {
851 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
852 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
853 const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
854 const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
855 if (result == 0) {
856 const err = windows.GetLastError();
857 switch (err) {
858 else => return unexpectedErrorWindows(err),
859 }
860 }
861 assert(result <= utf16le_buf.len);
862 const utf16le_slice = utf16le_buf[0..result];
863 // Trust that Windows gives us valid UTF-16LE.
864 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
865 return out_buffer[0..end_index];
866 },
867 else => {
868 const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
869 switch (err) {
870 0 => return cstr.toSlice(out_buffer),
871 posix.ERANGE => unreachable,
872 else => return unexpectedErrorPosix(err),
873 }
874 },
875 }
876}
877
878test "os.getCwd" {
879 // at least call it so it gets compiled
880 _ = getCwdAlloc(debug.global_allocator);
881 var buf: [MAX_PATH_BYTES]u8 = undefined;
882 _ = getCwd(&buf);
883}
884
885pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
886
887/// TODO add a symLinkC variant
888pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
889 if (is_windows) {
890 return symLinkWindows(existing_path, new_path);
891 } else {
892 return symLinkPosix(existing_path, new_path);
893 }
894}
895
896pub const WindowsSymLinkError = error{
897 NameTooLong,
898 InvalidUtf8,
899 BadPathName,
900
901 /// See https://github.com/ziglang/zig/issues/1396
902 Unexpected,
903};
904
905pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
906 if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
907 const err = windows.GetLastError();
908 switch (err) {
909 else => return unexpectedErrorWindows(err),
910 }
911 }
912}
913
914pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
915 const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
916 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
917 return symLinkW(&existing_path_w, &new_path_w);
918}
919
920pub const PosixSymLinkError = error{
921 AccessDenied,
922 DiskQuota,
923 PathAlreadyExists,
924 FileSystem,
925 SymLinkLoop,
926 NameTooLong,
927 FileNotFound,
928 SystemResources,
929 NoSpaceLeft,
930 ReadOnlyFileSystem,
931 NotDir,
932
933 /// See https://github.com/ziglang/zig/issues/1396
934 Unexpected,
935};
936
937pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
938 const err = posix.getErrno(posix.symlink(existing_path, new_path));
939 switch (err) {
940 0 => return,
941 posix.EFAULT => unreachable,
942 posix.EINVAL => unreachable,
943 posix.EACCES => return error.AccessDenied,
944 posix.EPERM => return error.AccessDenied,
945 posix.EDQUOT => return error.DiskQuota,
946 posix.EEXIST => return error.PathAlreadyExists,
947 posix.EIO => return error.FileSystem,
948 posix.ELOOP => return error.SymLinkLoop,
949 posix.ENAMETOOLONG => return error.NameTooLong,
950 posix.ENOENT => return error.FileNotFound,
951 posix.ENOTDIR => return error.NotDir,
952 posix.ENOMEM => return error.SystemResources,
953 posix.ENOSPC => return error.NoSpaceLeft,
954 posix.EROFS => return error.ReadOnlyFileSystem,
955 else => return unexpectedErrorPosix(err),
956 }
957}
958
959pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
960 const existing_path_c = try toPosixPath(existing_path);
961 const new_path_c = try toPosixPath(new_path);
962 return symLinkPosixC(&existing_path_c, &new_path_c);
963}
964
965// here we replace the standard +/ with -_ so that it can be used in a file name
966const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
967
968/// TODO remove the allocator requirement from this API
969pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
970 if (symLink(existing_path, new_path)) {
971 return;
972 } else |err| switch (err) {
973 error.PathAlreadyExists => {},
974 else => return err, // TODO zig should know this set does not include PathAlreadyExists
975 }
976
977 const dirname = os.path.dirname(new_path) orelse ".";
978
979 var rand_buf: [12]u8 = undefined;
980 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
981 defer allocator.free(tmp_path);
982 mem.copy(u8, tmp_path[0..], dirname);
983 tmp_path[dirname.len] = os.path.sep;
984 while (true) {
985 try getRandomBytes(rand_buf[0..]);
986 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
987
988 if (symLink(existing_path, tmp_path)) {
989 return rename(tmp_path, new_path);
990 } else |err| switch (err) {
991 error.PathAlreadyExists => continue,
992 else => return err, // TODO zig should know this set does not include PathAlreadyExists
993 }
994 }
995}
996
997pub const DeleteFileError = error{
998 FileNotFound,
999 AccessDenied,
1000 FileBusy,
1001 FileSystem,
1002 IsDir,
1003 SymLinkLoop,
1004 NameTooLong,
1005 NotDir,
1006 SystemResources,
1007 ReadOnlyFileSystem,
1008
1009 /// On Windows, file paths must be valid Unicode.
1010 InvalidUtf8,
1011
1012 /// On Windows, file paths cannot contain these characters:
1013 /// '/', '*', '?', '"', '<', '>', '|'
1014 BadPathName,
1015
1016 /// See https://github.com/ziglang/zig/issues/1396
1017 Unexpected,
1018};
1019
1020pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
1021 if (builtin.os == Os.windows) {
1022 const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
1023 return deleteFileW(&file_path_w);
1024 } else {
1025 const file_path_c = try toPosixPath(file_path);
1026 return deleteFileC(&file_path_c);
1027 }
1028}
1029
1030pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
1031 if (windows.DeleteFileW(file_path) == 0) {
1032 const err = windows.GetLastError();
1033 switch (err) {
1034 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1035 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
1036 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1037 windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
1038 else => return unexpectedErrorWindows(err),
1039 }
1040 }
1041}
1042
1043pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
1044 if (is_windows) {
1045 const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
1046 return deleteFileW(&file_path_w);
1047 } else {
1048 const err = posix.getErrno(posix.unlink(file_path));
1049 switch (err) {
1050 0 => return,
1051 posix.EACCES => return error.AccessDenied,
1052 posix.EPERM => return error.AccessDenied,
1053 posix.EBUSY => return error.FileBusy,
1054 posix.EFAULT => unreachable,
1055 posix.EINVAL => unreachable,
1056 posix.EIO => return error.FileSystem,
1057 posix.EISDIR => return error.IsDir,
1058 posix.ELOOP => return error.SymLinkLoop,
1059 posix.ENAMETOOLONG => return error.NameTooLong,
1060 posix.ENOENT => return error.FileNotFound,
1061 posix.ENOTDIR => return error.NotDir,
1062 posix.ENOMEM => return error.SystemResources,
1063 posix.EROFS => return error.ReadOnlyFileSystem,
1064 else => return unexpectedErrorPosix(err),
1065 }
1066 }
1067}
1068
1069/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
1070/// merged and readily available,
1071/// there is a possibility of power loss or application termination leaving temporary files present
1072/// in the same directory as dest_path.
1073/// Destination file will have the same mode as the source file.
1074pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
1075 var in_file = try os.File.openRead(source_path);
1076 defer in_file.close();
1077
1078 const mode = try in_file.mode();
1079
1080 var atomic_file = try AtomicFile.init(dest_path, mode);
1081 defer atomic_file.deinit();
1082
1083 var buf: [page_size]u8 = undefined;
1084 while (true) {
1085 const amt = try in_file.readFull(buf[0..]);
1086 try atomic_file.file.write(buf[0..amt]);
1087 if (amt != buf.len) {
1088 return atomic_file.finish();
1089 }
1090 }
1091}
1092
1093/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
1094/// merged and readily available,
1095/// there is a possibility of power loss or application termination leaving temporary files present
1096pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
1097 var in_file = try os.File.openRead(source_path);
1098 defer in_file.close();
1099
1100 var atomic_file = try AtomicFile.init(dest_path, mode);
1101 defer atomic_file.deinit();
1102
1103 var buf: [page_size]u8 = undefined;
1104 while (true) {
1105 const amt = try in_file.read(buf[0..]);
1106 try atomic_file.file.write(buf[0..amt]);
1107 if (amt != buf.len) {
1108 return atomic_file.finish();
1109 }
1110 }
1111}
1112
1113pub const AtomicFile = struct {
1114 file: os.File,
1115 tmp_path_buf: [MAX_PATH_BYTES]u8,
1116 dest_path: []const u8,
1117 finished: bool,
1118
1119 const InitError = os.File.OpenError;
1120
1121 /// dest_path must remain valid for the lifetime of AtomicFile
1122 /// call finish to atomically replace dest_path with contents
1123 /// TODO once we have null terminated pointers, use the
1124 /// openWriteNoClobberN function
1125 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
1126 const dirname = os.path.dirname(dest_path);
1127 var rand_buf: [12]u8 = undefined;
1128 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
1129 const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
1130 const tmp_path_len = dirname_component_len + encoded_rand_len;
1131 var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
1132 if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
1133
1134 if (dirname) |dir| {
1135 mem.copy(u8, tmp_path_buf[0..], dir);
1136 tmp_path_buf[dir.len] = os.path.sep;
1137 }
1138
1139 tmp_path_buf[tmp_path_len] = 0;
1140
1141 while (true) {
1142 try getRandomBytes(rand_buf[0..]);
1143 b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
1144
1145 const file = os.File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
1146 error.PathAlreadyExists => continue,
1147 // TODO zig should figure out that this error set does not include PathAlreadyExists since
1148 // it is handled in the above switch
1149 else => return err,
1150 };
1151
1152 return AtomicFile{
1153 .file = file,
1154 .tmp_path_buf = tmp_path_buf,
1155 .dest_path = dest_path,
1156 .finished = false,
1157 };
1158 }
1159 }
1160
1161 /// always call deinit, even after successful finish()
1162 pub fn deinit(self: *AtomicFile) void {
1163 if (!self.finished) {
1164 self.file.close();
1165 deleteFileC(&self.tmp_path_buf) catch {};
1166 self.finished = true;
1167 }
1168 }
1169
1170 pub fn finish(self: *AtomicFile) !void {
1171 assert(!self.finished);
1172 self.file.close();
1173 self.finished = true;
1174 if (is_posix) {
1175 const dest_path_c = try toPosixPath(self.dest_path);
1176 return renameC(&self.tmp_path_buf, &dest_path_c);
1177 } else if (is_windows) {
1178 const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
1179 const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
1180 return renameW(&tmp_path_w, &dest_path_w);
1181 } else {
1182 @compileError("Unsupported OS");
1183 }
1184 }
1185};
1186
1187pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
1188 if (is_windows) {
1189 const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
1190 const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
1191 return renameW(&old_path_w, &new_path_w);
1192 } else {
1193 const err = posix.getErrno(posix.rename(old_path, new_path));
1194 switch (err) {
1195 0 => return,
1196 posix.EACCES => return error.AccessDenied,
1197 posix.EPERM => return error.AccessDenied,
1198 posix.EBUSY => return error.FileBusy,
1199 posix.EDQUOT => return error.DiskQuota,
1200 posix.EFAULT => unreachable,
1201 posix.EINVAL => unreachable,
1202 posix.EISDIR => return error.IsDir,
1203 posix.ELOOP => return error.SymLinkLoop,
1204 posix.EMLINK => return error.LinkQuotaExceeded,
1205 posix.ENAMETOOLONG => return error.NameTooLong,
1206 posix.ENOENT => return error.FileNotFound,
1207 posix.ENOTDIR => return error.NotDir,
1208 posix.ENOMEM => return error.SystemResources,
1209 posix.ENOSPC => return error.NoSpaceLeft,
1210 posix.EEXIST => return error.PathAlreadyExists,
1211 posix.ENOTEMPTY => return error.PathAlreadyExists,
1212 posix.EROFS => return error.ReadOnlyFileSystem,
1213 posix.EXDEV => return error.RenameAcrossMountPoints,
1214 else => return unexpectedErrorPosix(err),
1215 }
1216 }
1217}
1218
1219pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
1220 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
1221 if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
1222 const err = windows.GetLastError();
1223 switch (err) {
1224 else => return unexpectedErrorWindows(err),
1225 }
1226 }
1227}
1228
1229pub fn rename(old_path: []const u8, new_path: []const u8) !void {
1230 if (is_windows) {
1231 const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
1232 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
1233 return renameW(&old_path_w, &new_path_w);
1234 } else {
1235 const old_path_c = try toPosixPath(old_path);
1236 const new_path_c = try toPosixPath(new_path);
1237 return renameC(&old_path_c, &new_path_c);
1238 }
1239}
1240
1241pub fn makeDir(dir_path: []const u8) !void {
1242 if (is_windows) {
1243 return makeDirWindows(dir_path);
1244 } else {
1245 return makeDirPosix(dir_path);
1246 }
1247}
1248
1249pub fn makeDirWindows(dir_path: []const u8) !void {
1250 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1251
1252 if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
1253 const err = windows.GetLastError();
1254 return switch (err) {
1255 windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
1256 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1257 else => unexpectedErrorWindows(err),
1258 };
1259 }
1260}
1261
1262pub fn makeDirPosixC(dir_path: [*]const u8) !void {
1263 const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
1264 switch (err) {
1265 0 => return,
1266 posix.EACCES => return error.AccessDenied,
1267 posix.EPERM => return error.AccessDenied,
1268 posix.EDQUOT => return error.DiskQuota,
1269 posix.EEXIST => return error.PathAlreadyExists,
1270 posix.EFAULT => unreachable,
1271 posix.ELOOP => return error.SymLinkLoop,
1272 posix.EMLINK => return error.LinkQuotaExceeded,
1273 posix.ENAMETOOLONG => return error.NameTooLong,
1274 posix.ENOENT => return error.FileNotFound,
1275 posix.ENOMEM => return error.SystemResources,
1276 posix.ENOSPC => return error.NoSpaceLeft,
1277 posix.ENOTDIR => return error.NotDir,
1278 posix.EROFS => return error.ReadOnlyFileSystem,
1279 else => return unexpectedErrorPosix(err),
1280 }
1281}
1282
1283pub fn makeDirPosix(dir_path: []const u8) !void {
1284 const dir_path_c = try toPosixPath(dir_path);
1285 return makeDirPosixC(&dir_path_c);
1286}
1287
1288/// Calls makeDir recursively to make an entire path. Returns success if the path
1289/// already exists and is a directory.
1290/// TODO determine if we can remove the allocator requirement from this function
1291pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
1292 const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
1293 defer allocator.free(resolved_path);
1294
1295 var end_index: usize = resolved_path.len;
1296 while (true) {
1297 makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
1298 error.PathAlreadyExists => {
1299 // TODO stat the file and return an error if it's not a directory
1300 // this is important because otherwise a dangling symlink
1301 // could cause an infinite loop
1302 if (end_index == resolved_path.len) return;
1303 },
1304 error.FileNotFound => {
1305 // march end_index backward until next path component
1306 while (true) {
1307 end_index -= 1;
1308 if (os.path.isSep(resolved_path[end_index])) break;
1309 }
1310 continue;
1311 },
1312 else => return err,
1313 };
1314 if (end_index == resolved_path.len) return;
1315 // march end_index forward until next path component
1316 while (true) {
1317 end_index += 1;
1318 if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
1319 }
1320 }
1321}
1322
1323pub const DeleteDirError = error{
1324 AccessDenied,
1325 FileBusy,
1326 SymLinkLoop,
1327 NameTooLong,
1328 FileNotFound,
1329 SystemResources,
1330 NotDir,
1331 DirNotEmpty,
1332 ReadOnlyFileSystem,
1333 InvalidUtf8,
1334 BadPathName,
1335
1336 /// See https://github.com/ziglang/zig/issues/1396
1337 Unexpected,
1338};
1339
1340pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
1341 switch (builtin.os) {
1342 Os.windows => {
1343 const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
1344 return deleteDirW(&dir_path_w);
1345 },
1346 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1347 const err = posix.getErrno(posix.rmdir(dir_path));
1348 switch (err) {
1349 0 => return,
1350 posix.EACCES => return error.AccessDenied,
1351 posix.EPERM => return error.AccessDenied,
1352 posix.EBUSY => return error.FileBusy,
1353 posix.EFAULT => unreachable,
1354 posix.EINVAL => unreachable,
1355 posix.ELOOP => return error.SymLinkLoop,
1356 posix.ENAMETOOLONG => return error.NameTooLong,
1357 posix.ENOENT => return error.FileNotFound,
1358 posix.ENOMEM => return error.SystemResources,
1359 posix.ENOTDIR => return error.NotDir,
1360 posix.EEXIST => return error.DirNotEmpty,
1361 posix.ENOTEMPTY => return error.DirNotEmpty,
1362 posix.EROFS => return error.ReadOnlyFileSystem,
1363 else => return unexpectedErrorPosix(err),
1364 }
1365 },
1366 else => @compileError("unimplemented"),
1367 }
1368}
1369
1370pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
1371 if (windows.RemoveDirectoryW(dir_path_w) == 0) {
1372 const err = windows.GetLastError();
1373 switch (err) {
1374 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1375 windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
1376 else => return unexpectedErrorWindows(err),
1377 }
1378 }
1379}
1380
1381/// Returns ::error.DirNotEmpty if the directory is not empty.
1382/// To delete a directory recursively, see ::deleteTree
1383pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
1384 switch (builtin.os) {
1385 Os.windows => {
1386 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1387 return deleteDirW(&dir_path_w);
1388 },
1389 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1390 const dir_path_c = try toPosixPath(dir_path);
1391 return deleteDirC(&dir_path_c);
1392 },
1393 else => @compileError("unimplemented"),
1394 }
1395}
1396
1397/// Whether ::full_path describes a symlink, file, or directory, this function
1398/// removes it. If it cannot be removed because it is a non-empty directory,
1399/// this function recursively removes its entries and then tries again.
1400const DeleteTreeError = error{
1401 OutOfMemory,
1402 AccessDenied,
1403 FileTooBig,
1404 IsDir,
1405 SymLinkLoop,
1406 ProcessFdQuotaExceeded,
1407 NameTooLong,
1408 SystemFdQuotaExceeded,
1409 NoDevice,
1410 SystemResources,
1411 NoSpaceLeft,
1412 PathAlreadyExists,
1413 ReadOnlyFileSystem,
1414 NotDir,
1415 FileNotFound,
1416 FileSystem,
1417 FileBusy,
1418 DirNotEmpty,
1419 DeviceBusy,
1420
1421 /// On Windows, file paths must be valid Unicode.
1422 InvalidUtf8,
1423
1424 /// On Windows, file paths cannot contain these characters:
1425 /// '/', '*', '?', '"', '<', '>', '|'
1426 BadPathName,
1427
1428 /// See https://github.com/ziglang/zig/issues/1396
1429 Unexpected,
1430};
1431
1432/// TODO determine if we can remove the allocator requirement
1433pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
1434 start_over: while (true) {
1435 var got_access_denied = false;
1436 // First, try deleting the item as a file. This way we don't follow sym links.
1437 if (deleteFile(full_path)) {
1438 return;
1439 } else |err| switch (err) {
1440 error.FileNotFound => return,
1441 error.IsDir => {},
1442 error.AccessDenied => got_access_denied = true,
1443
1444 error.InvalidUtf8,
1445 error.SymLinkLoop,
1446 error.NameTooLong,
1447 error.SystemResources,
1448 error.ReadOnlyFileSystem,
1449 error.NotDir,
1450 error.FileSystem,
1451 error.FileBusy,
1452 error.BadPathName,
1453 error.Unexpected,
1454 => return err,
1455 }
1456 {
1457 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
1458 error.NotDir => {
1459 if (got_access_denied) {
1460 return error.AccessDenied;
1461 }
1462 continue :start_over;
1463 },
1464
1465 error.OutOfMemory,
1466 error.AccessDenied,
1467 error.FileTooBig,
1468 error.IsDir,
1469 error.SymLinkLoop,
1470 error.ProcessFdQuotaExceeded,
1471 error.NameTooLong,
1472 error.SystemFdQuotaExceeded,
1473 error.NoDevice,
1474 error.FileNotFound,
1475 error.SystemResources,
1476 error.NoSpaceLeft,
1477 error.PathAlreadyExists,
1478 error.Unexpected,
1479 error.InvalidUtf8,
1480 error.BadPathName,
1481 error.DeviceBusy,
1482 => return err,
1483 };
1484 defer dir.close();
1485
1486 var full_entry_buf = ArrayList(u8).init(allocator);
1487 defer full_entry_buf.deinit();
1488
1489 while (try dir.next()) |entry| {
1490 try full_entry_buf.resize(full_path.len + entry.name.len + 1);
1491 const full_entry_path = full_entry_buf.toSlice();
1492 mem.copy(u8, full_entry_path, full_path);
1493 full_entry_path[full_path.len] = path.sep;
1494 mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
1495
1496 try deleteTree(allocator, full_entry_path);
1497 }
1498 }
1499 return deleteDir(full_path);
1500 }
1501}
1502
1503pub const Dir = struct {
1504 handle: Handle,
1505 allocator: *Allocator,
1506
1507 pub const Handle = switch (builtin.os) {
1508 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
1509 fd: i32,
1510 seek: i64,
1511 buf: []u8,
1512 index: usize,
1513 end_index: usize,
1514 },
1515 Os.linux => struct {
1516 fd: i32,
1517 buf: []u8,
1518 index: usize,
1519 end_index: usize,
1520 },
1521 Os.windows => struct {
1522 handle: windows.HANDLE,
1523 find_file_data: windows.WIN32_FIND_DATAW,
1524 first: bool,
1525 name_data: [256]u8,
1526 },
1527 else => @compileError("unimplemented"),
1528 };
1529
1530 pub const Entry = struct {
1531 name: []const u8,
1532 kind: Kind,
1533
1534 pub const Kind = enum {
1535 BlockDevice,
1536 CharacterDevice,
1537 Directory,
1538 NamedPipe,
1539 SymLink,
1540 File,
1541 UnixDomainSocket,
1542 Whiteout,
1543 Unknown,
1544 };
1545 };
1546
1547 pub const OpenError = error{
1548 FileNotFound,
1549 NotDir,
1550 AccessDenied,
1551 FileTooBig,
1552 IsDir,
1553 SymLinkLoop,
1554 ProcessFdQuotaExceeded,
1555 NameTooLong,
1556 SystemFdQuotaExceeded,
1557 NoDevice,
1558 SystemResources,
1559 NoSpaceLeft,
1560 PathAlreadyExists,
1561 OutOfMemory,
1562 InvalidUtf8,
1563 BadPathName,
1564 DeviceBusy,
1565
1566 /// See https://github.com/ziglang/zig/issues/1396
1567 Unexpected,
1568 };
1569
1570 /// TODO remove the allocator requirement from this API
1571 pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
1572 return Dir{
1573 .allocator = allocator,
1574 .handle = switch (builtin.os) {
1575 Os.windows => blk: {
1576 var find_file_data: windows.WIN32_FIND_DATAW = undefined;
1577 const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
1578 break :blk Handle{
1579 .handle = handle,
1580 .find_file_data = find_file_data, // TODO guaranteed copy elision
1581 .first = true,
1582 .name_data = undefined,
1583 };
1584 },
1585 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
1586 .fd = try posixOpen(
1587 dir_path,
1588 posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
1589 0,
1590 ),
1591 .seek = 0,
1592 .index = 0,
1593 .end_index = 0,
1594 .buf = []u8{},
1595 },
1596 Os.linux => Handle{
1597 .fd = try posixOpen(
1598 dir_path,
1599 posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
1600 0,
1601 ),
1602 .index = 0,
1603 .end_index = 0,
1604 .buf = []u8{},
1605 },
1606 else => @compileError("unimplemented"),
1607 },
1608 };
1609 }
1610
1611 pub fn close(self: *Dir) void {
1612 switch (builtin.os) {
1613 Os.windows => {
1614 _ = windows.FindClose(self.handle.handle);
1615 },
1616 Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
1617 self.allocator.free(self.handle.buf);
1618 os.close(self.handle.fd);
1619 },
1620 else => @compileError("unimplemented"),
1621 }
1622 }
1623
1624 /// Memory such as file names referenced in this returned entry becomes invalid
1625 /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
1626 pub fn next(self: *Dir) !?Entry {
1627 switch (builtin.os) {
1628 Os.linux => return self.nextLinux(),
1629 Os.macosx, Os.ios => return self.nextDarwin(),
1630 Os.windows => return self.nextWindows(),
1631 Os.freebsd => return self.nextFreebsd(),
1632 Os.netbsd => return self.nextFreebsd(),
1633 else => @compileError("unimplemented"),
1634 }
1635 }
1636
1637 fn nextDarwin(self: *Dir) !?Entry {
1638 start_over: while (true) {
1639 if (self.handle.index >= self.handle.end_index) {
1640 if (self.handle.buf.len == 0) {
1641 self.handle.buf = try self.allocator.alloc(u8, page_size);
1642 }
1643
1644 while (true) {
1645 const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
1646 const err = posix.getErrno(result);
1647 if (err > 0) {
1648 switch (err) {
1649 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1650 posix.EINVAL => {
1651 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
1652 continue;
1653 },
1654 else => return unexpectedErrorPosix(err),
1655 }
1656 }
1657 if (result == 0) return null;
1658 self.handle.index = 0;
1659 self.handle.end_index = result;
1660 break;
1661 }
1662 }
1663 const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1664 const next_index = self.handle.index + darwin_entry.d_reclen;
1665 self.handle.index = next_index;
1666
1667 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
1668
1669 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1670 continue :start_over;
1671 }
1672
1673 const entry_kind = switch (darwin_entry.d_type) {
1674 posix.DT_BLK => Entry.Kind.BlockDevice,
1675 posix.DT_CHR => Entry.Kind.CharacterDevice,
1676 posix.DT_DIR => Entry.Kind.Directory,
1677 posix.DT_FIFO => Entry.Kind.NamedPipe,
1678 posix.DT_LNK => Entry.Kind.SymLink,
1679 posix.DT_REG => Entry.Kind.File,
1680 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1681 posix.DT_WHT => Entry.Kind.Whiteout,
1682 else => Entry.Kind.Unknown,
1683 };
1684 return Entry{
1685 .name = name,
1686 .kind = entry_kind,
1687 };
1688 }
1689 }
1690
1691 fn nextWindows(self: *Dir) !?Entry {
1692 while (true) {
1693 if (self.handle.first) {
1694 self.handle.first = false;
1695 } else {
1696 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
1697 return null;
1698 }
1699 const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
1700 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
1701 continue;
1702 // Trust that Windows gives us valid UTF-16LE
1703 const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
1704 const name_utf8 = self.handle.name_data[0..name_utf8_len];
1705 const kind = blk: {
1706 const attrs = self.handle.find_file_data.dwFileAttributes;
1707 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
1708 if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
1709 if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
1710 break :blk Entry.Kind.Unknown;
1711 };
1712 return Entry{
1713 .name = name_utf8,
1714 .kind = kind,
1715 };
1716 }
1717 }
1718
1719 fn nextLinux(self: *Dir) !?Entry {
1720 start_over: while (true) {
1721 if (self.handle.index >= self.handle.end_index) {
1722 if (self.handle.buf.len == 0) {
1723 self.handle.buf = try self.allocator.alloc(u8, page_size);
1724 }
1725
1726 while (true) {
1727 const result = posix.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
1728 const err = posix.getErrno(result);
1729 if (err > 0) {
1730 switch (err) {
1731 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1732 posix.EINVAL => {
1733 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
1734 continue;
1735 },
1736 else => return unexpectedErrorPosix(err),
1737 }
1738 }
1739 if (result == 0) return null;
1740 self.handle.index = 0;
1741 self.handle.end_index = result;
1742 break;
1743 }
1744 }
1745 const linux_entry = @ptrCast(*align(1) posix.dirent64, &self.handle.buf[self.handle.index]);
1746 const next_index = self.handle.index + linux_entry.d_reclen;
1747 self.handle.index = next_index;
1748
1749 const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
1750
1751 // skip . and .. entries
1752 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1753 continue :start_over;
1754 }
1755
1756 const entry_kind = switch (linux_entry.d_type) {
1757 posix.DT_BLK => Entry.Kind.BlockDevice,
1758 posix.DT_CHR => Entry.Kind.CharacterDevice,
1759 posix.DT_DIR => Entry.Kind.Directory,
1760 posix.DT_FIFO => Entry.Kind.NamedPipe,
1761 posix.DT_LNK => Entry.Kind.SymLink,
1762 posix.DT_REG => Entry.Kind.File,
1763 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1764 else => Entry.Kind.Unknown,
1765 };
1766 return Entry{
1767 .name = name,
1768 .kind = entry_kind,
1769 };
1770 }
1771 }
1772
1773 fn nextFreebsd(self: *Dir) !?Entry {
1774 start_over: while (true) {
1775 if (self.handle.index >= self.handle.end_index) {
1776 if (self.handle.buf.len == 0) {
1777 self.handle.buf = try self.allocator.alloc(u8, page_size);
1778 }
1779
1780 while (true) {
1781 const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
1782 const err = posix.getErrno(result);
1783 if (err > 0) {
1784 switch (err) {
1785 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1786 posix.EINVAL => {
1787 self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
1788 continue;
1789 },
1790 else => return unexpectedErrorPosix(err),
1791 }
1792 }
1793 if (result == 0) return null;
1794 self.handle.index = 0;
1795 self.handle.end_index = result;
1796 break;
1797 }
1798 }
1799 const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1800 const next_index = self.handle.index + freebsd_entry.d_reclen;
1801 self.handle.index = next_index;
1802
1803 const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
1804
1805 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1806 continue :start_over;
1807 }
1808
1809 const entry_kind = switch (freebsd_entry.d_type) {
1810 posix.DT_BLK => Entry.Kind.BlockDevice,
1811 posix.DT_CHR => Entry.Kind.CharacterDevice,
1812 posix.DT_DIR => Entry.Kind.Directory,
1813 posix.DT_FIFO => Entry.Kind.NamedPipe,
1814 posix.DT_LNK => Entry.Kind.SymLink,
1815 posix.DT_REG => Entry.Kind.File,
1816 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1817 posix.DT_WHT => Entry.Kind.Whiteout,
1818 else => Entry.Kind.Unknown,
1819 };
1820 return Entry{
1821 .name = name,
1822 .kind = entry_kind,
1823 };
1824 }
1825 }
1826};
1827
1828pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
1829 const path_buf = try allocator.alloc(u8, dir_path.len + 1);
1830 defer allocator.free(path_buf);
1831
1832 mem.copy(u8, path_buf, dir_path);
1833 path_buf[dir_path.len] = 0;
1834
1835 const err = posix.getErrno(posix.chdir(path_buf.ptr));
1836 if (err > 0) {
1837 return switch (err) {
1838 posix.EACCES => error.AccessDenied,
1839 posix.EFAULT => unreachable,
1840 posix.EIO => error.FileSystem,
1841 posix.ELOOP => error.SymLinkLoop,
1842 posix.ENAMETOOLONG => error.NameTooLong,
1843 posix.ENOENT => error.FileNotFound,
1844 posix.ENOMEM => error.SystemResources,
1845 posix.ENOTDIR => error.NotDir,
1846 else => unexpectedErrorPosix(err),
1847 };
1848 }
1849}
1850
1851/// Read value of a symbolic link.
1852/// The return value is a slice of out_buffer.
1853pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
1854 const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
1855 const err = posix.getErrno(rc);
1856 switch (err) {
1857 0 => return out_buffer[0..rc],
1858 posix.EACCES => return error.AccessDenied,
1859 posix.EFAULT => unreachable,
1860 posix.EINVAL => unreachable,
1861 posix.EIO => return error.FileSystem,
1862 posix.ELOOP => return error.SymLinkLoop,
1863 posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
1864 posix.ENOENT => return error.FileNotFound,
1865 posix.ENOMEM => return error.SystemResources,
1866 posix.ENOTDIR => return error.NotDir,
1867 else => return unexpectedErrorPosix(err),
1868 }
1869}
1870
1871/// Read value of a symbolic link.
1872/// The return value is a slice of out_buffer.
1873pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
1874 const file_path_c = try toPosixPath(file_path);
1875 return readLinkC(out_buffer, &file_path_c);
1876}
1877
1878pub fn posix_setuid(uid: u32) !void {
1879 const err = posix.getErrno(posix.setuid(uid));
1880 if (err == 0) return;
1881 return switch (err) {
1882 posix.EAGAIN => error.ResourceLimitReached,
1883 posix.EINVAL => error.InvalidUserId,
1884 posix.EPERM => error.PermissionDenied,
1885 else => unexpectedErrorPosix(err),
1886 };
1887}
1888
1889pub fn posix_setreuid(ruid: u32, euid: u32) !void {
1890 const err = posix.getErrno(posix.setreuid(ruid, euid));
1891 if (err == 0) return;
1892 return switch (err) {
1893 posix.EAGAIN => error.ResourceLimitReached,
1894 posix.EINVAL => error.InvalidUserId,
1895 posix.EPERM => error.PermissionDenied,
1896 else => unexpectedErrorPosix(err),
1897 };
1898}
1899
1900pub fn posix_setgid(gid: u32) !void {
1901 const err = posix.getErrno(posix.setgid(gid));
1902 if (err == 0) return;
1903 return switch (err) {
1904 posix.EAGAIN => error.ResourceLimitReached,
1905 posix.EINVAL => error.InvalidUserId,
1906 posix.EPERM => error.PermissionDenied,
1907 else => unexpectedErrorPosix(err),
1908 };
1909}
1910
1911pub fn posix_setregid(rgid: u32, egid: u32) !void {
1912 const err = posix.getErrno(posix.setregid(rgid, egid));
1913 if (err == 0) return;
1914 return switch (err) {
1915 posix.EAGAIN => error.ResourceLimitReached,
1916 posix.EINVAL => error.InvalidUserId,
1917 posix.EPERM => error.PermissionDenied,
1918 else => unexpectedErrorPosix(err),
1919 };
1920}
1921
1922pub const WindowsGetStdHandleErrs = error{
1923 NoStdHandles,
1924
1925 /// See https://github.com/ziglang/zig/issues/1396
1926 Unexpected,
1927};
1928
1929pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
1930 if (windows.GetStdHandle(handle_id)) |handle| {
1931 if (handle == windows.INVALID_HANDLE_VALUE) {
1932 const err = windows.GetLastError();
1933 return switch (err) {
1934 else => os.unexpectedErrorWindows(err),
1935 };
1936 }
1937 return handle;
1938 } else {
1939 return error.NoStdHandles;
1940 }
1941}
1942
1943pub const ArgIteratorPosix = struct {
1944 index: usize,
1945 count: usize,
1946
1947 pub fn init() ArgIteratorPosix {
1948 return ArgIteratorPosix{
1949 .index = 0,
1950 .count = raw.len,
1951 };
1952 }
1953
1954 pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
1955 if (self.index == self.count) return null;
1956
1957 const s = raw[self.index];
1958 self.index += 1;
1959 return cstr.toSlice(s);
1960 }
1961
1962 pub fn skip(self: *ArgIteratorPosix) bool {
1963 if (self.index == self.count) return false;
1964
1965 self.index += 1;
1966 return true;
1967 }
1968
1969 /// This is marked as public but actually it's only meant to be used
1970 /// internally by zig's startup code.
1971 pub var raw: [][*]u8 = undefined;
1972};
1973
1974pub const ArgIteratorWindows = struct {
1975 index: usize,
1976 cmd_line: [*]const u8,
1977 in_quote: bool,
1978 quote_count: usize,
1979 seen_quote_count: usize,
1980
1981 pub const NextError = error{OutOfMemory};
1982
1983 pub fn init() ArgIteratorWindows {
1984 return initWithCmdLine(windows.GetCommandLineA());
1985 }
1986
1987 pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
1988 return ArgIteratorWindows{
1989 .index = 0,
1990 .cmd_line = cmd_line,
1991 .in_quote = false,
1992 .quote_count = countQuotes(cmd_line),
1993 .seen_quote_count = 0,
1994 };
1995 }
1996
1997 /// You must free the returned memory when done.
1998 pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
1999 // march forward over whitespace
2000 while (true) : (self.index += 1) {
2001 const byte = self.cmd_line[self.index];
2002 switch (byte) {
2003 0 => return null,
2004 ' ', '\t' => continue,
2005 else => break,
2006 }
2007 }
2008
2009 return self.internalNext(allocator);
2010 }
2011
2012 pub fn skip(self: *ArgIteratorWindows) bool {
2013 // march forward over whitespace
2014 while (true) : (self.index += 1) {
2015 const byte = self.cmd_line[self.index];
2016 switch (byte) {
2017 0 => return false,
2018 ' ', '\t' => continue,
2019 else => break,
2020 }
2021 }
2022
2023 var backslash_count: usize = 0;
2024 while (true) : (self.index += 1) {
2025 const byte = self.cmd_line[self.index];
2026 switch (byte) {
2027 0 => return true,
2028 '"' => {
2029 const quote_is_real = backslash_count % 2 == 0;
2030 if (quote_is_real) {
2031 self.seen_quote_count += 1;
2032 }
2033 },
2034 '\\' => {
2035 backslash_count += 1;
2036 },
2037 ' ', '\t' => {
2038 if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
2039 return true;
2040 }
2041 backslash_count = 0;
2042 },
2043 else => {
2044 backslash_count = 0;
2045 continue;
2046 },
2047 }
2048 }
2049 }
2050
2051 fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
2052 var buf = try Buffer.initSize(allocator, 0);
2053 defer buf.deinit();
2054
2055 var backslash_count: usize = 0;
2056 while (true) : (self.index += 1) {
2057 const byte = self.cmd_line[self.index];
2058 switch (byte) {
2059 0 => return buf.toOwnedSlice(),
2060 '"' => {
2061 const quote_is_real = backslash_count % 2 == 0;
2062 try self.emitBackslashes(&buf, backslash_count / 2);
2063 backslash_count = 0;
2064
2065 if (quote_is_real) {
2066 self.seen_quote_count += 1;
2067 if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
2068 try buf.appendByte('"');
2069 }
2070 } else {
2071 try buf.appendByte('"');
2072 }
2073 },
2074 '\\' => {
2075 backslash_count += 1;
2076 },
2077 ' ', '\t' => {
2078 try self.emitBackslashes(&buf, backslash_count);
2079 backslash_count = 0;
2080 if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
2081 try buf.appendByte(byte);
2082 } else {
2083 return buf.toOwnedSlice();
2084 }
2085 },
2086 else => {
2087 try self.emitBackslashes(&buf, backslash_count);
2088 backslash_count = 0;
2089 try buf.appendByte(byte);
2090 },
2091 }
2092 }
2093 }
2094
2095 fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
2096 var i: usize = 0;
2097 while (i < emit_count) : (i += 1) {
2098 try buf.appendByte('\\');
2099 }
2100 }
2101
2102 fn countQuotes(cmd_line: [*]const u8) usize {
2103 var result: usize = 0;
2104 var backslash_count: usize = 0;
2105 var index: usize = 0;
2106 while (true) : (index += 1) {
2107 const byte = cmd_line[index];
2108 switch (byte) {
2109 0 => return result,
2110 '\\' => backslash_count += 1,
2111 '"' => {
2112 result += 1 - (backslash_count % 2);
2113 backslash_count = 0;
2114 },
2115 else => {
2116 backslash_count = 0;
2117 },
2118 }
2119 }
2120 }
2121};
2122
2123pub const ArgIterator = struct {
2124 const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
2125
2126 inner: InnerType,
2127
2128 pub fn init() ArgIterator {
2129 return ArgIterator{ .inner = InnerType.init() };
2130 }
2131
2132 pub const NextError = ArgIteratorWindows.NextError;
2133
2134 /// You must free the returned memory when done.
2135 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
2136 if (builtin.os == Os.windows) {
2137 return self.inner.next(allocator);
2138 } else {
2139 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
2140 }
2141 }
2142
2143 /// If you only are targeting posix you can call this and not need an allocator.
2144 pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
2145 return self.inner.next();
2146 }
2147
2148 /// Parse past 1 argument without capturing it.
2149 /// Returns `true` if skipped an arg, `false` if we are at the end.
2150 pub fn skip(self: *ArgIterator) bool {
2151 return self.inner.skip();
2152 }
2153};
2154
2155pub fn args() ArgIterator {
2156 return ArgIterator.init();
2157}
2158
2159/// Caller must call argsFree on result.
2160pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
2161 // TODO refactor to only make 1 allocation.
2162 var it = args();
2163 var contents = try Buffer.initSize(allocator, 0);
2164 defer contents.deinit();
2165
2166 var slice_list = ArrayList(usize).init(allocator);
2167 defer slice_list.deinit();
2168
2169 while (it.next(allocator)) |arg_or_err| {
2170 const arg = try arg_or_err;
2171 defer allocator.free(arg);
2172 try contents.append(arg);
2173 try slice_list.append(arg.len);
2174 }
2175
2176 const contents_slice = contents.toSliceConst();
2177 const slice_sizes = slice_list.toSliceConst();
2178 const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
2179 const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
2180 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
2181 errdefer allocator.free(buf);
2182
2183 const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
2184 const result_contents = buf[slice_list_bytes..];
2185 mem.copy(u8, result_contents, contents_slice);
2186
2187 var contents_index: usize = 0;
2188 for (slice_sizes) |len, i| {
2189 const new_index = contents_index + len;
2190 result_slice_list[i] = result_contents[contents_index..new_index];
2191 contents_index = new_index;
2192 }
2193
2194 return result_slice_list;
2195}
2196
2197pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
2198 var total_bytes: usize = 0;
2199 for (args_alloc) |arg| {
2200 total_bytes += @sizeOf([]u8) + arg.len;
2201 }
2202 const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
2203 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
2204 return allocator.free(aligned_allocated_buf);
2205}
2206
2207test "windows arg parsing" {
2208 testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
2209 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
2210 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
2211 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
2212 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
2213 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
2214
2215 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
2216 ".\\..\\zig-cache\\build",
2217 "bin\\zig.exe",
2218 ".\\..",
2219 ".\\..\\zig-cache",
2220 "--help",
2221 });
2222}
2223
2224fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
2225 var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
2226 for (expected_args) |expected_arg| {
2227 const arg = it.next(debug.global_allocator).? catch unreachable;
2228 testing.expectEqualSlices(u8, expected_arg, arg);
2229 }
2230 testing.expect(it.next(debug.global_allocator) == null);
2231}
2232
2233// TODO make this a build variable that you can set
2234const unexpected_error_tracing = false;
2235const UnexpectedError = error{
2236 /// The Operating System returned an undocumented error code.
2237 Unexpected,
2238};
2239
2240/// Call this when you made a syscall or something that sets errno
2241/// and you get an unexpected error.
2242pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2243 if (unexpected_error_tracing) {
2244 debug.warn("unexpected errno: {}\n", errno);
2245 debug.dumpCurrentStackTrace(null);
2246 }
2247 return error.Unexpected;
2248}
2249
2250/// Call this when you made a windows DLL call or something that does SetLastError
2251/// and you get an unexpected error.
2252pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2253 if (unexpected_error_tracing) {
2254 debug.warn("unexpected GetLastError(): {}\n", err);
2255 @breakpoint();
2256 debug.dumpCurrentStackTrace(null);
2257 }
2258 return error.Unexpected;
2259}
2260
2261pub fn openSelfExe() !os.File {
2262 switch (builtin.os) {
2263 Os.linux => return os.File.openReadC(c"/proc/self/exe"),
2264 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
2265 var buf: [MAX_PATH_BYTES]u8 = undefined;
2266 const self_exe_path = try selfExePath(&buf);
2267 buf[self_exe_path.len] = 0;
2268 return os.File.openReadC(self_exe_path.ptr);
2269 },
2270 Os.windows => {
2271 var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2272 const wide_slice = try selfExePathW(&buf);
2273 return os.File.openReadW(wide_slice.ptr);
2274 },
2275 else => @compileError("Unsupported OS"),
2276 }
2277}
2278
2279test "openSelfExe" {
2280 switch (builtin.os) {
2281 Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
2282 else => return error.SkipZigTest, // Unsupported OS.
2283 }
2284}
2285
2286pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
2287 const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
2288 const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
2289 assert(rc <= out_buffer.len);
2290 if (rc == 0) {
2291 const err = windows.GetLastError();
2292 switch (err) {
2293 else => return unexpectedErrorWindows(err),
2294 }
2295 }
2296 return out_buffer[0..rc];
2297}
2298
2299/// Get the path to the current executable.
2300/// If you only need the directory, use selfExeDirPath.
2301/// If you only want an open file handle, use openSelfExe.
2302/// This function may return an error if the current executable
2303/// was deleted after spawning.
2304/// Returned value is a slice of out_buffer.
2305///
2306/// On Linux, depends on procfs being mounted. If the currently executing binary has
2307/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
2308/// TODO make the return type of this a null terminated pointer
2309pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
2310 switch (builtin.os) {
2311 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
2312 Os.freebsd => {
2313 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
2314 var out_len: usize = out_buffer.len;
2315 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
2316
2317 if (err == 0) return mem.toSlice(u8, out_buffer);
2318
2319 return switch (err) {
2320 posix.EFAULT => error.BadAdress,
2321 posix.EPERM => error.PermissionDenied,
2322 else => unexpectedErrorPosix(err),
2323 };
2324 },
2325 Os.netbsd => {
2326 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
2327 var out_len: usize = out_buffer.len;
2328 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
2329
2330 if (err == 0) return mem.toSlice(u8, out_buffer);
2331
2332 return switch (err) {
2333 posix.EFAULT => error.BadAdress,
2334 posix.EPERM => error.PermissionDenied,
2335 else => unexpectedErrorPosix(err),
2336 };
2337 },
2338 Os.windows => {
2339 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2340 const utf16le_slice = try selfExePathW(&utf16le_buf);
2341 // Trust that Windows gives us valid UTF-16LE.
2342 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
2343 return out_buffer[0..end_index];
2344 },
2345 Os.macosx, Os.ios => {
2346 var u32_len: u32 = @intCast(u32, out_buffer.len); // TODO shouldn't need this cast
2347 const rc = c._NSGetExecutablePath(out_buffer, &u32_len);
2348 if (rc != 0) return error.NameTooLong;
2349 return mem.toSlice(u8, out_buffer);
2350 },
2351 else => @compileError("Unsupported OS"),
2352 }
2353}
2354
2355/// `selfExeDirPath` except allocates the result on the heap.
2356/// Caller owns returned memory.
2357pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
2358 var buf: [MAX_PATH_BYTES]u8 = undefined;
2359 return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
2360}
2361
2362/// Get the directory path that contains the current executable.
2363/// Returned value is a slice of out_buffer.
2364pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
2365 switch (builtin.os) {
2366 Os.linux => {
2367 // If the currently executing binary has been deleted,
2368 // the file path looks something like `/a/b/c/exe (deleted)`
2369 // This path cannot be opened, but it's valid for determining the directory
2370 // the executable was in when it was run.
2371 const full_exe_path = try readLinkC(out_buffer, c"/proc/self/exe");
2372 // Assume that /proc/self/exe has an absolute path, and therefore dirname
2373 // will not return null.
2374 return path.dirname(full_exe_path).?;
2375 },
2376 Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
2377 const self_exe_path = try selfExePath(out_buffer);
2378 // Assume that the OS APIs return absolute paths, and therefore dirname
2379 // will not return null.
2380 return path.dirname(self_exe_path).?;
2381 },
2382 else => @compileError("Unsupported OS"),
2383 }
2384}
2385
2386pub fn isTty(handle: FileHandle) bool {
2387 if (is_windows) {
2388 return windows_util.windowsIsTty(handle);
2389 } else {
2390 if (builtin.link_libc) {
2391 return c.isatty(handle) != 0;
2392 } else {
2393 return posix.isatty(handle);
2394 }
2395 }
2396}
2397
2398pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
2399 if (is_windows) {
2400 return windows_util.windowsIsCygwinPty(handle);
2401 } else {
2402 if (builtin.link_libc) {
2403 return c.isatty(handle) != 0;
2404 } else {
2405 return posix.isatty(handle);
2406 }
2407 }
2408}
2409
2410pub const PosixSocketError = error{
2411 /// Permission to create a socket of the specified type and/or
2412 /// pro‐tocol is denied.
2413 PermissionDenied,
2414
2415 /// The implementation does not support the specified address family.
2416 AddressFamilyNotSupported,
2417
2418 /// Unknown protocol, or protocol family not available.
2419 ProtocolFamilyNotAvailable,
2420
2421 /// The per-process limit on the number of open file descriptors has been reached.
2422 ProcessFdQuotaExceeded,
2423
2424 /// The system-wide limit on the total number of open files has been reached.
2425 SystemFdQuotaExceeded,
2426
2427 /// Insufficient memory is available. The socket cannot be created until sufficient
2428 /// resources are freed.
2429 SystemResources,
2430
2431 /// The protocol type or the specified protocol is not supported within this domain.
2432 ProtocolNotSupported,
2433};
2434
2435pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
2436 const rc = posix.socket(domain, socket_type, protocol);
2437 const err = posix.getErrno(rc);
2438 switch (err) {
2439 0 => return @intCast(i32, rc),
2440 posix.EACCES => return PosixSocketError.PermissionDenied,
2441 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
2442 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
2443 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
2444 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
2445 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
2446 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
2447 else => return unexpectedErrorPosix(err),
2448 }
2449}
2450
2451pub const PosixBindError = error{
2452 /// The address is protected, and the user is not the superuser.
2453 /// For UNIX domain sockets: Search permission is denied on a component
2454 /// of the path prefix.
2455 AccessDenied,
2456
2457 /// The given address is already in use, or in the case of Internet domain sockets,
2458 /// The port number was specified as zero in the socket
2459 /// address structure, but, upon attempting to bind to an ephemeral port, it was
2460 /// determined that all port numbers in the ephemeral port range are currently in
2461 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
2462 AddressInUse,
2463
2464 /// A nonexistent interface was requested or the requested address was not local.
2465 AddressNotAvailable,
2466
2467 /// Too many symbolic links were encountered in resolving addr.
2468 SymLinkLoop,
2469
2470 /// addr is too long.
2471 NameTooLong,
2472
2473 /// A component in the directory prefix of the socket pathname does not exist.
2474 FileNotFound,
2475
2476 /// Insufficient kernel memory was available.
2477 SystemResources,
2478
2479 /// A component of the path prefix is not a directory.
2480 NotDir,
2481
2482 /// The socket inode would reside on a read-only filesystem.
2483 ReadOnlyFileSystem,
2484
2485 /// See https://github.com/ziglang/zig/issues/1396
2486 Unexpected,
2487};
2488
2489/// addr is `&const T` where T is one of the sockaddr
2490pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
2491 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
2492 const err = posix.getErrno(rc);
2493 switch (err) {
2494 0 => return,
2495 posix.EACCES => return PosixBindError.AccessDenied,
2496 posix.EADDRINUSE => return PosixBindError.AddressInUse,
2497 posix.EBADF => unreachable, // always a race condition if this error is returned
2498 posix.EINVAL => unreachable,
2499 posix.ENOTSOCK => unreachable,
2500 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
2501 posix.EFAULT => unreachable,
2502 posix.ELOOP => return PosixBindError.SymLinkLoop,
2503 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
2504 posix.ENOENT => return PosixBindError.FileNotFound,
2505 posix.ENOMEM => return PosixBindError.SystemResources,
2506 posix.ENOTDIR => return PosixBindError.NotDir,
2507 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
2508 else => return unexpectedErrorPosix(err),
2509 }
2510}
2511
2512const PosixListenError = error{
2513 /// Another socket is already listening on the same port.
2514 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2515 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
2516 /// was determined that all port numbers in the ephemeral port range are currently in
2517 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2518 AddressInUse,
2519
2520 /// The file descriptor sockfd does not refer to a socket.
2521 FileDescriptorNotASocket,
2522
2523 /// The socket is not of a type that supports the listen() operation.
2524 OperationNotSupported,
2525
2526 /// See https://github.com/ziglang/zig/issues/1396
2527 Unexpected,
2528};
2529
2530pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2531 const rc = posix.listen(sockfd, backlog);
2532 const err = posix.getErrno(rc);
2533 switch (err) {
2534 0 => return,
2535 posix.EADDRINUSE => return PosixListenError.AddressInUse,
2536 posix.EBADF => unreachable,
2537 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
2538 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
2539 else => return unexpectedErrorPosix(err),
2540 }
2541}
2542
2543pub const PosixAcceptError = error{
2544 ConnectionAborted,
2545
2546 /// The per-process limit on the number of open file descriptors has been reached.
2547 ProcessFdQuotaExceeded,
2548
2549 /// The system-wide limit on the total number of open files has been reached.
2550 SystemFdQuotaExceeded,
2551
2552 /// Not enough free memory. This often means that the memory allocation is limited
2553 /// by the socket buffer limits, not by the system memory.
2554 SystemResources,
2555
2556 /// The file descriptor sockfd does not refer to a socket.
2557 FileDescriptorNotASocket,
2558
2559 /// The referenced socket is not of type SOCK_STREAM.
2560 OperationNotSupported,
2561
2562 ProtocolFailure,
2563
2564 /// Firewall rules forbid connection.
2565 BlockedByFirewall,
2566
2567 /// See https://github.com/ziglang/zig/issues/1396
2568 Unexpected,
2569};
2570
2571pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2572 while (true) {
2573 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2574 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2575 const err = posix.getErrno(rc);
2576 switch (err) {
2577 0 => return @intCast(i32, rc),
2578 posix.EINTR => continue,
2579 else => return unexpectedErrorPosix(err),
2580
2581 posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
2582 posix.EBADF => unreachable, // always a race condition
2583 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2584 posix.EFAULT => unreachable,
2585 posix.EINVAL => unreachable,
2586 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2587 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2588 posix.ENOBUFS => return PosixAcceptError.SystemResources,
2589 posix.ENOMEM => return PosixAcceptError.SystemResources,
2590 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2591 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2592 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2593 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2594 }
2595 }
2596}
2597
2598/// Returns -1 if would block.
2599pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2600 while (true) {
2601 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2602 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2603 const err = posix.getErrno(rc);
2604 switch (err) {
2605 0 => return @intCast(i32, rc),
2606 posix.EINTR => continue,
2607 else => return unexpectedErrorPosix(err),
2608
2609 posix.EAGAIN => return -1,
2610 posix.EBADF => unreachable, // always a race condition
2611 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2612 posix.EFAULT => unreachable,
2613 posix.EINVAL => unreachable,
2614 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2615 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2616 posix.ENOBUFS => return PosixAcceptError.SystemResources,
2617 posix.ENOMEM => return PosixAcceptError.SystemResources,
2618 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2619 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2620 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2621 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2622 }
2623 }
2624}
2625
2626pub const LinuxEpollCreateError = error{
2627 /// The per-user limit on the number of epoll instances imposed by
2628 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2629 /// details.
2630 /// Or, The per-process limit on the number of open file descriptors has been reached.
2631 ProcessFdQuotaExceeded,
2632
2633 /// The system-wide limit on the total number of open files has been reached.
2634 SystemFdQuotaExceeded,
2635
2636 /// There was insufficient memory to create the kernel object.
2637 SystemResources,
2638
2639 /// See https://github.com/ziglang/zig/issues/1396
2640 Unexpected,
2641};
2642
2643pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2644 const rc = posix.epoll_create1(flags);
2645 const err = posix.getErrno(rc);
2646 switch (err) {
2647 0 => return @intCast(i32, rc),
2648 else => return unexpectedErrorPosix(err),
2649
2650 posix.EINVAL => unreachable,
2651 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
2652 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
2653 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
2654 }
2655}
2656
2657pub const LinuxEpollCtlError = error{
2658 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2659 /// with this epoll instance.
2660 FileDescriptorAlreadyPresentInSet,
2661
2662 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
2663 /// circular loop of epoll instances monitoring one another.
2664 OperationCausesCircularLoop,
2665
2666 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
2667 /// instance.
2668 FileDescriptorNotRegistered,
2669
2670 /// There was insufficient memory to handle the requested op control operation.
2671 SystemResources,
2672
2673 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
2674 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
2675 /// See epoll(7) for further details.
2676 UserResourceLimitReached,
2677
2678 /// The target file fd does not support epoll. This error can occur if fd refers to,
2679 /// for example, a regular file or a directory.
2680 FileDescriptorIncompatibleWithEpoll,
2681
2682 /// See https://github.com/ziglang/zig/issues/1396
2683 Unexpected,
2684};
2685
2686pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
2687 const rc = posix.epoll_ctl(epfd, op, fd, event);
2688 const err = posix.getErrno(rc);
2689 switch (err) {
2690 0 => return,
2691 else => return unexpectedErrorPosix(err),
2692
2693 posix.EBADF => unreachable, // always a race condition if this happens
2694 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
2695 posix.EINVAL => unreachable,
2696 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
2697 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
2698 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
2699 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
2700 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
2701 }
2702}
2703
2704pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2705 while (true) {
2706 const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
2707 const err = posix.getErrno(rc);
2708 switch (err) {
2709 0 => return rc,
2710 posix.EINTR => continue,
2711 posix.EBADF => unreachable,
2712 posix.EFAULT => unreachable,
2713 posix.EINVAL => unreachable,
2714 else => unreachable,
2715 }
2716 }
2717}
2718
2719pub const LinuxEventFdError = error{
2720 InvalidFlagValue,
2721 SystemResources,
2722 ProcessFdQuotaExceeded,
2723 SystemFdQuotaExceeded,
2724
2725 /// See https://github.com/ziglang/zig/issues/1396
2726 Unexpected,
2727};
2728
2729pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
2730 const rc = posix.eventfd(initval, flags);
2731 const err = posix.getErrno(rc);
2732 switch (err) {
2733 0 => return @intCast(i32, rc),
2734 else => return unexpectedErrorPosix(err),
2735
2736 posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
2737 posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
2738 posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
2739 posix.ENODEV => return LinuxEventFdError.SystemResources,
2740 posix.ENOMEM => return LinuxEventFdError.SystemResources,
2741 }
2742}
2743
2744pub const PosixGetSockNameError = error{
2745 /// Insufficient resources were available in the system to perform the operation.
2746 SystemResources,
2747
2748 /// See https://github.com/ziglang/zig/issues/1396
2749 Unexpected,
2750};
2751
2752pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2753 var addr: posix.sockaddr = undefined;
2754 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
2755 const rc = posix.getsockname(sockfd, &addr, &addrlen);
2756 const err = posix.getErrno(rc);
2757 switch (err) {
2758 0 => return addr,
2759 else => return unexpectedErrorPosix(err),
2760
2761 posix.EBADF => unreachable,
2762 posix.EFAULT => unreachable,
2763 posix.EINVAL => unreachable,
2764 posix.ENOTSOCK => unreachable,
2765 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2766 }
2767}
2768
2769pub const PosixConnectError = error{
2770 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2771 /// file, or search permission is denied for one of the directories in the path prefix.
2772 /// or
2773 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2774 /// the connection request failed because of a local firewall rule.
2775 PermissionDenied,
2776
2777 /// Local address is already in use.
2778 AddressInUse,
2779
2780 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2781 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2782 /// in the ephemeral port range are currently in use. See the discussion of
2783 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2784 AddressNotAvailable,
2785
2786 /// The passed address didn't have the correct address family in its sa_family field.
2787 AddressFamilyNotSupported,
2788
2789 /// Insufficient entries in the routing cache.
2790 SystemResources,
2791
2792 /// A connect() on a stream socket found no one listening on the remote address.
2793 ConnectionRefused,
2794
2795 /// Network is unreachable.
2796 NetworkUnreachable,
2797
2798 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2799 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2800 ConnectionTimedOut,
2801
2802 /// See https://github.com/ziglang/zig/issues/1396
2803 Unexpected,
2804};
2805
2806pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
2807 while (true) {
2808 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2809 const err = posix.getErrno(rc);
2810 switch (err) {
2811 0 => return,
2812 else => return unexpectedErrorPosix(err),
2813
2814 posix.EACCES => return PosixConnectError.PermissionDenied,
2815 posix.EPERM => return PosixConnectError.PermissionDenied,
2816 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2817 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2818 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2819 posix.EAGAIN => return PosixConnectError.SystemResources,
2820 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2821 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2822 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2823 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2824 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2825 posix.EINTR => continue,
2826 posix.EISCONN => unreachable, // The socket is already connected.
2827 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2828 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2829 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2830 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2831 }
2832 }
2833}
2834
2835/// Same as posixConnect except it is for blocking socket file descriptors.
2836/// It expects to receive EINPROGRESS.
2837pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
2838 while (true) {
2839 const rc = posix.connect(sockfd, sockaddr, len);
2840 const err = posix.getErrno(rc);
2841 switch (err) {
2842 0, posix.EINPROGRESS => return,
2843 else => return unexpectedErrorPosix(err),
2844
2845 posix.EACCES => return PosixConnectError.PermissionDenied,
2846 posix.EPERM => return PosixConnectError.PermissionDenied,
2847 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2848 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2849 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2850 posix.EAGAIN => return PosixConnectError.SystemResources,
2851 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2852 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2853 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2854 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2855 posix.EINTR => continue,
2856 posix.EISCONN => unreachable, // The socket is already connected.
2857 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2858 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2859 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2860 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2861 }
2862 }
2863}
2864
2865pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2866 var err_code: i32 = undefined;
2867 var size: u32 = @sizeOf(i32);
2868 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
2869 assert(size == 4);
2870 const err = posix.getErrno(rc);
2871 switch (err) {
2872 0 => switch (err_code) {
2873 0 => return,
2874 else => return unexpectedErrorPosix(err),
2875
2876 posix.EACCES => return PosixConnectError.PermissionDenied,
2877 posix.EPERM => return PosixConnectError.PermissionDenied,
2878 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2879 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2880 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2881 posix.EAGAIN => return PosixConnectError.SystemResources,
2882 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2883 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2884 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2885 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2886 posix.EISCONN => unreachable, // The socket is already connected.
2887 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2888 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2889 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2890 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2891 },
2892 else => return unexpectedErrorPosix(err),
2893 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2894 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2895 posix.EINVAL => unreachable,
2896 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2897 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2898 }
2899}
2900
2901pub const Thread = struct {
2902 data: Data,
2903
2904 pub const use_pthreads = is_posix and builtin.link_libc;
2905
2906 /// Represents a kernel thread handle.
2907 /// May be an integer or a pointer depending on the platform.
2908 /// On Linux and POSIX, this is the same as Id.
2909 pub const Handle = if (use_pthreads)
2910 c.pthread_t
2911 else switch (builtin.os) {
2912 builtin.Os.linux => i32,
2913 builtin.Os.windows => windows.HANDLE,
2914 else => @compileError("Unsupported OS"),
2915 };
2916
2917 /// Represents a unique ID per thread.
2918 /// May be an integer or pointer depending on the platform.
2919 /// On Linux and POSIX, this is the same as Handle.
2920 pub const Id = switch (builtin.os) {
2921 builtin.Os.windows => windows.DWORD,
2922 else => Handle,
2923 };
2924
2925 pub const Data = if (use_pthreads)
2926 struct {
2927 handle: Thread.Handle,
2928 mmap_addr: usize,
2929 mmap_len: usize,
2930 }
2931 else switch (builtin.os) {
2932 builtin.Os.linux => struct {
2933 handle: Thread.Handle,
2934 mmap_addr: usize,
2935 mmap_len: usize,
2936 tls_end_addr: usize,
2937 },
2938 builtin.Os.windows => struct {
2939 handle: Thread.Handle,
2940 alloc_start: *c_void,
2941 heap_handle: windows.HANDLE,
2942 },
2943 else => @compileError("Unsupported OS"),
2944 };
2945
2946 /// Returns the ID of the calling thread.
2947 /// Makes a syscall every time the function is called.
2948 /// On Linux and POSIX, this Id is the same as a Handle.
2949 pub fn getCurrentId() Id {
2950 if (use_pthreads) {
2951 return c.pthread_self();
2952 } else
2953 return switch (builtin.os) {
2954 builtin.Os.linux => linux.gettid(),
2955 builtin.Os.windows => windows.GetCurrentThreadId(),
2956 else => @compileError("Unsupported OS"),
2957 };
2958 }
2959
2960 /// Returns the handle of this thread.
2961 /// On Linux and POSIX, this is the same as Id.
2962 pub fn handle(self: Thread) Handle {
2963 return self.data.handle;
2964 }
2965
2966 pub fn wait(self: *const Thread) void {
2967 if (use_pthreads) {
2968 const err = c.pthread_join(self.data.handle, null);
2969 switch (err) {
2970 0 => {},
2971 posix.EINVAL => unreachable,
2972 posix.ESRCH => unreachable,
2973 posix.EDEADLK => unreachable,
2974 else => unreachable,
2975 }
2976 assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
2977 } else switch (builtin.os) {
2978 builtin.Os.linux => {
2979 while (true) {
2980 const pid_value = @atomicLoad(i32, &self.data.handle, builtin.AtomicOrder.SeqCst);
2981 if (pid_value == 0) break;
2982 const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null);
2983 switch (linux.getErrno(rc)) {
2984 0 => continue,
2985 posix.EINTR => continue,
2986 posix.EAGAIN => continue,
2987 else => unreachable,
2988 }
2989 }
2990 assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
2991 },
2992 builtin.Os.windows => {
2993 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
2994 assert(windows.CloseHandle(self.data.handle) != 0);
2995 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
2996 },
2997 else => @compileError("Unsupported OS"),
2998 }
2999 }
3000};
3001
3002pub const SpawnThreadError = error{
3003 /// A system-imposed limit on the number of threads was encountered.
3004 /// There are a number of limits that may trigger this error:
3005 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
3006 /// which limits the number of processes and threads for a real
3007 /// user ID, was reached;
3008 /// * the kernel's system-wide limit on the number of processes and
3009 /// threads, /proc/sys/kernel/threads-max, was reached (see
3010 /// proc(5));
3011 /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
3012 /// reached (see proc(5)); or
3013 /// * the PID limit (pids.max) imposed by the cgroup "process num‐
3014 /// ber" (PIDs) controller was reached.
3015 ThreadQuotaExceeded,
3016
3017 /// The kernel cannot allocate sufficient memory to allocate a task structure
3018 /// for the child, or to copy those parts of the caller's context that need to
3019 /// be copied.
3020 SystemResources,
3021
3022 /// Not enough userland memory to spawn the thread.
3023 OutOfMemory,
3024
3025 /// See https://github.com/ziglang/zig/issues/1396
3026 Unexpected,
3027};
3028
3029pub var linux_tls_phdr: ?*std.elf.Phdr = null;
3030pub var linux_tls_img_src: [*]const u8 = undefined; // defined if linux_tls_phdr is
3031
3032/// caller must call wait on the returned thread
3033/// fn startFn(@typeOf(context)) T
3034/// where T is u8, noreturn, void, or !void
3035/// caller must call wait on the returned thread
3036pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
3037 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
3038 // TODO compile-time call graph analysis to determine stack upper bound
3039 // https://github.com/ziglang/zig/issues/157
3040 const default_stack_size = 8 * 1024 * 1024;
3041
3042 const Context = @typeOf(context);
3043 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
3044
3045 if (builtin.os == builtin.Os.windows) {
3046 const WinThread = struct {
3047 const OuterContext = struct {
3048 thread: Thread,
3049 inner: Context,
3050 };
3051 extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
3052 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
3053 switch (@typeId(@typeOf(startFn).ReturnType)) {
3054 builtin.TypeId.Int => {
3055 return startFn(arg);
3056 },
3057 builtin.TypeId.Void => {
3058 startFn(arg);
3059 return 0;
3060 },
3061 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
3062 }
3063 }
3064 };
3065
3066 const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
3067 const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
3068 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
3069 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
3070 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
3071 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
3072 outer_context.* = WinThread.OuterContext{
3073 .thread = Thread{
3074 .data = Thread.Data{
3075 .heap_handle = heap_handle,
3076 .alloc_start = bytes_ptr,
3077 .handle = undefined,
3078 },
3079 },
3080 .inner = context,
3081 };
3082
3083 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
3084 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
3085 const err = windows.GetLastError();
3086 return switch (err) {
3087 else => os.unexpectedErrorWindows(err),
3088 };
3089 };
3090 return &outer_context.thread;
3091 }
3092
3093 const MainFuncs = struct {
3094 extern fn linuxThreadMain(ctx_addr: usize) u8 {
3095 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
3096
3097 switch (@typeId(@typeOf(startFn).ReturnType)) {
3098 builtin.TypeId.Int => {
3099 return startFn(arg);
3100 },
3101 builtin.TypeId.Void => {
3102 startFn(arg);
3103 return 0;
3104 },
3105 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
3106 }
3107 }
3108 extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
3109 if (@sizeOf(Context) == 0) {
3110 _ = startFn({});
3111 return null;
3112 } else {
3113 _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
3114 return null;
3115 }
3116 }
3117 };
3118
3119 const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
3120
3121 var stack_end_offset: usize = undefined;
3122 var thread_start_offset: usize = undefined;
3123 var context_start_offset: usize = undefined;
3124 var tls_start_offset: usize = undefined;
3125 const mmap_len = blk: {
3126 // First in memory will be the stack, which grows downwards.
3127 var l: usize = mem.alignForward(default_stack_size, os.page_size);
3128 stack_end_offset = l;
3129 // Above the stack, so that it can be in the same mmap call, put the Thread object.
3130 l = mem.alignForward(l, @alignOf(Thread));
3131 thread_start_offset = l;
3132 l += @sizeOf(Thread);
3133 // Next, the Context object.
3134 if (@sizeOf(Context) != 0) {
3135 l = mem.alignForward(l, @alignOf(Context));
3136 context_start_offset = l;
3137 l += @sizeOf(Context);
3138 }
3139 // Finally, the Thread Local Storage, if any.
3140 if (!Thread.use_pthreads) {
3141 if (linux_tls_phdr) |tls_phdr| {
3142 l = mem.alignForward(l, tls_phdr.p_align);
3143 tls_start_offset = l;
3144 l += tls_phdr.p_memsz;
3145 }
3146 }
3147 break :blk l;
3148 };
3149 const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
3150 if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
3151 errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
3152
3153 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
3154 thread_ptr.data.mmap_addr = mmap_addr;
3155 thread_ptr.data.mmap_len = mmap_len;
3156
3157 var arg: usize = undefined;
3158 if (@sizeOf(Context) != 0) {
3159 arg = mmap_addr + context_start_offset;
3160 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
3161 context_ptr.* = context;
3162 }
3163
3164 if (Thread.use_pthreads) {
3165 // use pthreads
3166 var attr: c.pthread_attr_t = undefined;
3167 if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
3168 defer assert(c.pthread_attr_destroy(&attr) == 0);
3169
3170 assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
3171
3172 const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
3173 switch (err) {
3174 0 => return thread_ptr,
3175 posix.EAGAIN => return SpawnThreadError.SystemResources,
3176 posix.EPERM => unreachable,
3177 posix.EINVAL => unreachable,
3178 else => return unexpectedErrorPosix(@intCast(usize, err)),
3179 }
3180 } else if (builtin.os == builtin.Os.linux) {
3181 var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
3182 posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
3183 posix.CLONE_DETACHED;
3184 var newtls: usize = undefined;
3185 if (linux_tls_phdr) |tls_phdr| {
3186 @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz);
3187 thread_ptr.data.tls_end_addr = mmap_addr + mmap_len;
3188 newtls = @ptrToInt(&thread_ptr.data.tls_end_addr);
3189 flags |= posix.CLONE_SETTLS;
3190 }
3191 const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
3192 const err = posix.getErrno(rc);
3193 switch (err) {
3194 0 => return thread_ptr,
3195 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
3196 posix.EINVAL => unreachable,
3197 posix.ENOMEM => return SpawnThreadError.SystemResources,
3198 posix.ENOSPC => unreachable,
3199 posix.EPERM => unreachable,
3200 posix.EUSERS => unreachable,
3201 else => return unexpectedErrorPosix(err),
3202 }
3203 } else {
3204 @compileError("Unsupported OS");
3205 }
3206}
3207
3208pub fn posixWait(pid: i32) i32 {
3209 var status: i32 = undefined;
3210 while (true) {
3211 const err = posix.getErrno(posix.waitpid(pid, &status, 0));
3212 switch (err) {
3213 0 => return status,
3214 posix.EINTR => continue,
3215 posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
3216 posix.EINVAL => unreachable, // The options argument was invalid
3217 else => unreachable,
3218 }
3219 }
3220}
3221
3222pub fn posixFStat(fd: i32) !posix.Stat {
3223 var stat: posix.Stat = undefined;
3224 const err = posix.getErrno(posix.fstat(fd, &stat));
3225 if (err > 0) {
3226 return switch (err) {
3227 // We do not make this an error code because if you get EBADF it's always a bug,
3228 // since the fd could have been reused.
3229 posix.EBADF => unreachable,
3230 posix.ENOMEM => error.SystemResources,
3231 else => os.unexpectedErrorPosix(err),
3232 };
3233 }
3234
3235 return stat;
3236}
3237
3238pub const CpuCountError = error{
3239 OutOfMemory,
3240 PermissionDenied,
3241
3242 /// See https://github.com/ziglang/zig/issues/1396
3243 Unexpected,
3244};
3245
3246pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
3247 switch (builtin.os) {
3248 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
3249 var count: c_int = undefined;
3250 var count_len: usize = @sizeOf(c_int);
3251 const rc = posix.sysctlbyname(switch (builtin.os) {
3252 builtin.Os.macosx => c"hw.logicalcpu",
3253 else => c"hw.ncpu",
3254 }, @ptrCast(*c_void, &count), &count_len, null, 0);
3255 const err = posix.getErrno(rc);
3256 switch (err) {
3257 0 => return @intCast(usize, count),
3258 posix.EFAULT => unreachable,
3259 posix.EINVAL => unreachable,
3260 posix.ENOMEM => return CpuCountError.OutOfMemory,
3261 posix.ENOTDIR => unreachable,
3262 posix.EISDIR => unreachable,
3263 posix.ENOENT => unreachable,
3264 posix.EPERM => unreachable,
3265 else => return os.unexpectedErrorPosix(err),
3266 }
3267 },
3268 builtin.Os.linux => {
3269 const usize_count = 16;
3270 const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
3271
3272 var set = try allocator.alloc(usize, usize_count);
3273 defer allocator.free(set);
3274
3275 while (true) {
3276 const rc = posix.sched_getaffinity(0, set);
3277 const err = posix.getErrno(rc);
3278 switch (err) {
3279 0 => {
3280 if (rc < set.len * @sizeOf(usize)) {
3281 const result = set[0 .. rc / @sizeOf(usize)];
3282 var sum: usize = 0;
3283 for (result) |x| {
3284 sum += @popCount(x);
3285 }
3286 return sum;
3287 } else {
3288 set = try allocator.realloc(usize, set, set.len * 2);
3289 continue;
3290 }
3291 },
3292 posix.EFAULT => unreachable,
3293 posix.EINVAL => unreachable,
3294 posix.EPERM => return CpuCountError.PermissionDenied,
3295 posix.ESRCH => unreachable,
3296 else => return os.unexpectedErrorPosix(err),
3297 }
3298 }
3299 },
3300 builtin.Os.windows => {
3301 var system_info: windows.SYSTEM_INFO = undefined;
3302 windows.GetSystemInfo(&system_info);
3303 return @intCast(usize, system_info.dwNumberOfProcessors);
3304 },
3305 else => @compileError("unsupported OS"),
3306 }
3307}
3308
3309pub const BsdKQueueError = error{
3310 /// The per-process limit on the number of open file descriptors has been reached.
3311 ProcessFdQuotaExceeded,
3312
3313 /// The system-wide limit on the total number of open files has been reached.
3314 SystemFdQuotaExceeded,
3315
3316 /// See https://github.com/ziglang/zig/issues/1396
3317 Unexpected,
3318};
3319
3320pub fn bsdKQueue() BsdKQueueError!i32 {
3321 const rc = posix.kqueue();
3322 const err = posix.getErrno(rc);
3323 switch (err) {
3324 0 => return @intCast(i32, rc),
3325 posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
3326 posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
3327 else => return unexpectedErrorPosix(err),
3328 }
3329}
3330
3331pub const BsdKEventError = error{
3332 /// The process does not have permission to register a filter.
3333 AccessDenied,
3334
3335 /// The event could not be found to be modified or deleted.
3336 EventNotFound,
3337
3338 /// No memory was available to register the event.
3339 SystemResources,
3340
3341 /// The specified process to attach to does not exist.
3342 ProcessNotFound,
3343};
3344
3345pub fn bsdKEvent(
3346 kq: i32,
3347 changelist: []const posix.Kevent,
3348 eventlist: []posix.Kevent,
3349 timeout: ?*const posix.timespec,
3350) BsdKEventError!usize {
3351 while (true) {
3352 const rc = posix.kevent(kq, changelist, eventlist, timeout);
3353 const err = posix.getErrno(rc);
3354 switch (err) {
3355 0 => return rc,
3356 posix.EACCES => return BsdKEventError.AccessDenied,
3357 posix.EFAULT => unreachable,
3358 posix.EBADF => unreachable,
3359 posix.EINTR => continue,
3360 posix.EINVAL => unreachable,
3361 posix.ENOENT => return BsdKEventError.EventNotFound,
3362 posix.ENOMEM => return BsdKEventError.SystemResources,
3363 posix.ESRCH => return BsdKEventError.ProcessNotFound,
3364 else => unreachable,
3365 }
3366 }
3367}
3368
3369pub fn linuxINotifyInit1(flags: u32) !i32 {
3370 const rc = linux.inotify_init1(flags);
3371 const err = posix.getErrno(rc);
3372 switch (err) {
3373 0 => return @intCast(i32, rc),
3374 posix.EINVAL => unreachable,
3375 posix.EMFILE => return error.ProcessFdQuotaExceeded,
3376 posix.ENFILE => return error.SystemFdQuotaExceeded,
3377 posix.ENOMEM => return error.SystemResources,
3378 else => return unexpectedErrorPosix(err),
3379 }
3380}
3381
3382pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
3383 const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
3384 const err = posix.getErrno(rc);
3385 switch (err) {
3386 0 => return @intCast(i32, rc),
3387 posix.EACCES => return error.AccessDenied,
3388 posix.EBADF => unreachable,
3389 posix.EFAULT => unreachable,
3390 posix.EINVAL => unreachable,
3391 posix.ENAMETOOLONG => return error.NameTooLong,
3392 posix.ENOENT => return error.FileNotFound,
3393 posix.ENOMEM => return error.SystemResources,
3394 posix.ENOSPC => return error.UserResourceLimitReached,
3395 else => return unexpectedErrorPosix(err),
3396 }
3397}
3398
3399pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
3400 const rc = linux.inotify_rm_watch(inotify_fd, wd);
3401 const err = posix.getErrno(rc);
3402 switch (err) {
3403 0 => return rc,
3404 posix.EBADF => unreachable,
3405 posix.EINVAL => unreachable,
3406 else => unreachable,
3407 }
3408}
std/os/linux.zig created+1541
...@@ -0,0 +1,1541 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");
4const maxInt = std.math.maxInt;
5const vdso = @import("linux/vdso.zig");
6pub use switch (builtin.arch) {
7 builtin.Arch.x86_64 => @import("linux/x86_64.zig"),
8 builtin.Arch.i386 => @import("linux/i386.zig"),
9 builtin.Arch.aarch64 => @import("linux/arm64.zig"),
10 else => @compileError("unsupported arch"),
11};
12pub use @import("linux/errno.zig");
13
14pub const PATH_MAX = 4096;
15
16pub const STDIN_FILENO = 0;
17pub const STDOUT_FILENO = 1;
18pub const STDERR_FILENO = 2;
19
20pub const FUTEX_WAIT = 0;
21pub const FUTEX_WAKE = 1;
22pub const FUTEX_FD = 2;
23pub const FUTEX_REQUEUE = 3;
24pub const FUTEX_CMP_REQUEUE = 4;
25pub const FUTEX_WAKE_OP = 5;
26pub const FUTEX_LOCK_PI = 6;
27pub const FUTEX_UNLOCK_PI = 7;
28pub const FUTEX_TRYLOCK_PI = 8;
29pub const FUTEX_WAIT_BITSET = 9;
30
31pub const FUTEX_PRIVATE_FLAG = 128;
32
33pub const FUTEX_CLOCK_REALTIME = 256;
34
35pub const PROT_NONE = 0;
36pub const PROT_READ = 1;
37pub const PROT_WRITE = 2;
38pub const PROT_EXEC = 4;
39pub const PROT_GROWSDOWN = 0x01000000;
40pub const PROT_GROWSUP = 0x02000000;
41
42pub const MAP_FAILED = maxInt(usize);
43pub const MAP_SHARED = 0x01;
44pub const MAP_PRIVATE = 0x02;
45pub const MAP_TYPE = 0x0f;
46pub const MAP_FIXED = 0x10;
47pub const MAP_ANONYMOUS = 0x20;
48pub const MAP_NORESERVE = 0x4000;
49pub const MAP_GROWSDOWN = 0x0100;
50pub const MAP_DENYWRITE = 0x0800;
51pub const MAP_EXECUTABLE = 0x1000;
52pub const MAP_LOCKED = 0x2000;
53pub const MAP_POPULATE = 0x8000;
54pub const MAP_NONBLOCK = 0x10000;
55pub const MAP_STACK = 0x20000;
56pub const MAP_HUGETLB = 0x40000;
57pub const MAP_FILE = 0;
58
59pub const F_OK = 0;
60pub const X_OK = 1;
61pub const W_OK = 2;
62pub const R_OK = 4;
63
64pub const WNOHANG = 1;
65pub const WUNTRACED = 2;
66pub const WSTOPPED = 2;
67pub const WEXITED = 4;
68pub const WCONTINUED = 8;
69pub const WNOWAIT = 0x1000000;
70
71pub const SA_NOCLDSTOP = 1;
72pub const SA_NOCLDWAIT = 2;
73pub const SA_SIGINFO = 4;
74pub const SA_ONSTACK = 0x08000000;
75pub const SA_RESTART = 0x10000000;
76pub const SA_NODEFER = 0x40000000;
77pub const SA_RESETHAND = 0x80000000;
78pub const SA_RESTORER = 0x04000000;
79
80pub const SIGHUP = 1;
81pub const SIGINT = 2;
82pub const SIGQUIT = 3;
83pub const SIGILL = 4;
84pub const SIGTRAP = 5;
85pub const SIGABRT = 6;
86pub const SIGIOT = SIGABRT;
87pub const SIGBUS = 7;
88pub const SIGFPE = 8;
89pub const SIGKILL = 9;
90pub const SIGUSR1 = 10;
91pub const SIGSEGV = 11;
92pub const SIGUSR2 = 12;
93pub const SIGPIPE = 13;
94pub const SIGALRM = 14;
95pub const SIGTERM = 15;
96pub const SIGSTKFLT = 16;
97pub const SIGCHLD = 17;
98pub const SIGCONT = 18;
99pub const SIGSTOP = 19;
100pub const SIGTSTP = 20;
101pub const SIGTTIN = 21;
102pub const SIGTTOU = 22;
103pub const SIGURG = 23;
104pub const SIGXCPU = 24;
105pub const SIGXFSZ = 25;
106pub const SIGVTALRM = 26;
107pub const SIGPROF = 27;
108pub const SIGWINCH = 28;
109pub const SIGIO = 29;
110pub const SIGPOLL = 29;
111pub const SIGPWR = 30;
112pub const SIGSYS = 31;
113pub const SIGUNUSED = SIGSYS;
114
115pub const O_RDONLY = 0o0;
116pub const O_WRONLY = 0o1;
117pub const O_RDWR = 0o2;
118
119pub const SEEK_SET = 0;
120pub const SEEK_CUR = 1;
121pub const SEEK_END = 2;
122
123pub const SIG_BLOCK = 0;
124pub const SIG_UNBLOCK = 1;
125pub const SIG_SETMASK = 2;
126
127pub const PROTO_ip = 0o000;
128pub const PROTO_icmp = 0o001;
129pub const PROTO_igmp = 0o002;
130pub const PROTO_ggp = 0o003;
131pub const PROTO_ipencap = 0o004;
132pub const PROTO_st = 0o005;
133pub const PROTO_tcp = 0o006;
134pub const PROTO_egp = 0o010;
135pub const PROTO_pup = 0o014;
136pub const PROTO_udp = 0o021;
137pub const PROTO_hmp = 0o024;
138pub const PROTO_xns_idp = 0o026;
139pub const PROTO_rdp = 0o033;
140pub const PROTO_iso_tp4 = 0o035;
141pub const PROTO_xtp = 0o044;
142pub const PROTO_ddp = 0o045;
143pub const PROTO_idpr_cmtp = 0o046;
144pub const PROTO_ipv6 = 0o051;
145pub const PROTO_ipv6_route = 0o053;
146pub const PROTO_ipv6_frag = 0o054;
147pub const PROTO_idrp = 0o055;
148pub const PROTO_rsvp = 0o056;
149pub const PROTO_gre = 0o057;
150pub const PROTO_esp = 0o062;
151pub const PROTO_ah = 0o063;
152pub const PROTO_skip = 0o071;
153pub const PROTO_ipv6_icmp = 0o072;
154pub const PROTO_ipv6_nonxt = 0o073;
155pub const PROTO_ipv6_opts = 0o074;
156pub const PROTO_rspf = 0o111;
157pub const PROTO_vmtp = 0o121;
158pub const PROTO_ospf = 0o131;
159pub const PROTO_ipip = 0o136;
160pub const PROTO_encap = 0o142;
161pub const PROTO_pim = 0o147;
162pub const PROTO_raw = 0o377;
163
164pub const SHUT_RD = 0;
165pub const SHUT_WR = 1;
166pub const SHUT_RDWR = 2;
167
168pub const SOCK_STREAM = 1;
169pub const SOCK_DGRAM = 2;
170pub const SOCK_RAW = 3;
171pub const SOCK_RDM = 4;
172pub const SOCK_SEQPACKET = 5;
173pub const SOCK_DCCP = 6;
174pub const SOCK_PACKET = 10;
175pub const SOCK_CLOEXEC = 0o2000000;
176pub const SOCK_NONBLOCK = 0o4000;
177
178pub const PF_UNSPEC = 0;
179pub const PF_LOCAL = 1;
180pub const PF_UNIX = PF_LOCAL;
181pub const PF_FILE = PF_LOCAL;
182pub const PF_INET = 2;
183pub const PF_AX25 = 3;
184pub const PF_IPX = 4;
185pub const PF_APPLETALK = 5;
186pub const PF_NETROM = 6;
187pub const PF_BRIDGE = 7;
188pub const PF_ATMPVC = 8;
189pub const PF_X25 = 9;
190pub const PF_INET6 = 10;
191pub const PF_ROSE = 11;
192pub const PF_DECnet = 12;
193pub const PF_NETBEUI = 13;
194pub const PF_SECURITY = 14;
195pub const PF_KEY = 15;
196pub const PF_NETLINK = 16;
197pub const PF_ROUTE = PF_NETLINK;
198pub const PF_PACKET = 17;
199pub const PF_ASH = 18;
200pub const PF_ECONET = 19;
201pub const PF_ATMSVC = 20;
202pub const PF_RDS = 21;
203pub const PF_SNA = 22;
204pub const PF_IRDA = 23;
205pub const PF_PPPOX = 24;
206pub const PF_WANPIPE = 25;
207pub const PF_LLC = 26;
208pub const PF_IB = 27;
209pub const PF_MPLS = 28;
210pub const PF_CAN = 29;
211pub const PF_TIPC = 30;
212pub const PF_BLUETOOTH = 31;
213pub const PF_IUCV = 32;
214pub const PF_RXRPC = 33;
215pub const PF_ISDN = 34;
216pub const PF_PHONET = 35;
217pub const PF_IEEE802154 = 36;
218pub const PF_CAIF = 37;
219pub const PF_ALG = 38;
220pub const PF_NFC = 39;
221pub const PF_VSOCK = 40;
222pub const PF_KCM = 41;
223pub const PF_QIPCRTR = 42;
224pub const PF_SMC = 43;
225pub const PF_MAX = 44;
226
227pub const AF_UNSPEC = PF_UNSPEC;
228pub const AF_LOCAL = PF_LOCAL;
229pub const AF_UNIX = AF_LOCAL;
230pub const AF_FILE = AF_LOCAL;
231pub const AF_INET = PF_INET;
232pub const AF_AX25 = PF_AX25;
233pub const AF_IPX = PF_IPX;
234pub const AF_APPLETALK = PF_APPLETALK;
235pub const AF_NETROM = PF_NETROM;
236pub const AF_BRIDGE = PF_BRIDGE;
237pub const AF_ATMPVC = PF_ATMPVC;
238pub const AF_X25 = PF_X25;
239pub const AF_INET6 = PF_INET6;
240pub const AF_ROSE = PF_ROSE;
241pub const AF_DECnet = PF_DECnet;
242pub const AF_NETBEUI = PF_NETBEUI;
243pub const AF_SECURITY = PF_SECURITY;
244pub const AF_KEY = PF_KEY;
245pub const AF_NETLINK = PF_NETLINK;
246pub const AF_ROUTE = PF_ROUTE;
247pub const AF_PACKET = PF_PACKET;
248pub const AF_ASH = PF_ASH;
249pub const AF_ECONET = PF_ECONET;
250pub const AF_ATMSVC = PF_ATMSVC;
251pub const AF_RDS = PF_RDS;
252pub const AF_SNA = PF_SNA;
253pub const AF_IRDA = PF_IRDA;
254pub const AF_PPPOX = PF_PPPOX;
255pub const AF_WANPIPE = PF_WANPIPE;
256pub const AF_LLC = PF_LLC;
257pub const AF_IB = PF_IB;
258pub const AF_MPLS = PF_MPLS;
259pub const AF_CAN = PF_CAN;
260pub const AF_TIPC = PF_TIPC;
261pub const AF_BLUETOOTH = PF_BLUETOOTH;
262pub const AF_IUCV = PF_IUCV;
263pub const AF_RXRPC = PF_RXRPC;
264pub const AF_ISDN = PF_ISDN;
265pub const AF_PHONET = PF_PHONET;
266pub const AF_IEEE802154 = PF_IEEE802154;
267pub const AF_CAIF = PF_CAIF;
268pub const AF_ALG = PF_ALG;
269pub const AF_NFC = PF_NFC;
270pub const AF_VSOCK = PF_VSOCK;
271pub const AF_KCM = PF_KCM;
272pub const AF_QIPCRTR = PF_QIPCRTR;
273pub const AF_SMC = PF_SMC;
274pub const AF_MAX = PF_MAX;
275
276pub const SO_DEBUG = 1;
277pub const SO_REUSEADDR = 2;
278pub const SO_TYPE = 3;
279pub const SO_ERROR = 4;
280pub const SO_DONTROUTE = 5;
281pub const SO_BROADCAST = 6;
282pub const SO_SNDBUF = 7;
283pub const SO_RCVBUF = 8;
284pub const SO_KEEPALIVE = 9;
285pub const SO_OOBINLINE = 10;
286pub const SO_NO_CHECK = 11;
287pub const SO_PRIORITY = 12;
288pub const SO_LINGER = 13;
289pub const SO_BSDCOMPAT = 14;
290pub const SO_REUSEPORT = 15;
291pub const SO_PASSCRED = 16;
292pub const SO_PEERCRED = 17;
293pub const SO_RCVLOWAT = 18;
294pub const SO_SNDLOWAT = 19;
295pub const SO_RCVTIMEO = 20;
296pub const SO_SNDTIMEO = 21;
297pub const SO_ACCEPTCONN = 30;
298pub const SO_SNDBUFFORCE = 32;
299pub const SO_RCVBUFFORCE = 33;
300pub const SO_PROTOCOL = 38;
301pub const SO_DOMAIN = 39;
302
303pub const SO_SECURITY_AUTHENTICATION = 22;
304pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
305pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
306
307pub const SO_BINDTODEVICE = 25;
308
309pub const SO_ATTACH_FILTER = 26;
310pub const SO_DETACH_FILTER = 27;
311pub const SO_GET_FILTER = SO_ATTACH_FILTER;
312
313pub const SO_PEERNAME = 28;
314pub const SO_TIMESTAMP = 29;
315pub const SCM_TIMESTAMP = SO_TIMESTAMP;
316
317pub const SO_PEERSEC = 31;
318pub const SO_PASSSEC = 34;
319pub const SO_TIMESTAMPNS = 35;
320pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
321pub const SO_MARK = 36;
322pub const SO_TIMESTAMPING = 37;
323pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
324pub const SO_RXQ_OVFL = 40;
325pub const SO_WIFI_STATUS = 41;
326pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
327pub const SO_PEEK_OFF = 42;
328pub const SO_NOFCS = 43;
329pub const SO_LOCK_FILTER = 44;
330pub const SO_SELECT_ERR_QUEUE = 45;
331pub const SO_BUSY_POLL = 46;
332pub const SO_MAX_PACING_RATE = 47;
333pub const SO_BPF_EXTENSIONS = 48;
334pub const SO_INCOMING_CPU = 49;
335pub const SO_ATTACH_BPF = 50;
336pub const SO_DETACH_BPF = SO_DETACH_FILTER;
337pub const SO_ATTACH_REUSEPORT_CBPF = 51;
338pub const SO_ATTACH_REUSEPORT_EBPF = 52;
339pub const SO_CNX_ADVICE = 53;
340pub const SCM_TIMESTAMPING_OPT_STATS = 54;
341pub const SO_MEMINFO = 55;
342pub const SO_INCOMING_NAPI_ID = 56;
343pub const SO_COOKIE = 57;
344pub const SCM_TIMESTAMPING_PKTINFO = 58;
345pub const SO_PEERGROUPS = 59;
346pub const SO_ZEROCOPY = 60;
347
348pub const SOL_SOCKET = 1;
349
350pub const SOL_IP = 0;
351pub const SOL_IPV6 = 41;
352pub const SOL_ICMPV6 = 58;
353
354pub const SOL_RAW = 255;
355pub const SOL_DECNET = 261;
356pub const SOL_X25 = 262;
357pub const SOL_PACKET = 263;
358pub const SOL_ATM = 264;
359pub const SOL_AAL = 265;
360pub const SOL_IRDA = 266;
361pub const SOL_NETBEUI = 267;
362pub const SOL_LLC = 268;
363pub const SOL_DCCP = 269;
364pub const SOL_NETLINK = 270;
365pub const SOL_TIPC = 271;
366pub const SOL_RXRPC = 272;
367pub const SOL_PPPOL2TP = 273;
368pub const SOL_BLUETOOTH = 274;
369pub const SOL_PNPIPE = 275;
370pub const SOL_RDS = 276;
371pub const SOL_IUCV = 277;
372pub const SOL_CAIF = 278;
373pub const SOL_ALG = 279;
374pub const SOL_NFC = 280;
375pub const SOL_KCM = 281;
376pub const SOL_TLS = 282;
377
378pub const SOMAXCONN = 128;
379
380pub const MSG_OOB = 0x0001;
381pub const MSG_PEEK = 0x0002;
382pub const MSG_DONTROUTE = 0x0004;
383pub const MSG_CTRUNC = 0x0008;
384pub const MSG_PROXY = 0x0010;
385pub const MSG_TRUNC = 0x0020;
386pub const MSG_DONTWAIT = 0x0040;
387pub const MSG_EOR = 0x0080;
388pub const MSG_WAITALL = 0x0100;
389pub const MSG_FIN = 0x0200;
390pub const MSG_SYN = 0x0400;
391pub const MSG_CONFIRM = 0x0800;
392pub const MSG_RST = 0x1000;
393pub const MSG_ERRQUEUE = 0x2000;
394pub const MSG_NOSIGNAL = 0x4000;
395pub const MSG_MORE = 0x8000;
396pub const MSG_WAITFORONE = 0x10000;
397pub const MSG_BATCH = 0x40000;
398pub const MSG_ZEROCOPY = 0x4000000;
399pub const MSG_FASTOPEN = 0x20000000;
400pub const MSG_CMSG_CLOEXEC = 0x40000000;
401
402pub const DT_UNKNOWN = 0;
403pub const DT_FIFO = 1;
404pub const DT_CHR = 2;
405pub const DT_DIR = 4;
406pub const DT_BLK = 6;
407pub const DT_REG = 8;
408pub const DT_LNK = 10;
409pub const DT_SOCK = 12;
410pub const DT_WHT = 14;
411
412pub const TCGETS = 0x5401;
413pub const TCSETS = 0x5402;
414pub const TCSETSW = 0x5403;
415pub const TCSETSF = 0x5404;
416pub const TCGETA = 0x5405;
417pub const TCSETA = 0x5406;
418pub const TCSETAW = 0x5407;
419pub const TCSETAF = 0x5408;
420pub const TCSBRK = 0x5409;
421pub const TCXONC = 0x540A;
422pub const TCFLSH = 0x540B;
423pub const TIOCEXCL = 0x540C;
424pub const TIOCNXCL = 0x540D;
425pub const TIOCSCTTY = 0x540E;
426pub const TIOCGPGRP = 0x540F;
427pub const TIOCSPGRP = 0x5410;
428pub const TIOCOUTQ = 0x5411;
429pub const TIOCSTI = 0x5412;
430pub const TIOCGWINSZ = 0x5413;
431pub const TIOCSWINSZ = 0x5414;
432pub const TIOCMGET = 0x5415;
433pub const TIOCMBIS = 0x5416;
434pub const TIOCMBIC = 0x5417;
435pub const TIOCMSET = 0x5418;
436pub const TIOCGSOFTCAR = 0x5419;
437pub const TIOCSSOFTCAR = 0x541A;
438pub const FIONREAD = 0x541B;
439pub const TIOCINQ = FIONREAD;
440pub const TIOCLINUX = 0x541C;
441pub const TIOCCONS = 0x541D;
442pub const TIOCGSERIAL = 0x541E;
443pub const TIOCSSERIAL = 0x541F;
444pub const TIOCPKT = 0x5420;
445pub const FIONBIO = 0x5421;
446pub const TIOCNOTTY = 0x5422;
447pub const TIOCSETD = 0x5423;
448pub const TIOCGETD = 0x5424;
449pub const TCSBRKP = 0x5425;
450pub const TIOCSBRK = 0x5427;
451pub const TIOCCBRK = 0x5428;
452pub const TIOCGSID = 0x5429;
453pub const TIOCGRS485 = 0x542E;
454pub const TIOCSRS485 = 0x542F;
455pub const TIOCGPTN = 0x80045430;
456pub const TIOCSPTLCK = 0x40045431;
457pub const TIOCGDEV = 0x80045432;
458pub const TCGETX = 0x5432;
459pub const TCSETX = 0x5433;
460pub const TCSETXF = 0x5434;
461pub const TCSETXW = 0x5435;
462pub const TIOCSIG = 0x40045436;
463pub const TIOCVHANGUP = 0x5437;
464pub const TIOCGPKT = 0x80045438;
465pub const TIOCGPTLCK = 0x80045439;
466pub const TIOCGEXCL = 0x80045440;
467
468pub const EPOLL_CLOEXEC = O_CLOEXEC;
469
470pub const EPOLL_CTL_ADD = 1;
471pub const EPOLL_CTL_DEL = 2;
472pub const EPOLL_CTL_MOD = 3;
473
474pub const EPOLLIN = 0x001;
475pub const EPOLLPRI = 0x002;
476pub const EPOLLOUT = 0x004;
477pub const EPOLLRDNORM = 0x040;
478pub const EPOLLRDBAND = 0x080;
479pub const EPOLLWRNORM = 0x100;
480pub const EPOLLWRBAND = 0x200;
481pub const EPOLLMSG = 0x400;
482pub const EPOLLERR = 0x008;
483pub const EPOLLHUP = 0x010;
484pub const EPOLLRDHUP = 0x2000;
485pub const EPOLLEXCLUSIVE = (u32(1) << 28);
486pub const EPOLLWAKEUP = (u32(1) << 29);
487pub const EPOLLONESHOT = (u32(1) << 30);
488pub const EPOLLET = (u32(1) << 31);
489
490pub const CLOCK_REALTIME = 0;
491pub const CLOCK_MONOTONIC = 1;
492pub const CLOCK_PROCESS_CPUTIME_ID = 2;
493pub const CLOCK_THREAD_CPUTIME_ID = 3;
494pub const CLOCK_MONOTONIC_RAW = 4;
495pub const CLOCK_REALTIME_COARSE = 5;
496pub const CLOCK_MONOTONIC_COARSE = 6;
497pub const CLOCK_BOOTTIME = 7;
498pub const CLOCK_REALTIME_ALARM = 8;
499pub const CLOCK_BOOTTIME_ALARM = 9;
500pub const CLOCK_SGI_CYCLE = 10;
501pub const CLOCK_TAI = 11;
502
503pub const CSIGNAL = 0x000000ff;
504pub const CLONE_VM = 0x00000100;
505pub const CLONE_FS = 0x00000200;
506pub const CLONE_FILES = 0x00000400;
507pub const CLONE_SIGHAND = 0x00000800;
508pub const CLONE_PTRACE = 0x00002000;
509pub const CLONE_VFORK = 0x00004000;
510pub const CLONE_PARENT = 0x00008000;
511pub const CLONE_THREAD = 0x00010000;
512pub const CLONE_NEWNS = 0x00020000;
513pub const CLONE_SYSVSEM = 0x00040000;
514pub const CLONE_SETTLS = 0x00080000;
515pub const CLONE_PARENT_SETTID = 0x00100000;
516pub const CLONE_CHILD_CLEARTID = 0x00200000;
517pub const CLONE_DETACHED = 0x00400000;
518pub const CLONE_UNTRACED = 0x00800000;
519pub const CLONE_CHILD_SETTID = 0x01000000;
520pub const CLONE_NEWCGROUP = 0x02000000;
521pub const CLONE_NEWUTS = 0x04000000;
522pub const CLONE_NEWIPC = 0x08000000;
523pub const CLONE_NEWUSER = 0x10000000;
524pub const CLONE_NEWPID = 0x20000000;
525pub const CLONE_NEWNET = 0x40000000;
526pub const CLONE_IO = 0x80000000;
527
528pub const EFD_SEMAPHORE = 1;
529pub const EFD_CLOEXEC = O_CLOEXEC;
530pub const EFD_NONBLOCK = O_NONBLOCK;
531
532pub const MS_RDONLY = 1;
533pub const MS_NOSUID = 2;
534pub const MS_NODEV = 4;
535pub const MS_NOEXEC = 8;
536pub const MS_SYNCHRONOUS = 16;
537pub const MS_REMOUNT = 32;
538pub const MS_MANDLOCK = 64;
539pub const MS_DIRSYNC = 128;
540pub const MS_NOATIME = 1024;
541pub const MS_NODIRATIME = 2048;
542pub const MS_BIND = 4096;
543pub const MS_MOVE = 8192;
544pub const MS_REC = 16384;
545pub const MS_SILENT = 32768;
546pub const MS_POSIXACL = (1 << 16);
547pub const MS_UNBINDABLE = (1 << 17);
548pub const MS_PRIVATE = (1 << 18);
549pub const MS_SLAVE = (1 << 19);
550pub const MS_SHARED = (1 << 20);
551pub const MS_RELATIME = (1 << 21);
552pub const MS_KERNMOUNT = (1 << 22);
553pub const MS_I_VERSION = (1 << 23);
554pub const MS_STRICTATIME = (1 << 24);
555pub const MS_LAZYTIME = (1 << 25);
556pub const MS_NOREMOTELOCK = (1 << 27);
557pub const MS_NOSEC = (1 << 28);
558pub const MS_BORN = (1 << 29);
559pub const MS_ACTIVE = (1 << 30);
560pub const MS_NOUSER = (1 << 31);
561
562pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
563
564pub const MS_MGC_VAL = 0xc0ed0000;
565pub const MS_MGC_MSK = 0xffff0000;
566
567pub const MNT_FORCE = 1;
568pub const MNT_DETACH = 2;
569pub const MNT_EXPIRE = 4;
570pub const UMOUNT_NOFOLLOW = 8;
571
572pub const IN_CLOEXEC = O_CLOEXEC;
573pub const IN_NONBLOCK = O_NONBLOCK;
574
575pub const IN_ACCESS = 0x00000001;
576pub const IN_MODIFY = 0x00000002;
577pub const IN_ATTRIB = 0x00000004;
578pub const IN_CLOSE_WRITE = 0x00000008;
579pub const IN_CLOSE_NOWRITE = 0x00000010;
580pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
581pub const IN_OPEN = 0x00000020;
582pub const IN_MOVED_FROM = 0x00000040;
583pub const IN_MOVED_TO = 0x00000080;
584pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
585pub const IN_CREATE = 0x00000100;
586pub const IN_DELETE = 0x00000200;
587pub const IN_DELETE_SELF = 0x00000400;
588pub const IN_MOVE_SELF = 0x00000800;
589pub const IN_ALL_EVENTS = 0x00000fff;
590
591pub const IN_UNMOUNT = 0x00002000;
592pub const IN_Q_OVERFLOW = 0x00004000;
593pub const IN_IGNORED = 0x00008000;
594
595pub const IN_ONLYDIR = 0x01000000;
596pub const IN_DONT_FOLLOW = 0x02000000;
597pub const IN_EXCL_UNLINK = 0x04000000;
598pub const IN_MASK_ADD = 0x20000000;
599
600pub const IN_ISDIR = 0x40000000;
601pub const IN_ONESHOT = 0x80000000;
602
603pub const S_IFMT = 0o170000;
604
605pub const S_IFDIR = 0o040000;
606pub const S_IFCHR = 0o020000;
607pub const S_IFBLK = 0o060000;
608pub const S_IFREG = 0o100000;
609pub const S_IFIFO = 0o010000;
610pub const S_IFLNK = 0o120000;
611pub const S_IFSOCK = 0o140000;
612
613pub const S_ISUID = 0o4000;
614pub const S_ISGID = 0o2000;
615pub const S_ISVTX = 0o1000;
616pub const S_IRUSR = 0o400;
617pub const S_IWUSR = 0o200;
618pub const S_IXUSR = 0o100;
619pub const S_IRWXU = 0o700;
620pub const S_IRGRP = 0o040;
621pub const S_IWGRP = 0o020;
622pub const S_IXGRP = 0o010;
623pub const S_IRWXG = 0o070;
624pub const S_IROTH = 0o004;
625pub const S_IWOTH = 0o002;
626pub const S_IXOTH = 0o001;
627pub const S_IRWXO = 0o007;
628
629pub fn S_ISREG(m: u32) bool {
630 return m & S_IFMT == S_IFREG;
631}
632
633pub fn S_ISDIR(m: u32) bool {
634 return m & S_IFMT == S_IFDIR;
635}
636
637pub fn S_ISCHR(m: u32) bool {
638 return m & S_IFMT == S_IFCHR;
639}
640
641pub fn S_ISBLK(m: u32) bool {
642 return m & S_IFMT == S_IFBLK;
643}
644
645pub fn S_ISFIFO(m: u32) bool {
646 return m & S_IFMT == S_IFIFO;
647}
648
649pub fn S_ISLNK(m: u32) bool {
650 return m & S_IFMT == S_IFLNK;
651}
652
653pub fn S_ISSOCK(m: u32) bool {
654 return m & S_IFMT == S_IFSOCK;
655}
656
657pub const TFD_NONBLOCK = O_NONBLOCK;
658pub const TFD_CLOEXEC = O_CLOEXEC;
659
660pub const TFD_TIMER_ABSTIME = 1;
661pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
662
663fn unsigned(s: i32) u32 {
664 return @bitCast(u32, s);
665}
666fn signed(s: u32) i32 {
667 return @bitCast(i32, s);
668}
669pub fn WEXITSTATUS(s: i32) i32 {
670 return signed((unsigned(s) & 0xff00) >> 8);
671}
672pub fn WTERMSIG(s: i32) i32 {
673 return signed(unsigned(s) & 0x7f);
674}
675pub fn WSTOPSIG(s: i32) i32 {
676 return WEXITSTATUS(s);
677}
678pub fn WIFEXITED(s: i32) bool {
679 return WTERMSIG(s) == 0;
680}
681pub fn WIFSTOPPED(s: i32) bool {
682 return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
683}
684pub fn WIFSIGNALED(s: i32) bool {
685 return (unsigned(s) & 0xffff) -% 1 < 0xff;
686}
687
688pub const winsize = extern struct {
689 ws_row: u16,
690 ws_col: u16,
691 ws_xpixel: u16,
692 ws_ypixel: u16,
693};
694
695/// Get the errno from a syscall return value, or 0 for no error.
696pub fn getErrno(r: usize) usize {
697 const signed_r = @bitCast(isize, r);
698 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
699}
700
701pub fn dup2(old: i32, new: i32) usize {
702 return dup3(old, new, 0);
703}
704
705pub fn dup3(old: i32, new: i32, flags: u32) usize {
706 return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags);
707}
708
709// TODO https://github.com/ziglang/zig/issues/265
710pub fn chdir(path: [*]const u8) usize {
711 return syscall1(SYS_chdir, @ptrToInt(path));
712}
713
714// TODO https://github.com/ziglang/zig/issues/265
715pub fn chroot(path: [*]const u8) usize {
716 return syscall1(SYS_chroot, @ptrToInt(path));
717}
718
719// TODO https://github.com/ziglang/zig/issues/265
720pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
721 return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
722}
723
724pub fn fork() usize {
725 return clone2(SIGCHLD, 0);
726}
727
728/// This must be inline, and inline call the syscall function, because if the
729/// child does a return it will clobber the parent's stack.
730/// It is advised to avoid this function and use clone instead, because
731/// the compiler is not aware of how vfork affects control flow and you may
732/// see different results in optimized builds.
733pub inline fn vfork() usize {
734 return @inlineCall(syscall0, SYS_vfork);
735}
736
737pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize {
738 return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout));
739}
740
741pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize {
742 return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val));
743}
744
745pub fn getcwd(buf: [*]u8, size: usize) usize {
746 return syscall2(SYS_getcwd, @ptrToInt(buf), size);
747}
748
749pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
750 return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
751}
752
753pub fn inotify_init1(flags: u32) usize {
754 return syscall1(SYS_inotify_init1, flags);
755}
756
757pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
758 return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask);
759}
760
761pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
762 return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
763}
764
765pub fn isatty(fd: i32) bool {
766 var wsz: winsize = undefined;
767 return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
768}
769
770// TODO https://github.com/ziglang/zig/issues/265
771pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
772 return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
773}
774
775// TODO https://github.com/ziglang/zig/issues/265
776pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
777 return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
778}
779
780// TODO https://github.com/ziglang/zig/issues/265
781pub fn mkdir(path: [*]const u8, mode: u32) usize {
782 return mkdirat(AT_FDCWD, path, mode);
783}
784
785// TODO https://github.com/ziglang/zig/issues/265
786pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
787 return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
788}
789
790// TODO https://github.com/ziglang/zig/issues/265
791pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize {
792 return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
793}
794
795// TODO https://github.com/ziglang/zig/issues/265
796pub fn umount(special: [*]const u8) usize {
797 return syscall2(SYS_umount2, @ptrToInt(special), 0);
798}
799
800// TODO https://github.com/ziglang/zig/issues/265
801pub fn umount2(special: [*]const u8, flags: u32) usize {
802 return syscall2(SYS_umount2, @ptrToInt(special), flags);
803}
804
805pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
806 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
807}
808
809pub fn mprotect(address: usize, length: usize, protection: usize) usize {
810 return syscall3(SYS_mprotect, address, length, protection);
811}
812
813pub fn munmap(address: usize, length: usize) usize {
814 return syscall2(SYS_munmap, address, length);
815}
816
817pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
818 return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
819}
820
821pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
822 return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
823}
824
825pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
826 return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
827}
828
829pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
830 return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
831}
832
833pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
834 return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
835}
836
837// TODO https://github.com/ziglang/zig/issues/265
838pub fn rmdir(path: [*]const u8) usize {
839 return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
840}
841
842// TODO https://github.com/ziglang/zig/issues/265
843pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
844 return symlinkat(existing, AT_FDCWD, new);
845}
846
847// TODO https://github.com/ziglang/zig/issues/265
848pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
849 return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath));
850}
851
852// TODO https://github.com/ziglang/zig/issues/265
853pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
854 return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
855}
856
857// TODO https://github.com/ziglang/zig/issues/265
858pub fn access(path: [*]const u8, mode: u32) usize {
859 return faccessat(AT_FDCWD, path, mode);
860}
861
862pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
863 return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
864}
865
866pub fn pipe(fd: *[2]i32) usize {
867 return pipe2(fd, 0);
868}
869
870pub fn pipe2(fd: *[2]i32, flags: u32) usize {
871 return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
872}
873
874pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
875 return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
876}
877
878pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
879 return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
880}
881
882// TODO https://github.com/ziglang/zig/issues/265
883pub fn rename(old: [*]const u8, new: [*]const u8) usize {
884 return renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);
885}
886
887// TODO https://github.com/ziglang/zig/issues/265
888pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
889 return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
890}
891
892// TODO https://github.com/ziglang/zig/issues/265
893pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
894 return openat(AT_FDCWD, path, flags, perm);
895}
896
897// TODO https://github.com/ziglang/zig/issues/265
898pub fn create(path: [*]const u8, perm: usize) usize {
899 return syscall2(SYS_creat, @ptrToInt(path), perm);
900}
901
902// TODO https://github.com/ziglang/zig/issues/265
903pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
904 // dirfd could be negative, for example AT_FDCWD is -100
905 return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
906}
907
908/// See also `clone` (from the arch-specific include)
909pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize {
910 return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
911}
912
913/// See also `clone` (from the arch-specific include)
914pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
915 return syscall2(SYS_clone, flags, child_stack_ptr);
916}
917
918pub fn close(fd: i32) usize {
919 return syscall1(SYS_close, @bitCast(usize, isize(fd)));
920}
921
922pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
923 return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
924}
925
926pub fn exit(status: i32) noreturn {
927 _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
928 unreachable;
929}
930
931pub fn exit_group(status: i32) noreturn {
932 _ = syscall1(SYS_exit_group, @bitCast(usize, isize(status)));
933 unreachable;
934}
935
936pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
937 return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags);
938}
939
940pub fn kill(pid: i32, sig: i32) usize {
941 return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
942}
943
944// TODO https://github.com/ziglang/zig/issues/265
945pub fn unlink(path: [*]const u8) usize {
946 return unlinkat(AT_FDCWD, path, 0);
947}
948
949// TODO https://github.com/ziglang/zig/issues/265
950pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
951 return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
952}
953
954pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
955 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
956}
957
958pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
959 if (VDSO_CGT_SYM.len != 0) {
960 const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);
961 if (@ptrToInt(f) != 0) {
962 const rc = f(clk_id, tp);
963 switch (rc) {
964 0, @bitCast(usize, isize(-EINVAL)) => return rc,
965 else => {},
966 }
967 }
968 }
969 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
970}
971var vdso_clock_gettime = init_vdso_clock_gettime;
972extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
973 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
974 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
975 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
976 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
977 return f(clk, ts);
978}
979
980pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
981 return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
982}
983
984pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
985 return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
986}
987
988pub fn gettimeofday(tv: *timeval, tz: *timezone) usize {
989 return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
990}
991
992pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
993 return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
994}
995
996pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
997 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
998}
999
1000pub fn setuid(uid: u32) usize {
1001 return syscall1(SYS_setuid, uid);
1002}
1003
1004pub fn setgid(gid: u32) usize {
1005 return syscall1(SYS_setgid, gid);
1006}
1007
1008pub fn setreuid(ruid: u32, euid: u32) usize {
1009 return syscall2(SYS_setreuid, ruid, euid);
1010}
1011
1012pub fn setregid(rgid: u32, egid: u32) usize {
1013 return syscall2(SYS_setregid, rgid, egid);
1014}
1015
1016pub fn getuid() u32 {
1017 return u32(syscall0(SYS_getuid));
1018}
1019
1020pub fn getgid() u32 {
1021 return u32(syscall0(SYS_getgid));
1022}
1023
1024pub fn geteuid() u32 {
1025 return u32(syscall0(SYS_geteuid));
1026}
1027
1028pub fn getegid() u32 {
1029 return u32(syscall0(SYS_getegid));
1030}
1031
1032pub fn seteuid(euid: u32) usize {
1033 return syscall1(SYS_seteuid, euid);
1034}
1035
1036pub fn setegid(egid: u32) usize {
1037 return syscall1(SYS_setegid, egid);
1038}
1039
1040pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize {
1041 return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
1042}
1043
1044pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize {
1045 return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
1046}
1047
1048pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
1049 return syscall3(SYS_setresuid, ruid, euid, suid);
1050}
1051
1052pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
1053 return syscall3(SYS_setresgid, rgid, egid, sgid);
1054}
1055
1056pub fn getgroups(size: usize, list: *u32) usize {
1057 return syscall2(SYS_getgroups, size, @ptrToInt(list));
1058}
1059
1060pub fn setgroups(size: usize, list: *const u32) usize {
1061 return syscall2(SYS_setgroups, size, @ptrToInt(list));
1062}
1063
1064pub fn getpid() i32 {
1065 return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
1066}
1067
1068pub fn gettid() i32 {
1069 return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid)));
1070}
1071
1072pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
1073 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
1074}
1075
1076pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
1077 assert(sig >= 1);
1078 assert(sig != SIGKILL);
1079 assert(sig != SIGSTOP);
1080 var ksa = k_sigaction{
1081 .handler = act.handler,
1082 .flags = act.flags | SA_RESTORER,
1083 .mask = undefined,
1084 .restorer = @ptrCast(extern fn () void, restore_rt),
1085 };
1086 var ksa_old: k_sigaction = undefined;
1087 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8);
1088 const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
1089 const err = getErrno(result);
1090 if (err != 0) {
1091 return result;
1092 }
1093 if (oact) |old| {
1094 old.handler = ksa_old.handler;
1095 old.flags = @truncate(u32, ksa_old.flags);
1096 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
1097 }
1098 return 0;
1099}
1100
1101const NSIG = 65;
1102const sigset_t = [128 / @sizeOf(usize)]usize;
1103const all_mask = []usize{maxInt(usize)};
1104const app_mask = []usize{0xfffffffc7fffffff};
1105
1106const k_sigaction = extern struct {
1107 handler: extern fn (i32) void,
1108 flags: usize,
1109 restorer: extern fn () void,
1110 mask: [2]u32,
1111};
1112
1113/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
1114pub const Sigaction = struct {
1115 handler: extern fn (i32) void,
1116 mask: sigset_t,
1117 flags: u32,
1118};
1119
1120pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
1121pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
1122pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
1123pub const empty_sigset = []usize{0} ** sigset_t.len;
1124
1125pub fn raise(sig: i32) usize {
1126 var set: sigset_t = undefined;
1127 blockAppSignals(&set);
1128 const tid = syscall0(SYS_gettid);
1129 const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
1130 restoreSignals(&set);
1131 return ret;
1132}
1133
1134fn blockAllSignals(set: *sigset_t) void {
1135 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
1136}
1137
1138fn blockAppSignals(set: *sigset_t) void {
1139 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
1140}
1141
1142fn restoreSignals(set: *sigset_t) void {
1143 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
1144}
1145
1146pub fn sigaddset(set: *sigset_t, sig: u6) void {
1147 const s = sig - 1;
1148 (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1));
1149}
1150
1151pub fn sigismember(set: *const sigset_t, sig: u6) bool {
1152 const s = sig - 1;
1153 return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
1154}
1155
1156pub const in_port_t = u16;
1157pub const sa_family_t = u16;
1158pub const socklen_t = u32;
1159
1160/// This intentionally only has ip4 and ip6
1161pub const sockaddr = extern union {
1162 in: sockaddr_in,
1163 in6: sockaddr_in6,
1164};
1165
1166pub const sockaddr_in = extern struct {
1167 family: sa_family_t,
1168 port: in_port_t,
1169 addr: u32,
1170 zero: [8]u8,
1171};
1172
1173pub const sockaddr_in6 = extern struct {
1174 family: sa_family_t,
1175 port: in_port_t,
1176 flowinfo: u32,
1177 addr: [16]u8,
1178 scope_id: u32,
1179};
1180
1181pub const sockaddr_un = extern struct {
1182 family: sa_family_t,
1183 path: [108]u8,
1184};
1185
1186pub const iovec = extern struct {
1187 iov_base: [*]u8,
1188 iov_len: usize,
1189};
1190
1191pub const iovec_const = extern struct {
1192 iov_base: [*]const u8,
1193 iov_len: usize,
1194};
1195
1196pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1197 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
1198}
1199
1200pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1201 return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
1202}
1203
1204pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
1205 return syscall3(SYS_socket, domain, socket_type, protocol);
1206}
1207
1208pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
1209 return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
1210}
1211
1212pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
1213 return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
1214}
1215
1216pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
1217 return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
1218}
1219
1220pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
1221 return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
1222}
1223
1224pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
1225 return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
1226}
1227
1228pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
1229 return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
1230}
1231
1232pub fn shutdown(fd: i32, how: i32) usize {
1233 return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how)));
1234}
1235
1236pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
1237 return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len));
1238}
1239
1240pub fn listen(fd: i32, backlog: u32) usize {
1241 return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog);
1242}
1243
1244pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
1245 return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
1246}
1247
1248pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
1249 return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
1250}
1251
1252pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1253 return accept4(fd, addr, len, 0);
1254}
1255
1256pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
1257 return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags);
1258}
1259
1260pub fn fstat(fd: i32, stat_buf: *Stat) usize {
1261 return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
1262}
1263
1264// TODO https://github.com/ziglang/zig/issues/265
1265pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
1266 return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT);
1267}
1268
1269// TODO https://github.com/ziglang/zig/issues/265
1270pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
1271 return fstatat(AF_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);
1272}
1273
1274// TODO https://github.com/ziglang/zig/issues/265
1275pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
1276 return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
1277}
1278
1279// TODO https://github.com/ziglang/zig/issues/265
1280pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
1281 return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
1282}
1283
1284// TODO https://github.com/ziglang/zig/issues/265
1285pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
1286 return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
1287}
1288
1289pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize {
1290 return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
1291}
1292
1293// TODO https://github.com/ziglang/zig/issues/265
1294pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
1295 return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1296}
1297
1298// TODO https://github.com/ziglang/zig/issues/265
1299pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
1300 return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1301}
1302
1303// TODO https://github.com/ziglang/zig/issues/265
1304pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize {
1305 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
1306}
1307
1308// TODO https://github.com/ziglang/zig/issues/265
1309pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1310 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
1311}
1312
1313// TODO https://github.com/ziglang/zig/issues/265
1314pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1315 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
1316}
1317
1318// TODO https://github.com/ziglang/zig/issues/265
1319pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1320 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
1321}
1322
1323// TODO https://github.com/ziglang/zig/issues/265
1324pub fn removexattr(path: [*]const u8, name: [*]const u8) usize {
1325 return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
1326}
1327
1328// TODO https://github.com/ziglang/zig/issues/265
1329pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize {
1330 return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
1331}
1332
1333// TODO https://github.com/ziglang/zig/issues/265
1334pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
1335 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
1336}
1337
1338pub fn sched_getaffinity(pid: i32, set: []usize) usize {
1339 return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
1340}
1341
1342pub const epoll_data = packed union {
1343 ptr: usize,
1344 fd: i32,
1345 @"u32": u32,
1346 @"u64": u64,
1347};
1348
1349pub const epoll_event = packed struct {
1350 events: u32,
1351 data: epoll_data,
1352};
1353
1354pub fn epoll_create() usize {
1355 return epoll_create1(0);
1356}
1357
1358pub fn epoll_create1(flags: usize) usize {
1359 return syscall1(SYS_epoll_create1, flags);
1360}
1361
1362pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
1363 return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev));
1364}
1365
1366pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
1367 return epoll_pwait(epoll_fd, events, maxevents, timeout, null);
1368}
1369
1370pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
1371 return syscall6(
1372 SYS_epoll_pwait,
1373 @bitCast(usize, isize(epoll_fd)),
1374 @ptrToInt(events),
1375 @intCast(usize, maxevents),
1376 @bitCast(usize, isize(timeout)),
1377 @ptrToInt(sigmask),
1378 @sizeOf(sigset_t),
1379 );
1380}
1381
1382pub fn eventfd(count: u32, flags: u32) usize {
1383 return syscall2(SYS_eventfd2, count, flags);
1384}
1385
1386pub fn timerfd_create(clockid: i32, flags: u32) usize {
1387 return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags);
1388}
1389
1390pub const itimerspec = extern struct {
1391 it_interval: timespec,
1392 it_value: timespec,
1393};
1394
1395pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
1396 return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value));
1397}
1398
1399pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
1400 return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
1401}
1402
1403pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1404pub const _LINUX_CAPABILITY_U32S_1 = 1;
1405
1406pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1407pub const _LINUX_CAPABILITY_U32S_2 = 2;
1408
1409pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1410pub const _LINUX_CAPABILITY_U32S_3 = 2;
1411
1412pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1413pub const VFS_CAP_REVISION_SHIFT = 24;
1414pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1415pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
1416
1417pub const VFS_CAP_REVISION_1 = 0x01000000;
1418pub const VFS_CAP_U32_1 = 1;
1419pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
1420
1421pub const VFS_CAP_REVISION_2 = 0x02000000;
1422pub const VFS_CAP_U32_2 = 2;
1423pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
1424
1425pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1426pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1427pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
1428
1429pub const vfs_cap_data = extern struct {
1430 //all of these are mandated as little endian
1431 //when on disk.
1432 const Data = struct {
1433 permitted: u32,
1434 inheritable: u32,
1435 };
1436
1437 magic_etc: u32,
1438 data: [VFS_CAP_U32]Data,
1439};
1440
1441pub const CAP_CHOWN = 0;
1442pub const CAP_DAC_OVERRIDE = 1;
1443pub const CAP_DAC_READ_SEARCH = 2;
1444pub const CAP_FOWNER = 3;
1445pub const CAP_FSETID = 4;
1446pub const CAP_KILL = 5;
1447pub const CAP_SETGID = 6;
1448pub const CAP_SETUID = 7;
1449pub const CAP_SETPCAP = 8;
1450pub const CAP_LINUX_IMMUTABLE = 9;
1451pub const CAP_NET_BIND_SERVICE = 10;
1452pub const CAP_NET_BROADCAST = 11;
1453pub const CAP_NET_ADMIN = 12;
1454pub const CAP_NET_RAW = 13;
1455pub const CAP_IPC_LOCK = 14;
1456pub const CAP_IPC_OWNER = 15;
1457pub const CAP_SYS_MODULE = 16;
1458pub const CAP_SYS_RAWIO = 17;
1459pub const CAP_SYS_CHROOT = 18;
1460pub const CAP_SYS_PTRACE = 19;
1461pub const CAP_SYS_PACCT = 20;
1462pub const CAP_SYS_ADMIN = 21;
1463pub const CAP_SYS_BOOT = 22;
1464pub const CAP_SYS_NICE = 23;
1465pub const CAP_SYS_RESOURCE = 24;
1466pub const CAP_SYS_TIME = 25;
1467pub const CAP_SYS_TTY_CONFIG = 26;
1468pub const CAP_MKNOD = 27;
1469pub const CAP_LEASE = 28;
1470pub const CAP_AUDIT_WRITE = 29;
1471pub const CAP_AUDIT_CONTROL = 30;
1472pub const CAP_SETFCAP = 31;
1473pub const CAP_MAC_OVERRIDE = 32;
1474pub const CAP_MAC_ADMIN = 33;
1475pub const CAP_SYSLOG = 34;
1476pub const CAP_WAKE_ALARM = 35;
1477pub const CAP_BLOCK_SUSPEND = 36;
1478pub const CAP_AUDIT_READ = 37;
1479pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1480
1481pub fn cap_valid(u8: x) bool {
1482 return x >= 0 and x <= CAP_LAST_CAP;
1483}
1484
1485pub fn CAP_TO_MASK(cap: u8) u32 {
1486 return u32(1) << u5(cap & 31);
1487}
1488
1489pub fn CAP_TO_INDEX(cap: u8) u8 {
1490 return cap >> 5;
1491}
1492
1493pub const cap_t = extern struct {
1494 hdrp: *cap_user_header_t,
1495 datap: *cap_user_data_t,
1496};
1497
1498pub const cap_user_header_t = extern struct {
1499 version: u32,
1500 pid: usize,
1501};
1502
1503pub const cap_user_data_t = extern struct {
1504 effective: u32,
1505 permitted: u32,
1506 inheritable: u32,
1507};
1508
1509pub fn unshare(flags: usize) usize {
1510 return syscall1(SYS_unshare, flags);
1511}
1512
1513pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize {
1514 return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
1515}
1516
1517pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
1518 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
1519}
1520
1521pub const inotify_event = extern struct {
1522 wd: i32,
1523 mask: u32,
1524 cookie: u32,
1525 len: u32,
1526 //name: [?]u8,
1527};
1528
1529pub const dirent64 = extern struct {
1530 d_ino: u64,
1531 d_off: u64,
1532 d_reclen: u16,
1533 d_type: u8,
1534 d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
1535};
1536
1537test "import" {
1538 if (builtin.os == builtin.Os.linux) {
1539 _ = @import("linux/test.zig");
1540 }
1541}
std/os/linux/arm64.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const linux = std.os.linux;2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;4const iovec = linux.iovec;
std/os/linux/index.zig deleted-1537
...@@ -1,1537 +0,0 @@
1const std = @import("../../index.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");
4const maxInt = std.math.maxInt;
5const vdso = @import("vdso.zig");
6pub use switch (builtin.arch) {
7 builtin.Arch.x86_64 => @import("x86_64.zig"),
8 builtin.Arch.i386 => @import("i386.zig"),
9 builtin.Arch.aarch64 => @import("arm64.zig"),
10 else => @compileError("unsupported arch"),
11};
12pub use @import("errno.zig");
13
14pub const PATH_MAX = 4096;
15
16pub const STDIN_FILENO = 0;
17pub const STDOUT_FILENO = 1;
18pub const STDERR_FILENO = 2;
19
20pub const FUTEX_WAIT = 0;
21pub const FUTEX_WAKE = 1;
22pub const FUTEX_FD = 2;
23pub const FUTEX_REQUEUE = 3;
24pub const FUTEX_CMP_REQUEUE = 4;
25pub const FUTEX_WAKE_OP = 5;
26pub const FUTEX_LOCK_PI = 6;
27pub const FUTEX_UNLOCK_PI = 7;
28pub const FUTEX_TRYLOCK_PI = 8;
29pub const FUTEX_WAIT_BITSET = 9;
30
31pub const FUTEX_PRIVATE_FLAG = 128;
32
33pub const FUTEX_CLOCK_REALTIME = 256;
34
35pub const PROT_NONE = 0;
36pub const PROT_READ = 1;
37pub const PROT_WRITE = 2;
38pub const PROT_EXEC = 4;
39pub const PROT_GROWSDOWN = 0x01000000;
40pub const PROT_GROWSUP = 0x02000000;
41
42pub const MAP_FAILED = maxInt(usize);
43pub const MAP_SHARED = 0x01;
44pub const MAP_PRIVATE = 0x02;
45pub const MAP_TYPE = 0x0f;
46pub const MAP_FIXED = 0x10;
47pub const MAP_ANONYMOUS = 0x20;
48pub const MAP_NORESERVE = 0x4000;
49pub const MAP_GROWSDOWN = 0x0100;
50pub const MAP_DENYWRITE = 0x0800;
51pub const MAP_EXECUTABLE = 0x1000;
52pub const MAP_LOCKED = 0x2000;
53pub const MAP_POPULATE = 0x8000;
54pub const MAP_NONBLOCK = 0x10000;
55pub const MAP_STACK = 0x20000;
56pub const MAP_HUGETLB = 0x40000;
57pub const MAP_FILE = 0;
58
59pub const F_OK = 0;
60pub const X_OK = 1;
61pub const W_OK = 2;
62pub const R_OK = 4;
63
64pub const WNOHANG = 1;
65pub const WUNTRACED = 2;
66pub const WSTOPPED = 2;
67pub const WEXITED = 4;
68pub const WCONTINUED = 8;
69pub const WNOWAIT = 0x1000000;
70
71pub const SA_NOCLDSTOP = 1;
72pub const SA_NOCLDWAIT = 2;
73pub const SA_SIGINFO = 4;
74pub const SA_ONSTACK = 0x08000000;
75pub const SA_RESTART = 0x10000000;
76pub const SA_NODEFER = 0x40000000;
77pub const SA_RESETHAND = 0x80000000;
78pub const SA_RESTORER = 0x04000000;
79
80pub const SIGHUP = 1;
81pub const SIGINT = 2;
82pub const SIGQUIT = 3;
83pub const SIGILL = 4;
84pub const SIGTRAP = 5;
85pub const SIGABRT = 6;
86pub const SIGIOT = SIGABRT;
87pub const SIGBUS = 7;
88pub const SIGFPE = 8;
89pub const SIGKILL = 9;
90pub const SIGUSR1 = 10;
91pub const SIGSEGV = 11;
92pub const SIGUSR2 = 12;
93pub const SIGPIPE = 13;
94pub const SIGALRM = 14;
95pub const SIGTERM = 15;
96pub const SIGSTKFLT = 16;
97pub const SIGCHLD = 17;
98pub const SIGCONT = 18;
99pub const SIGSTOP = 19;
100pub const SIGTSTP = 20;
101pub const SIGTTIN = 21;
102pub const SIGTTOU = 22;
103pub const SIGURG = 23;
104pub const SIGXCPU = 24;
105pub const SIGXFSZ = 25;
106pub const SIGVTALRM = 26;
107pub const SIGPROF = 27;
108pub const SIGWINCH = 28;
109pub const SIGIO = 29;
110pub const SIGPOLL = 29;
111pub const SIGPWR = 30;
112pub const SIGSYS = 31;
113pub const SIGUNUSED = SIGSYS;
114
115pub const O_RDONLY = 0o0;
116pub const O_WRONLY = 0o1;
117pub const O_RDWR = 0o2;
118
119pub const SEEK_SET = 0;
120pub const SEEK_CUR = 1;
121pub const SEEK_END = 2;
122
123pub const SIG_BLOCK = 0;
124pub const SIG_UNBLOCK = 1;
125pub const SIG_SETMASK = 2;
126
127pub const PROTO_ip = 0o000;
128pub const PROTO_icmp = 0o001;
129pub const PROTO_igmp = 0o002;
130pub const PROTO_ggp = 0o003;
131pub const PROTO_ipencap = 0o004;
132pub const PROTO_st = 0o005;
133pub const PROTO_tcp = 0o006;
134pub const PROTO_egp = 0o010;
135pub const PROTO_pup = 0o014;
136pub const PROTO_udp = 0o021;
137pub const PROTO_hmp = 0o024;
138pub const PROTO_xns_idp = 0o026;
139pub const PROTO_rdp = 0o033;
140pub const PROTO_iso_tp4 = 0o035;
141pub const PROTO_xtp = 0o044;
142pub const PROTO_ddp = 0o045;
143pub const PROTO_idpr_cmtp = 0o046;
144pub const PROTO_ipv6 = 0o051;
145pub const PROTO_ipv6_route = 0o053;
146pub const PROTO_ipv6_frag = 0o054;
147pub const PROTO_idrp = 0o055;
148pub const PROTO_rsvp = 0o056;
149pub const PROTO_gre = 0o057;
150pub const PROTO_esp = 0o062;
151pub const PROTO_ah = 0o063;
152pub const PROTO_skip = 0o071;
153pub const PROTO_ipv6_icmp = 0o072;
154pub const PROTO_ipv6_nonxt = 0o073;
155pub const PROTO_ipv6_opts = 0o074;
156pub const PROTO_rspf = 0o111;
157pub const PROTO_vmtp = 0o121;
158pub const PROTO_ospf = 0o131;
159pub const PROTO_ipip = 0o136;
160pub const PROTO_encap = 0o142;
161pub const PROTO_pim = 0o147;
162pub const PROTO_raw = 0o377;
163
164pub const SHUT_RD = 0;
165pub const SHUT_WR = 1;
166pub const SHUT_RDWR = 2;
167
168pub const SOCK_STREAM = 1;
169pub const SOCK_DGRAM = 2;
170pub const SOCK_RAW = 3;
171pub const SOCK_RDM = 4;
172pub const SOCK_SEQPACKET = 5;
173pub const SOCK_DCCP = 6;
174pub const SOCK_PACKET = 10;
175pub const SOCK_CLOEXEC = 0o2000000;
176pub const SOCK_NONBLOCK = 0o4000;
177
178pub const PF_UNSPEC = 0;
179pub const PF_LOCAL = 1;
180pub const PF_UNIX = PF_LOCAL;
181pub const PF_FILE = PF_LOCAL;
182pub const PF_INET = 2;
183pub const PF_AX25 = 3;
184pub const PF_IPX = 4;
185pub const PF_APPLETALK = 5;
186pub const PF_NETROM = 6;
187pub const PF_BRIDGE = 7;
188pub const PF_ATMPVC = 8;
189pub const PF_X25 = 9;
190pub const PF_INET6 = 10;
191pub const PF_ROSE = 11;
192pub const PF_DECnet = 12;
193pub const PF_NETBEUI = 13;
194pub const PF_SECURITY = 14;
195pub const PF_KEY = 15;
196pub const PF_NETLINK = 16;
197pub const PF_ROUTE = PF_NETLINK;
198pub const PF_PACKET = 17;
199pub const PF_ASH = 18;
200pub const PF_ECONET = 19;
201pub const PF_ATMSVC = 20;
202pub const PF_RDS = 21;
203pub const PF_SNA = 22;
204pub const PF_IRDA = 23;
205pub const PF_PPPOX = 24;
206pub const PF_WANPIPE = 25;
207pub const PF_LLC = 26;
208pub const PF_IB = 27;
209pub const PF_MPLS = 28;
210pub const PF_CAN = 29;
211pub const PF_TIPC = 30;
212pub const PF_BLUETOOTH = 31;
213pub const PF_IUCV = 32;
214pub const PF_RXRPC = 33;
215pub const PF_ISDN = 34;
216pub const PF_PHONET = 35;
217pub const PF_IEEE802154 = 36;
218pub const PF_CAIF = 37;
219pub const PF_ALG = 38;
220pub const PF_NFC = 39;
221pub const PF_VSOCK = 40;
222pub const PF_KCM = 41;
223pub const PF_QIPCRTR = 42;
224pub const PF_SMC = 43;
225pub const PF_MAX = 44;
226
227pub const AF_UNSPEC = PF_UNSPEC;
228pub const AF_LOCAL = PF_LOCAL;
229pub const AF_UNIX = AF_LOCAL;
230pub const AF_FILE = AF_LOCAL;
231pub const AF_INET = PF_INET;
232pub const AF_AX25 = PF_AX25;
233pub const AF_IPX = PF_IPX;
234pub const AF_APPLETALK = PF_APPLETALK;
235pub const AF_NETROM = PF_NETROM;
236pub const AF_BRIDGE = PF_BRIDGE;
237pub const AF_ATMPVC = PF_ATMPVC;
238pub const AF_X25 = PF_X25;
239pub const AF_INET6 = PF_INET6;
240pub const AF_ROSE = PF_ROSE;
241pub const AF_DECnet = PF_DECnet;
242pub const AF_NETBEUI = PF_NETBEUI;
243pub const AF_SECURITY = PF_SECURITY;
244pub const AF_KEY = PF_KEY;
245pub const AF_NETLINK = PF_NETLINK;
246pub const AF_ROUTE = PF_ROUTE;
247pub const AF_PACKET = PF_PACKET;
248pub const AF_ASH = PF_ASH;
249pub const AF_ECONET = PF_ECONET;
250pub const AF_ATMSVC = PF_ATMSVC;
251pub const AF_RDS = PF_RDS;
252pub const AF_SNA = PF_SNA;
253pub const AF_IRDA = PF_IRDA;
254pub const AF_PPPOX = PF_PPPOX;
255pub const AF_WANPIPE = PF_WANPIPE;
256pub const AF_LLC = PF_LLC;
257pub const AF_IB = PF_IB;
258pub const AF_MPLS = PF_MPLS;
259pub const AF_CAN = PF_CAN;
260pub const AF_TIPC = PF_TIPC;
261pub const AF_BLUETOOTH = PF_BLUETOOTH;
262pub const AF_IUCV = PF_IUCV;
263pub const AF_RXRPC = PF_RXRPC;
264pub const AF_ISDN = PF_ISDN;
265pub const AF_PHONET = PF_PHONET;
266pub const AF_IEEE802154 = PF_IEEE802154;
267pub const AF_CAIF = PF_CAIF;
268pub const AF_ALG = PF_ALG;
269pub const AF_NFC = PF_NFC;
270pub const AF_VSOCK = PF_VSOCK;
271pub const AF_KCM = PF_KCM;
272pub const AF_QIPCRTR = PF_QIPCRTR;
273pub const AF_SMC = PF_SMC;
274pub const AF_MAX = PF_MAX;
275
276pub const SO_DEBUG = 1;
277pub const SO_REUSEADDR = 2;
278pub const SO_TYPE = 3;
279pub const SO_ERROR = 4;
280pub const SO_DONTROUTE = 5;
281pub const SO_BROADCAST = 6;
282pub const SO_SNDBUF = 7;
283pub const SO_RCVBUF = 8;
284pub const SO_KEEPALIVE = 9;
285pub const SO_OOBINLINE = 10;
286pub const SO_NO_CHECK = 11;
287pub const SO_PRIORITY = 12;
288pub const SO_LINGER = 13;
289pub const SO_BSDCOMPAT = 14;
290pub const SO_REUSEPORT = 15;
291pub const SO_PASSCRED = 16;
292pub const SO_PEERCRED = 17;
293pub const SO_RCVLOWAT = 18;
294pub const SO_SNDLOWAT = 19;
295pub const SO_RCVTIMEO = 20;
296pub const SO_SNDTIMEO = 21;
297pub const SO_ACCEPTCONN = 30;
298pub const SO_SNDBUFFORCE = 32;
299pub const SO_RCVBUFFORCE = 33;
300pub const SO_PROTOCOL = 38;
301pub const SO_DOMAIN = 39;
302
303pub const SO_SECURITY_AUTHENTICATION = 22;
304pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
305pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
306
307pub const SO_BINDTODEVICE = 25;
308
309pub const SO_ATTACH_FILTER = 26;
310pub const SO_DETACH_FILTER = 27;
311pub const SO_GET_FILTER = SO_ATTACH_FILTER;
312
313pub const SO_PEERNAME = 28;
314pub const SO_TIMESTAMP = 29;
315pub const SCM_TIMESTAMP = SO_TIMESTAMP;
316
317pub const SO_PEERSEC = 31;
318pub const SO_PASSSEC = 34;
319pub const SO_TIMESTAMPNS = 35;
320pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
321pub const SO_MARK = 36;
322pub const SO_TIMESTAMPING = 37;
323pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
324pub const SO_RXQ_OVFL = 40;
325pub const SO_WIFI_STATUS = 41;
326pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
327pub const SO_PEEK_OFF = 42;
328pub const SO_NOFCS = 43;
329pub const SO_LOCK_FILTER = 44;
330pub const SO_SELECT_ERR_QUEUE = 45;
331pub const SO_BUSY_POLL = 46;
332pub const SO_MAX_PACING_RATE = 47;
333pub const SO_BPF_EXTENSIONS = 48;
334pub const SO_INCOMING_CPU = 49;
335pub const SO_ATTACH_BPF = 50;
336pub const SO_DETACH_BPF = SO_DETACH_FILTER;
337pub const SO_ATTACH_REUSEPORT_CBPF = 51;
338pub const SO_ATTACH_REUSEPORT_EBPF = 52;
339pub const SO_CNX_ADVICE = 53;
340pub const SCM_TIMESTAMPING_OPT_STATS = 54;
341pub const SO_MEMINFO = 55;
342pub const SO_INCOMING_NAPI_ID = 56;
343pub const SO_COOKIE = 57;
344pub const SCM_TIMESTAMPING_PKTINFO = 58;
345pub const SO_PEERGROUPS = 59;
346pub const SO_ZEROCOPY = 60;
347
348pub const SOL_SOCKET = 1;
349
350pub const SOL_IP = 0;
351pub const SOL_IPV6 = 41;
352pub const SOL_ICMPV6 = 58;
353
354pub const SOL_RAW = 255;
355pub const SOL_DECNET = 261;
356pub const SOL_X25 = 262;
357pub const SOL_PACKET = 263;
358pub const SOL_ATM = 264;
359pub const SOL_AAL = 265;
360pub const SOL_IRDA = 266;
361pub const SOL_NETBEUI = 267;
362pub const SOL_LLC = 268;
363pub const SOL_DCCP = 269;
364pub const SOL_NETLINK = 270;
365pub const SOL_TIPC = 271;
366pub const SOL_RXRPC = 272;
367pub const SOL_PPPOL2TP = 273;
368pub const SOL_BLUETOOTH = 274;
369pub const SOL_PNPIPE = 275;
370pub const SOL_RDS = 276;
371pub const SOL_IUCV = 277;
372pub const SOL_CAIF = 278;
373pub const SOL_ALG = 279;
374pub const SOL_NFC = 280;
375pub const SOL_KCM = 281;
376pub const SOL_TLS = 282;
377
378pub const SOMAXCONN = 128;
379
380pub const MSG_OOB = 0x0001;
381pub const MSG_PEEK = 0x0002;
382pub const MSG_DONTROUTE = 0x0004;
383pub const MSG_CTRUNC = 0x0008;
384pub const MSG_PROXY = 0x0010;
385pub const MSG_TRUNC = 0x0020;
386pub const MSG_DONTWAIT = 0x0040;
387pub const MSG_EOR = 0x0080;
388pub const MSG_WAITALL = 0x0100;
389pub const MSG_FIN = 0x0200;
390pub const MSG_SYN = 0x0400;
391pub const MSG_CONFIRM = 0x0800;
392pub const MSG_RST = 0x1000;
393pub const MSG_ERRQUEUE = 0x2000;
394pub const MSG_NOSIGNAL = 0x4000;
395pub const MSG_MORE = 0x8000;
396pub const MSG_WAITFORONE = 0x10000;
397pub const MSG_BATCH = 0x40000;
398pub const MSG_ZEROCOPY = 0x4000000;
399pub const MSG_FASTOPEN = 0x20000000;
400pub const MSG_CMSG_CLOEXEC = 0x40000000;
401
402pub const DT_UNKNOWN = 0;
403pub const DT_FIFO = 1;
404pub const DT_CHR = 2;
405pub const DT_DIR = 4;
406pub const DT_BLK = 6;
407pub const DT_REG = 8;
408pub const DT_LNK = 10;
409pub const DT_SOCK = 12;
410pub const DT_WHT = 14;
411
412pub const TCGETS = 0x5401;
413pub const TCSETS = 0x5402;
414pub const TCSETSW = 0x5403;
415pub const TCSETSF = 0x5404;
416pub const TCGETA = 0x5405;
417pub const TCSETA = 0x5406;
418pub const TCSETAW = 0x5407;
419pub const TCSETAF = 0x5408;
420pub const TCSBRK = 0x5409;
421pub const TCXONC = 0x540A;
422pub const TCFLSH = 0x540B;
423pub const TIOCEXCL = 0x540C;
424pub const TIOCNXCL = 0x540D;
425pub const TIOCSCTTY = 0x540E;
426pub const TIOCGPGRP = 0x540F;
427pub const TIOCSPGRP = 0x5410;
428pub const TIOCOUTQ = 0x5411;
429pub const TIOCSTI = 0x5412;
430pub const TIOCGWINSZ = 0x5413;
431pub const TIOCSWINSZ = 0x5414;
432pub const TIOCMGET = 0x5415;
433pub const TIOCMBIS = 0x5416;
434pub const TIOCMBIC = 0x5417;
435pub const TIOCMSET = 0x5418;
436pub const TIOCGSOFTCAR = 0x5419;
437pub const TIOCSSOFTCAR = 0x541A;
438pub const FIONREAD = 0x541B;
439pub const TIOCINQ = FIONREAD;
440pub const TIOCLINUX = 0x541C;
441pub const TIOCCONS = 0x541D;
442pub const TIOCGSERIAL = 0x541E;
443pub const TIOCSSERIAL = 0x541F;
444pub const TIOCPKT = 0x5420;
445pub const FIONBIO = 0x5421;
446pub const TIOCNOTTY = 0x5422;
447pub const TIOCSETD = 0x5423;
448pub const TIOCGETD = 0x5424;
449pub const TCSBRKP = 0x5425;
450pub const TIOCSBRK = 0x5427;
451pub const TIOCCBRK = 0x5428;
452pub const TIOCGSID = 0x5429;
453pub const TIOCGRS485 = 0x542E;
454pub const TIOCSRS485 = 0x542F;
455pub const TIOCGPTN = 0x80045430;
456pub const TIOCSPTLCK = 0x40045431;
457pub const TIOCGDEV = 0x80045432;
458pub const TCGETX = 0x5432;
459pub const TCSETX = 0x5433;
460pub const TCSETXF = 0x5434;
461pub const TCSETXW = 0x5435;
462pub const TIOCSIG = 0x40045436;
463pub const TIOCVHANGUP = 0x5437;
464pub const TIOCGPKT = 0x80045438;
465pub const TIOCGPTLCK = 0x80045439;
466pub const TIOCGEXCL = 0x80045440;
467
468pub const EPOLL_CLOEXEC = O_CLOEXEC;
469
470pub const EPOLL_CTL_ADD = 1;
471pub const EPOLL_CTL_DEL = 2;
472pub const EPOLL_CTL_MOD = 3;
473
474pub const EPOLLIN = 0x001;
475pub const EPOLLPRI = 0x002;
476pub const EPOLLOUT = 0x004;
477pub const EPOLLRDNORM = 0x040;
478pub const EPOLLRDBAND = 0x080;
479pub const EPOLLWRNORM = 0x100;
480pub const EPOLLWRBAND = 0x200;
481pub const EPOLLMSG = 0x400;
482pub const EPOLLERR = 0x008;
483pub const EPOLLHUP = 0x010;
484pub const EPOLLRDHUP = 0x2000;
485pub const EPOLLEXCLUSIVE = (u32(1) << 28);
486pub const EPOLLWAKEUP = (u32(1) << 29);
487pub const EPOLLONESHOT = (u32(1) << 30);
488pub const EPOLLET = (u32(1) << 31);
489
490pub const CLOCK_REALTIME = 0;
491pub const CLOCK_MONOTONIC = 1;
492pub const CLOCK_PROCESS_CPUTIME_ID = 2;
493pub const CLOCK_THREAD_CPUTIME_ID = 3;
494pub const CLOCK_MONOTONIC_RAW = 4;
495pub const CLOCK_REALTIME_COARSE = 5;
496pub const CLOCK_MONOTONIC_COARSE = 6;
497pub const CLOCK_BOOTTIME = 7;
498pub const CLOCK_REALTIME_ALARM = 8;
499pub const CLOCK_BOOTTIME_ALARM = 9;
500pub const CLOCK_SGI_CYCLE = 10;
501pub const CLOCK_TAI = 11;
502
503pub const CSIGNAL = 0x000000ff;
504pub const CLONE_VM = 0x00000100;
505pub const CLONE_FS = 0x00000200;
506pub const CLONE_FILES = 0x00000400;
507pub const CLONE_SIGHAND = 0x00000800;
508pub const CLONE_PTRACE = 0x00002000;
509pub const CLONE_VFORK = 0x00004000;
510pub const CLONE_PARENT = 0x00008000;
511pub const CLONE_THREAD = 0x00010000;
512pub const CLONE_NEWNS = 0x00020000;
513pub const CLONE_SYSVSEM = 0x00040000;
514pub const CLONE_SETTLS = 0x00080000;
515pub const CLONE_PARENT_SETTID = 0x00100000;
516pub const CLONE_CHILD_CLEARTID = 0x00200000;
517pub const CLONE_DETACHED = 0x00400000;
518pub const CLONE_UNTRACED = 0x00800000;
519pub const CLONE_CHILD_SETTID = 0x01000000;
520pub const CLONE_NEWCGROUP = 0x02000000;
521pub const CLONE_NEWUTS = 0x04000000;
522pub const CLONE_NEWIPC = 0x08000000;
523pub const CLONE_NEWUSER = 0x10000000;
524pub const CLONE_NEWPID = 0x20000000;
525pub const CLONE_NEWNET = 0x40000000;
526pub const CLONE_IO = 0x80000000;
527
528pub const EFD_SEMAPHORE = 1;
529pub const EFD_CLOEXEC = O_CLOEXEC;
530pub const EFD_NONBLOCK = O_NONBLOCK;
531
532pub const MS_RDONLY = 1;
533pub const MS_NOSUID = 2;
534pub const MS_NODEV = 4;
535pub const MS_NOEXEC = 8;
536pub const MS_SYNCHRONOUS = 16;
537pub const MS_REMOUNT = 32;
538pub const MS_MANDLOCK = 64;
539pub const MS_DIRSYNC = 128;
540pub const MS_NOATIME = 1024;
541pub const MS_NODIRATIME = 2048;
542pub const MS_BIND = 4096;
543pub const MS_MOVE = 8192;
544pub const MS_REC = 16384;
545pub const MS_SILENT = 32768;
546pub const MS_POSIXACL = (1 << 16);
547pub const MS_UNBINDABLE = (1 << 17);
548pub const MS_PRIVATE = (1 << 18);
549pub const MS_SLAVE = (1 << 19);
550pub const MS_SHARED = (1 << 20);
551pub const MS_RELATIME = (1 << 21);
552pub const MS_KERNMOUNT = (1 << 22);
553pub const MS_I_VERSION = (1 << 23);
554pub const MS_STRICTATIME = (1 << 24);
555pub const MS_LAZYTIME = (1 << 25);
556pub const MS_NOREMOTELOCK = (1 << 27);
557pub const MS_NOSEC = (1 << 28);
558pub const MS_BORN = (1 << 29);
559pub const MS_ACTIVE = (1 << 30);
560pub const MS_NOUSER = (1 << 31);
561
562pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
563
564pub const MS_MGC_VAL = 0xc0ed0000;
565pub const MS_MGC_MSK = 0xffff0000;
566
567pub const MNT_FORCE = 1;
568pub const MNT_DETACH = 2;
569pub const MNT_EXPIRE = 4;
570pub const UMOUNT_NOFOLLOW = 8;
571
572pub const IN_CLOEXEC = O_CLOEXEC;
573pub const IN_NONBLOCK = O_NONBLOCK;
574
575pub const IN_ACCESS = 0x00000001;
576pub const IN_MODIFY = 0x00000002;
577pub const IN_ATTRIB = 0x00000004;
578pub const IN_CLOSE_WRITE = 0x00000008;
579pub const IN_CLOSE_NOWRITE = 0x00000010;
580pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
581pub const IN_OPEN = 0x00000020;
582pub const IN_MOVED_FROM = 0x00000040;
583pub const IN_MOVED_TO = 0x00000080;
584pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
585pub const IN_CREATE = 0x00000100;
586pub const IN_DELETE = 0x00000200;
587pub const IN_DELETE_SELF = 0x00000400;
588pub const IN_MOVE_SELF = 0x00000800;
589pub const IN_ALL_EVENTS = 0x00000fff;
590
591pub const IN_UNMOUNT = 0x00002000;
592pub const IN_Q_OVERFLOW = 0x00004000;
593pub const IN_IGNORED = 0x00008000;
594
595pub const IN_ONLYDIR = 0x01000000;
596pub const IN_DONT_FOLLOW = 0x02000000;
597pub const IN_EXCL_UNLINK = 0x04000000;
598pub const IN_MASK_ADD = 0x20000000;
599
600pub const IN_ISDIR = 0x40000000;
601pub const IN_ONESHOT = 0x80000000;
602
603pub const S_IFMT = 0o170000;
604
605pub const S_IFDIR = 0o040000;
606pub const S_IFCHR = 0o020000;
607pub const S_IFBLK = 0o060000;
608pub const S_IFREG = 0o100000;
609pub const S_IFIFO = 0o010000;
610pub const S_IFLNK = 0o120000;
611pub const S_IFSOCK = 0o140000;
612
613pub const S_ISUID = 0o4000;
614pub const S_ISGID = 0o2000;
615pub const S_ISVTX = 0o1000;
616pub const S_IRUSR = 0o400;
617pub const S_IWUSR = 0o200;
618pub const S_IXUSR = 0o100;
619pub const S_IRWXU = 0o700;
620pub const S_IRGRP = 0o040;
621pub const S_IWGRP = 0o020;
622pub const S_IXGRP = 0o010;
623pub const S_IRWXG = 0o070;
624pub const S_IROTH = 0o004;
625pub const S_IWOTH = 0o002;
626pub const S_IXOTH = 0o001;
627pub const S_IRWXO = 0o007;
628
629pub fn S_ISREG(m: u32) bool {
630 return m & S_IFMT == S_IFREG;
631}
632
633pub fn S_ISDIR(m: u32) bool {
634 return m & S_IFMT == S_IFDIR;
635}
636
637pub fn S_ISCHR(m: u32) bool {
638 return m & S_IFMT == S_IFCHR;
639}
640
641pub fn S_ISBLK(m: u32) bool {
642 return m & S_IFMT == S_IFBLK;
643}
644
645pub fn S_ISFIFO(m: u32) bool {
646 return m & S_IFMT == S_IFIFO;
647}
648
649pub fn S_ISLNK(m: u32) bool {
650 return m & S_IFMT == S_IFLNK;
651}
652
653pub fn S_ISSOCK(m: u32) bool {
654 return m & S_IFMT == S_IFSOCK;
655}
656
657pub const TFD_NONBLOCK = O_NONBLOCK;
658pub const TFD_CLOEXEC = O_CLOEXEC;
659
660pub const TFD_TIMER_ABSTIME = 1;
661pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
662
663fn unsigned(s: i32) u32 {
664 return @bitCast(u32, s);
665}
666fn signed(s: u32) i32 {
667 return @bitCast(i32, s);
668}
669pub fn WEXITSTATUS(s: i32) i32 {
670 return signed((unsigned(s) & 0xff00) >> 8);
671}
672pub fn WTERMSIG(s: i32) i32 {
673 return signed(unsigned(s) & 0x7f);
674}
675pub fn WSTOPSIG(s: i32) i32 {
676 return WEXITSTATUS(s);
677}
678pub fn WIFEXITED(s: i32) bool {
679 return WTERMSIG(s) == 0;
680}
681pub fn WIFSTOPPED(s: i32) bool {
682 return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
683}
684pub fn WIFSIGNALED(s: i32) bool {
685 return (unsigned(s) & 0xffff) -% 1 < 0xff;
686}
687
688pub const winsize = extern struct {
689 ws_row: u16,
690 ws_col: u16,
691 ws_xpixel: u16,
692 ws_ypixel: u16,
693};
694
695/// Get the errno from a syscall return value, or 0 for no error.
696pub fn getErrno(r: usize) usize {
697 const signed_r = @bitCast(isize, r);
698 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
699}
700
701pub fn dup2(old: i32, new: i32) usize {
702 return dup3(old, new, 0);
703}
704
705pub fn dup3(old: i32, new: i32, flags: u32) usize {
706 return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags);
707}
708
709// TODO https://github.com/ziglang/zig/issues/265
710pub fn chdir(path: [*]const u8) usize {
711 return syscall1(SYS_chdir, @ptrToInt(path));
712}
713
714// TODO https://github.com/ziglang/zig/issues/265
715pub fn chroot(path: [*]const u8) usize {
716 return syscall1(SYS_chroot, @ptrToInt(path));
717}
718
719// TODO https://github.com/ziglang/zig/issues/265
720pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
721 return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
722}
723
724pub fn fork() usize {
725 return clone2(SIGCHLD, 0);
726}
727
728/// This must be inline, and inline call the syscall function, because if the
729/// child does a return it will clobber the parent's stack.
730/// It is advised to avoid this function and use clone instead, because
731/// the compiler is not aware of how vfork affects control flow and you may
732/// see different results in optimized builds.
733pub inline fn vfork() usize {
734 return @inlineCall(syscall0, SYS_vfork);
735}
736
737pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize {
738 return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout));
739}
740
741pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize {
742 return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val));
743}
744
745pub fn getcwd(buf: [*]u8, size: usize) usize {
746 return syscall2(SYS_getcwd, @ptrToInt(buf), size);
747}
748
749pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
750 return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
751}
752
753pub fn inotify_init1(flags: u32) usize {
754 return syscall1(SYS_inotify_init1, flags);
755}
756
757pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
758 return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask);
759}
760
761pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
762 return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
763}
764
765pub fn isatty(fd: i32) bool {
766 var wsz: winsize = undefined;
767 return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
768}
769
770// TODO https://github.com/ziglang/zig/issues/265
771pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
772 return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
773}
774
775// TODO https://github.com/ziglang/zig/issues/265
776pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
777 return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
778}
779
780// TODO https://github.com/ziglang/zig/issues/265
781pub fn mkdir(path: [*]const u8, mode: u32) usize {
782 return mkdirat(AT_FDCWD, path, mode);
783}
784
785// TODO https://github.com/ziglang/zig/issues/265
786pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
787 return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
788}
789
790// TODO https://github.com/ziglang/zig/issues/265
791pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize {
792 return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
793}
794
795// TODO https://github.com/ziglang/zig/issues/265
796pub fn umount(special: [*]const u8) usize {
797 return syscall2(SYS_umount2, @ptrToInt(special), 0);
798}
799
800// TODO https://github.com/ziglang/zig/issues/265
801pub fn umount2(special: [*]const u8, flags: u32) usize {
802 return syscall2(SYS_umount2, @ptrToInt(special), flags);
803}
804
805pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
806 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
807}
808
809pub fn munmap(address: usize, length: usize) usize {
810 return syscall2(SYS_munmap, address, length);
811}
812
813pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
814 return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
815}
816
817pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
818 return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
819}
820
821pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
822 return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
823}
824
825pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
826 return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
827}
828
829pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
830 return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
831}
832
833// TODO https://github.com/ziglang/zig/issues/265
834pub fn rmdir(path: [*]const u8) usize {
835 return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
836}
837
838// TODO https://github.com/ziglang/zig/issues/265
839pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
840 return symlinkat(existing, AT_FDCWD, new);
841}
842
843// TODO https://github.com/ziglang/zig/issues/265
844pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
845 return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath));
846}
847
848// TODO https://github.com/ziglang/zig/issues/265
849pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
850 return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
851}
852
853// TODO https://github.com/ziglang/zig/issues/265
854pub fn access(path: [*]const u8, mode: u32) usize {
855 return faccessat(AT_FDCWD, path, mode);
856}
857
858pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
859 return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
860}
861
862pub fn pipe(fd: *[2]i32) usize {
863 return pipe2(fd, 0);
864}
865
866pub fn pipe2(fd: *[2]i32, flags: u32) usize {
867 return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
868}
869
870pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
871 return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
872}
873
874pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
875 return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
876}
877
878// TODO https://github.com/ziglang/zig/issues/265
879pub fn rename(old: [*]const u8, new: [*]const u8) usize {
880 return renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);
881}
882
883// TODO https://github.com/ziglang/zig/issues/265
884pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
885 return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
886}
887
888// TODO https://github.com/ziglang/zig/issues/265
889pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
890 return openat(AT_FDCWD, path, flags, perm);
891}
892
893// TODO https://github.com/ziglang/zig/issues/265
894pub fn create(path: [*]const u8, perm: usize) usize {
895 return syscall2(SYS_creat, @ptrToInt(path), perm);
896}
897
898// TODO https://github.com/ziglang/zig/issues/265
899pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
900 // dirfd could be negative, for example AT_FDCWD is -100
901 return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
902}
903
904/// See also `clone` (from the arch-specific include)
905pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize {
906 return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
907}
908
909/// See also `clone` (from the arch-specific include)
910pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
911 return syscall2(SYS_clone, flags, child_stack_ptr);
912}
913
914pub fn close(fd: i32) usize {
915 return syscall1(SYS_close, @bitCast(usize, isize(fd)));
916}
917
918pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
919 return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
920}
921
922pub fn exit(status: i32) noreturn {
923 _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
924 unreachable;
925}
926
927pub fn exit_group(status: i32) noreturn {
928 _ = syscall1(SYS_exit_group, @bitCast(usize, isize(status)));
929 unreachable;
930}
931
932pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
933 return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags);
934}
935
936pub fn kill(pid: i32, sig: i32) usize {
937 return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
938}
939
940// TODO https://github.com/ziglang/zig/issues/265
941pub fn unlink(path: [*]const u8) usize {
942 return unlinkat(AT_FDCWD, path, 0);
943}
944
945// TODO https://github.com/ziglang/zig/issues/265
946pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
947 return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
948}
949
950pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
951 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
952}
953
954pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
955 if (VDSO_CGT_SYM.len != 0) {
956 const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);
957 if (@ptrToInt(f) != 0) {
958 const rc = f(clk_id, tp);
959 switch (rc) {
960 0, @bitCast(usize, isize(-EINVAL)) => return rc,
961 else => {},
962 }
963 }
964 }
965 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
966}
967var vdso_clock_gettime = init_vdso_clock_gettime;
968extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
969 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
970 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
971 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
972 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
973 return f(clk, ts);
974}
975
976pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
977 return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
978}
979
980pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
981 return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
982}
983
984pub fn gettimeofday(tv: *timeval, tz: *timezone) usize {
985 return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
986}
987
988pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
989 return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
990}
991
992pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
993 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
994}
995
996pub fn setuid(uid: u32) usize {
997 return syscall1(SYS_setuid, uid);
998}
999
1000pub fn setgid(gid: u32) usize {
1001 return syscall1(SYS_setgid, gid);
1002}
1003
1004pub fn setreuid(ruid: u32, euid: u32) usize {
1005 return syscall2(SYS_setreuid, ruid, euid);
1006}
1007
1008pub fn setregid(rgid: u32, egid: u32) usize {
1009 return syscall2(SYS_setregid, rgid, egid);
1010}
1011
1012pub fn getuid() u32 {
1013 return u32(syscall0(SYS_getuid));
1014}
1015
1016pub fn getgid() u32 {
1017 return u32(syscall0(SYS_getgid));
1018}
1019
1020pub fn geteuid() u32 {
1021 return u32(syscall0(SYS_geteuid));
1022}
1023
1024pub fn getegid() u32 {
1025 return u32(syscall0(SYS_getegid));
1026}
1027
1028pub fn seteuid(euid: u32) usize {
1029 return syscall1(SYS_seteuid, euid);
1030}
1031
1032pub fn setegid(egid: u32) usize {
1033 return syscall1(SYS_setegid, egid);
1034}
1035
1036pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize {
1037 return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
1038}
1039
1040pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize {
1041 return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
1042}
1043
1044pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
1045 return syscall3(SYS_setresuid, ruid, euid, suid);
1046}
1047
1048pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
1049 return syscall3(SYS_setresgid, rgid, egid, sgid);
1050}
1051
1052pub fn getgroups(size: usize, list: *u32) usize {
1053 return syscall2(SYS_getgroups, size, @ptrToInt(list));
1054}
1055
1056pub fn setgroups(size: usize, list: *const u32) usize {
1057 return syscall2(SYS_setgroups, size, @ptrToInt(list));
1058}
1059
1060pub fn getpid() i32 {
1061 return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
1062}
1063
1064pub fn gettid() i32 {
1065 return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid)));
1066}
1067
1068pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
1069 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
1070}
1071
1072pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
1073 assert(sig >= 1);
1074 assert(sig != SIGKILL);
1075 assert(sig != SIGSTOP);
1076 var ksa = k_sigaction{
1077 .handler = act.handler,
1078 .flags = act.flags | SA_RESTORER,
1079 .mask = undefined,
1080 .restorer = @ptrCast(extern fn () void, restore_rt),
1081 };
1082 var ksa_old: k_sigaction = undefined;
1083 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8);
1084 const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
1085 const err = getErrno(result);
1086 if (err != 0) {
1087 return result;
1088 }
1089 if (oact) |old| {
1090 old.handler = ksa_old.handler;
1091 old.flags = @truncate(u32, ksa_old.flags);
1092 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
1093 }
1094 return 0;
1095}
1096
1097const NSIG = 65;
1098const sigset_t = [128 / @sizeOf(usize)]usize;
1099const all_mask = []usize{maxInt(usize)};
1100const app_mask = []usize{0xfffffffc7fffffff};
1101
1102const k_sigaction = extern struct {
1103 handler: extern fn (i32) void,
1104 flags: usize,
1105 restorer: extern fn () void,
1106 mask: [2]u32,
1107};
1108
1109/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
1110pub const Sigaction = struct {
1111 handler: extern fn (i32) void,
1112 mask: sigset_t,
1113 flags: u32,
1114};
1115
1116pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
1117pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
1118pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
1119pub const empty_sigset = []usize{0} ** sigset_t.len;
1120
1121pub fn raise(sig: i32) usize {
1122 var set: sigset_t = undefined;
1123 blockAppSignals(&set);
1124 const tid = syscall0(SYS_gettid);
1125 const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
1126 restoreSignals(&set);
1127 return ret;
1128}
1129
1130fn blockAllSignals(set: *sigset_t) void {
1131 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
1132}
1133
1134fn blockAppSignals(set: *sigset_t) void {
1135 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
1136}
1137
1138fn restoreSignals(set: *sigset_t) void {
1139 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
1140}
1141
1142pub fn sigaddset(set: *sigset_t, sig: u6) void {
1143 const s = sig - 1;
1144 (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1));
1145}
1146
1147pub fn sigismember(set: *const sigset_t, sig: u6) bool {
1148 const s = sig - 1;
1149 return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
1150}
1151
1152pub const in_port_t = u16;
1153pub const sa_family_t = u16;
1154pub const socklen_t = u32;
1155
1156/// This intentionally only has ip4 and ip6
1157pub const sockaddr = extern union {
1158 in: sockaddr_in,
1159 in6: sockaddr_in6,
1160};
1161
1162pub const sockaddr_in = extern struct {
1163 family: sa_family_t,
1164 port: in_port_t,
1165 addr: u32,
1166 zero: [8]u8,
1167};
1168
1169pub const sockaddr_in6 = extern struct {
1170 family: sa_family_t,
1171 port: in_port_t,
1172 flowinfo: u32,
1173 addr: [16]u8,
1174 scope_id: u32,
1175};
1176
1177pub const sockaddr_un = extern struct {
1178 family: sa_family_t,
1179 path: [108]u8,
1180};
1181
1182pub const iovec = extern struct {
1183 iov_base: [*]u8,
1184 iov_len: usize,
1185};
1186
1187pub const iovec_const = extern struct {
1188 iov_base: [*]const u8,
1189 iov_len: usize,
1190};
1191
1192pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1193 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
1194}
1195
1196pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1197 return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
1198}
1199
1200pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
1201 return syscall3(SYS_socket, domain, socket_type, protocol);
1202}
1203
1204pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
1205 return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
1206}
1207
1208pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
1209 return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
1210}
1211
1212pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
1213 return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
1214}
1215
1216pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
1217 return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
1218}
1219
1220pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
1221 return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
1222}
1223
1224pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
1225 return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
1226}
1227
1228pub fn shutdown(fd: i32, how: i32) usize {
1229 return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how)));
1230}
1231
1232pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
1233 return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len));
1234}
1235
1236pub fn listen(fd: i32, backlog: u32) usize {
1237 return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog);
1238}
1239
1240pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
1241 return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
1242}
1243
1244pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
1245 return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
1246}
1247
1248pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1249 return accept4(fd, addr, len, 0);
1250}
1251
1252pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
1253 return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags);
1254}
1255
1256pub fn fstat(fd: i32, stat_buf: *Stat) usize {
1257 return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
1258}
1259
1260// TODO https://github.com/ziglang/zig/issues/265
1261pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
1262 return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT);
1263}
1264
1265// TODO https://github.com/ziglang/zig/issues/265
1266pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
1267 return fstatat(AF_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);
1268}
1269
1270// TODO https://github.com/ziglang/zig/issues/265
1271pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
1272 return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
1273}
1274
1275// TODO https://github.com/ziglang/zig/issues/265
1276pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
1277 return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
1278}
1279
1280// TODO https://github.com/ziglang/zig/issues/265
1281pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
1282 return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
1283}
1284
1285pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize {
1286 return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
1287}
1288
1289// TODO https://github.com/ziglang/zig/issues/265
1290pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
1291 return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1292}
1293
1294// TODO https://github.com/ziglang/zig/issues/265
1295pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
1296 return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1297}
1298
1299// TODO https://github.com/ziglang/zig/issues/265
1300pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize {
1301 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
1302}
1303
1304// TODO https://github.com/ziglang/zig/issues/265
1305pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1306 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
1307}
1308
1309// TODO https://github.com/ziglang/zig/issues/265
1310pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1311 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
1312}
1313
1314// TODO https://github.com/ziglang/zig/issues/265
1315pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
1316 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
1317}
1318
1319// TODO https://github.com/ziglang/zig/issues/265
1320pub fn removexattr(path: [*]const u8, name: [*]const u8) usize {
1321 return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
1322}
1323
1324// TODO https://github.com/ziglang/zig/issues/265
1325pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize {
1326 return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
1327}
1328
1329// TODO https://github.com/ziglang/zig/issues/265
1330pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
1331 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
1332}
1333
1334pub fn sched_getaffinity(pid: i32, set: []usize) usize {
1335 return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
1336}
1337
1338pub const epoll_data = packed union {
1339 ptr: usize,
1340 fd: i32,
1341 @"u32": u32,
1342 @"u64": u64,
1343};
1344
1345pub const epoll_event = packed struct {
1346 events: u32,
1347 data: epoll_data,
1348};
1349
1350pub fn epoll_create() usize {
1351 return epoll_create1(0);
1352}
1353
1354pub fn epoll_create1(flags: usize) usize {
1355 return syscall1(SYS_epoll_create1, flags);
1356}
1357
1358pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
1359 return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev));
1360}
1361
1362pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
1363 return epoll_pwait(epoll_fd, events, maxevents, timeout, null);
1364}
1365
1366pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
1367 return syscall6(
1368 SYS_epoll_pwait,
1369 @bitCast(usize, isize(epoll_fd)),
1370 @ptrToInt(events),
1371 @intCast(usize, maxevents),
1372 @bitCast(usize, isize(timeout)),
1373 @ptrToInt(sigmask),
1374 @sizeOf(sigset_t),
1375 );
1376}
1377
1378pub fn eventfd(count: u32, flags: u32) usize {
1379 return syscall2(SYS_eventfd2, count, flags);
1380}
1381
1382pub fn timerfd_create(clockid: i32, flags: u32) usize {
1383 return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags);
1384}
1385
1386pub const itimerspec = extern struct {
1387 it_interval: timespec,
1388 it_value: timespec,
1389};
1390
1391pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
1392 return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value));
1393}
1394
1395pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
1396 return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
1397}
1398
1399pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1400pub const _LINUX_CAPABILITY_U32S_1 = 1;
1401
1402pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1403pub const _LINUX_CAPABILITY_U32S_2 = 2;
1404
1405pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1406pub const _LINUX_CAPABILITY_U32S_3 = 2;
1407
1408pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1409pub const VFS_CAP_REVISION_SHIFT = 24;
1410pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1411pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
1412
1413pub const VFS_CAP_REVISION_1 = 0x01000000;
1414pub const VFS_CAP_U32_1 = 1;
1415pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
1416
1417pub const VFS_CAP_REVISION_2 = 0x02000000;
1418pub const VFS_CAP_U32_2 = 2;
1419pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
1420
1421pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1422pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1423pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
1424
1425pub const vfs_cap_data = extern struct {
1426 //all of these are mandated as little endian
1427 //when on disk.
1428 const Data = struct {
1429 permitted: u32,
1430 inheritable: u32,
1431 };
1432
1433 magic_etc: u32,
1434 data: [VFS_CAP_U32]Data,
1435};
1436
1437pub const CAP_CHOWN = 0;
1438pub const CAP_DAC_OVERRIDE = 1;
1439pub const CAP_DAC_READ_SEARCH = 2;
1440pub const CAP_FOWNER = 3;
1441pub const CAP_FSETID = 4;
1442pub const CAP_KILL = 5;
1443pub const CAP_SETGID = 6;
1444pub const CAP_SETUID = 7;
1445pub const CAP_SETPCAP = 8;
1446pub const CAP_LINUX_IMMUTABLE = 9;
1447pub const CAP_NET_BIND_SERVICE = 10;
1448pub const CAP_NET_BROADCAST = 11;
1449pub const CAP_NET_ADMIN = 12;
1450pub const CAP_NET_RAW = 13;
1451pub const CAP_IPC_LOCK = 14;
1452pub const CAP_IPC_OWNER = 15;
1453pub const CAP_SYS_MODULE = 16;
1454pub const CAP_SYS_RAWIO = 17;
1455pub const CAP_SYS_CHROOT = 18;
1456pub const CAP_SYS_PTRACE = 19;
1457pub const CAP_SYS_PACCT = 20;
1458pub const CAP_SYS_ADMIN = 21;
1459pub const CAP_SYS_BOOT = 22;
1460pub const CAP_SYS_NICE = 23;
1461pub const CAP_SYS_RESOURCE = 24;
1462pub const CAP_SYS_TIME = 25;
1463pub const CAP_SYS_TTY_CONFIG = 26;
1464pub const CAP_MKNOD = 27;
1465pub const CAP_LEASE = 28;
1466pub const CAP_AUDIT_WRITE = 29;
1467pub const CAP_AUDIT_CONTROL = 30;
1468pub const CAP_SETFCAP = 31;
1469pub const CAP_MAC_OVERRIDE = 32;
1470pub const CAP_MAC_ADMIN = 33;
1471pub const CAP_SYSLOG = 34;
1472pub const CAP_WAKE_ALARM = 35;
1473pub const CAP_BLOCK_SUSPEND = 36;
1474pub const CAP_AUDIT_READ = 37;
1475pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1476
1477pub fn cap_valid(u8: x) bool {
1478 return x >= 0 and x <= CAP_LAST_CAP;
1479}
1480
1481pub fn CAP_TO_MASK(cap: u8) u32 {
1482 return u32(1) << u5(cap & 31);
1483}
1484
1485pub fn CAP_TO_INDEX(cap: u8) u8 {
1486 return cap >> 5;
1487}
1488
1489pub const cap_t = extern struct {
1490 hdrp: *cap_user_header_t,
1491 datap: *cap_user_data_t,
1492};
1493
1494pub const cap_user_header_t = extern struct {
1495 version: u32,
1496 pid: usize,
1497};
1498
1499pub const cap_user_data_t = extern struct {
1500 effective: u32,
1501 permitted: u32,
1502 inheritable: u32,
1503};
1504
1505pub fn unshare(flags: usize) usize {
1506 return syscall1(SYS_unshare, flags);
1507}
1508
1509pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize {
1510 return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
1511}
1512
1513pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
1514 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
1515}
1516
1517pub const inotify_event = extern struct {
1518 wd: i32,
1519 mask: u32,
1520 cookie: u32,
1521 len: u32,
1522 //name: [?]u8,
1523};
1524
1525pub const dirent64 = extern struct {
1526 d_ino: u64,
1527 d_off: u64,
1528 d_reclen: u16,
1529 d_type: u8,
1530 d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
1531};
1532
1533test "import" {
1534 if (builtin.os == builtin.Os.linux) {
1535 _ = @import("test.zig");
1536 }
1537}
std/os/linux/test.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const linux = std.os.linux;3const linux = std.os.linux;
4const expect = std.testing.expect;4const expect = std.testing.expect;
std/os/linux/vdso.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const elf = std.elf;2const elf = std.elf;
3const linux = std.os.linux;3const linux = std.os.linux;
4const cstr = std.cstr;4const cstr = std.cstr;
std/os/linux/x86_64.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const linux = std.os.linux;2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;4const iovec = linux.iovec;
std/os/netbsd.zig created+724
...@@ -0,0 +1,724 @@
1const builtin = @import("builtin");
2
3pub use @import("netbsd/errno.zig");
4
5const std = @import("../std.zig");
6const c = std.c;
7
8const assert = std.debug.assert;
9const maxInt = std.math.maxInt;
10pub const Kevent = c.Kevent;
11
12pub const CTL_KERN = 1;
13pub const CTL_DEBUG = 5;
14
15pub const KERN_PROC_ARGS = 48; // struct: process argv/env
16pub const KERN_PROC_PATHNAME = 5; // path to executable
17
18pub const PATH_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const PROT_NONE = 0;
25pub const PROT_READ = 1;
26pub const PROT_WRITE = 2;
27pub const PROT_EXEC = 4;
28
29pub const CLOCK_REALTIME = 0;
30pub const CLOCK_VIRTUAL = 1;
31pub const CLOCK_PROF = 2;
32pub const CLOCK_MONOTONIC = 3;
33pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
34pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
35
36pub const MAP_FAILED = maxInt(usize);
37pub const MAP_SHARED = 0x0001;
38pub const MAP_PRIVATE = 0x0002;
39pub const MAP_REMAPDUP = 0x0004;
40pub const MAP_FIXED = 0x0010;
41pub const MAP_RENAME = 0x0020;
42pub const MAP_NORESERVE = 0x0040;
43pub const MAP_INHERIT = 0x0080;
44pub const MAP_HASSEMAPHORE = 0x0200;
45pub const MAP_TRYFIXED = 0x0400;
46pub const MAP_WIRED = 0x0800;
47
48pub const MAP_FILE = 0x0000;
49pub const MAP_NOSYNC = 0x0800;
50pub const MAP_ANON = 0x1000;
51pub const MAP_ANONYMOUS = MAP_ANON;
52pub const MAP_STACK = 0x2000;
53
54pub const WNOHANG = 0x00000001;
55pub const WUNTRACED = 0x00000002;
56pub const WSTOPPED = WUNTRACED;
57pub const WCONTINUED = 0x00000010;
58pub const WNOWAIT = 0x00010000;
59pub const WEXITED = 0x00000020;
60pub const WTRAPPED = 0x00000040;
61
62pub const SA_ONSTACK = 0x0001;
63pub const SA_RESTART = 0x0002;
64pub const SA_RESETHAND = 0x0004;
65pub const SA_NOCLDSTOP = 0x0008;
66pub const SA_NODEFER = 0x0010;
67pub const SA_NOCLDWAIT = 0x0020;
68pub const SA_SIGINFO = 0x0040;
69
70pub const SIGHUP = 1;
71pub const SIGINT = 2;
72pub const SIGQUIT = 3;
73pub const SIGILL = 4;
74pub const SIGTRAP = 5;
75pub const SIGABRT = 6;
76pub const SIGIOT = SIGABRT;
77pub const SIGEMT = 7;
78pub const SIGFPE = 8;
79pub const SIGKILL = 9;
80pub const SIGBUS = 10;
81pub const SIGSEGV = 11;
82pub const SIGSYS = 12;
83pub const SIGPIPE = 13;
84pub const SIGALRM = 14;
85pub const SIGTERM = 15;
86pub const SIGURG = 16;
87pub const SIGSTOP = 17;
88pub const SIGTSTP = 18;
89pub const SIGCONT = 19;
90pub const SIGCHLD = 20;
91pub const SIGTTIN = 21;
92pub const SIGTTOU = 22;
93pub const SIGIO = 23;
94pub const SIGXCPU = 24;
95pub const SIGXFSZ = 25;
96pub const SIGVTALRM = 26;
97pub const SIGPROF = 27;
98pub const SIGWINCH = 28;
99pub const SIGINFO = 29;
100pub const SIGUSR1 = 30;
101pub const SIGUSR2 = 31;
102pub const SIGPWR = 32;
103
104pub const SIGRTMIN = 33;
105pub const SIGRTMAX = 63;
106
107// access function
108pub const F_OK = 0; // test for existence of file
109pub const X_OK = 1; // test for execute or search permission
110pub const W_OK = 2; // test for write permission
111pub const R_OK = 4; // test for read permission
112
113pub const O_RDONLY = 0x0000;
114pub const O_WRONLY = 0x0001;
115pub const O_RDWR = 0x0002;
116pub const O_ACCMODE = 0x0003;
117
118pub const O_CREAT = 0x0200;
119pub const O_EXCL = 0x0800;
120pub const O_NOCTTY = 0x8000;
121pub const O_TRUNC = 0x0400;
122pub const O_APPEND = 0x0008;
123pub const O_NONBLOCK = 0x0004;
124pub const O_DSYNC = 0x00010000;
125pub const O_SYNC = 0x0080;
126pub const O_RSYNC = 0x00020000;
127pub const O_DIRECTORY = 0x00080000;
128pub const O_NOFOLLOW = 0x00000100;
129pub const O_CLOEXEC = 0x00400000;
130
131pub const O_ASYNC = 0x0040;
132pub const O_DIRECT = 0x00080000;
133pub const O_LARGEFILE = 0;
134pub const O_NOATIME = 0;
135pub const O_PATH = 0;
136pub const O_TMPFILE = 0;
137pub const O_NDELAY = O_NONBLOCK;
138
139pub const F_DUPFD = 0;
140pub const F_GETFD = 1;
141pub const F_SETFD = 2;
142pub const F_GETFL = 3;
143pub const F_SETFL = 4;
144
145pub const F_GETOWN = 5;
146pub const F_SETOWN = 6;
147
148pub const F_GETLK = 7;
149pub const F_SETLK = 8;
150pub const F_SETLKW = 9;
151
152pub const SEEK_SET = 0;
153pub const SEEK_CUR = 1;
154pub const SEEK_END = 2;
155
156pub const SIG_BLOCK = 1;
157pub const SIG_UNBLOCK = 2;
158pub const SIG_SETMASK = 3;
159
160pub const SOCK_STREAM = 1;
161pub const SOCK_DGRAM = 2;
162pub const SOCK_RAW = 3;
163pub const SOCK_RDM = 4;
164pub const SOCK_SEQPACKET = 5;
165
166pub const SOCK_CLOEXEC = 0x10000000;
167pub const SOCK_NONBLOCK = 0x20000000;
168
169pub const PROTO_ip = 0;
170pub const PROTO_icmp = 1;
171pub const PROTO_igmp = 2;
172pub const PROTO_ggp = 3;
173pub const PROTO_ipencap = 4;
174pub const PROTO_tcp = 6;
175pub const PROTO_egp = 8;
176pub const PROTO_pup = 12;
177pub const PROTO_udp = 17;
178pub const PROTO_xns_idp = 22;
179pub const PROTO_iso_tp4 = 29;
180pub const PROTO_ipv6 = 41;
181pub const PROTO_ipv6_route = 43;
182pub const PROTO_ipv6_frag = 44;
183pub const PROTO_rsvp = 46;
184pub const PROTO_gre = 47;
185pub const PROTO_esp = 50;
186pub const PROTO_ah = 51;
187pub const PROTO_ipv6_icmp = 58;
188pub const PROTO_ipv6_nonxt = 59;
189pub const PROTO_ipv6_opts = 60;
190pub const PROTO_encap = 98;
191pub const PROTO_pim = 103;
192pub const PROTO_raw = 255;
193
194pub const PF_UNSPEC = 0;
195pub const PF_LOCAL = 1;
196pub const PF_UNIX = PF_LOCAL;
197pub const PF_FILE = PF_LOCAL;
198pub const PF_INET = 2;
199pub const PF_APPLETALK = 16;
200pub const PF_INET6 = 24;
201pub const PF_DECnet = 12;
202pub const PF_KEY = 29;
203pub const PF_ROUTE = 34;
204pub const PF_SNA = 11;
205pub const PF_MPLS = 33;
206pub const PF_CAN = 35;
207pub const PF_BLUETOOTH = 31;
208pub const PF_ISDN = 26;
209pub const PF_MAX = 37;
210
211pub const AF_UNSPEC = PF_UNSPEC;
212pub const AF_LOCAL = PF_LOCAL;
213pub const AF_UNIX = AF_LOCAL;
214pub const AF_FILE = AF_LOCAL;
215pub const AF_INET = PF_INET;
216pub const AF_APPLETALK = PF_APPLETALK;
217pub const AF_INET6 = PF_INET6;
218pub const AF_KEY = PF_KEY;
219pub const AF_ROUTE = PF_ROUTE;
220pub const AF_SNA = PF_SNA;
221pub const AF_MPLS = PF_MPLS;
222pub const AF_CAN = PF_CAN;
223pub const AF_BLUETOOTH = PF_BLUETOOTH;
224pub const AF_ISDN = PF_ISDN;
225pub const AF_MAX = PF_MAX;
226
227pub const DT_UNKNOWN = 0;
228pub const DT_FIFO = 1;
229pub const DT_CHR = 2;
230pub const DT_DIR = 4;
231pub const DT_BLK = 6;
232pub const DT_REG = 8;
233pub const DT_LNK = 10;
234pub const DT_SOCK = 12;
235pub const DT_WHT = 14;
236
237/// add event to kq (implies enable)
238pub const EV_ADD = 0x0001;
239
240/// delete event from kq
241pub const EV_DELETE = 0x0002;
242
243/// enable event
244pub const EV_ENABLE = 0x0004;
245
246/// disable event (not reported)
247pub const EV_DISABLE = 0x0008;
248
249/// only report one occurrence
250pub const EV_ONESHOT = 0x0010;
251
252/// clear event state after reporting
253pub const EV_CLEAR = 0x0020;
254
255/// force immediate event output
256/// ... with or without EV_ERROR
257/// ... use KEVENT_FLAG_ERROR_EVENTS
258/// on syscalls supporting flags
259pub const EV_RECEIPT = 0x0040;
260
261/// disable event after reporting
262pub const EV_DISPATCH = 0x0080;
263
264pub const EVFILT_READ = 0;
265pub const EVFILT_WRITE = 1;
266
267/// attached to aio requests
268pub const EVFILT_AIO = 2;
269
270/// attached to vnodes
271pub const EVFILT_VNODE = 3;
272
273/// attached to struct proc
274pub const EVFILT_PROC = 4;
275
276/// attached to struct proc
277pub const EVFILT_SIGNAL = 5;
278
279/// timers
280pub const EVFILT_TIMER = 6;
281
282/// Filesystem events
283pub const EVFILT_FS = 7;
284
285/// On input, NOTE_TRIGGER causes the event to be triggered for output.
286pub const NOTE_TRIGGER = 0x08000000;
287
288/// low water mark
289pub const NOTE_LOWAT = 0x00000001;
290
291/// vnode was removed
292pub const NOTE_DELETE = 0x00000001;
293
294/// data contents changed
295pub const NOTE_WRITE = 0x00000002;
296
297/// size increased
298pub const NOTE_EXTEND = 0x00000004;
299
300/// attributes changed
301pub const NOTE_ATTRIB = 0x00000008;
302
303/// link count changed
304pub const NOTE_LINK = 0x00000010;
305
306/// vnode was renamed
307pub const NOTE_RENAME = 0x00000020;
308
309/// vnode access was revoked
310pub const NOTE_REVOKE = 0x00000040;
311
312/// process exited
313pub const NOTE_EXIT = 0x80000000;
314
315/// process forked
316pub const NOTE_FORK = 0x40000000;
317
318/// process exec'd
319pub const NOTE_EXEC = 0x20000000;
320
321/// mask for signal & exit status
322pub const NOTE_PDATAMASK = 0x000fffff;
323pub const NOTE_PCTRLMASK = 0xf0000000;
324
325pub const TIOCCBRK = 0x2000747a;
326pub const TIOCCDTR = 0x20007478;
327pub const TIOCCONS = 0x80047462;
328pub const TIOCDCDTIMESTAMP = 0x40107458;
329pub const TIOCDRAIN = 0x2000745e;
330pub const TIOCEXCL = 0x2000740d;
331pub const TIOCEXT = 0x80047460;
332pub const TIOCFLAG_CDTRCTS = 0x10;
333pub const TIOCFLAG_CLOCAL = 0x2;
334pub const TIOCFLAG_CRTSCTS = 0x4;
335pub const TIOCFLAG_MDMBUF = 0x8;
336pub const TIOCFLAG_SOFTCAR = 0x1;
337pub const TIOCFLUSH = 0x80047410;
338pub const TIOCGETA = 0x402c7413;
339pub const TIOCGETD = 0x4004741a;
340pub const TIOCGFLAGS = 0x4004745d;
341pub const TIOCGLINED = 0x40207442;
342pub const TIOCGPGRP = 0x40047477;
343pub const TIOCGQSIZE = 0x40047481;
344pub const TIOCGRANTPT = 0x20007447;
345pub const TIOCGSID = 0x40047463;
346pub const TIOCGSIZE = 0x40087468;
347pub const TIOCGWINSZ = 0x40087468;
348pub const TIOCMBIC = 0x8004746b;
349pub const TIOCMBIS = 0x8004746c;
350pub const TIOCMGET = 0x4004746a;
351pub const TIOCMSET = 0x8004746d;
352pub const TIOCM_CAR = 0x40;
353pub const TIOCM_CD = 0x40;
354pub const TIOCM_CTS = 0x20;
355pub const TIOCM_DSR = 0x100;
356pub const TIOCM_DTR = 0x2;
357pub const TIOCM_LE = 0x1;
358pub const TIOCM_RI = 0x80;
359pub const TIOCM_RNG = 0x80;
360pub const TIOCM_RTS = 0x4;
361pub const TIOCM_SR = 0x10;
362pub const TIOCM_ST = 0x8;
363pub const TIOCNOTTY = 0x20007471;
364pub const TIOCNXCL = 0x2000740e;
365pub const TIOCOUTQ = 0x40047473;
366pub const TIOCPKT = 0x80047470;
367pub const TIOCPKT_DATA = 0x0;
368pub const TIOCPKT_DOSTOP = 0x20;
369pub const TIOCPKT_FLUSHREAD = 0x1;
370pub const TIOCPKT_FLUSHWRITE = 0x2;
371pub const TIOCPKT_IOCTL = 0x40;
372pub const TIOCPKT_NOSTOP = 0x10;
373pub const TIOCPKT_START = 0x8;
374pub const TIOCPKT_STOP = 0x4;
375pub const TIOCPTMGET = 0x40287446;
376pub const TIOCPTSNAME = 0x40287448;
377pub const TIOCRCVFRAME = 0x80087445;
378pub const TIOCREMOTE = 0x80047469;
379pub const TIOCSBRK = 0x2000747b;
380pub const TIOCSCTTY = 0x20007461;
381pub const TIOCSDTR = 0x20007479;
382pub const TIOCSETA = 0x802c7414;
383pub const TIOCSETAF = 0x802c7416;
384pub const TIOCSETAW = 0x802c7415;
385pub const TIOCSETD = 0x8004741b;
386pub const TIOCSFLAGS = 0x8004745c;
387pub const TIOCSIG = 0x2000745f;
388pub const TIOCSLINED = 0x80207443;
389pub const TIOCSPGRP = 0x80047476;
390pub const TIOCSQSIZE = 0x80047480;
391pub const TIOCSSIZE = 0x80087467;
392pub const TIOCSTART = 0x2000746e;
393pub const TIOCSTAT = 0x80047465;
394pub const TIOCSTI = 0x80017472;
395pub const TIOCSTOP = 0x2000746f;
396pub const TIOCSWINSZ = 0x80087467;
397pub const TIOCUCNTL = 0x80047466;
398pub const TIOCXMTFRAME = 0x80087444;
399
400pub const sockaddr = c.sockaddr;
401pub const sockaddr_in = c.sockaddr_in;
402pub const sockaddr_in6 = c.sockaddr_in6;
403
404fn unsigned(s: i32) u32 {
405 return @bitCast(u32, s);
406}
407fn signed(s: u32) i32 {
408 return @bitCast(i32, s);
409}
410pub fn WEXITSTATUS(s: i32) i32 {
411 return signed((unsigned(s) >> 8) & 0xff);
412}
413pub fn WTERMSIG(s: i32) i32 {
414 return signed(unsigned(s) & 0x7f);
415}
416pub fn WSTOPSIG(s: i32) i32 {
417 return WEXITSTATUS(s);
418}
419pub fn WIFEXITED(s: i32) bool {
420 return WTERMSIG(s) == 0;
421}
422
423pub fn WIFCONTINUED(s: i32) bool {
424 return ((s & 0x7f) == 0xffff);
425}
426
427pub fn WIFSTOPPED(s: i32) bool {
428 return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
429}
430
431pub fn WIFSIGNALED(s: i32) bool {
432 return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
433}
434
435pub const winsize = extern struct {
436 ws_row: u16,
437 ws_col: u16,
438 ws_xpixel: u16,
439 ws_ypixel: u16,
440};
441
442/// Get the errno from a syscall return value, or 0 for no error.
443pub fn getErrno(r: usize) usize {
444 const signed_r = @bitCast(isize, r);
445 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
446}
447
448pub fn dup2(old: i32, new: i32) usize {
449 return errnoWrap(c.dup2(old, new));
450}
451
452pub fn chdir(path: [*]const u8) usize {
453 return errnoWrap(c.chdir(path));
454}
455
456pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
457 return errnoWrap(c.execve(path, argv, envp));
458}
459
460pub fn fork() usize {
461 return errnoWrap(c.fork());
462}
463
464pub fn access(path: [*]const u8, mode: u32) usize {
465 return errnoWrap(c.access(path, mode));
466}
467
468pub fn getcwd(buf: [*]u8, size: usize) usize {
469 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
470}
471
472pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
473 return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
474}
475
476pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
477 return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
478}
479
480pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
481 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
482}
483
484pub fn isatty(fd: i32) bool {
485 return c.isatty(fd) != 0;
486}
487
488pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
489 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
490}
491
492pub fn mkdir(path: [*]const u8, mode: u32) usize {
493 return errnoWrap(c.mkdir(path, mode));
494}
495
496pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
497 const ptr_result = c.mmap(
498 @ptrCast(?*c_void, address),
499 length,
500 @bitCast(c_int, @intCast(c_uint, prot)),
501 @bitCast(c_int, c_uint(flags)),
502 fd,
503 offset,
504 );
505 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
506 return errnoWrap(isize_result);
507}
508
509pub fn munmap(address: usize, length: usize) usize {
510 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
511}
512
513pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
514 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
515}
516
517pub fn rmdir(path: [*]const u8) usize {
518 return errnoWrap(c.rmdir(path));
519}
520
521pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
522 return errnoWrap(c.symlink(existing, new));
523}
524
525pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
526 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
527}
528
529pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
530 return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
531}
532
533pub fn pipe(fd: *[2]i32) usize {
534 return pipe2(fd, 0);
535}
536
537pub fn pipe2(fd: *[2]i32, flags: u32) usize {
538 comptime assert(i32.bit_count == c_int.bit_count);
539 return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
540}
541
542pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
543 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
544}
545
546pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
547 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
548}
549
550pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
551 return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
552}
553
554pub fn rename(old: [*]const u8, new: [*]const u8) usize {
555 return errnoWrap(c.rename(old, new));
556}
557
558pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
559 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
560}
561
562pub fn create(path: [*]const u8, perm: usize) usize {
563 return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
564}
565
566pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
567 return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
568}
569
570pub fn close(fd: i32) usize {
571 return errnoWrap(c.close(fd));
572}
573
574pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
575 return errnoWrap(c.lseek(fd, offset, whence));
576}
577
578pub fn exit(code: i32) noreturn {
579 c.exit(code);
580}
581
582pub fn kill(pid: i32, sig: i32) usize {
583 return errnoWrap(c.kill(pid, sig));
584}
585
586pub fn unlink(path: [*]const u8) usize {
587 return errnoWrap(c.unlink(path));
588}
589
590pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
591 comptime assert(i32.bit_count == c_int.bit_count);
592 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
593}
594
595pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
596 return errnoWrap(c.nanosleep(req, rem));
597}
598
599pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
600 return errnoWrap(c.clock_gettime(clk_id, tp));
601}
602
603pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
604 return errnoWrap(c.clock_getres(clk_id, tp));
605}
606
607pub fn setuid(uid: u32) usize {
608 return errnoWrap(c.setuid(uid));
609}
610
611pub fn setgid(gid: u32) usize {
612 return errnoWrap(c.setgid(gid));
613}
614
615pub fn setreuid(ruid: u32, euid: u32) usize {
616 return errnoWrap(c.setreuid(ruid, euid));
617}
618
619pub fn setregid(rgid: u32, egid: u32) usize {
620 return errnoWrap(c.setregid(rgid, egid));
621}
622
623const NSIG = 32;
624
625pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
626pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
627pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
628
629/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
630pub const Sigaction = extern struct {
631 /// signal handler
632 __sigaction_u: extern union {
633 __sa_handler: extern fn (i32) void,
634 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
635 },
636
637 /// see signal options
638 sa_flags: u32,
639
640 /// signal mask to apply
641 sa_mask: sigset_t,
642};
643
644pub const _SIG_WORDS = 4;
645pub const _SIG_MAXSIG = 128;
646
647pub inline fn _SIG_IDX(sig: usize) usize {
648 return sig - 1;
649}
650pub inline fn _SIG_WORD(sig: usize) usize {
651 return_SIG_IDX(sig) >> 5;
652}
653pub inline fn _SIG_BIT(sig: usize) usize {
654 return 1 << (_SIG_IDX(sig) & 31);
655}
656pub inline fn _SIG_VALID(sig: usize) usize {
657 return sig <= _SIG_MAXSIG and sig > 0;
658}
659
660pub const sigset_t = extern struct {
661 __bits: [_SIG_WORDS]u32,
662};
663
664pub fn raise(sig: i32) usize {
665 return errnoWrap(c.raise(sig));
666}
667
668pub const Stat = c.Stat;
669pub const dirent = c.dirent;
670pub const timespec = c.timespec;
671
672pub fn fstat(fd: i32, buf: *c.Stat) usize {
673 return errnoWrap(c.fstat(fd, buf));
674}
675pub const iovec = extern struct {
676 iov_base: [*]u8,
677 iov_len: usize,
678};
679
680pub const iovec_const = extern struct {
681 iov_base: [*]const u8,
682 iov_len: usize,
683};
684
685// TODO avoid libc dependency
686pub fn kqueue() usize {
687 return errnoWrap(c.kqueue());
688}
689
690// TODO avoid libc dependency
691pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
692 return errnoWrap(c.kevent(
693 kq,
694 changelist.ptr,
695 @intCast(c_int, changelist.len),
696 eventlist.ptr,
697 @intCast(c_int, eventlist.len),
698 timeout,
699 ));
700}
701
702// TODO avoid libc dependency
703pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
704 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
705}
706
707// TODO avoid libc dependency
708pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
709 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
710}
711
712// TODO avoid libc dependency
713pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
714 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
715}
716
717// TODO avoid libc dependency
718
719/// Takes the return value from a syscall and formats it back in the way
720/// that the kernel represents it to libc. Errno was a mistake, let's make
721/// it go away forever.
722fn errnoWrap(value: isize) usize {
723 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
724}
std/os/netbsd/index.zig deleted-725
...@@ -1,725 +0,0 @@
1const builtin = @import("builtin");
2
3pub use @import("errno.zig");
4
5const std = @import("../../index.zig");
6const c = std.c;
7
8const assert = std.debug.assert;
9const maxInt = std.math.maxInt;
10pub const Kevent = c.Kevent;
11
12pub const CTL_KERN = 1;
13pub const CTL_DEBUG = 5;
14
15pub const KERN_PROC_ARGS = 48; // struct: process argv/env
16pub const KERN_PROC_PATHNAME = 5; // path to executable
17
18pub const PATH_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const PROT_NONE = 0;
25pub const PROT_READ = 1;
26pub const PROT_WRITE = 2;
27pub const PROT_EXEC = 4;
28
29pub const CLOCK_REALTIME = 0;
30pub const CLOCK_VIRTUAL = 1;
31pub const CLOCK_PROF = 2;
32pub const CLOCK_MONOTONIC = 3;
33pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
34pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
35
36pub const MAP_FAILED = maxInt(usize);
37pub const MAP_SHARED = 0x0001;
38pub const MAP_PRIVATE = 0x0002;
39pub const MAP_REMAPDUP = 0x0004;
40pub const MAP_FIXED = 0x0010;
41pub const MAP_RENAME = 0x0020;
42pub const MAP_NORESERVE = 0x0040;
43pub const MAP_INHERIT = 0x0080;
44pub const MAP_HASSEMAPHORE = 0x0200;
45pub const MAP_TRYFIXED = 0x0400;
46pub const MAP_WIRED = 0x0800;
47
48pub const MAP_FILE = 0x0000;
49pub const MAP_NOSYNC = 0x0800;
50pub const MAP_ANON = 0x1000;
51pub const MAP_ANONYMOUS = MAP_ANON;
52pub const MAP_STACK = 0x2000;
53
54pub const WNOHANG = 0x00000001;
55pub const WUNTRACED = 0x00000002;
56pub const WSTOPPED = WUNTRACED;
57pub const WCONTINUED = 0x00000010;
58pub const WNOWAIT = 0x00010000;
59pub const WEXITED = 0x00000020;
60pub const WTRAPPED = 0x00000040;
61
62pub const SA_ONSTACK = 0x0001;
63pub const SA_RESTART = 0x0002;
64pub const SA_RESETHAND = 0x0004;
65pub const SA_NOCLDSTOP = 0x0008;
66pub const SA_NODEFER = 0x0010;
67pub const SA_NOCLDWAIT = 0x0020;
68pub const SA_SIGINFO = 0x0040;
69
70pub const SIGHUP = 1;
71pub const SIGINT = 2;
72pub const SIGQUIT = 3;
73pub const SIGILL = 4;
74pub const SIGTRAP = 5;
75pub const SIGABRT = 6;
76pub const SIGIOT = SIGABRT;
77pub const SIGEMT = 7;
78pub const SIGFPE = 8;
79pub const SIGKILL = 9;
80pub const SIGBUS = 10;
81pub const SIGSEGV = 11;
82pub const SIGSYS = 12;
83pub const SIGPIPE = 13;
84pub const SIGALRM = 14;
85pub const SIGTERM = 15;
86pub const SIGURG = 16;
87pub const SIGSTOP = 17;
88pub const SIGTSTP = 18;
89pub const SIGCONT = 19;
90pub const SIGCHLD = 20;
91pub const SIGTTIN = 21;
92pub const SIGTTOU = 22;
93pub const SIGIO = 23;
94pub const SIGXCPU = 24;
95pub const SIGXFSZ = 25;
96pub const SIGVTALRM = 26;
97pub const SIGPROF = 27;
98pub const SIGWINCH = 28;
99pub const SIGINFO = 29;
100pub const SIGUSR1 = 30;
101pub const SIGUSR2 = 31;
102pub const SIGPWR = 32;
103
104pub const SIGRTMIN = 33;
105pub const SIGRTMAX = 63;
106
107// access function
108pub const F_OK = 0; // test for existence of file
109pub const X_OK = 1; // test for execute or search permission
110pub const W_OK = 2; // test for write permission
111pub const R_OK = 4; // test for read permission
112
113
114pub const O_RDONLY = 0x0000;
115pub const O_WRONLY = 0x0001;
116pub const O_RDWR = 0x0002;
117pub const O_ACCMODE = 0x0003;
118
119pub const O_CREAT = 0x0200;
120pub const O_EXCL = 0x0800;
121pub const O_NOCTTY = 0x8000;
122pub const O_TRUNC = 0x0400;
123pub const O_APPEND = 0x0008;
124pub const O_NONBLOCK = 0x0004;
125pub const O_DSYNC = 0x00010000;
126pub const O_SYNC = 0x0080;
127pub const O_RSYNC = 0x00020000;
128pub const O_DIRECTORY = 0x00080000;
129pub const O_NOFOLLOW = 0x00000100;
130pub const O_CLOEXEC = 0x00400000;
131
132pub const O_ASYNC = 0x0040;
133pub const O_DIRECT = 0x00080000;
134pub const O_LARGEFILE = 0;
135pub const O_NOATIME = 0;
136pub const O_PATH = 0;
137pub const O_TMPFILE = 0;
138pub const O_NDELAY = O_NONBLOCK;
139
140pub const F_DUPFD = 0;
141pub const F_GETFD = 1;
142pub const F_SETFD = 2;
143pub const F_GETFL = 3;
144pub const F_SETFL = 4;
145
146pub const F_GETOWN = 5;
147pub const F_SETOWN = 6;
148
149pub const F_GETLK = 7;
150pub const F_SETLK = 8;
151pub const F_SETLKW = 9;
152
153pub const SEEK_SET = 0;
154pub const SEEK_CUR = 1;
155pub const SEEK_END = 2;
156
157pub const SIG_BLOCK = 1;
158pub const SIG_UNBLOCK = 2;
159pub const SIG_SETMASK = 3;
160
161pub const SOCK_STREAM = 1;
162pub const SOCK_DGRAM = 2;
163pub const SOCK_RAW = 3;
164pub const SOCK_RDM = 4;
165pub const SOCK_SEQPACKET = 5;
166
167pub const SOCK_CLOEXEC = 0x10000000;
168pub const SOCK_NONBLOCK = 0x20000000;
169
170pub const PROTO_ip = 0;
171pub const PROTO_icmp = 1;
172pub const PROTO_igmp = 2;
173pub const PROTO_ggp = 3;
174pub const PROTO_ipencap = 4;
175pub const PROTO_tcp = 6;
176pub const PROTO_egp = 8;
177pub const PROTO_pup = 12;
178pub const PROTO_udp = 17;
179pub const PROTO_xns_idp = 22;
180pub const PROTO_iso_tp4 = 29;
181pub const PROTO_ipv6 = 41;
182pub const PROTO_ipv6_route = 43;
183pub const PROTO_ipv6_frag = 44;
184pub const PROTO_rsvp = 46;
185pub const PROTO_gre = 47;
186pub const PROTO_esp = 50;
187pub const PROTO_ah = 51;
188pub const PROTO_ipv6_icmp = 58;
189pub const PROTO_ipv6_nonxt = 59;
190pub const PROTO_ipv6_opts = 60;
191pub const PROTO_encap = 98;
192pub const PROTO_pim = 103;
193pub const PROTO_raw = 255;
194
195pub const PF_UNSPEC = 0;
196pub const PF_LOCAL = 1;
197pub const PF_UNIX = PF_LOCAL;
198pub const PF_FILE = PF_LOCAL;
199pub const PF_INET = 2;
200pub const PF_APPLETALK = 16;
201pub const PF_INET6 = 24;
202pub const PF_DECnet = 12;
203pub const PF_KEY = 29;
204pub const PF_ROUTE = 34;
205pub const PF_SNA = 11;
206pub const PF_MPLS = 33;
207pub const PF_CAN = 35;
208pub const PF_BLUETOOTH = 31;
209pub const PF_ISDN = 26;
210pub const PF_MAX = 37;
211
212pub const AF_UNSPEC = PF_UNSPEC;
213pub const AF_LOCAL = PF_LOCAL;
214pub const AF_UNIX = AF_LOCAL;
215pub const AF_FILE = AF_LOCAL;
216pub const AF_INET = PF_INET;
217pub const AF_APPLETALK = PF_APPLETALK;
218pub const AF_INET6 = PF_INET6;
219pub const AF_KEY = PF_KEY;
220pub const AF_ROUTE = PF_ROUTE;
221pub const AF_SNA = PF_SNA;
222pub const AF_MPLS = PF_MPLS;
223pub const AF_CAN = PF_CAN;
224pub const AF_BLUETOOTH = PF_BLUETOOTH;
225pub const AF_ISDN = PF_ISDN;
226pub const AF_MAX = PF_MAX;
227
228pub const DT_UNKNOWN = 0;
229pub const DT_FIFO = 1;
230pub const DT_CHR = 2;
231pub const DT_DIR = 4;
232pub const DT_BLK = 6;
233pub const DT_REG = 8;
234pub const DT_LNK = 10;
235pub const DT_SOCK = 12;
236pub const DT_WHT = 14;
237
238/// add event to kq (implies enable)
239pub const EV_ADD = 0x0001;
240
241/// delete event from kq
242pub const EV_DELETE = 0x0002;
243
244/// enable event
245pub const EV_ENABLE = 0x0004;
246
247/// disable event (not reported)
248pub const EV_DISABLE = 0x0008;
249
250/// only report one occurrence
251pub const EV_ONESHOT = 0x0010;
252
253/// clear event state after reporting
254pub const EV_CLEAR = 0x0020;
255
256/// force immediate event output
257/// ... with or without EV_ERROR
258/// ... use KEVENT_FLAG_ERROR_EVENTS
259/// on syscalls supporting flags
260pub const EV_RECEIPT = 0x0040;
261
262/// disable event after reporting
263pub const EV_DISPATCH = 0x0080;
264
265pub const EVFILT_READ = 0;
266pub const EVFILT_WRITE = 1;
267
268/// attached to aio requests
269pub const EVFILT_AIO = 2;
270
271/// attached to vnodes
272pub const EVFILT_VNODE = 3;
273
274/// attached to struct proc
275pub const EVFILT_PROC = 4;
276
277/// attached to struct proc
278pub const EVFILT_SIGNAL = 5;
279
280/// timers
281pub const EVFILT_TIMER = 6;
282
283/// Filesystem events
284pub const EVFILT_FS = 7;
285
286/// On input, NOTE_TRIGGER causes the event to be triggered for output.
287pub const NOTE_TRIGGER = 0x08000000;
288
289/// low water mark
290pub const NOTE_LOWAT = 0x00000001;
291
292/// vnode was removed
293pub const NOTE_DELETE = 0x00000001;
294
295/// data contents changed
296pub const NOTE_WRITE = 0x00000002;
297
298/// size increased
299pub const NOTE_EXTEND = 0x00000004;
300
301/// attributes changed
302pub const NOTE_ATTRIB = 0x00000008;
303
304/// link count changed
305pub const NOTE_LINK = 0x00000010;
306
307/// vnode was renamed
308pub const NOTE_RENAME = 0x00000020;
309
310/// vnode access was revoked
311pub const NOTE_REVOKE = 0x00000040;
312
313/// process exited
314pub const NOTE_EXIT = 0x80000000;
315
316/// process forked
317pub const NOTE_FORK = 0x40000000;
318
319/// process exec'd
320pub const NOTE_EXEC = 0x20000000;
321
322/// mask for signal & exit status
323pub const NOTE_PDATAMASK = 0x000fffff;
324pub const NOTE_PCTRLMASK = 0xf0000000;
325
326pub const TIOCCBRK = 0x2000747a;
327pub const TIOCCDTR = 0x20007478;
328pub const TIOCCONS = 0x80047462;
329pub const TIOCDCDTIMESTAMP = 0x40107458;
330pub const TIOCDRAIN = 0x2000745e;
331pub const TIOCEXCL = 0x2000740d;
332pub const TIOCEXT = 0x80047460;
333pub const TIOCFLAG_CDTRCTS = 0x10;
334pub const TIOCFLAG_CLOCAL = 0x2;
335pub const TIOCFLAG_CRTSCTS = 0x4;
336pub const TIOCFLAG_MDMBUF = 0x8;
337pub const TIOCFLAG_SOFTCAR = 0x1;
338pub const TIOCFLUSH = 0x80047410;
339pub const TIOCGETA = 0x402c7413;
340pub const TIOCGETD = 0x4004741a;
341pub const TIOCGFLAGS = 0x4004745d;
342pub const TIOCGLINED = 0x40207442;
343pub const TIOCGPGRP = 0x40047477;
344pub const TIOCGQSIZE = 0x40047481;
345pub const TIOCGRANTPT = 0x20007447;
346pub const TIOCGSID = 0x40047463;
347pub const TIOCGSIZE = 0x40087468;
348pub const TIOCGWINSZ = 0x40087468;
349pub const TIOCMBIC = 0x8004746b;
350pub const TIOCMBIS = 0x8004746c;
351pub const TIOCMGET = 0x4004746a;
352pub const TIOCMSET = 0x8004746d;
353pub const TIOCM_CAR = 0x40;
354pub const TIOCM_CD = 0x40;
355pub const TIOCM_CTS = 0x20;
356pub const TIOCM_DSR = 0x100;
357pub const TIOCM_DTR = 0x2;
358pub const TIOCM_LE = 0x1;
359pub const TIOCM_RI = 0x80;
360pub const TIOCM_RNG = 0x80;
361pub const TIOCM_RTS = 0x4;
362pub const TIOCM_SR = 0x10;
363pub const TIOCM_ST = 0x8;
364pub const TIOCNOTTY = 0x20007471;
365pub const TIOCNXCL = 0x2000740e;
366pub const TIOCOUTQ = 0x40047473;
367pub const TIOCPKT = 0x80047470;
368pub const TIOCPKT_DATA = 0x0;
369pub const TIOCPKT_DOSTOP = 0x20;
370pub const TIOCPKT_FLUSHREAD = 0x1;
371pub const TIOCPKT_FLUSHWRITE = 0x2;
372pub const TIOCPKT_IOCTL = 0x40;
373pub const TIOCPKT_NOSTOP = 0x10;
374pub const TIOCPKT_START = 0x8;
375pub const TIOCPKT_STOP = 0x4;
376pub const TIOCPTMGET = 0x40287446;
377pub const TIOCPTSNAME = 0x40287448;
378pub const TIOCRCVFRAME = 0x80087445;
379pub const TIOCREMOTE = 0x80047469;
380pub const TIOCSBRK = 0x2000747b;
381pub const TIOCSCTTY = 0x20007461;
382pub const TIOCSDTR = 0x20007479;
383pub const TIOCSETA = 0x802c7414;
384pub const TIOCSETAF = 0x802c7416;
385pub const TIOCSETAW = 0x802c7415;
386pub const TIOCSETD = 0x8004741b;
387pub const TIOCSFLAGS = 0x8004745c;
388pub const TIOCSIG = 0x2000745f;
389pub const TIOCSLINED = 0x80207443;
390pub const TIOCSPGRP = 0x80047476;
391pub const TIOCSQSIZE = 0x80047480;
392pub const TIOCSSIZE = 0x80087467;
393pub const TIOCSTART = 0x2000746e;
394pub const TIOCSTAT = 0x80047465;
395pub const TIOCSTI = 0x80017472;
396pub const TIOCSTOP = 0x2000746f;
397pub const TIOCSWINSZ = 0x80087467;
398pub const TIOCUCNTL = 0x80047466;
399pub const TIOCXMTFRAME = 0x80087444;
400
401pub const sockaddr = c.sockaddr;
402pub const sockaddr_in = c.sockaddr_in;
403pub const sockaddr_in6 = c.sockaddr_in6;
404
405fn unsigned(s: i32) u32 {
406 return @bitCast(u32, s);
407}
408fn signed(s: u32) i32 {
409 return @bitCast(i32, s);
410}
411pub fn WEXITSTATUS(s: i32) i32 {
412 return signed((unsigned(s) >> 8) & 0xff);
413}
414pub fn WTERMSIG(s: i32) i32 {
415 return signed(unsigned(s) & 0x7f);
416}
417pub fn WSTOPSIG(s: i32) i32 {
418 return WEXITSTATUS(s);
419}
420pub fn WIFEXITED(s: i32) bool {
421 return WTERMSIG(s) == 0;
422}
423
424pub fn WIFCONTINUED(s: i32) bool {
425 return ((s & 0x7f) == 0xffff);
426}
427
428pub fn WIFSTOPPED(s: i32) bool {
429 return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
430}
431
432pub fn WIFSIGNALED(s: i32) bool {
433 return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
434}
435
436pub const winsize = extern struct {
437 ws_row: u16,
438 ws_col: u16,
439 ws_xpixel: u16,
440 ws_ypixel: u16,
441};
442
443/// Get the errno from a syscall return value, or 0 for no error.
444pub fn getErrno(r: usize) usize {
445 const signed_r = @bitCast(isize, r);
446 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
447}
448
449pub fn dup2(old: i32, new: i32) usize {
450 return errnoWrap(c.dup2(old, new));
451}
452
453pub fn chdir(path: [*]const u8) usize {
454 return errnoWrap(c.chdir(path));
455}
456
457pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
458 return errnoWrap(c.execve(path, argv, envp));
459}
460
461pub fn fork() usize {
462 return errnoWrap(c.fork());
463}
464
465pub fn access(path: [*]const u8, mode: u32) usize {
466 return errnoWrap(c.access(path, mode));
467}
468
469pub fn getcwd(buf: [*]u8, size: usize) usize {
470 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
471}
472
473pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
474 return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
475}
476
477pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
478 return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
479}
480
481pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
482 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
483}
484
485pub fn isatty(fd: i32) bool {
486 return c.isatty(fd) != 0;
487}
488
489pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
490 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
491}
492
493pub fn mkdir(path: [*]const u8, mode: u32) usize {
494 return errnoWrap(c.mkdir(path, mode));
495}
496
497pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
498 const ptr_result = c.mmap(
499 @ptrCast(?*c_void, address),
500 length,
501 @bitCast(c_int, @intCast(c_uint, prot)),
502 @bitCast(c_int, c_uint(flags)),
503 fd,
504 offset,
505 );
506 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
507 return errnoWrap(isize_result);
508}
509
510pub fn munmap(address: usize, length: usize) usize {
511 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
512}
513
514pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
515 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
516}
517
518pub fn rmdir(path: [*]const u8) usize {
519 return errnoWrap(c.rmdir(path));
520}
521
522pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
523 return errnoWrap(c.symlink(existing, new));
524}
525
526pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
527 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
528}
529
530pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
531 return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
532}
533
534pub fn pipe(fd: *[2]i32) usize {
535 return pipe2(fd, 0);
536}
537
538pub fn pipe2(fd: *[2]i32, flags: u32) usize {
539 comptime assert(i32.bit_count == c_int.bit_count);
540 return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
541}
542
543pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
544 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
545}
546
547pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
548 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
549}
550
551pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
552 return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
553}
554
555pub fn rename(old: [*]const u8, new: [*]const u8) usize {
556 return errnoWrap(c.rename(old, new));
557}
558
559pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
560 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
561}
562
563pub fn create(path: [*]const u8, perm: usize) usize {
564 return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
565}
566
567pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
568 return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
569}
570
571pub fn close(fd: i32) usize {
572 return errnoWrap(c.close(fd));
573}
574
575pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
576 return errnoWrap(c.lseek(fd, offset, whence));
577}
578
579pub fn exit(code: i32) noreturn {
580 c.exit(code);
581}
582
583pub fn kill(pid: i32, sig: i32) usize {
584 return errnoWrap(c.kill(pid, sig));
585}
586
587pub fn unlink(path: [*]const u8) usize {
588 return errnoWrap(c.unlink(path));
589}
590
591pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
592 comptime assert(i32.bit_count == c_int.bit_count);
593 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
594}
595
596pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
597 return errnoWrap(c.nanosleep(req, rem));
598}
599
600pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
601 return errnoWrap(c.clock_gettime(clk_id, tp));
602}
603
604pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
605 return errnoWrap(c.clock_getres(clk_id, tp));
606}
607
608pub fn setuid(uid: u32) usize {
609 return errnoWrap(c.setuid(uid));
610}
611
612pub fn setgid(gid: u32) usize {
613 return errnoWrap(c.setgid(gid));
614}
615
616pub fn setreuid(ruid: u32, euid: u32) usize {
617 return errnoWrap(c.setreuid(ruid, euid));
618}
619
620pub fn setregid(rgid: u32, egid: u32) usize {
621 return errnoWrap(c.setregid(rgid, egid));
622}
623
624const NSIG = 32;
625
626pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
627pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
628pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
629
630/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
631pub const Sigaction = extern struct {
632 /// signal handler
633 __sigaction_u: extern union {
634 __sa_handler: extern fn (i32) void,
635 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
636 },
637
638 /// see signal options
639 sa_flags: u32,
640
641 /// signal mask to apply
642 sa_mask: sigset_t,
643};
644
645pub const _SIG_WORDS = 4;
646pub const _SIG_MAXSIG = 128;
647
648pub inline fn _SIG_IDX(sig: usize) usize {
649 return sig - 1;
650}
651pub inline fn _SIG_WORD(sig: usize) usize {
652 return_SIG_IDX(sig) >> 5;
653}
654pub inline fn _SIG_BIT(sig: usize) usize {
655 return 1 << (_SIG_IDX(sig) & 31);
656}
657pub inline fn _SIG_VALID(sig: usize) usize {
658 return sig <= _SIG_MAXSIG and sig > 0;
659}
660
661pub const sigset_t = extern struct {
662 __bits: [_SIG_WORDS]u32,
663};
664
665pub fn raise(sig: i32) usize {
666 return errnoWrap(c.raise(sig));
667}
668
669pub const Stat = c.Stat;
670pub const dirent = c.dirent;
671pub const timespec = c.timespec;
672
673pub fn fstat(fd: i32, buf: *c.Stat) usize {
674 return errnoWrap(c.fstat(fd, buf));
675}
676pub const iovec = extern struct {
677 iov_base: [*]u8,
678 iov_len: usize,
679};
680
681pub const iovec_const = extern struct {
682 iov_base: [*]const u8,
683 iov_len: usize,
684};
685
686// TODO avoid libc dependency
687pub fn kqueue() usize {
688 return errnoWrap(c.kqueue());
689}
690
691// TODO avoid libc dependency
692pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
693 return errnoWrap(c.kevent(
694 kq,
695 changelist.ptr,
696 @intCast(c_int, changelist.len),
697 eventlist.ptr,
698 @intCast(c_int, eventlist.len),
699 timeout,
700 ));
701}
702
703// TODO avoid libc dependency
704pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
705 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
706}
707
708// TODO avoid libc dependency
709pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
710 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
711}
712
713// TODO avoid libc dependency
714pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
715 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
716}
717
718// TODO avoid libc dependency
719
720/// Takes the return value from a syscall and formats it back in the way
721/// that the kernel represents it to libc. Errno was a mistake, let's make
722/// it go away forever.
723fn errnoWrap(value: isize) usize {
724 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
725}
std/os/path.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Os = builtin.Os;3const Os = builtin.Os;
4const debug = std.debug;4const debug = std.debug;
std/os/test.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const os = std.os;2const os = std.os;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const io = std.io;4const io = std.io;
std/os/time.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Os = builtin.Os;3const Os = builtin.Os;
4const debug = std.debug;4const debug = std.debug;
std/os/windows.zig created+399
...@@ -0,0 +1,399 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const maxInt = std.math.maxInt;
4
5pub use @import("windows/advapi32.zig");
6pub use @import("windows/kernel32.zig");
7pub use @import("windows/ntdll.zig");
8pub use @import("windows/ole32.zig");
9pub use @import("windows/shell32.zig");
10
11test "import" {
12 _ = @import("windows/util.zig");
13}
14
15pub const ERROR = @import("windows/error.zig");
16
17pub const SHORT = c_short;
18pub const BOOL = c_int;
19pub const BOOLEAN = BYTE;
20pub const BYTE = u8;
21pub const CHAR = u8;
22pub const DWORD = u32;
23pub const FLOAT = f32;
24pub const HANDLE = *c_void;
25pub const HCRYPTPROV = ULONG_PTR;
26pub const HINSTANCE = *@OpaqueType();
27pub const HMODULE = *@OpaqueType();
28pub const FARPROC = *@OpaqueType();
29pub const INT = c_int;
30pub const LPBYTE = *BYTE;
31pub const LPCH = *CHAR;
32pub const LPCSTR = [*]const CHAR;
33pub const LPCTSTR = [*]const TCHAR;
34pub const LPCVOID = *const c_void;
35pub const LPDWORD = *DWORD;
36pub const LPSTR = [*]CHAR;
37pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
38pub const LPVOID = *c_void;
39pub const LPWSTR = [*]WCHAR;
40pub const LPCWSTR = [*]const WCHAR;
41pub const PVOID = *c_void;
42pub const PWSTR = [*]WCHAR;
43pub const SIZE_T = usize;
44pub const TCHAR = if (UNICODE) WCHAR else u8;
45pub const UINT = c_uint;
46pub const ULONG_PTR = usize;
47pub const DWORD_PTR = ULONG_PTR;
48pub const UNICODE = false;
49pub const WCHAR = u16;
50pub const WORD = u16;
51pub const LARGE_INTEGER = i64;
52pub const ULONG = u32;
53pub const LONG = i32;
54pub const ULONGLONG = u64;
55pub const LONGLONG = i64;
56
57pub const TRUE = 1;
58pub const FALSE = 0;
59
60/// The standard input device. Initially, this is the console input buffer, CONIN$.
61pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
62
63/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
64pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
65
66/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
67pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
68
69pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
70
71pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
72
73pub const OVERLAPPED = extern struct {
74 Internal: ULONG_PTR,
75 InternalHigh: ULONG_PTR,
76 Offset: DWORD,
77 OffsetHigh: DWORD,
78 hEvent: ?HANDLE,
79};
80pub const LPOVERLAPPED = *OVERLAPPED;
81
82pub const MAX_PATH = 260;
83
84// TODO issue #305
85pub const FILE_INFO_BY_HANDLE_CLASS = u32;
86pub const FileBasicInfo = 0;
87pub const FileStandardInfo = 1;
88pub const FileNameInfo = 2;
89pub const FileRenameInfo = 3;
90pub const FileDispositionInfo = 4;
91pub const FileAllocationInfo = 5;
92pub const FileEndOfFileInfo = 6;
93pub const FileStreamInfo = 7;
94pub const FileCompressionInfo = 8;
95pub const FileAttributeTagInfo = 9;
96pub const FileIdBothDirectoryInfo = 10;
97pub const FileIdBothDirectoryRestartInfo = 11;
98pub const FileIoPriorityHintInfo = 12;
99pub const FileRemoteProtocolInfo = 13;
100pub const FileFullDirectoryInfo = 14;
101pub const FileFullDirectoryRestartInfo = 15;
102pub const FileStorageInfo = 16;
103pub const FileAlignmentInfo = 17;
104pub const FileIdInfo = 18;
105pub const FileIdExtdDirectoryInfo = 19;
106pub const FileIdExtdDirectoryRestartInfo = 20;
107
108pub const FILE_NAME_INFO = extern struct {
109 FileNameLength: DWORD,
110 FileName: [1]WCHAR,
111};
112
113/// Return the normalized drive name. This is the default.
114pub const FILE_NAME_NORMALIZED = 0x0;
115
116/// Return the opened file name (not normalized).
117pub const FILE_NAME_OPENED = 0x8;
118
119/// Return the path with the drive letter. This is the default.
120pub const VOLUME_NAME_DOS = 0x0;
121
122/// Return the path with a volume GUID path instead of the drive name.
123pub const VOLUME_NAME_GUID = 0x1;
124
125/// Return the path with no drive information.
126pub const VOLUME_NAME_NONE = 0x4;
127
128/// Return the path with the volume device path.
129pub const VOLUME_NAME_NT = 0x2;
130
131pub const SECURITY_ATTRIBUTES = extern struct {
132 nLength: DWORD,
133 lpSecurityDescriptor: ?*c_void,
134 bInheritHandle: BOOL,
135};
136pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
137pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
138
139pub const GENERIC_READ = 0x80000000;
140pub const GENERIC_WRITE = 0x40000000;
141pub const GENERIC_EXECUTE = 0x20000000;
142pub const GENERIC_ALL = 0x10000000;
143
144pub const FILE_SHARE_DELETE = 0x00000004;
145pub const FILE_SHARE_READ = 0x00000001;
146pub const FILE_SHARE_WRITE = 0x00000002;
147
148pub const CREATE_ALWAYS = 2;
149pub const CREATE_NEW = 1;
150pub const OPEN_ALWAYS = 4;
151pub const OPEN_EXISTING = 3;
152pub const TRUNCATE_EXISTING = 5;
153
154pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
155pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
156pub const FILE_ATTRIBUTE_DEVICE = 0x40;
157pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
158pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
159pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
160pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
161pub const FILE_ATTRIBUTE_NORMAL = 0x80;
162pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
163pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
164pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
165pub const FILE_ATTRIBUTE_READONLY = 0x1;
166pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
167pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
168pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
169pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
170pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
171pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
172pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
173
174pub const PROCESS_INFORMATION = extern struct {
175 hProcess: HANDLE,
176 hThread: HANDLE,
177 dwProcessId: DWORD,
178 dwThreadId: DWORD,
179};
180
181pub const STARTUPINFOW = extern struct {
182 cb: DWORD,
183 lpReserved: ?LPWSTR,
184 lpDesktop: ?LPWSTR,
185 lpTitle: ?LPWSTR,
186 dwX: DWORD,
187 dwY: DWORD,
188 dwXSize: DWORD,
189 dwYSize: DWORD,
190 dwXCountChars: DWORD,
191 dwYCountChars: DWORD,
192 dwFillAttribute: DWORD,
193 dwFlags: DWORD,
194 wShowWindow: WORD,
195 cbReserved2: WORD,
196 lpReserved2: ?LPBYTE,
197 hStdInput: ?HANDLE,
198 hStdOutput: ?HANDLE,
199 hStdError: ?HANDLE,
200};
201
202pub const STARTF_FORCEONFEEDBACK = 0x00000040;
203pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
204pub const STARTF_PREVENTPINNING = 0x00002000;
205pub const STARTF_RUNFULLSCREEN = 0x00000020;
206pub const STARTF_TITLEISAPPID = 0x00001000;
207pub const STARTF_TITLEISLINKNAME = 0x00000800;
208pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
209pub const STARTF_USECOUNTCHARS = 0x00000008;
210pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
211pub const STARTF_USEHOTKEY = 0x00000200;
212pub const STARTF_USEPOSITION = 0x00000004;
213pub const STARTF_USESHOWWINDOW = 0x00000001;
214pub const STARTF_USESIZE = 0x00000002;
215pub const STARTF_USESTDHANDLES = 0x00000100;
216
217pub const INFINITE = 4294967295;
218
219pub const WAIT_ABANDONED = 0x00000080;
220pub const WAIT_OBJECT_0 = 0x00000000;
221pub const WAIT_TIMEOUT = 0x00000102;
222pub const WAIT_FAILED = 0xFFFFFFFF;
223
224pub const HANDLE_FLAG_INHERIT = 0x00000001;
225pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
226
227pub const MOVEFILE_COPY_ALLOWED = 2;
228pub const MOVEFILE_CREATE_HARDLINK = 16;
229pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
230pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
231pub const MOVEFILE_REPLACE_EXISTING = 1;
232pub const MOVEFILE_WRITE_THROUGH = 8;
233
234pub const FILE_BEGIN = 0;
235pub const FILE_CURRENT = 1;
236pub const FILE_END = 2;
237
238pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
239pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
240pub const HEAP_NO_SERIALIZE = 0x00000001;
241
242pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
243pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
244
245pub const WIN32_FIND_DATAW = extern struct {
246 dwFileAttributes: DWORD,
247 ftCreationTime: FILETIME,
248 ftLastAccessTime: FILETIME,
249 ftLastWriteTime: FILETIME,
250 nFileSizeHigh: DWORD,
251 nFileSizeLow: DWORD,
252 dwReserved0: DWORD,
253 dwReserved1: DWORD,
254 cFileName: [260]u16,
255 cAlternateFileName: [14]u16,
256};
257
258pub const FILETIME = extern struct {
259 dwLowDateTime: DWORD,
260 dwHighDateTime: DWORD,
261};
262
263pub const SYSTEM_INFO = extern struct {
264 anon1: extern union {
265 dwOemId: DWORD,
266 anon2: extern struct {
267 wProcessorArchitecture: WORD,
268 wReserved: WORD,
269 },
270 },
271 dwPageSize: DWORD,
272 lpMinimumApplicationAddress: LPVOID,
273 lpMaximumApplicationAddress: LPVOID,
274 dwActiveProcessorMask: DWORD_PTR,
275 dwNumberOfProcessors: DWORD,
276 dwProcessorType: DWORD,
277 dwAllocationGranularity: DWORD,
278 wProcessorLevel: WORD,
279 wProcessorRevision: WORD,
280};
281
282pub const HRESULT = c_long;
283
284pub const KNOWNFOLDERID = GUID;
285pub const GUID = extern struct {
286 Data1: c_ulong,
287 Data2: c_ushort,
288 Data3: c_ushort,
289 Data4: [8]u8,
290
291 pub fn parse(str: []const u8) GUID {
292 var guid: GUID = undefined;
293 var index: usize = 0;
294 assert(str[index] == '{');
295 index += 1;
296
297 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
298 index += 8;
299
300 assert(str[index] == '-');
301 index += 1;
302
303 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
304 index += 4;
305
306 assert(str[index] == '-');
307 index += 1;
308
309 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
310 index += 4;
311
312 assert(str[index] == '-');
313 index += 1;
314
315 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
316 index += 2;
317 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
318 index += 2;
319
320 assert(str[index] == '-');
321 index += 1;
322
323 var i: usize = 2;
324 while (i < guid.Data4.len) : (i += 1) {
325 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
326 index += 2;
327 }
328
329 assert(str[index] == '}');
330 index += 1;
331 return guid;
332 }
333};
334
335pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
336
337pub const KF_FLAG_DEFAULT = 0;
338pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
339pub const KF_FLAG_CREATE = 32768;
340pub const KF_FLAG_DONT_VERIFY = 16384;
341pub const KF_FLAG_DONT_UNEXPAND = 8192;
342pub const KF_FLAG_NO_ALIAS = 4096;
343pub const KF_FLAG_INIT = 2048;
344pub const KF_FLAG_DEFAULT_PATH = 1024;
345pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
346pub const KF_FLAG_SIMPLE_IDLIST = 256;
347pub const KF_FLAG_ALIAS_ONLY = -2147483648;
348
349pub const S_OK = 0;
350pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
351pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
352pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
353pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
354pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
355pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
356pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
357pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
358pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
359pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
360
361pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
362pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
363pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
364pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
365pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
366pub const FILE_FLAG_OVERLAPPED = 0x40000000;
367pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
368pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
369pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
370pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
371pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
372
373pub const SMALL_RECT = extern struct {
374 Left: SHORT,
375 Top: SHORT,
376 Right: SHORT,
377 Bottom: SHORT,
378};
379
380pub const COORD = extern struct {
381 X: SHORT,
382 Y: SHORT,
383};
384
385pub const CREATE_UNICODE_ENVIRONMENT = 1024;
386
387pub const TLS_OUT_OF_INDEXES = 4294967295;
388pub const IMAGE_TLS_DIRECTORY = extern struct {
389 StartAddressOfRawData: usize,
390 EndAddressOfRawData: usize,
391 AddressOfIndex: usize,
392 AddressOfCallBacks: usize,
393 SizeOfZeroFill: u32,
394 Characteristics: u32,
395};
396pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
397pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
398
399pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;
std/os/windows/advapi32.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1use @import("index.zig");1use @import("../windows.zig");
22
3pub const PROV_RSA_FULL = 1;3pub const PROV_RSA_FULL = 1;
44
std/os/windows/index.zig deleted-399
...@@ -1,399 +0,0 @@
1const std = @import("../../index.zig");
2const assert = std.debug.assert;
3const maxInt = std.math.maxInt;
4
5pub use @import("advapi32.zig");
6pub use @import("kernel32.zig");
7pub use @import("ntdll.zig");
8pub use @import("ole32.zig");
9pub use @import("shell32.zig");
10
11test "import" {
12 _ = @import("util.zig");
13}
14
15pub const ERROR = @import("error.zig");
16
17pub const SHORT = c_short;
18pub const BOOL = c_int;
19pub const BOOLEAN = BYTE;
20pub const BYTE = u8;
21pub const CHAR = u8;
22pub const DWORD = u32;
23pub const FLOAT = f32;
24pub const HANDLE = *c_void;
25pub const HCRYPTPROV = ULONG_PTR;
26pub const HINSTANCE = *@OpaqueType();
27pub const HMODULE = *@OpaqueType();
28pub const FARPROC = *@OpaqueType();
29pub const INT = c_int;
30pub const LPBYTE = *BYTE;
31pub const LPCH = *CHAR;
32pub const LPCSTR = [*]const CHAR;
33pub const LPCTSTR = [*]const TCHAR;
34pub const LPCVOID = *const c_void;
35pub const LPDWORD = *DWORD;
36pub const LPSTR = [*]CHAR;
37pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
38pub const LPVOID = *c_void;
39pub const LPWSTR = [*]WCHAR;
40pub const LPCWSTR = [*]const WCHAR;
41pub const PVOID = *c_void;
42pub const PWSTR = [*]WCHAR;
43pub const SIZE_T = usize;
44pub const TCHAR = if (UNICODE) WCHAR else u8;
45pub const UINT = c_uint;
46pub const ULONG_PTR = usize;
47pub const DWORD_PTR = ULONG_PTR;
48pub const UNICODE = false;
49pub const WCHAR = u16;
50pub const WORD = u16;
51pub const LARGE_INTEGER = i64;
52pub const ULONG = u32;
53pub const LONG = i32;
54pub const ULONGLONG = u64;
55pub const LONGLONG = i64;
56
57pub const TRUE = 1;
58pub const FALSE = 0;
59
60/// The standard input device. Initially, this is the console input buffer, CONIN$.
61pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
62
63/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
64pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
65
66/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
67pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
68
69pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
70
71pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
72
73pub const OVERLAPPED = extern struct {
74 Internal: ULONG_PTR,
75 InternalHigh: ULONG_PTR,
76 Offset: DWORD,
77 OffsetHigh: DWORD,
78 hEvent: ?HANDLE,
79};
80pub const LPOVERLAPPED = *OVERLAPPED;
81
82pub const MAX_PATH = 260;
83
84// TODO issue #305
85pub const FILE_INFO_BY_HANDLE_CLASS = u32;
86pub const FileBasicInfo = 0;
87pub const FileStandardInfo = 1;
88pub const FileNameInfo = 2;
89pub const FileRenameInfo = 3;
90pub const FileDispositionInfo = 4;
91pub const FileAllocationInfo = 5;
92pub const FileEndOfFileInfo = 6;
93pub const FileStreamInfo = 7;
94pub const FileCompressionInfo = 8;
95pub const FileAttributeTagInfo = 9;
96pub const FileIdBothDirectoryInfo = 10;
97pub const FileIdBothDirectoryRestartInfo = 11;
98pub const FileIoPriorityHintInfo = 12;
99pub const FileRemoteProtocolInfo = 13;
100pub const FileFullDirectoryInfo = 14;
101pub const FileFullDirectoryRestartInfo = 15;
102pub const FileStorageInfo = 16;
103pub const FileAlignmentInfo = 17;
104pub const FileIdInfo = 18;
105pub const FileIdExtdDirectoryInfo = 19;
106pub const FileIdExtdDirectoryRestartInfo = 20;
107
108pub const FILE_NAME_INFO = extern struct {
109 FileNameLength: DWORD,
110 FileName: [1]WCHAR,
111};
112
113/// Return the normalized drive name. This is the default.
114pub const FILE_NAME_NORMALIZED = 0x0;
115
116/// Return the opened file name (not normalized).
117pub const FILE_NAME_OPENED = 0x8;
118
119/// Return the path with the drive letter. This is the default.
120pub const VOLUME_NAME_DOS = 0x0;
121
122/// Return the path with a volume GUID path instead of the drive name.
123pub const VOLUME_NAME_GUID = 0x1;
124
125/// Return the path with no drive information.
126pub const VOLUME_NAME_NONE = 0x4;
127
128/// Return the path with the volume device path.
129pub const VOLUME_NAME_NT = 0x2;
130
131pub const SECURITY_ATTRIBUTES = extern struct {
132 nLength: DWORD,
133 lpSecurityDescriptor: ?*c_void,
134 bInheritHandle: BOOL,
135};
136pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
137pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
138
139pub const GENERIC_READ = 0x80000000;
140pub const GENERIC_WRITE = 0x40000000;
141pub const GENERIC_EXECUTE = 0x20000000;
142pub const GENERIC_ALL = 0x10000000;
143
144pub const FILE_SHARE_DELETE = 0x00000004;
145pub const FILE_SHARE_READ = 0x00000001;
146pub const FILE_SHARE_WRITE = 0x00000002;
147
148pub const CREATE_ALWAYS = 2;
149pub const CREATE_NEW = 1;
150pub const OPEN_ALWAYS = 4;
151pub const OPEN_EXISTING = 3;
152pub const TRUNCATE_EXISTING = 5;
153
154pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
155pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
156pub const FILE_ATTRIBUTE_DEVICE = 0x40;
157pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
158pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
159pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
160pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
161pub const FILE_ATTRIBUTE_NORMAL = 0x80;
162pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
163pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
164pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
165pub const FILE_ATTRIBUTE_READONLY = 0x1;
166pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
167pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
168pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
169pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
170pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
171pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
172pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
173
174pub const PROCESS_INFORMATION = extern struct {
175 hProcess: HANDLE,
176 hThread: HANDLE,
177 dwProcessId: DWORD,
178 dwThreadId: DWORD,
179};
180
181pub const STARTUPINFOW = extern struct {
182 cb: DWORD,
183 lpReserved: ?LPWSTR,
184 lpDesktop: ?LPWSTR,
185 lpTitle: ?LPWSTR,
186 dwX: DWORD,
187 dwY: DWORD,
188 dwXSize: DWORD,
189 dwYSize: DWORD,
190 dwXCountChars: DWORD,
191 dwYCountChars: DWORD,
192 dwFillAttribute: DWORD,
193 dwFlags: DWORD,
194 wShowWindow: WORD,
195 cbReserved2: WORD,
196 lpReserved2: ?LPBYTE,
197 hStdInput: ?HANDLE,
198 hStdOutput: ?HANDLE,
199 hStdError: ?HANDLE,
200};
201
202pub const STARTF_FORCEONFEEDBACK = 0x00000040;
203pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
204pub const STARTF_PREVENTPINNING = 0x00002000;
205pub const STARTF_RUNFULLSCREEN = 0x00000020;
206pub const STARTF_TITLEISAPPID = 0x00001000;
207pub const STARTF_TITLEISLINKNAME = 0x00000800;
208pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
209pub const STARTF_USECOUNTCHARS = 0x00000008;
210pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
211pub const STARTF_USEHOTKEY = 0x00000200;
212pub const STARTF_USEPOSITION = 0x00000004;
213pub const STARTF_USESHOWWINDOW = 0x00000001;
214pub const STARTF_USESIZE = 0x00000002;
215pub const STARTF_USESTDHANDLES = 0x00000100;
216
217pub const INFINITE = 4294967295;
218
219pub const WAIT_ABANDONED = 0x00000080;
220pub const WAIT_OBJECT_0 = 0x00000000;
221pub const WAIT_TIMEOUT = 0x00000102;
222pub const WAIT_FAILED = 0xFFFFFFFF;
223
224pub const HANDLE_FLAG_INHERIT = 0x00000001;
225pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
226
227pub const MOVEFILE_COPY_ALLOWED = 2;
228pub const MOVEFILE_CREATE_HARDLINK = 16;
229pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
230pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
231pub const MOVEFILE_REPLACE_EXISTING = 1;
232pub const MOVEFILE_WRITE_THROUGH = 8;
233
234pub const FILE_BEGIN = 0;
235pub const FILE_CURRENT = 1;
236pub const FILE_END = 2;
237
238pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
239pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
240pub const HEAP_NO_SERIALIZE = 0x00000001;
241
242pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
243pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
244
245pub const WIN32_FIND_DATAW = extern struct {
246 dwFileAttributes: DWORD,
247 ftCreationTime: FILETIME,
248 ftLastAccessTime: FILETIME,
249 ftLastWriteTime: FILETIME,
250 nFileSizeHigh: DWORD,
251 nFileSizeLow: DWORD,
252 dwReserved0: DWORD,
253 dwReserved1: DWORD,
254 cFileName: [260]u16,
255 cAlternateFileName: [14]u16,
256};
257
258pub const FILETIME = extern struct {
259 dwLowDateTime: DWORD,
260 dwHighDateTime: DWORD,
261};
262
263pub const SYSTEM_INFO = extern struct {
264 anon1: extern union {
265 dwOemId: DWORD,
266 anon2: extern struct {
267 wProcessorArchitecture: WORD,
268 wReserved: WORD,
269 },
270 },
271 dwPageSize: DWORD,
272 lpMinimumApplicationAddress: LPVOID,
273 lpMaximumApplicationAddress: LPVOID,
274 dwActiveProcessorMask: DWORD_PTR,
275 dwNumberOfProcessors: DWORD,
276 dwProcessorType: DWORD,
277 dwAllocationGranularity: DWORD,
278 wProcessorLevel: WORD,
279 wProcessorRevision: WORD,
280};
281
282pub const HRESULT = c_long;
283
284pub const KNOWNFOLDERID = GUID;
285pub const GUID = extern struct {
286 Data1: c_ulong,
287 Data2: c_ushort,
288 Data3: c_ushort,
289 Data4: [8]u8,
290
291 pub fn parse(str: []const u8) GUID {
292 var guid: GUID = undefined;
293 var index: usize = 0;
294 assert(str[index] == '{');
295 index += 1;
296
297 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
298 index += 8;
299
300 assert(str[index] == '-');
301 index += 1;
302
303 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
304 index += 4;
305
306 assert(str[index] == '-');
307 index += 1;
308
309 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
310 index += 4;
311
312 assert(str[index] == '-');
313 index += 1;
314
315 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
316 index += 2;
317 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
318 index += 2;
319
320 assert(str[index] == '-');
321 index += 1;
322
323 var i: usize = 2;
324 while (i < guid.Data4.len) : (i += 1) {
325 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
326 index += 2;
327 }
328
329 assert(str[index] == '}');
330 index += 1;
331 return guid;
332 }
333};
334
335pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
336
337pub const KF_FLAG_DEFAULT = 0;
338pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
339pub const KF_FLAG_CREATE = 32768;
340pub const KF_FLAG_DONT_VERIFY = 16384;
341pub const KF_FLAG_DONT_UNEXPAND = 8192;
342pub const KF_FLAG_NO_ALIAS = 4096;
343pub const KF_FLAG_INIT = 2048;
344pub const KF_FLAG_DEFAULT_PATH = 1024;
345pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
346pub const KF_FLAG_SIMPLE_IDLIST = 256;
347pub const KF_FLAG_ALIAS_ONLY = -2147483648;
348
349pub const S_OK = 0;
350pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
351pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
352pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
353pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
354pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
355pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
356pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
357pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
358pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
359pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
360
361pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
362pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
363pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
364pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
365pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
366pub const FILE_FLAG_OVERLAPPED = 0x40000000;
367pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
368pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
369pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
370pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
371pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
372
373pub const SMALL_RECT = extern struct {
374 Left: SHORT,
375 Top: SHORT,
376 Right: SHORT,
377 Bottom: SHORT,
378};
379
380pub const COORD = extern struct {
381 X: SHORT,
382 Y: SHORT,
383};
384
385pub const CREATE_UNICODE_ENVIRONMENT = 1024;
386
387pub const TLS_OUT_OF_INDEXES = 4294967295;
388pub const IMAGE_TLS_DIRECTORY = extern struct {
389 StartAddressOfRawData: usize,
390 EndAddressOfRawData: usize,
391 AddressOfIndex: usize,
392 AddressOfCallBacks: usize,
393 SizeOfZeroFill: u32,
394 Characteristics: u32,
395};
396pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
397pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
398
399pub const PIMAGE_TLS_CALLBACK = ?extern fn(PVOID, DWORD, PVOID) void;
std/os/windows/kernel32.zig+3-5
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1use @import("index.zig");1use @import("../windows.zig");
22
3pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;3pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
44
...@@ -262,12 +262,10 @@ pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;...@@ -262,12 +262,10 @@ pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
262262
263pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;263pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;
264264
265pub const INIT_ONCE_FN = extern fn(InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;265pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
266266
267pub const RTL_RUN_ONCE = extern struct {267pub const RTL_RUN_ONCE = extern struct {
268 Ptr: ?*c_void,268 Ptr: ?*c_void,
269};269};
270270
271pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE {271pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
272 .Ptr = null,
273};
std/os/windows/ntdll.zig+1-1
...@@ -1,3 +1,3 @@...@@ -1,3 +1,3 @@
1use @import("index.zig");1use @import("../windows.zig");
22
3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
std/os/windows/ole32.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1use @import("index.zig");1use @import("../windows.zig");
22
3pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;3pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
4pub extern "ole32" stdcallcc fn CoUninitialize() void;4pub extern "ole32" stdcallcc fn CoUninitialize() void;
std/os/windows/shell32.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1use @import("index.zig");1use @import("../windows.zig");
22
3pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;3pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
44
std/os/windows/tls.zig deleted-36
...@@ -1,36 +0,0 @@
1const std = @import("../../index.zig");
2
3export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES;
4export var _tls_start: u8 linksection(".tls") = 0;
5export var _tls_end: u8 linksection(".tls$ZZZ") = 0;
6export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
7export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
8
9// TODO this is how I would like it to be expressed
10// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate
11// why they do that.
12//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY {
13// .StartAddressOfRawData = @ptrToInt(&_tls_start),
14// .EndAddressOfRawData = @ptrToInt(&_tls_end),
15// .AddressOfIndex = @ptrToInt(&_tls_index),
16// .AddressOfCallBacks = @ptrToInt(__xl_a),
17// .SizeOfZeroFill = 0,
18// .Characteristics = 0,
19//};
20// This is the workaround because we can't do @ptrToInt at comptime like that.
21pub const IMAGE_TLS_DIRECTORY = extern struct {
22 StartAddressOfRawData: *c_void,
23 EndAddressOfRawData: *c_void,
24 AddressOfIndex: *c_void,
25 AddressOfCallBacks: *c_void,
26 SizeOfZeroFill: u32,
27 Characteristics: u32,
28};
29export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY {
30 .StartAddressOfRawData = &_tls_start,
31 .EndAddressOfRawData = &_tls_end,
32 .AddressOfIndex = &_tls_index,
33 .AddressOfCallBacks = &__xl_a,
34 .SizeOfZeroFill = 0,
35 .Characteristics = 0,
36};
std/os/windows/util.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");1const std = @import("../../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const os = std.os;3const os = std.os;
4const unicode = std.unicode;4const unicode = std.unicode;
std/os/zen.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
33
4//////////////////////////4//////////////////////////
std/pdb.zig+2-4
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("index.zig");2const std = @import("std.zig");
3const io = std.io;3const io = std.io;
4const math = std.math;4const math = std.math;
5const mem = std.mem;5const mem = std.mem;
...@@ -12,7 +12,6 @@ const ArrayList = std.ArrayList;...@@ -12,7 +12,6 @@ const ArrayList = std.ArrayList;
12// Note: most of this is based on information gathered from LLVM source code,12// Note: most of this is based on information gathered from LLVM source code,
13// documentation and/or contributors.13// documentation and/or contributors.
1414
15
16// https://llvm.org/docs/PDB/DbiStream.html#stream-header15// https://llvm.org/docs/PDB/DbiStream.html#stream-header
17pub const DbiStreamHeader = packed struct {16pub const DbiStreamHeader = packed struct {
18 VersionSignature: i32,17 VersionSignature: i32,
...@@ -393,10 +392,9 @@ pub const LineNumberEntry = packed struct {...@@ -393,10 +392,9 @@ pub const LineNumberEntry = packed struct {
393 Flags: u32,392 Flags: u32,
394393
395 /// TODO runtime crash when I make the actual type of Flags this394 /// TODO runtime crash when I make the actual type of Flags this
396 const Flags = packed struct {395 pub const Flags = packed struct {
397 /// Start line number396 /// Start line number
398 Start: u24,397 Start: u24,
399
400 /// Delta of lines to the end of the expression. Still unclear.398 /// Delta of lines to the end of the expression. Still unclear.
401 // TODO figure out the point of this field.399 // TODO figure out the point of this field.
402 End: u7,400 End: u7,
std/priority_queue.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
3const debug = std.debug;3const debug = std.debug;
4const expect = std.testing.expect;4const expect = std.testing.expect;
std/rand.zig created+1005
...@@ -0,0 +1,1005 @@
1// The engines provided here should be initialized from an external source. For now, getRandomBytes
2// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.
4//
5// ```
6// var buf: [8]u8 = undefined;
7// try std.os.getRandomBytes(buf[0..]);
8// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
9//
10// var r = DefaultPrng.init(seed);
11//
12// const s = r.random.int(u64);
13// ```
14//
15// TODO(tiehuis): Benchmark these against other reference implementations.
16
17const std = @import("std.zig");
18const builtin = @import("builtin");
19const assert = std.debug.assert;
20const expect = std.testing.expect;
21const mem = std.mem;
22const math = std.math;
23const ziggurat = @import("rand/ziggurat.zig");
24const maxInt = std.math.maxInt;
25
26// When you need fast unbiased random numbers
27pub const DefaultPrng = Xoroshiro128;
28
29// When you need cryptographically secure random numbers
30pub const DefaultCsprng = Isaac64;
31
32pub const Random = struct {
33 fillFn: fn (r: *Random, buf: []u8) void,
34
35 /// Read random bytes into the specified buffer until full.
36 pub fn bytes(r: *Random, buf: []u8) void {
37 r.fillFn(r, buf);
38 }
39
40 pub fn boolean(r: *Random) bool {
41 return r.int(u1) != 0;
42 }
43
44 /// Returns a random int `i` such that `0 <= i <= maxInt(T)`.
45 /// `i` is evenly distributed.
46 pub fn int(r: *Random, comptime T: type) T {
47 const UnsignedT = @IntType(false, T.bit_count);
48 const ByteAlignedT = @IntType(false, @divTrunc(T.bit_count + 7, 8) * 8);
49
50 var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined;
51 r.bytes(rand_bytes[0..]);
52
53 // use LE instead of native endian for better portability maybe?
54 // TODO: endian portability is pointless if the underlying prng isn't endian portable.
55 // TODO: document the endian portability of this library.
56 const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes);
57 const unsigned_result = @truncate(UnsignedT, byte_aligned_result);
58 return @bitCast(T, unsigned_result);
59 }
60
61 /// Constant-time implementation off ::uintLessThan.
62 /// The results of this function may be biased.
63 pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
64 comptime assert(T.is_signed == false);
65 comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
66 assert(0 < less_than);
67 if (T.bit_count <= 32) {
68 return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than));
69 } else {
70 return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
71 }
72 }
73
74 /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
75 /// This function assumes that the underlying ::fillFn produces evenly distributed values.
76 /// Within this assumption, the runtime of this function is exponentially distributed.
77 /// If ::fillFn were backed by a true random generator,
78 /// the runtime of this function would technically be unbounded.
79 /// However, if ::fillFn is backed by any evenly distributed pseudo random number generator,
80 /// this function is guaranteed to return.
81 /// If you need deterministic runtime bounds, use `::uintLessThanBiased`.
82 pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
83 comptime assert(T.is_signed == false);
84 comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
85 assert(0 < less_than);
86 // Small is typically u32
87 const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32);
88 // Large is typically u64
89 const Large = @IntType(false, Small.bit_count * 2);
90
91 // adapted from:
92 // http://www.pcg-random.org/posts/bounded-rands.html
93 // "Lemire's (with an extra tweak from me)"
94 var x: Small = r.int(Small);
95 var m: Large = Large(x) * Large(less_than);
96 var l: Small = @truncate(Small, m);
97 if (l < less_than) {
98 // TODO: workaround for https://github.com/ziglang/zig/issues/1770
99 // should be:
100 // var t: Small = -%less_than;
101 var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than)));
102
103 if (t >= less_than) {
104 t -= less_than;
105 if (t >= less_than) {
106 t %= less_than;
107 }
108 }
109 while (l < t) {
110 x = r.int(Small);
111 m = Large(x) * Large(less_than);
112 l = @truncate(Small, m);
113 }
114 }
115 return @intCast(T, m >> Small.bit_count);
116 }
117
118 /// Constant-time implementation off ::uintAtMost.
119 /// The results of this function may be biased.
120 pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
121 assert(T.is_signed == false);
122 if (at_most == maxInt(T)) {
123 // have the full range
124 return r.int(T);
125 }
126 return r.uintLessThanBiased(T, at_most + 1);
127 }
128
129 /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
130 /// See ::uintLessThan, which this function uses in most cases,
131 /// for commentary on the runtime of this function.
132 pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T {
133 assert(T.is_signed == false);
134 if (at_most == maxInt(T)) {
135 // have the full range
136 return r.int(T);
137 }
138 return r.uintLessThan(T, at_most + 1);
139 }
140
141 /// Constant-time implementation off ::intRangeLessThan.
142 /// The results of this function may be biased.
143 pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
144 assert(at_least < less_than);
145 if (T.is_signed) {
146 // Two's complement makes this math pretty easy.
147 const UnsignedT = @IntType(false, T.bit_count);
148 const lo = @bitCast(UnsignedT, at_least);
149 const hi = @bitCast(UnsignedT, less_than);
150 const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo);
151 return @bitCast(T, result);
152 } else {
153 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
154 return at_least + r.uintLessThanBiased(T, less_than - at_least);
155 }
156 }
157
158 /// Returns an evenly distributed random integer `at_least <= i < less_than`.
159 /// See ::uintLessThan, which this function uses in most cases,
160 /// for commentary on the runtime of this function.
161 pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T {
162 assert(at_least < less_than);
163 if (T.is_signed) {
164 // Two's complement makes this math pretty easy.
165 const UnsignedT = @IntType(false, T.bit_count);
166 const lo = @bitCast(UnsignedT, at_least);
167 const hi = @bitCast(UnsignedT, less_than);
168 const result = lo +% r.uintLessThan(UnsignedT, hi -% lo);
169 return @bitCast(T, result);
170 } else {
171 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
172 return at_least + r.uintLessThan(T, less_than - at_least);
173 }
174 }
175
176 /// Constant-time implementation off ::intRangeAtMostBiased.
177 /// The results of this function may be biased.
178 pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
179 assert(at_least <= at_most);
180 if (T.is_signed) {
181 // Two's complement makes this math pretty easy.
182 const UnsignedT = @IntType(false, T.bit_count);
183 const lo = @bitCast(UnsignedT, at_least);
184 const hi = @bitCast(UnsignedT, at_most);
185 const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo);
186 return @bitCast(T, result);
187 } else {
188 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
189 return at_least + r.uintAtMostBiased(T, at_most - at_least);
190 }
191 }
192
193 /// Returns an evenly distributed random integer `at_least <= i <= at_most`.
194 /// See ::uintLessThan, which this function uses in most cases,
195 /// for commentary on the runtime of this function.
196 pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T {
197 assert(at_least <= at_most);
198 if (T.is_signed) {
199 // Two's complement makes this math pretty easy.
200 const UnsignedT = @IntType(false, T.bit_count);
201 const lo = @bitCast(UnsignedT, at_least);
202 const hi = @bitCast(UnsignedT, at_most);
203 const result = lo +% r.uintAtMost(UnsignedT, hi -% lo);
204 return @bitCast(T, result);
205 } else {
206 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
207 return at_least + r.uintAtMost(T, at_most - at_least);
208 }
209 }
210
211 /// TODO: deprecated. use ::boolean or ::int instead.
212 pub fn scalar(r: *Random, comptime T: type) T {
213 return if (T == bool) r.boolean() else r.int(T);
214 }
215
216 /// TODO: deprecated. renamed to ::intRangeLessThan
217 pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
218 return r.intRangeLessThan(T, start, end);
219 }
220
221 /// Return a floating point value evenly distributed in the range [0, 1).
222 pub fn float(r: *Random, comptime T: type) T {
223 // Generate a uniform value between [1, 2) and scale down to [0, 1).
224 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
225 switch (T) {
226 f32 => {
227 const s = r.int(u32);
228 const repr = (0x7f << 23) | (s >> 9);
229 return @bitCast(f32, repr) - 1.0;
230 },
231 f64 => {
232 const s = r.int(u64);
233 const repr = (0x3ff << 52) | (s >> 12);
234 return @bitCast(f64, repr) - 1.0;
235 },
236 else => @compileError("unknown floating point type"),
237 }
238 }
239
240 /// Return a floating point value normally distributed with mean = 0, stddev = 1.
241 ///
242 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
243 pub fn floatNorm(r: *Random, comptime T: type) T {
244 const value = ziggurat.next_f64(r, ziggurat.NormDist);
245 switch (T) {
246 f32 => return @floatCast(f32, value),
247 f64 => return value,
248 else => @compileError("unknown floating point type"),
249 }
250 }
251
252 /// Return an exponentially distributed float with a rate parameter of 1.
253 ///
254 /// To use a different rate parameter, use: floatExp(...) / desiredRate.
255 pub fn floatExp(r: *Random, comptime T: type) T {
256 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
257 switch (T) {
258 f32 => return @floatCast(f32, value),
259 f64 => return value,
260 else => @compileError("unknown floating point type"),
261 }
262 }
263
264 /// Shuffle a slice into a random order.
265 pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {
266 if (buf.len < 2) {
267 return;
268 }
269
270 var i: usize = 0;
271 while (i < buf.len - 1) : (i += 1) {
272 const j = r.intRangeLessThan(usize, i, buf.len);
273 mem.swap(T, &buf[i], &buf[j]);
274 }
275 }
276};
277
278/// Convert a random integer 0 <= random_int <= maxValue(T),
279/// into an integer 0 <= result < less_than.
280/// This function introduces a minor bias.
281pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
282 comptime assert(T.is_signed == false);
283 const T2 = @IntType(false, T.bit_count * 2);
284
285 // adapted from:
286 // http://www.pcg-random.org/posts/bounded-rands.html
287 // "Integer Multiplication (Biased)"
288 var m: T2 = T2(random_int) * T2(less_than);
289 return @intCast(T, m >> T.bit_count);
290}
291
292const SequentialPrng = struct {
293 const Self = @This();
294 random: Random,
295 next_value: u8,
296
297 pub fn init() Self {
298 return Self{
299 .random = Random{ .fillFn = fill },
300 .next_value = 0,
301 };
302 }
303
304 fn fill(r: *Random, buf: []u8) void {
305 const self = @fieldParentPtr(Self, "random", r);
306 for (buf) |*b| {
307 b.* = self.next_value;
308 }
309 self.next_value +%= 1;
310 }
311};
312
313test "Random int" {
314 testRandomInt();
315 comptime testRandomInt();
316}
317fn testRandomInt() void {
318 var r = SequentialPrng.init();
319
320 expect(r.random.int(u0) == 0);
321
322 r.next_value = 0;
323 expect(r.random.int(u1) == 0);
324 expect(r.random.int(u1) == 1);
325 expect(r.random.int(u2) == 2);
326 expect(r.random.int(u2) == 3);
327 expect(r.random.int(u2) == 0);
328
329 r.next_value = 0xff;
330 expect(r.random.int(u8) == 0xff);
331 r.next_value = 0x11;
332 expect(r.random.int(u8) == 0x11);
333
334 r.next_value = 0xff;
335 expect(r.random.int(u32) == 0xffffffff);
336 r.next_value = 0x11;
337 expect(r.random.int(u32) == 0x11111111);
338
339 r.next_value = 0xff;
340 expect(r.random.int(i32) == -1);
341 r.next_value = 0x11;
342 expect(r.random.int(i32) == 0x11111111);
343
344 r.next_value = 0xff;
345 expect(r.random.int(i8) == -1);
346 r.next_value = 0x11;
347 expect(r.random.int(i8) == 0x11);
348
349 r.next_value = 0xff;
350 expect(r.random.int(u33) == 0x1ffffffff);
351 r.next_value = 0xff;
352 expect(r.random.int(i1) == -1);
353 r.next_value = 0xff;
354 expect(r.random.int(i2) == -1);
355 r.next_value = 0xff;
356 expect(r.random.int(i33) == -1);
357}
358
359test "Random boolean" {
360 testRandomBoolean();
361 comptime testRandomBoolean();
362}
363fn testRandomBoolean() void {
364 var r = SequentialPrng.init();
365 expect(r.random.boolean() == false);
366 expect(r.random.boolean() == true);
367 expect(r.random.boolean() == false);
368 expect(r.random.boolean() == true);
369}
370
371test "Random intLessThan" {
372 @setEvalBranchQuota(10000);
373 testRandomIntLessThan();
374 comptime testRandomIntLessThan();
375}
376fn testRandomIntLessThan() void {
377 var r = SequentialPrng.init();
378 r.next_value = 0xff;
379 expect(r.random.uintLessThan(u8, 4) == 3);
380 expect(r.next_value == 0);
381 expect(r.random.uintLessThan(u8, 4) == 0);
382 expect(r.next_value == 1);
383
384 r.next_value = 0;
385 expect(r.random.uintLessThan(u64, 32) == 0);
386
387 // trigger the bias rejection code path
388 r.next_value = 0;
389 expect(r.random.uintLessThan(u8, 3) == 0);
390 // verify we incremented twice
391 expect(r.next_value == 2);
392
393 r.next_value = 0xff;
394 expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
395 r.next_value = 0xff;
396 expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
397
398 r.next_value = 0xff;
399 expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
400 r.next_value = 0xff;
401 expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
402 r.next_value = 0xff;
403 expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
404
405 r.next_value = 0xff;
406 expect(r.random.intRangeLessThan(i3, -4, 0) == -1);
407 r.next_value = 0xff;
408 expect(r.random.intRangeLessThan(i3, -2, 2) == 1);
409}
410
411test "Random intAtMost" {
412 @setEvalBranchQuota(10000);
413 testRandomIntAtMost();
414 comptime testRandomIntAtMost();
415}
416fn testRandomIntAtMost() void {
417 var r = SequentialPrng.init();
418 r.next_value = 0xff;
419 expect(r.random.uintAtMost(u8, 3) == 3);
420 expect(r.next_value == 0);
421 expect(r.random.uintAtMost(u8, 3) == 0);
422
423 // trigger the bias rejection code path
424 r.next_value = 0;
425 expect(r.random.uintAtMost(u8, 2) == 0);
426 // verify we incremented twice
427 expect(r.next_value == 2);
428
429 r.next_value = 0xff;
430 expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
431 r.next_value = 0xff;
432 expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
433
434 r.next_value = 0xff;
435 expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
436 r.next_value = 0xff;
437 expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
438 r.next_value = 0xff;
439 expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
440
441 r.next_value = 0xff;
442 expect(r.random.intRangeAtMost(i3, -4, -1) == -1);
443 r.next_value = 0xff;
444 expect(r.random.intRangeAtMost(i3, -2, 1) == 1);
445
446 expect(r.random.uintAtMost(u0, 0) == 0);
447}
448
449test "Random Biased" {
450 var r = DefaultPrng.init(0);
451 // Not thoroughly checking the logic here.
452 // Just want to execute all the paths with different types.
453
454 expect(r.random.uintLessThanBiased(u1, 1) == 0);
455 expect(r.random.uintLessThanBiased(u32, 10) < 10);
456 expect(r.random.uintLessThanBiased(u64, 20) < 20);
457
458 expect(r.random.uintAtMostBiased(u0, 0) == 0);
459 expect(r.random.uintAtMostBiased(u1, 0) <= 0);
460 expect(r.random.uintAtMostBiased(u32, 10) <= 10);
461 expect(r.random.uintAtMostBiased(u64, 20) <= 20);
462
463 expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
464 expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
465 expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
466 expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
467 expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
468 expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
469
470 // uncomment for broken module error:
471 //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
472 expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
473 expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
474 expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
475 expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
476 expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
477 expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
478}
479
480// Generator to extend 64-bit seed values into longer sequences.
481//
482// The number of cycles is thus limited to 64-bits regardless of the engine, but this
483// is still plenty for practical purposes.
484const SplitMix64 = struct {
485 s: u64,
486
487 pub fn init(seed: u64) SplitMix64 {
488 return SplitMix64{ .s = seed };
489 }
490
491 pub fn next(self: *SplitMix64) u64 {
492 self.s +%= 0x9e3779b97f4a7c15;
493
494 var z = self.s;
495 z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
496 z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
497 return z ^ (z >> 31);
498 }
499};
500
501test "splitmix64 sequence" {
502 var r = SplitMix64.init(0xaeecf86f7878dd75);
503
504 const seq = []const u64{
505 0x5dbd39db0178eb44,
506 0xa9900fb66b397da3,
507 0x5c1a28b1aeebcf5c,
508 0x64a963238f776912,
509 0xc6d4177b21d1c0ab,
510 0xb2cbdbdb5ea35394,
511 };
512
513 for (seq) |s| {
514 expect(s == r.next());
515 }
516}
517
518// PCG32 - http://www.pcg-random.org/
519//
520// PRNG
521pub const Pcg = struct {
522 const default_multiplier = 6364136223846793005;
523
524 random: Random,
525
526 s: u64,
527 i: u64,
528
529 pub fn init(init_s: u64) Pcg {
530 var pcg = Pcg{
531 .random = Random{ .fillFn = fill },
532 .s = undefined,
533 .i = undefined,
534 };
535
536 pcg.seed(init_s);
537 return pcg;
538 }
539
540 fn next(self: *Pcg) u32 {
541 const l = self.s;
542 self.s = l *% default_multiplier +% (self.i | 1);
543
544 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
545 const rot = @intCast(u32, l >> 59);
546
547 return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
548 }
549
550 fn seed(self: *Pcg, init_s: u64) void {
551 // Pcg requires 128-bits of seed.
552 var gen = SplitMix64.init(init_s);
553 self.seedTwo(gen.next(), gen.next());
554 }
555
556 fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
557 self.s = 0;
558 self.i = (init_s << 1) | 1;
559 self.s = self.s *% default_multiplier +% self.i;
560 self.s +%= init_i;
561 self.s = self.s *% default_multiplier +% self.i;
562 }
563
564 fn fill(r: *Random, buf: []u8) void {
565 const self = @fieldParentPtr(Pcg, "random", r);
566
567 var i: usize = 0;
568 const aligned_len = buf.len - (buf.len & 7);
569
570 // Complete 4 byte segments.
571 while (i < aligned_len) : (i += 4) {
572 var n = self.next();
573 comptime var j: usize = 0;
574 inline while (j < 4) : (j += 1) {
575 buf[i + j] = @truncate(u8, n);
576 n >>= 8;
577 }
578 }
579
580 // Remaining. (cuts the stream)
581 if (i != buf.len) {
582 var n = self.next();
583 while (i < buf.len) : (i += 1) {
584 buf[i] = @truncate(u8, n);
585 n >>= 4;
586 }
587 }
588 }
589};
590
591test "pcg sequence" {
592 var r = Pcg.init(0);
593 const s0: u64 = 0x9394bf54ce5d79de;
594 const s1: u64 = 0x84e9c579ef59bbf7;
595 r.seedTwo(s0, s1);
596
597 const seq = []const u32{
598 2881561918,
599 3063928540,
600 1199791034,
601 2487695858,
602 1479648952,
603 3247963454,
604 };
605
606 for (seq) |s| {
607 expect(s == r.next());
608 }
609}
610
611// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
612//
613// PRNG
614pub const Xoroshiro128 = struct {
615 random: Random,
616
617 s: [2]u64,
618
619 pub fn init(init_s: u64) Xoroshiro128 {
620 var x = Xoroshiro128{
621 .random = Random{ .fillFn = fill },
622 .s = undefined,
623 };
624
625 x.seed(init_s);
626 return x;
627 }
628
629 fn next(self: *Xoroshiro128) u64 {
630 const s0 = self.s[0];
631 var s1 = self.s[1];
632 const r = s0 +% s1;
633
634 s1 ^= s0;
635 self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
636 self.s[1] = math.rotl(u64, s1, u8(36));
637
638 return r;
639 }
640
641 // Skip 2^64 places ahead in the sequence
642 fn jump(self: *Xoroshiro128) void {
643 var s0: u64 = 0;
644 var s1: u64 = 0;
645
646 const table = []const u64{
647 0xbeac0467eba5facb,
648 0xd86b048b86aa9922,
649 };
650
651 inline for (table) |entry| {
652 var b: usize = 0;
653 while (b < 64) : (b += 1) {
654 if ((entry & (u64(1) << @intCast(u6, b))) != 0) {
655 s0 ^= self.s[0];
656 s1 ^= self.s[1];
657 }
658 _ = self.next();
659 }
660 }
661
662 self.s[0] = s0;
663 self.s[1] = s1;
664 }
665
666 fn seed(self: *Xoroshiro128, init_s: u64) void {
667 // Xoroshiro requires 128-bits of seed.
668 var gen = SplitMix64.init(init_s);
669
670 self.s[0] = gen.next();
671 self.s[1] = gen.next();
672 }
673
674 fn fill(r: *Random, buf: []u8) void {
675 const self = @fieldParentPtr(Xoroshiro128, "random", r);
676
677 var i: usize = 0;
678 const aligned_len = buf.len - (buf.len & 7);
679
680 // Complete 8 byte segments.
681 while (i < aligned_len) : (i += 8) {
682 var n = self.next();
683 comptime var j: usize = 0;
684 inline while (j < 8) : (j += 1) {
685 buf[i + j] = @truncate(u8, n);
686 n >>= 8;
687 }
688 }
689
690 // Remaining. (cuts the stream)
691 if (i != buf.len) {
692 var n = self.next();
693 while (i < buf.len) : (i += 1) {
694 buf[i] = @truncate(u8, n);
695 n >>= 8;
696 }
697 }
698 }
699};
700
701test "xoroshiro sequence" {
702 var r = Xoroshiro128.init(0);
703 r.s[0] = 0xaeecf86f7878dd75;
704 r.s[1] = 0x01cd153642e72622;
705
706 const seq1 = []const u64{
707 0xb0ba0da5bb600397,
708 0x18a08afde614dccc,
709 0xa2635b956a31b929,
710 0xabe633c971efa045,
711 0x9ac19f9706ca3cac,
712 0xf62b426578c1e3fb,
713 };
714
715 for (seq1) |s| {
716 expect(s == r.next());
717 }
718
719 r.jump();
720
721 const seq2 = []const u64{
722 0x95344a13556d3e22,
723 0xb4fb32dafa4d00df,
724 0xb2011d9ccdcfe2dd,
725 0x05679a9b2119b908,
726 0xa860a1da7c9cd8a0,
727 0x658a96efe3f86550,
728 };
729
730 for (seq2) |s| {
731 expect(s == r.next());
732 }
733}
734
735// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
736//
737// CSPRNG
738//
739// Follows the general idea of the implementation from here with a few shortcuts.
740// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
741pub const Isaac64 = struct {
742 random: Random,
743
744 r: [256]u64,
745 m: [256]u64,
746 a: u64,
747 b: u64,
748 c: u64,
749 i: usize,
750
751 pub fn init(init_s: u64) Isaac64 {
752 var isaac = Isaac64{
753 .random = Random{ .fillFn = fill },
754 .r = undefined,
755 .m = undefined,
756 .a = undefined,
757 .b = undefined,
758 .c = undefined,
759 .i = undefined,
760 };
761
762 // seed == 0 => same result as the unseeded reference implementation
763 isaac.seed(init_s, 1);
764 return isaac;
765 }
766
767 fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
768 const x = self.m[base + m1];
769 self.a = mix +% self.m[base + m2];
770
771 const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
772 self.m[base + m1] = y;
773
774 self.b = x +% self.m[(y >> 11) % self.m.len];
775 self.r[self.r.len - 1 - base - m1] = self.b;
776 }
777
778 fn refill(self: *Isaac64) void {
779 const midpoint = self.r.len / 2;
780
781 self.c +%= 1;
782 self.b +%= self.c;
783
784 {
785 var i: usize = 0;
786 while (i < midpoint) : (i += 4) {
787 self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
788 self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
789 self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
790 self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
791 }
792 }
793
794 {
795 var i: usize = 0;
796 while (i < midpoint) : (i += 4) {
797 self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
798 self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
799 self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
800 self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
801 }
802 }
803
804 self.i = 0;
805 }
806
807 fn next(self: *Isaac64) u64 {
808 if (self.i >= self.r.len) {
809 self.refill();
810 }
811
812 const value = self.r[self.i];
813 self.i += 1;
814 return value;
815 }
816
817 fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
818 // We ignore the multi-pass requirement since we don't currently expose full access to
819 // seeding the self.m array completely.
820 mem.set(u64, self.m[0..], 0);
821 self.m[0] = init_s;
822
823 // prescrambled golden ratio constants
824 var a = []const u64{
825 0x647c4677a2884b7c,
826 0xb9f8b322c73ac862,
827 0x8c0ea5053d4712a0,
828 0xb29b2e824a595524,
829 0x82f053db8355e0ce,
830 0x48fe4a0fa5a09315,
831 0xae985bf2cbfc89ed,
832 0x98f5704f6c44c0ab,
833 };
834
835 comptime var i: usize = 0;
836 inline while (i < rounds) : (i += 1) {
837 var j: usize = 0;
838 while (j < self.m.len) : (j += 8) {
839 comptime var x1: usize = 0;
840 inline while (x1 < 8) : (x1 += 1) {
841 a[x1] +%= self.m[j + x1];
842 }
843
844 a[0] -%= a[4];
845 a[5] ^= a[7] >> 9;
846 a[7] +%= a[0];
847 a[1] -%= a[5];
848 a[6] ^= a[0] << 9;
849 a[0] +%= a[1];
850 a[2] -%= a[6];
851 a[7] ^= a[1] >> 23;
852 a[1] +%= a[2];
853 a[3] -%= a[7];
854 a[0] ^= a[2] << 15;
855 a[2] +%= a[3];
856 a[4] -%= a[0];
857 a[1] ^= a[3] >> 14;
858 a[3] +%= a[4];
859 a[5] -%= a[1];
860 a[2] ^= a[4] << 20;
861 a[4] +%= a[5];
862 a[6] -%= a[2];
863 a[3] ^= a[5] >> 17;
864 a[5] +%= a[6];
865 a[7] -%= a[3];
866 a[4] ^= a[6] << 14;
867 a[6] +%= a[7];
868
869 comptime var x2: usize = 0;
870 inline while (x2 < 8) : (x2 += 1) {
871 self.m[j + x2] = a[x2];
872 }
873 }
874 }
875
876 mem.set(u64, self.r[0..], 0);
877 self.a = 0;
878 self.b = 0;
879 self.c = 0;
880 self.i = self.r.len; // trigger refill on first value
881 }
882
883 fn fill(r: *Random, buf: []u8) void {
884 const self = @fieldParentPtr(Isaac64, "random", r);
885
886 var i: usize = 0;
887 const aligned_len = buf.len - (buf.len & 7);
888
889 // Fill complete 64-byte segments
890 while (i < aligned_len) : (i += 8) {
891 var n = self.next();
892 comptime var j: usize = 0;
893 inline while (j < 8) : (j += 1) {
894 buf[i + j] = @truncate(u8, n);
895 n >>= 8;
896 }
897 }
898
899 // Fill trailing, ignoring excess (cut the stream).
900 if (i != buf.len) {
901 var n = self.next();
902 while (i < buf.len) : (i += 1) {
903 buf[i] = @truncate(u8, n);
904 n >>= 8;
905 }
906 }
907 }
908};
909
910test "isaac64 sequence" {
911 var r = Isaac64.init(0);
912
913 // from reference implementation
914 const seq = []const u64{
915 0xf67dfba498e4937c,
916 0x84a5066a9204f380,
917 0xfee34bd5f5514dbb,
918 0x4d1664739b8f80d6,
919 0x8607459ab52a14aa,
920 0x0e78bc5a98529e49,
921 0xfe5332822ad13777,
922 0x556c27525e33d01a,
923 0x08643ca615f3149f,
924 0xd0771faf3cb04714,
925 0x30e86f68a37b008d,
926 0x3074ebc0488a3adf,
927 0x270645ea7a2790bc,
928 0x5601a0a8d3763c6a,
929 0x2f83071f53f325dd,
930 0xb9090f3d42d2d2ea,
931 };
932
933 for (seq) |s| {
934 expect(s == r.next());
935 }
936}
937
938// Actual Random helper function tests, pcg engine is assumed correct.
939test "Random float" {
940 var prng = DefaultPrng.init(0);
941
942 var i: usize = 0;
943 while (i < 1000) : (i += 1) {
944 const val1 = prng.random.float(f32);
945 expect(val1 >= 0.0);
946 expect(val1 < 1.0);
947
948 const val2 = prng.random.float(f64);
949 expect(val2 >= 0.0);
950 expect(val2 < 1.0);
951 }
952}
953
954test "Random shuffle" {
955 var prng = DefaultPrng.init(0);
956
957 var seq = []const u8{ 0, 1, 2, 3, 4 };
958 var seen = []bool{false} ** 5;
959
960 var i: usize = 0;
961 while (i < 1000) : (i += 1) {
962 prng.random.shuffle(u8, seq[0..]);
963 seen[seq[0]] = true;
964 expect(sumArray(seq[0..]) == 10);
965 }
966
967 // we should see every entry at the head at least once
968 for (seen) |e| {
969 expect(e == true);
970 }
971}
972
973fn sumArray(s: []const u8) u32 {
974 var r: u32 = 0;
975 for (s) |e|
976 r += e;
977 return r;
978}
979
980test "Random range" {
981 var prng = DefaultPrng.init(0);
982 testRange(&prng.random, -4, 3);
983 testRange(&prng.random, -4, -1);
984 testRange(&prng.random, 10, 14);
985 testRange(&prng.random, -0x80, 0x7f);
986}
987
988fn testRange(r: *Random, start: i8, end: i8) void {
989 testRangeBias(r, start, end, true);
990 testRangeBias(r, start, end, false);
991}
992fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
993 const count = @intCast(usize, i32(end) - i32(start));
994 var values_buffer = []bool{false} ** 0x100;
995 const values = values_buffer[0..count];
996 var i: usize = 0;
997 while (i < count) {
998 const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end);
999 const index = @intCast(usize, value - start);
1000 if (!values[index]) {
1001 i += 1;
1002 values[index] = true;
1003 }
1004 }
1005}
std/rand/index.zig deleted-1005
...@@ -1,1005 +0,0 @@
1// The engines provided here should be initialized from an external source. For now, getRandomBytes
2// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.
4//
5// ```
6// var buf: [8]u8 = undefined;
7// try std.os.getRandomBytes(buf[0..]);
8// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
9//
10// var r = DefaultPrng.init(seed);
11//
12// const s = r.random.int(u64);
13// ```
14//
15// TODO(tiehuis): Benchmark these against other reference implementations.
16
17const std = @import("../index.zig");
18const builtin = @import("builtin");
19const assert = std.debug.assert;
20const expect = std.testing.expect;
21const mem = std.mem;
22const math = std.math;
23const ziggurat = @import("ziggurat.zig");
24const maxInt = std.math.maxInt;
25
26// When you need fast unbiased random numbers
27pub const DefaultPrng = Xoroshiro128;
28
29// When you need cryptographically secure random numbers
30pub const DefaultCsprng = Isaac64;
31
32pub const Random = struct {
33 fillFn: fn (r: *Random, buf: []u8) void,
34
35 /// Read random bytes into the specified buffer until full.
36 pub fn bytes(r: *Random, buf: []u8) void {
37 r.fillFn(r, buf);
38 }
39
40 pub fn boolean(r: *Random) bool {
41 return r.int(u1) != 0;
42 }
43
44 /// Returns a random int `i` such that `0 <= i <= maxInt(T)`.
45 /// `i` is evenly distributed.
46 pub fn int(r: *Random, comptime T: type) T {
47 const UnsignedT = @IntType(false, T.bit_count);
48 const ByteAlignedT = @IntType(false, @divTrunc(T.bit_count + 7, 8) * 8);
49
50 var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined;
51 r.bytes(rand_bytes[0..]);
52
53 // use LE instead of native endian for better portability maybe?
54 // TODO: endian portability is pointless if the underlying prng isn't endian portable.
55 // TODO: document the endian portability of this library.
56 const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes);
57 const unsigned_result = @truncate(UnsignedT, byte_aligned_result);
58 return @bitCast(T, unsigned_result);
59 }
60
61 /// Constant-time implementation off ::uintLessThan.
62 /// The results of this function may be biased.
63 pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
64 comptime assert(T.is_signed == false);
65 comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
66 assert(0 < less_than);
67 if (T.bit_count <= 32) {
68 return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than));
69 } else {
70 return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
71 }
72 }
73
74 /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
75 /// This function assumes that the underlying ::fillFn produces evenly distributed values.
76 /// Within this assumption, the runtime of this function is exponentially distributed.
77 /// If ::fillFn were backed by a true random generator,
78 /// the runtime of this function would technically be unbounded.
79 /// However, if ::fillFn is backed by any evenly distributed pseudo random number generator,
80 /// this function is guaranteed to return.
81 /// If you need deterministic runtime bounds, use `::uintLessThanBiased`.
82 pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
83 comptime assert(T.is_signed == false);
84 comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
85 assert(0 < less_than);
86 // Small is typically u32
87 const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32);
88 // Large is typically u64
89 const Large = @IntType(false, Small.bit_count * 2);
90
91 // adapted from:
92 // http://www.pcg-random.org/posts/bounded-rands.html
93 // "Lemire's (with an extra tweak from me)"
94 var x: Small = r.int(Small);
95 var m: Large = Large(x) * Large(less_than);
96 var l: Small = @truncate(Small, m);
97 if (l < less_than) {
98 // TODO: workaround for https://github.com/ziglang/zig/issues/1770
99 // should be:
100 // var t: Small = -%less_than;
101 var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than)));
102
103 if (t >= less_than) {
104 t -= less_than;
105 if (t >= less_than) {
106 t %= less_than;
107 }
108 }
109 while (l < t) {
110 x = r.int(Small);
111 m = Large(x) * Large(less_than);
112 l = @truncate(Small, m);
113 }
114 }
115 return @intCast(T, m >> Small.bit_count);
116 }
117
118 /// Constant-time implementation off ::uintAtMost.
119 /// The results of this function may be biased.
120 pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
121 assert(T.is_signed == false);
122 if (at_most == maxInt(T)) {
123 // have the full range
124 return r.int(T);
125 }
126 return r.uintLessThanBiased(T, at_most + 1);
127 }
128
129 /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
130 /// See ::uintLessThan, which this function uses in most cases,
131 /// for commentary on the runtime of this function.
132 pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T {
133 assert(T.is_signed == false);
134 if (at_most == maxInt(T)) {
135 // have the full range
136 return r.int(T);
137 }
138 return r.uintLessThan(T, at_most + 1);
139 }
140
141 /// Constant-time implementation off ::intRangeLessThan.
142 /// The results of this function may be biased.
143 pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
144 assert(at_least < less_than);
145 if (T.is_signed) {
146 // Two's complement makes this math pretty easy.
147 const UnsignedT = @IntType(false, T.bit_count);
148 const lo = @bitCast(UnsignedT, at_least);
149 const hi = @bitCast(UnsignedT, less_than);
150 const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo);
151 return @bitCast(T, result);
152 } else {
153 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
154 return at_least + r.uintLessThanBiased(T, less_than - at_least);
155 }
156 }
157
158 /// Returns an evenly distributed random integer `at_least <= i < less_than`.
159 /// See ::uintLessThan, which this function uses in most cases,
160 /// for commentary on the runtime of this function.
161 pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T {
162 assert(at_least < less_than);
163 if (T.is_signed) {
164 // Two's complement makes this math pretty easy.
165 const UnsignedT = @IntType(false, T.bit_count);
166 const lo = @bitCast(UnsignedT, at_least);
167 const hi = @bitCast(UnsignedT, less_than);
168 const result = lo +% r.uintLessThan(UnsignedT, hi -% lo);
169 return @bitCast(T, result);
170 } else {
171 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
172 return at_least + r.uintLessThan(T, less_than - at_least);
173 }
174 }
175
176 /// Constant-time implementation off ::intRangeAtMostBiased.
177 /// The results of this function may be biased.
178 pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
179 assert(at_least <= at_most);
180 if (T.is_signed) {
181 // Two's complement makes this math pretty easy.
182 const UnsignedT = @IntType(false, T.bit_count);
183 const lo = @bitCast(UnsignedT, at_least);
184 const hi = @bitCast(UnsignedT, at_most);
185 const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo);
186 return @bitCast(T, result);
187 } else {
188 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
189 return at_least + r.uintAtMostBiased(T, at_most - at_least);
190 }
191 }
192
193 /// Returns an evenly distributed random integer `at_least <= i <= at_most`.
194 /// See ::uintLessThan, which this function uses in most cases,
195 /// for commentary on the runtime of this function.
196 pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T {
197 assert(at_least <= at_most);
198 if (T.is_signed) {
199 // Two's complement makes this math pretty easy.
200 const UnsignedT = @IntType(false, T.bit_count);
201 const lo = @bitCast(UnsignedT, at_least);
202 const hi = @bitCast(UnsignedT, at_most);
203 const result = lo +% r.uintAtMost(UnsignedT, hi -% lo);
204 return @bitCast(T, result);
205 } else {
206 // The signed implementation would work fine, but we can use stricter arithmetic operators here.
207 return at_least + r.uintAtMost(T, at_most - at_least);
208 }
209 }
210
211 /// TODO: deprecated. use ::boolean or ::int instead.
212 pub fn scalar(r: *Random, comptime T: type) T {
213 return if (T == bool) r.boolean() else r.int(T);
214 }
215
216 /// TODO: deprecated. renamed to ::intRangeLessThan
217 pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
218 return r.intRangeLessThan(T, start, end);
219 }
220
221 /// Return a floating point value evenly distributed in the range [0, 1).
222 pub fn float(r: *Random, comptime T: type) T {
223 // Generate a uniform value between [1, 2) and scale down to [0, 1).
224 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
225 switch (T) {
226 f32 => {
227 const s = r.int(u32);
228 const repr = (0x7f << 23) | (s >> 9);
229 return @bitCast(f32, repr) - 1.0;
230 },
231 f64 => {
232 const s = r.int(u64);
233 const repr = (0x3ff << 52) | (s >> 12);
234 return @bitCast(f64, repr) - 1.0;
235 },
236 else => @compileError("unknown floating point type"),
237 }
238 }
239
240 /// Return a floating point value normally distributed with mean = 0, stddev = 1.
241 ///
242 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
243 pub fn floatNorm(r: *Random, comptime T: type) T {
244 const value = ziggurat.next_f64(r, ziggurat.NormDist);
245 switch (T) {
246 f32 => return @floatCast(f32, value),
247 f64 => return value,
248 else => @compileError("unknown floating point type"),
249 }
250 }
251
252 /// Return an exponentially distributed float with a rate parameter of 1.
253 ///
254 /// To use a different rate parameter, use: floatExp(...) / desiredRate.
255 pub fn floatExp(r: *Random, comptime T: type) T {
256 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
257 switch (T) {
258 f32 => return @floatCast(f32, value),
259 f64 => return value,
260 else => @compileError("unknown floating point type"),
261 }
262 }
263
264 /// Shuffle a slice into a random order.
265 pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {
266 if (buf.len < 2) {
267 return;
268 }
269
270 var i: usize = 0;
271 while (i < buf.len - 1) : (i += 1) {
272 const j = r.intRangeLessThan(usize, i, buf.len);
273 mem.swap(T, &buf[i], &buf[j]);
274 }
275 }
276};
277
278/// Convert a random integer 0 <= random_int <= maxValue(T),
279/// into an integer 0 <= result < less_than.
280/// This function introduces a minor bias.
281pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
282 comptime assert(T.is_signed == false);
283 const T2 = @IntType(false, T.bit_count * 2);
284
285 // adapted from:
286 // http://www.pcg-random.org/posts/bounded-rands.html
287 // "Integer Multiplication (Biased)"
288 var m: T2 = T2(random_int) * T2(less_than);
289 return @intCast(T, m >> T.bit_count);
290}
291
292const SequentialPrng = struct {
293 const Self = @This();
294 random: Random,
295 next_value: u8,
296
297 pub fn init() Self {
298 return Self{
299 .random = Random{ .fillFn = fill },
300 .next_value = 0,
301 };
302 }
303
304 fn fill(r: *Random, buf: []u8) void {
305 const self = @fieldParentPtr(Self, "random", r);
306 for (buf) |*b| {
307 b.* = self.next_value;
308 }
309 self.next_value +%= 1;
310 }
311};
312
313test "Random int" {
314 testRandomInt();
315 comptime testRandomInt();
316}
317fn testRandomInt() void {
318 var r = SequentialPrng.init();
319
320 expect(r.random.int(u0) == 0);
321
322 r.next_value = 0;
323 expect(r.random.int(u1) == 0);
324 expect(r.random.int(u1) == 1);
325 expect(r.random.int(u2) == 2);
326 expect(r.random.int(u2) == 3);
327 expect(r.random.int(u2) == 0);
328
329 r.next_value = 0xff;
330 expect(r.random.int(u8) == 0xff);
331 r.next_value = 0x11;
332 expect(r.random.int(u8) == 0x11);
333
334 r.next_value = 0xff;
335 expect(r.random.int(u32) == 0xffffffff);
336 r.next_value = 0x11;
337 expect(r.random.int(u32) == 0x11111111);
338
339 r.next_value = 0xff;
340 expect(r.random.int(i32) == -1);
341 r.next_value = 0x11;
342 expect(r.random.int(i32) == 0x11111111);
343
344 r.next_value = 0xff;
345 expect(r.random.int(i8) == -1);
346 r.next_value = 0x11;
347 expect(r.random.int(i8) == 0x11);
348
349 r.next_value = 0xff;
350 expect(r.random.int(u33) == 0x1ffffffff);
351 r.next_value = 0xff;
352 expect(r.random.int(i1) == -1);
353 r.next_value = 0xff;
354 expect(r.random.int(i2) == -1);
355 r.next_value = 0xff;
356 expect(r.random.int(i33) == -1);
357}
358
359test "Random boolean" {
360 testRandomBoolean();
361 comptime testRandomBoolean();
362}
363fn testRandomBoolean() void {
364 var r = SequentialPrng.init();
365 expect(r.random.boolean() == false);
366 expect(r.random.boolean() == true);
367 expect(r.random.boolean() == false);
368 expect(r.random.boolean() == true);
369}
370
371test "Random intLessThan" {
372 @setEvalBranchQuota(10000);
373 testRandomIntLessThan();
374 comptime testRandomIntLessThan();
375}
376fn testRandomIntLessThan() void {
377 var r = SequentialPrng.init();
378 r.next_value = 0xff;
379 expect(r.random.uintLessThan(u8, 4) == 3);
380 expect(r.next_value == 0);
381 expect(r.random.uintLessThan(u8, 4) == 0);
382 expect(r.next_value == 1);
383
384 r.next_value = 0;
385 expect(r.random.uintLessThan(u64, 32) == 0);
386
387 // trigger the bias rejection code path
388 r.next_value = 0;
389 expect(r.random.uintLessThan(u8, 3) == 0);
390 // verify we incremented twice
391 expect(r.next_value == 2);
392
393 r.next_value = 0xff;
394 expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
395 r.next_value = 0xff;
396 expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
397
398 r.next_value = 0xff;
399 expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
400 r.next_value = 0xff;
401 expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
402 r.next_value = 0xff;
403 expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
404
405 r.next_value = 0xff;
406 expect(r.random.intRangeLessThan(i3, -4, 0) == -1);
407 r.next_value = 0xff;
408 expect(r.random.intRangeLessThan(i3, -2, 2) == 1);
409}
410
411test "Random intAtMost" {
412 @setEvalBranchQuota(10000);
413 testRandomIntAtMost();
414 comptime testRandomIntAtMost();
415}
416fn testRandomIntAtMost() void {
417 var r = SequentialPrng.init();
418 r.next_value = 0xff;
419 expect(r.random.uintAtMost(u8, 3) == 3);
420 expect(r.next_value == 0);
421 expect(r.random.uintAtMost(u8, 3) == 0);
422
423 // trigger the bias rejection code path
424 r.next_value = 0;
425 expect(r.random.uintAtMost(u8, 2) == 0);
426 // verify we incremented twice
427 expect(r.next_value == 2);
428
429 r.next_value = 0xff;
430 expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
431 r.next_value = 0xff;
432 expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
433
434 r.next_value = 0xff;
435 expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
436 r.next_value = 0xff;
437 expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
438 r.next_value = 0xff;
439 expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
440
441 r.next_value = 0xff;
442 expect(r.random.intRangeAtMost(i3, -4, -1) == -1);
443 r.next_value = 0xff;
444 expect(r.random.intRangeAtMost(i3, -2, 1) == 1);
445
446 expect(r.random.uintAtMost(u0, 0) == 0);
447}
448
449test "Random Biased" {
450 var r = DefaultPrng.init(0);
451 // Not thoroughly checking the logic here.
452 // Just want to execute all the paths with different types.
453
454 expect(r.random.uintLessThanBiased(u1, 1) == 0);
455 expect(r.random.uintLessThanBiased(u32, 10) < 10);
456 expect(r.random.uintLessThanBiased(u64, 20) < 20);
457
458 expect(r.random.uintAtMostBiased(u0, 0) == 0);
459 expect(r.random.uintAtMostBiased(u1, 0) <= 0);
460 expect(r.random.uintAtMostBiased(u32, 10) <= 10);
461 expect(r.random.uintAtMostBiased(u64, 20) <= 20);
462
463 expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
464 expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
465 expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
466 expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
467 expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
468 expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
469
470 // uncomment for broken module error:
471 //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
472 expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
473 expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
474 expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
475 expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
476 expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
477 expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
478}
479
480// Generator to extend 64-bit seed values into longer sequences.
481//
482// The number of cycles is thus limited to 64-bits regardless of the engine, but this
483// is still plenty for practical purposes.
484const SplitMix64 = struct {
485 s: u64,
486
487 pub fn init(seed: u64) SplitMix64 {
488 return SplitMix64{ .s = seed };
489 }
490
491 pub fn next(self: *SplitMix64) u64 {
492 self.s +%= 0x9e3779b97f4a7c15;
493
494 var z = self.s;
495 z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
496 z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
497 return z ^ (z >> 31);
498 }
499};
500
501test "splitmix64 sequence" {
502 var r = SplitMix64.init(0xaeecf86f7878dd75);
503
504 const seq = []const u64{
505 0x5dbd39db0178eb44,
506 0xa9900fb66b397da3,
507 0x5c1a28b1aeebcf5c,
508 0x64a963238f776912,
509 0xc6d4177b21d1c0ab,
510 0xb2cbdbdb5ea35394,
511 };
512
513 for (seq) |s| {
514 expect(s == r.next());
515 }
516}
517
518// PCG32 - http://www.pcg-random.org/
519//
520// PRNG
521pub const Pcg = struct {
522 const default_multiplier = 6364136223846793005;
523
524 random: Random,
525
526 s: u64,
527 i: u64,
528
529 pub fn init(init_s: u64) Pcg {
530 var pcg = Pcg{
531 .random = Random{ .fillFn = fill },
532 .s = undefined,
533 .i = undefined,
534 };
535
536 pcg.seed(init_s);
537 return pcg;
538 }
539
540 fn next(self: *Pcg) u32 {
541 const l = self.s;
542 self.s = l *% default_multiplier +% (self.i | 1);
543
544 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
545 const rot = @intCast(u32, l >> 59);
546
547 return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
548 }
549
550 fn seed(self: *Pcg, init_s: u64) void {
551 // Pcg requires 128-bits of seed.
552 var gen = SplitMix64.init(init_s);
553 self.seedTwo(gen.next(), gen.next());
554 }
555
556 fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
557 self.s = 0;
558 self.i = (init_s << 1) | 1;
559 self.s = self.s *% default_multiplier +% self.i;
560 self.s +%= init_i;
561 self.s = self.s *% default_multiplier +% self.i;
562 }
563
564 fn fill(r: *Random, buf: []u8) void {
565 const self = @fieldParentPtr(Pcg, "random", r);
566
567 var i: usize = 0;
568 const aligned_len = buf.len - (buf.len & 7);
569
570 // Complete 4 byte segments.
571 while (i < aligned_len) : (i += 4) {
572 var n = self.next();
573 comptime var j: usize = 0;
574 inline while (j < 4) : (j += 1) {
575 buf[i + j] = @truncate(u8, n);
576 n >>= 8;
577 }
578 }
579
580 // Remaining. (cuts the stream)
581 if (i != buf.len) {
582 var n = self.next();
583 while (i < buf.len) : (i += 1) {
584 buf[i] = @truncate(u8, n);
585 n >>= 4;
586 }
587 }
588 }
589};
590
591test "pcg sequence" {
592 var r = Pcg.init(0);
593 const s0: u64 = 0x9394bf54ce5d79de;
594 const s1: u64 = 0x84e9c579ef59bbf7;
595 r.seedTwo(s0, s1);
596
597 const seq = []const u32{
598 2881561918,
599 3063928540,
600 1199791034,
601 2487695858,
602 1479648952,
603 3247963454,
604 };
605
606 for (seq) |s| {
607 expect(s == r.next());
608 }
609}
610
611// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
612//
613// PRNG
614pub const Xoroshiro128 = struct {
615 random: Random,
616
617 s: [2]u64,
618
619 pub fn init(init_s: u64) Xoroshiro128 {
620 var x = Xoroshiro128{
621 .random = Random{ .fillFn = fill },
622 .s = undefined,
623 };
624
625 x.seed(init_s);
626 return x;
627 }
628
629 fn next(self: *Xoroshiro128) u64 {
630 const s0 = self.s[0];
631 var s1 = self.s[1];
632 const r = s0 +% s1;
633
634 s1 ^= s0;
635 self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
636 self.s[1] = math.rotl(u64, s1, u8(36));
637
638 return r;
639 }
640
641 // Skip 2^64 places ahead in the sequence
642 fn jump(self: *Xoroshiro128) void {
643 var s0: u64 = 0;
644 var s1: u64 = 0;
645
646 const table = []const u64{
647 0xbeac0467eba5facb,
648 0xd86b048b86aa9922,
649 };
650
651 inline for (table) |entry| {
652 var b: usize = 0;
653 while (b < 64) : (b += 1) {
654 if ((entry & (u64(1) << @intCast(u6, b))) != 0) {
655 s0 ^= self.s[0];
656 s1 ^= self.s[1];
657 }
658 _ = self.next();
659 }
660 }
661
662 self.s[0] = s0;
663 self.s[1] = s1;
664 }
665
666 fn seed(self: *Xoroshiro128, init_s: u64) void {
667 // Xoroshiro requires 128-bits of seed.
668 var gen = SplitMix64.init(init_s);
669
670 self.s[0] = gen.next();
671 self.s[1] = gen.next();
672 }
673
674 fn fill(r: *Random, buf: []u8) void {
675 const self = @fieldParentPtr(Xoroshiro128, "random", r);
676
677 var i: usize = 0;
678 const aligned_len = buf.len - (buf.len & 7);
679
680 // Complete 8 byte segments.
681 while (i < aligned_len) : (i += 8) {
682 var n = self.next();
683 comptime var j: usize = 0;
684 inline while (j < 8) : (j += 1) {
685 buf[i + j] = @truncate(u8, n);
686 n >>= 8;
687 }
688 }
689
690 // Remaining. (cuts the stream)
691 if (i != buf.len) {
692 var n = self.next();
693 while (i < buf.len) : (i += 1) {
694 buf[i] = @truncate(u8, n);
695 n >>= 8;
696 }
697 }
698 }
699};
700
701test "xoroshiro sequence" {
702 var r = Xoroshiro128.init(0);
703 r.s[0] = 0xaeecf86f7878dd75;
704 r.s[1] = 0x01cd153642e72622;
705
706 const seq1 = []const u64{
707 0xb0ba0da5bb600397,
708 0x18a08afde614dccc,
709 0xa2635b956a31b929,
710 0xabe633c971efa045,
711 0x9ac19f9706ca3cac,
712 0xf62b426578c1e3fb,
713 };
714
715 for (seq1) |s| {
716 expect(s == r.next());
717 }
718
719 r.jump();
720
721 const seq2 = []const u64{
722 0x95344a13556d3e22,
723 0xb4fb32dafa4d00df,
724 0xb2011d9ccdcfe2dd,
725 0x05679a9b2119b908,
726 0xa860a1da7c9cd8a0,
727 0x658a96efe3f86550,
728 };
729
730 for (seq2) |s| {
731 expect(s == r.next());
732 }
733}
734
735// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
736//
737// CSPRNG
738//
739// Follows the general idea of the implementation from here with a few shortcuts.
740// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
741pub const Isaac64 = struct {
742 random: Random,
743
744 r: [256]u64,
745 m: [256]u64,
746 a: u64,
747 b: u64,
748 c: u64,
749 i: usize,
750
751 pub fn init(init_s: u64) Isaac64 {
752 var isaac = Isaac64{
753 .random = Random{ .fillFn = fill },
754 .r = undefined,
755 .m = undefined,
756 .a = undefined,
757 .b = undefined,
758 .c = undefined,
759 .i = undefined,
760 };
761
762 // seed == 0 => same result as the unseeded reference implementation
763 isaac.seed(init_s, 1);
764 return isaac;
765 }
766
767 fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
768 const x = self.m[base + m1];
769 self.a = mix +% self.m[base + m2];
770
771 const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
772 self.m[base + m1] = y;
773
774 self.b = x +% self.m[(y >> 11) % self.m.len];
775 self.r[self.r.len - 1 - base - m1] = self.b;
776 }
777
778 fn refill(self: *Isaac64) void {
779 const midpoint = self.r.len / 2;
780
781 self.c +%= 1;
782 self.b +%= self.c;
783
784 {
785 var i: usize = 0;
786 while (i < midpoint) : (i += 4) {
787 self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
788 self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
789 self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
790 self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
791 }
792 }
793
794 {
795 var i: usize = 0;
796 while (i < midpoint) : (i += 4) {
797 self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
798 self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
799 self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
800 self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
801 }
802 }
803
804 self.i = 0;
805 }
806
807 fn next(self: *Isaac64) u64 {
808 if (self.i >= self.r.len) {
809 self.refill();
810 }
811
812 const value = self.r[self.i];
813 self.i += 1;
814 return value;
815 }
816
817 fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
818 // We ignore the multi-pass requirement since we don't currently expose full access to
819 // seeding the self.m array completely.
820 mem.set(u64, self.m[0..], 0);
821 self.m[0] = init_s;
822
823 // prescrambled golden ratio constants
824 var a = []const u64{
825 0x647c4677a2884b7c,
826 0xb9f8b322c73ac862,
827 0x8c0ea5053d4712a0,
828 0xb29b2e824a595524,
829 0x82f053db8355e0ce,
830 0x48fe4a0fa5a09315,
831 0xae985bf2cbfc89ed,
832 0x98f5704f6c44c0ab,
833 };
834
835 comptime var i: usize = 0;
836 inline while (i < rounds) : (i += 1) {
837 var j: usize = 0;
838 while (j < self.m.len) : (j += 8) {
839 comptime var x1: usize = 0;
840 inline while (x1 < 8) : (x1 += 1) {
841 a[x1] +%= self.m[j + x1];
842 }
843
844 a[0] -%= a[4];
845 a[5] ^= a[7] >> 9;
846 a[7] +%= a[0];
847 a[1] -%= a[5];
848 a[6] ^= a[0] << 9;
849 a[0] +%= a[1];
850 a[2] -%= a[6];
851 a[7] ^= a[1] >> 23;
852 a[1] +%= a[2];
853 a[3] -%= a[7];
854 a[0] ^= a[2] << 15;
855 a[2] +%= a[3];
856 a[4] -%= a[0];
857 a[1] ^= a[3] >> 14;
858 a[3] +%= a[4];
859 a[5] -%= a[1];
860 a[2] ^= a[4] << 20;
861 a[4] +%= a[5];
862 a[6] -%= a[2];
863 a[3] ^= a[5] >> 17;
864 a[5] +%= a[6];
865 a[7] -%= a[3];
866 a[4] ^= a[6] << 14;
867 a[6] +%= a[7];
868
869 comptime var x2: usize = 0;
870 inline while (x2 < 8) : (x2 += 1) {
871 self.m[j + x2] = a[x2];
872 }
873 }
874 }
875
876 mem.set(u64, self.r[0..], 0);
877 self.a = 0;
878 self.b = 0;
879 self.c = 0;
880 self.i = self.r.len; // trigger refill on first value
881 }
882
883 fn fill(r: *Random, buf: []u8) void {
884 const self = @fieldParentPtr(Isaac64, "random", r);
885
886 var i: usize = 0;
887 const aligned_len = buf.len - (buf.len & 7);
888
889 // Fill complete 64-byte segments
890 while (i < aligned_len) : (i += 8) {
891 var n = self.next();
892 comptime var j: usize = 0;
893 inline while (j < 8) : (j += 1) {
894 buf[i + j] = @truncate(u8, n);
895 n >>= 8;
896 }
897 }
898
899 // Fill trailing, ignoring excess (cut the stream).
900 if (i != buf.len) {
901 var n = self.next();
902 while (i < buf.len) : (i += 1) {
903 buf[i] = @truncate(u8, n);
904 n >>= 8;
905 }
906 }
907 }
908};
909
910test "isaac64 sequence" {
911 var r = Isaac64.init(0);
912
913 // from reference implementation
914 const seq = []const u64{
915 0xf67dfba498e4937c,
916 0x84a5066a9204f380,
917 0xfee34bd5f5514dbb,
918 0x4d1664739b8f80d6,
919 0x8607459ab52a14aa,
920 0x0e78bc5a98529e49,
921 0xfe5332822ad13777,
922 0x556c27525e33d01a,
923 0x08643ca615f3149f,
924 0xd0771faf3cb04714,
925 0x30e86f68a37b008d,
926 0x3074ebc0488a3adf,
927 0x270645ea7a2790bc,
928 0x5601a0a8d3763c6a,
929 0x2f83071f53f325dd,
930 0xb9090f3d42d2d2ea,
931 };
932
933 for (seq) |s| {
934 expect(s == r.next());
935 }
936}
937
938// Actual Random helper function tests, pcg engine is assumed correct.
939test "Random float" {
940 var prng = DefaultPrng.init(0);
941
942 var i: usize = 0;
943 while (i < 1000) : (i += 1) {
944 const val1 = prng.random.float(f32);
945 expect(val1 >= 0.0);
946 expect(val1 < 1.0);
947
948 const val2 = prng.random.float(f64);
949 expect(val2 >= 0.0);
950 expect(val2 < 1.0);
951 }
952}
953
954test "Random shuffle" {
955 var prng = DefaultPrng.init(0);
956
957 var seq = []const u8{ 0, 1, 2, 3, 4 };
958 var seen = []bool{false} ** 5;
959
960 var i: usize = 0;
961 while (i < 1000) : (i += 1) {
962 prng.random.shuffle(u8, seq[0..]);
963 seen[seq[0]] = true;
964 expect(sumArray(seq[0..]) == 10);
965 }
966
967 // we should see every entry at the head at least once
968 for (seen) |e| {
969 expect(e == true);
970 }
971}
972
973fn sumArray(s: []const u8) u32 {
974 var r: u32 = 0;
975 for (s) |e|
976 r += e;
977 return r;
978}
979
980test "Random range" {
981 var prng = DefaultPrng.init(0);
982 testRange(&prng.random, -4, 3);
983 testRange(&prng.random, -4, -1);
984 testRange(&prng.random, 10, 14);
985 testRange(&prng.random, -0x80, 0x7f);
986}
987
988fn testRange(r: *Random, start: i8, end: i8) void {
989 testRangeBias(r, start, end, true);
990 testRangeBias(r, start, end, false);
991}
992fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
993 const count = @intCast(usize, i32(end) - i32(start));
994 var values_buffer = []bool{false} ** 0x100;
995 const values = values_buffer[0..count];
996 var i: usize = 0;
997 while (i < count) {
998 const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end);
999 const index = @intCast(usize, value - start);
1000 if (!values[index]) {
1001 i += 1;
1002 values[index] = true;
1003 }
1004 }
1005}
std/rand/ziggurat.zig+1-1
...@@ -8,7 +8,7 @@...@@ -8,7 +8,7 @@
8// NOTE: This seems interesting but reference code is a bit hard to grok:8// NOTE: This seems interesting but reference code is a bit hard to grok:
9// https://sbarral.github.io/etf.9// https://sbarral.github.io/etf.
1010
11const std = @import("../index.zig");11const std = @import("../std.zig");
12const math = std.math;12const math = std.math;
13const Random = std.rand.Random;13const Random = std.rand.Random;
1414
std/rb.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const mem = std.mem; // For mem.Compare4const mem = std.mem; // For mem.Compare
std/segmented_list.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
std/sort.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const mem = std.mem;4const mem = std.mem;
std/special/bootstrap.zig+1-1
...@@ -46,7 +46,7 @@ nakedcc fn _start() noreturn {...@@ -46,7 +46,7 @@ nakedcc fn _start() noreturn {
46extern fn WinMainCRTStartup() noreturn {46extern fn WinMainCRTStartup() noreturn {
47 @setAlignStack(16);47 @setAlignStack(16);
48 if (!builtin.single_threaded) {48 if (!builtin.single_threaded) {
49 _ = @import("../os/windows/tls.zig");49 _ = @import("bootstrap_windows_tls.zig");
50 }50 }
51 std.os.windows.ExitProcess(callMain());51 std.os.windows.ExitProcess(callMain());
52}52}
std/special/bootstrap_windows_tls.zig created+36
...@@ -0,0 +1,36 @@
1const std = @import("std");
2
3export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES;
4export var _tls_start: u8 linksection(".tls") = 0;
5export var _tls_end: u8 linksection(".tls$ZZZ") = 0;
6export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
7export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
8
9// TODO this is how I would like it to be expressed
10// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate
11// why they do that.
12//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY {
13// .StartAddressOfRawData = @ptrToInt(&_tls_start),
14// .EndAddressOfRawData = @ptrToInt(&_tls_end),
15// .AddressOfIndex = @ptrToInt(&_tls_index),
16// .AddressOfCallBacks = @ptrToInt(__xl_a),
17// .SizeOfZeroFill = 0,
18// .Characteristics = 0,
19//};
20// This is the workaround because we can't do @ptrToInt at comptime like that.
21pub const IMAGE_TLS_DIRECTORY = extern struct {
22 StartAddressOfRawData: *c_void,
23 EndAddressOfRawData: *c_void,
24 AddressOfIndex: *c_void,
25 AddressOfCallBacks: *c_void,
26 SizeOfZeroFill: u32,
27 Characteristics: u32,
28};
29export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{
30 .StartAddressOfRawData = &_tls_start,
31 .EndAddressOfRawData = &_tls_end,
32 .AddressOfIndex = &_tls_index,
33 .AddressOfCallBacks = &__xl_a,
34 .SizeOfZeroFill = 0,
35 .Characteristics = 0,
36};
std/special/builtin.zig+1-1
...@@ -134,7 +134,7 @@ nakedcc fn clone() void {...@@ -134,7 +134,7 @@ nakedcc fn clone() void {
134 }134 }
135}135}
136136
137const math = @import("../math/index.zig");137const math = std.math;
138138
139export fn fmodf(x: f32, y: f32) f32 {139export fn fmodf(x: f32, y: f32) f32 {
140 return generic_fmod(f32, x, y);140 return generic_fmod(f32, x, y);
std/special/compiler_rt.zig created+1038
...@@ -0,0 +1,1038 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4comptime {
5 const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
6 const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
7
8 @export("__letf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
9 @export("__getf2", @import("compiler_rt/comparetf2.zig").__getf2, linkage);
10
11 if (!is_test) {
12 // only create these aliases when not testing
13 @export("__cmptf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
14 @export("__eqtf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
15 @export("__lttf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
16 @export("__netf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
17 @export("__gttf2", @import("compiler_rt/comparetf2.zig").__getf2, linkage);
18 @export("__gnu_h2f_ieee", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage);
19 @export("__gnu_f2h_ieee", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage);
20 }
21
22 @export("__unordtf2", @import("compiler_rt/comparetf2.zig").__unordtf2, linkage);
23
24 @export("__addtf3", @import("compiler_rt/addXf3.zig").__addtf3, linkage);
25 @export("__subtf3", @import("compiler_rt/addXf3.zig").__subtf3, linkage);
26
27 @export("__floattitf", @import("compiler_rt/floattitf.zig").__floattitf, linkage);
28 @export("__floattidf", @import("compiler_rt/floattidf.zig").__floattidf, linkage);
29 @export("__floattisf", @import("compiler_rt/floattisf.zig").__floattisf, linkage);
30
31 @export("__floatunditf", @import("compiler_rt/floatunditf.zig").__floatunditf, linkage);
32 @export("__floatunsitf", @import("compiler_rt/floatunsitf.zig").__floatunsitf, linkage);
33
34 @export("__floatuntitf", @import("compiler_rt/floatuntitf.zig").__floatuntitf, linkage);
35 @export("__floatuntidf", @import("compiler_rt/floatuntidf.zig").__floatuntidf, linkage);
36 @export("__floatuntisf", @import("compiler_rt/floatuntisf.zig").__floatuntisf, linkage);
37
38 @export("__extenddftf2", @import("compiler_rt/extendXfYf2.zig").__extenddftf2, linkage);
39 @export("__extendsftf2", @import("compiler_rt/extendXfYf2.zig").__extendsftf2, linkage);
40 @export("__extendhfsf2", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage);
41
42 @export("__truncsfhf2", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage);
43 @export("__truncdfhf2", @import("compiler_rt/truncXfYf2.zig").__truncdfhf2, linkage);
44 @export("__trunctfdf2", @import("compiler_rt/truncXfYf2.zig").__trunctfdf2, linkage);
45 @export("__trunctfsf2", @import("compiler_rt/truncXfYf2.zig").__trunctfsf2, linkage);
46
47 @export("__fixunssfsi", @import("compiler_rt/fixunssfsi.zig").__fixunssfsi, linkage);
48 @export("__fixunssfdi", @import("compiler_rt/fixunssfdi.zig").__fixunssfdi, linkage);
49 @export("__fixunssfti", @import("compiler_rt/fixunssfti.zig").__fixunssfti, linkage);
50
51 @export("__fixunsdfsi", @import("compiler_rt/fixunsdfsi.zig").__fixunsdfsi, linkage);
52 @export("__fixunsdfdi", @import("compiler_rt/fixunsdfdi.zig").__fixunsdfdi, linkage);
53 @export("__fixunsdfti", @import("compiler_rt/fixunsdfti.zig").__fixunsdfti, linkage);
54
55 @export("__fixunstfsi", @import("compiler_rt/fixunstfsi.zig").__fixunstfsi, linkage);
56 @export("__fixunstfdi", @import("compiler_rt/fixunstfdi.zig").__fixunstfdi, linkage);
57 @export("__fixunstfti", @import("compiler_rt/fixunstfti.zig").__fixunstfti, linkage);
58
59 @export("__fixdfdi", @import("compiler_rt/fixdfdi.zig").__fixdfdi, linkage);
60 @export("__fixdfsi", @import("compiler_rt/fixdfsi.zig").__fixdfsi, linkage);
61 @export("__fixdfti", @import("compiler_rt/fixdfti.zig").__fixdfti, linkage);
62 @export("__fixsfdi", @import("compiler_rt/fixsfdi.zig").__fixsfdi, linkage);
63 @export("__fixsfsi", @import("compiler_rt/fixsfsi.zig").__fixsfsi, linkage);
64 @export("__fixsfti", @import("compiler_rt/fixsfti.zig").__fixsfti, linkage);
65 @export("__fixtfdi", @import("compiler_rt/fixtfdi.zig").__fixtfdi, linkage);
66 @export("__fixtfsi", @import("compiler_rt/fixtfsi.zig").__fixtfsi, linkage);
67 @export("__fixtfti", @import("compiler_rt/fixtfti.zig").__fixtfti, linkage);
68
69 @export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage);
70
71 @export("__udivsi3", __udivsi3, linkage);
72 @export("__udivdi3", __udivdi3, linkage);
73 @export("__umoddi3", __umoddi3, linkage);
74 @export("__udivmodsi4", __udivmodsi4, linkage);
75
76 if (is_arm_arch and !is_arm_64) {
77 @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage);
78 @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage);
79 @export("__aeabi_uidiv", __udivsi3, linkage);
80 }
81 if (builtin.os == builtin.Os.windows) {
82 switch (builtin.arch) {
83 builtin.Arch.i386 => {
84 if (!builtin.link_libc) {
85 @export("_chkstk", _chkstk, strong_linkage);
86 @export("__chkstk_ms", __chkstk_ms, linkage);
87 }
88 @export("_aulldiv", @import("compiler_rt/aulldiv.zig")._aulldiv, strong_linkage);
89 @export("_aullrem", @import("compiler_rt/aullrem.zig")._aullrem, strong_linkage);
90 },
91 builtin.Arch.x86_64 => {
92 if (!builtin.link_libc) {
93 @export("__chkstk", __chkstk, strong_linkage);
94 @export("___chkstk_ms", ___chkstk_ms, linkage);
95 }
96 @export("__divti3", @import("compiler_rt/divti3.zig").__divti3_windows_x86_64, linkage);
97 @export("__multi3", @import("compiler_rt/multi3.zig").__multi3_windows_x86_64, linkage);
98 @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4_windows_x86_64, linkage);
99 @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3_windows_x86_64, linkage);
100 @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
101 @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3_windows_x86_64, linkage);
102 },
103 else => {},
104 }
105 } else {
106 @export("__divti3", @import("compiler_rt/divti3.zig").__divti3, linkage);
107 @export("__multi3", @import("compiler_rt/multi3.zig").__multi3, linkage);
108 @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4, linkage);
109 @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3, linkage);
110 @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4, linkage);
111 @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3, linkage);
112 }
113}
114
115const std = @import("std");
116const assert = std.debug.assert;
117const testing = std.testing;
118
119const __udivmoddi4 = @import("compiler_rt/udivmoddi4.zig").__udivmoddi4;
120
121// Avoid dragging in the runtime safety mechanisms into this .o file,
122// unless we're trying to test this file.
123pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
124 @setCold(true);
125 if (is_test) {
126 std.debug.panic("{}", msg);
127 } else {
128 unreachable;
129 }
130}
131
132pub fn setXmm0(comptime T: type, value: T) void {
133 comptime assert(builtin.arch == builtin.Arch.x86_64);
134 const aligned_value: T align(16) = value;
135 asm volatile (
136 \\movaps (%[ptr]), %%xmm0
137 :
138 : [ptr] "r" (&aligned_value)
139 : "xmm0"
140 );
141}
142
143extern fn __udivdi3(a: u64, b: u64) u64 {
144 @setRuntimeSafety(is_test);
145 return __udivmoddi4(a, b, null);
146}
147
148extern fn __umoddi3(a: u64, b: u64) u64 {
149 @setRuntimeSafety(is_test);
150
151 var r: u64 = undefined;
152 _ = __udivmoddi4(a, b, &r);
153 return r;
154}
155
156const AeabiUlDivModResult = extern struct {
157 quot: u64,
158 rem: u64,
159};
160extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult {
161 @setRuntimeSafety(is_test);
162 var result: AeabiUlDivModResult = undefined;
163 result.quot = __udivmoddi4(numerator, denominator, &result.rem);
164 return result;
165}
166
167const is_arm_64 = switch (builtin.arch) {
168 builtin.Arch.aarch64,
169 builtin.Arch.aarch64_be,
170 => true,
171 else => false,
172};
173
174const is_arm_arch = switch (builtin.arch) {
175 builtin.Arch.arm,
176 builtin.Arch.armeb,
177 builtin.Arch.aarch64,
178 builtin.Arch.aarch64_be,
179 builtin.Arch.thumb,
180 builtin.Arch.thumbeb,
181 => true,
182 else => false,
183};
184
185nakedcc fn __aeabi_uidivmod() void {
186 @setRuntimeSafety(false);
187 asm volatile (
188 \\ push { lr }
189 \\ sub sp, sp, #4
190 \\ mov r2, sp
191 \\ bl __udivmodsi4
192 \\ ldr r1, [sp]
193 \\ add sp, sp, #4
194 \\ pop { pc }
195 :
196 :
197 : "r2", "r1"
198 );
199}
200
201// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
202// then decrement %esp by %eax. Preserves all registers except %esp and flags.
203// This routine is windows specific
204// http://msdn.microsoft.com/en-us/library/ms648426.aspx
205nakedcc fn _chkstk() align(4) void {
206 @setRuntimeSafety(false);
207
208 asm volatile (
209 \\ push %%ecx
210 \\ push %%eax
211 \\ cmp $0x1000,%%eax
212 \\ lea 12(%%esp),%%ecx
213 \\ jb 1f
214 \\ 2:
215 \\ sub $0x1000,%%ecx
216 \\ test %%ecx,(%%ecx)
217 \\ sub $0x1000,%%eax
218 \\ cmp $0x1000,%%eax
219 \\ ja 2b
220 \\ 1:
221 \\ sub %%eax,%%ecx
222 \\ test %%ecx,(%%ecx)
223 \\ pop %%eax
224 \\ pop %%ecx
225 \\ ret
226 );
227}
228
229nakedcc fn __chkstk() align(4) void {
230 @setRuntimeSafety(false);
231
232 asm volatile (
233 \\ push %%rcx
234 \\ push %%rax
235 \\ cmp $0x1000,%%rax
236 \\ lea 24(%%rsp),%%rcx
237 \\ jb 1f
238 \\2:
239 \\ sub $0x1000,%%rcx
240 \\ test %%rcx,(%%rcx)
241 \\ sub $0x1000,%%rax
242 \\ cmp $0x1000,%%rax
243 \\ ja 2b
244 \\1:
245 \\ sub %%rax,%%rcx
246 \\ test %%rcx,(%%rcx)
247 \\ pop %%rax
248 \\ pop %%rcx
249 \\ ret
250 );
251}
252
253// _chkstk routine
254// This routine is windows specific
255// http://msdn.microsoft.com/en-us/library/ms648426.aspx
256nakedcc fn __chkstk_ms() align(4) void {
257 @setRuntimeSafety(false);
258
259 asm volatile (
260 \\ push %%ecx
261 \\ push %%eax
262 \\ cmp $0x1000,%%eax
263 \\ lea 12(%%esp),%%ecx
264 \\ jb 1f
265 \\ 2:
266 \\ sub $0x1000,%%ecx
267 \\ test %%ecx,(%%ecx)
268 \\ sub $0x1000,%%eax
269 \\ cmp $0x1000,%%eax
270 \\ ja 2b
271 \\ 1:
272 \\ sub %%eax,%%ecx
273 \\ test %%ecx,(%%ecx)
274 \\ pop %%eax
275 \\ pop %%ecx
276 \\ ret
277 );
278}
279
280nakedcc fn ___chkstk_ms() align(4) void {
281 @setRuntimeSafety(false);
282
283 asm volatile (
284 \\ push %%rcx
285 \\ push %%rax
286 \\ cmp $0x1000,%%rax
287 \\ lea 24(%%rsp),%%rcx
288 \\ jb 1f
289 \\2:
290 \\ sub $0x1000,%%rcx
291 \\ test %%rcx,(%%rcx)
292 \\ sub $0x1000,%%rax
293 \\ cmp $0x1000,%%rax
294 \\ ja 2b
295 \\1:
296 \\ sub %%rax,%%rcx
297 \\ test %%rcx,(%%rcx)
298 \\ pop %%rax
299 \\ pop %%rcx
300 \\ ret
301 );
302}
303
304extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 {
305 @setRuntimeSafety(is_test);
306
307 const d = __udivsi3(a, b);
308 rem.* = @bitCast(u32, @bitCast(i32, a) -% (@bitCast(i32, d) * @bitCast(i32, b)));
309 return d;
310}
311
312extern fn __udivsi3(n: u32, d: u32) u32 {
313 @setRuntimeSafety(is_test);
314
315 const n_uword_bits: c_uint = u32.bit_count;
316 // special cases
317 if (d == 0) return 0; // ?!
318 if (n == 0) return 0;
319 var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
320 // 0 <= sr <= n_uword_bits - 1 or sr large
321 if (sr > n_uword_bits - 1) {
322 // d > r
323 return 0;
324 }
325 if (sr == n_uword_bits - 1) {
326 // d == 1
327 return n;
328 }
329 sr += 1;
330 // 1 <= sr <= n_uword_bits - 1
331 // Not a special case
332 var q: u32 = n << @intCast(u5, n_uword_bits - sr);
333 var r: u32 = n >> @intCast(u5, sr);
334 var carry: u32 = 0;
335 while (sr > 0) : (sr -= 1) {
336 // r:q = ((r:q) << 1) | carry
337 r = (r << 1) | (q >> @intCast(u5, n_uword_bits - 1));
338 q = (q << 1) | carry;
339 // carry = 0;
340 // if (r.all >= d.all)
341 // {
342 // r.all -= d.all;
343 // carry = 1;
344 // }
345 const s = @intCast(i32, d -% r -% 1) >> @intCast(u5, n_uword_bits - 1);
346 carry = @intCast(u32, s & 1);
347 r -= d & @bitCast(u32, s);
348 }
349 q = (q << 1) | carry;
350 return q;
351}
352
353test "test_umoddi3" {
354 test_one_umoddi3(0, 1, 0);
355 test_one_umoddi3(2, 1, 0);
356 test_one_umoddi3(0x8000000000000000, 1, 0x0);
357 test_one_umoddi3(0x8000000000000000, 2, 0x0);
358 test_one_umoddi3(0xFFFFFFFFFFFFFFFF, 2, 0x1);
359}
360
361fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
362 const r = __umoddi3(a, b);
363 testing.expect(r == expected_r);
364}
365
366test "test_udivsi3" {
367 const cases = [][3]u32{
368 []u32{
369 0x00000000,
370 0x00000001,
371 0x00000000,
372 },
373 []u32{
374 0x00000000,
375 0x00000002,
376 0x00000000,
377 },
378 []u32{
379 0x00000000,
380 0x00000003,
381 0x00000000,
382 },
383 []u32{
384 0x00000000,
385 0x00000010,
386 0x00000000,
387 },
388 []u32{
389 0x00000000,
390 0x078644FA,
391 0x00000000,
392 },
393 []u32{
394 0x00000000,
395 0x0747AE14,
396 0x00000000,
397 },
398 []u32{
399 0x00000000,
400 0x7FFFFFFF,
401 0x00000000,
402 },
403 []u32{
404 0x00000000,
405 0x80000000,
406 0x00000000,
407 },
408 []u32{
409 0x00000000,
410 0xFFFFFFFD,
411 0x00000000,
412 },
413 []u32{
414 0x00000000,
415 0xFFFFFFFE,
416 0x00000000,
417 },
418 []u32{
419 0x00000000,
420 0xFFFFFFFF,
421 0x00000000,
422 },
423 []u32{
424 0x00000001,
425 0x00000001,
426 0x00000001,
427 },
428 []u32{
429 0x00000001,
430 0x00000002,
431 0x00000000,
432 },
433 []u32{
434 0x00000001,
435 0x00000003,
436 0x00000000,
437 },
438 []u32{
439 0x00000001,
440 0x00000010,
441 0x00000000,
442 },
443 []u32{
444 0x00000001,
445 0x078644FA,
446 0x00000000,
447 },
448 []u32{
449 0x00000001,
450 0x0747AE14,
451 0x00000000,
452 },
453 []u32{
454 0x00000001,
455 0x7FFFFFFF,
456 0x00000000,
457 },
458 []u32{
459 0x00000001,
460 0x80000000,
461 0x00000000,
462 },
463 []u32{
464 0x00000001,
465 0xFFFFFFFD,
466 0x00000000,
467 },
468 []u32{
469 0x00000001,
470 0xFFFFFFFE,
471 0x00000000,
472 },
473 []u32{
474 0x00000001,
475 0xFFFFFFFF,
476 0x00000000,
477 },
478 []u32{
479 0x00000002,
480 0x00000001,
481 0x00000002,
482 },
483 []u32{
484 0x00000002,
485 0x00000002,
486 0x00000001,
487 },
488 []u32{
489 0x00000002,
490 0x00000003,
491 0x00000000,
492 },
493 []u32{
494 0x00000002,
495 0x00000010,
496 0x00000000,
497 },
498 []u32{
499 0x00000002,
500 0x078644FA,
501 0x00000000,
502 },
503 []u32{
504 0x00000002,
505 0x0747AE14,
506 0x00000000,
507 },
508 []u32{
509 0x00000002,
510 0x7FFFFFFF,
511 0x00000000,
512 },
513 []u32{
514 0x00000002,
515 0x80000000,
516 0x00000000,
517 },
518 []u32{
519 0x00000002,
520 0xFFFFFFFD,
521 0x00000000,
522 },
523 []u32{
524 0x00000002,
525 0xFFFFFFFE,
526 0x00000000,
527 },
528 []u32{
529 0x00000002,
530 0xFFFFFFFF,
531 0x00000000,
532 },
533 []u32{
534 0x00000003,
535 0x00000001,
536 0x00000003,
537 },
538 []u32{
539 0x00000003,
540 0x00000002,
541 0x00000001,
542 },
543 []u32{
544 0x00000003,
545 0x00000003,
546 0x00000001,
547 },
548 []u32{
549 0x00000003,
550 0x00000010,
551 0x00000000,
552 },
553 []u32{
554 0x00000003,
555 0x078644FA,
556 0x00000000,
557 },
558 []u32{
559 0x00000003,
560 0x0747AE14,
561 0x00000000,
562 },
563 []u32{
564 0x00000003,
565 0x7FFFFFFF,
566 0x00000000,
567 },
568 []u32{
569 0x00000003,
570 0x80000000,
571 0x00000000,
572 },
573 []u32{
574 0x00000003,
575 0xFFFFFFFD,
576 0x00000000,
577 },
578 []u32{
579 0x00000003,
580 0xFFFFFFFE,
581 0x00000000,
582 },
583 []u32{
584 0x00000003,
585 0xFFFFFFFF,
586 0x00000000,
587 },
588 []u32{
589 0x00000010,
590 0x00000001,
591 0x00000010,
592 },
593 []u32{
594 0x00000010,
595 0x00000002,
596 0x00000008,
597 },
598 []u32{
599 0x00000010,
600 0x00000003,
601 0x00000005,
602 },
603 []u32{
604 0x00000010,
605 0x00000010,
606 0x00000001,
607 },
608 []u32{
609 0x00000010,
610 0x078644FA,
611 0x00000000,
612 },
613 []u32{
614 0x00000010,
615 0x0747AE14,
616 0x00000000,
617 },
618 []u32{
619 0x00000010,
620 0x7FFFFFFF,
621 0x00000000,
622 },
623 []u32{
624 0x00000010,
625 0x80000000,
626 0x00000000,
627 },
628 []u32{
629 0x00000010,
630 0xFFFFFFFD,
631 0x00000000,
632 },
633 []u32{
634 0x00000010,
635 0xFFFFFFFE,
636 0x00000000,
637 },
638 []u32{
639 0x00000010,
640 0xFFFFFFFF,
641 0x00000000,
642 },
643 []u32{
644 0x078644FA,
645 0x00000001,
646 0x078644FA,
647 },
648 []u32{
649 0x078644FA,
650 0x00000002,
651 0x03C3227D,
652 },
653 []u32{
654 0x078644FA,
655 0x00000003,
656 0x028216FE,
657 },
658 []u32{
659 0x078644FA,
660 0x00000010,
661 0x0078644F,
662 },
663 []u32{
664 0x078644FA,
665 0x078644FA,
666 0x00000001,
667 },
668 []u32{
669 0x078644FA,
670 0x0747AE14,
671 0x00000001,
672 },
673 []u32{
674 0x078644FA,
675 0x7FFFFFFF,
676 0x00000000,
677 },
678 []u32{
679 0x078644FA,
680 0x80000000,
681 0x00000000,
682 },
683 []u32{
684 0x078644FA,
685 0xFFFFFFFD,
686 0x00000000,
687 },
688 []u32{
689 0x078644FA,
690 0xFFFFFFFE,
691 0x00000000,
692 },
693 []u32{
694 0x078644FA,
695 0xFFFFFFFF,
696 0x00000000,
697 },
698 []u32{
699 0x0747AE14,
700 0x00000001,
701 0x0747AE14,
702 },
703 []u32{
704 0x0747AE14,
705 0x00000002,
706 0x03A3D70A,
707 },
708 []u32{
709 0x0747AE14,
710 0x00000003,
711 0x026D3A06,
712 },
713 []u32{
714 0x0747AE14,
715 0x00000010,
716 0x00747AE1,
717 },
718 []u32{
719 0x0747AE14,
720 0x078644FA,
721 0x00000000,
722 },
723 []u32{
724 0x0747AE14,
725 0x0747AE14,
726 0x00000001,
727 },
728 []u32{
729 0x0747AE14,
730 0x7FFFFFFF,
731 0x00000000,
732 },
733 []u32{
734 0x0747AE14,
735 0x80000000,
736 0x00000000,
737 },
738 []u32{
739 0x0747AE14,
740 0xFFFFFFFD,
741 0x00000000,
742 },
743 []u32{
744 0x0747AE14,
745 0xFFFFFFFE,
746 0x00000000,
747 },
748 []u32{
749 0x0747AE14,
750 0xFFFFFFFF,
751 0x00000000,
752 },
753 []u32{
754 0x7FFFFFFF,
755 0x00000001,
756 0x7FFFFFFF,
757 },
758 []u32{
759 0x7FFFFFFF,
760 0x00000002,
761 0x3FFFFFFF,
762 },
763 []u32{
764 0x7FFFFFFF,
765 0x00000003,
766 0x2AAAAAAA,
767 },
768 []u32{
769 0x7FFFFFFF,
770 0x00000010,
771 0x07FFFFFF,
772 },
773 []u32{
774 0x7FFFFFFF,
775 0x078644FA,
776 0x00000011,
777 },
778 []u32{
779 0x7FFFFFFF,
780 0x0747AE14,
781 0x00000011,
782 },
783 []u32{
784 0x7FFFFFFF,
785 0x7FFFFFFF,
786 0x00000001,
787 },
788 []u32{
789 0x7FFFFFFF,
790 0x80000000,
791 0x00000000,
792 },
793 []u32{
794 0x7FFFFFFF,
795 0xFFFFFFFD,
796 0x00000000,
797 },
798 []u32{
799 0x7FFFFFFF,
800 0xFFFFFFFE,
801 0x00000000,
802 },
803 []u32{
804 0x7FFFFFFF,
805 0xFFFFFFFF,
806 0x00000000,
807 },
808 []u32{
809 0x80000000,
810 0x00000001,
811 0x80000000,
812 },
813 []u32{
814 0x80000000,
815 0x00000002,
816 0x40000000,
817 },
818 []u32{
819 0x80000000,
820 0x00000003,
821 0x2AAAAAAA,
822 },
823 []u32{
824 0x80000000,
825 0x00000010,
826 0x08000000,
827 },
828 []u32{
829 0x80000000,
830 0x078644FA,
831 0x00000011,
832 },
833 []u32{
834 0x80000000,
835 0x0747AE14,
836 0x00000011,
837 },
838 []u32{
839 0x80000000,
840 0x7FFFFFFF,
841 0x00000001,
842 },
843 []u32{
844 0x80000000,
845 0x80000000,
846 0x00000001,
847 },
848 []u32{
849 0x80000000,
850 0xFFFFFFFD,
851 0x00000000,
852 },
853 []u32{
854 0x80000000,
855 0xFFFFFFFE,
856 0x00000000,
857 },
858 []u32{
859 0x80000000,
860 0xFFFFFFFF,
861 0x00000000,
862 },
863 []u32{
864 0xFFFFFFFD,
865 0x00000001,
866 0xFFFFFFFD,
867 },
868 []u32{
869 0xFFFFFFFD,
870 0x00000002,
871 0x7FFFFFFE,
872 },
873 []u32{
874 0xFFFFFFFD,
875 0x00000003,
876 0x55555554,
877 },
878 []u32{
879 0xFFFFFFFD,
880 0x00000010,
881 0x0FFFFFFF,
882 },
883 []u32{
884 0xFFFFFFFD,
885 0x078644FA,
886 0x00000022,
887 },
888 []u32{
889 0xFFFFFFFD,
890 0x0747AE14,
891 0x00000023,
892 },
893 []u32{
894 0xFFFFFFFD,
895 0x7FFFFFFF,
896 0x00000001,
897 },
898 []u32{
899 0xFFFFFFFD,
900 0x80000000,
901 0x00000001,
902 },
903 []u32{
904 0xFFFFFFFD,
905 0xFFFFFFFD,
906 0x00000001,
907 },
908 []u32{
909 0xFFFFFFFD,
910 0xFFFFFFFE,
911 0x00000000,
912 },
913 []u32{
914 0xFFFFFFFD,
915 0xFFFFFFFF,
916 0x00000000,
917 },
918 []u32{
919 0xFFFFFFFE,
920 0x00000001,
921 0xFFFFFFFE,
922 },
923 []u32{
924 0xFFFFFFFE,
925 0x00000002,
926 0x7FFFFFFF,
927 },
928 []u32{
929 0xFFFFFFFE,
930 0x00000003,
931 0x55555554,
932 },
933 []u32{
934 0xFFFFFFFE,
935 0x00000010,
936 0x0FFFFFFF,
937 },
938 []u32{
939 0xFFFFFFFE,
940 0x078644FA,
941 0x00000022,
942 },
943 []u32{
944 0xFFFFFFFE,
945 0x0747AE14,
946 0x00000023,
947 },
948 []u32{
949 0xFFFFFFFE,
950 0x7FFFFFFF,
951 0x00000002,
952 },
953 []u32{
954 0xFFFFFFFE,
955 0x80000000,
956 0x00000001,
957 },
958 []u32{
959 0xFFFFFFFE,
960 0xFFFFFFFD,
961 0x00000001,
962 },
963 []u32{
964 0xFFFFFFFE,
965 0xFFFFFFFE,
966 0x00000001,
967 },
968 []u32{
969 0xFFFFFFFE,
970 0xFFFFFFFF,
971 0x00000000,
972 },
973 []u32{
974 0xFFFFFFFF,
975 0x00000001,
976 0xFFFFFFFF,
977 },
978 []u32{
979 0xFFFFFFFF,
980 0x00000002,
981 0x7FFFFFFF,
982 },
983 []u32{
984 0xFFFFFFFF,
985 0x00000003,
986 0x55555555,
987 },
988 []u32{
989 0xFFFFFFFF,
990 0x00000010,
991 0x0FFFFFFF,
992 },
993 []u32{
994 0xFFFFFFFF,
995 0x078644FA,
996 0x00000022,
997 },
998 []u32{
999 0xFFFFFFFF,
1000 0x0747AE14,
1001 0x00000023,
1002 },
1003 []u32{
1004 0xFFFFFFFF,
1005 0x7FFFFFFF,
1006 0x00000002,
1007 },
1008 []u32{
1009 0xFFFFFFFF,
1010 0x80000000,
1011 0x00000001,
1012 },
1013 []u32{
1014 0xFFFFFFFF,
1015 0xFFFFFFFD,
1016 0x00000001,
1017 },
1018 []u32{
1019 0xFFFFFFFF,
1020 0xFFFFFFFE,
1021 0x00000001,
1022 },
1023 []u32{
1024 0xFFFFFFFF,
1025 0xFFFFFFFF,
1026 0x00000001,
1027 },
1028 };
1029
1030 for (cases) |case| {
1031 test_one_udivsi3(case[0], case[1], case[2]);
1032 }
1033}
1034
1035fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void {
1036 const q: u32 = __udivsi3(a, b);
1037 testing.expect(q == expected_q);
1038}
std/special/compiler_rt/addXf3.zig+1-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
44
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const compiler_rt = @import("index.zig");7const compiler_rt = @import("../compiler_rt.zig");
88
9pub extern fn __addtf3(a: f128, b: f128) f128 {9pub extern fn __addtf3(a: f128, b: f128) f128 {
10 return addXf3(f128, a, b);10 return addXf3(f128, a, b);
std/special/compiler_rt/divti3.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const udivmod = @import("udivmod.zig").udivmod;1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");3const compiler_rt = @import("../compiler_rt.zig");
44
5pub extern fn __divti3(a: i128, b: i128) i128 {5pub extern fn __divti3(a: i128, b: i128) i128 {
6 @setRuntimeSafety(builtin.is_test);6 @setRuntimeSafety(builtin.is_test);
std/special/compiler_rt/index.zig deleted-1050
...@@ -1,1050 +0,0 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4comptime {
5 const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
6 const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
7
8 @export("__letf2", @import("comparetf2.zig").__letf2, linkage);
9 @export("__getf2", @import("comparetf2.zig").__getf2, linkage);
10
11 if (!is_test) {
12 // only create these aliases when not testing
13 @export("__cmptf2", @import("comparetf2.zig").__letf2, linkage);
14 @export("__eqtf2", @import("comparetf2.zig").__letf2, linkage);
15 @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);
16 @export("__netf2", @import("comparetf2.zig").__letf2, linkage);
17 @export("__gttf2", @import("comparetf2.zig").__getf2, linkage);
18 @export("__gnu_h2f_ieee", @import("extendXfYf2.zig").__extendhfsf2, linkage);
19 @export("__gnu_f2h_ieee", @import("truncXfYf2.zig").__truncsfhf2, linkage);
20 }
21
22 @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
23
24 @export("__addtf3", @import("addXf3.zig").__addtf3, linkage);
25 @export("__subtf3", @import("addXf3.zig").__subtf3, linkage);
26
27 @export("__floattitf", @import("floattitf.zig").__floattitf, linkage);
28 @export("__floattidf", @import("floattidf.zig").__floattidf, linkage);
29 @export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
30
31 @export("__floatunditf", @import("floatunditf.zig").__floatunditf, linkage);
32 @export("__floatunsitf", @import("floatunsitf.zig").__floatunsitf, linkage);
33
34 @export("__floatuntitf", @import("floatuntitf.zig").__floatuntitf, linkage);
35 @export("__floatuntidf", @import("floatuntidf.zig").__floatuntidf, linkage);
36 @export("__floatuntisf", @import("floatuntisf.zig").__floatuntisf, linkage);
37
38 @export("__extenddftf2", @import("extendXfYf2.zig").__extenddftf2, linkage);
39 @export("__extendsftf2", @import("extendXfYf2.zig").__extendsftf2, linkage);
40 @export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
41
42 @export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
43 @export("__truncdfhf2", @import("truncXfYf2.zig").__truncdfhf2, linkage);
44 @export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage);
45 @export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage);
46
47 @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);
48 @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);
49 @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage);
50
51 @export("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage);
52 @export("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage);
53 @export("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage);
54
55 @export("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage);
56 @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage);
57 @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage);
58
59 @export("__fixdfdi", @import("fixdfdi.zig").__fixdfdi, linkage);
60 @export("__fixdfsi", @import("fixdfsi.zig").__fixdfsi, linkage);
61 @export("__fixdfti", @import("fixdfti.zig").__fixdfti, linkage);
62 @export("__fixsfdi", @import("fixsfdi.zig").__fixsfdi, linkage);
63 @export("__fixsfsi", @import("fixsfsi.zig").__fixsfsi, linkage);
64 @export("__fixsfti", @import("fixsfti.zig").__fixsfti, linkage);
65 @export("__fixtfdi", @import("fixtfdi.zig").__fixtfdi, linkage);
66 @export("__fixtfsi", @import("fixtfsi.zig").__fixtfsi, linkage);
67 @export("__fixtfti", @import("fixtfti.zig").__fixtfti, linkage);
68
69 @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage);
70
71 @export("__udivsi3", __udivsi3, linkage);
72 @export("__udivdi3", __udivdi3, linkage);
73 @export("__umoddi3", __umoddi3, linkage);
74 @export("__udivmodsi4", __udivmodsi4, linkage);
75
76 if (is_arm_arch and !is_arm_64) {
77 @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage);
78 @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage);
79 @export("__aeabi_uidiv", __udivsi3, linkage);
80 }
81 if (builtin.os == builtin.Os.windows) {
82 switch (builtin.arch) {
83 builtin.Arch.i386 => {
84 if (!builtin.link_libc) {
85 @export("_chkstk", _chkstk, strong_linkage);
86 @export("__chkstk_ms", __chkstk_ms, linkage);
87 }
88 @export("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage);
89 @export("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage);
90 },
91 builtin.Arch.x86_64 => {
92 if (!builtin.link_libc) {
93 @export("__chkstk", __chkstk, strong_linkage);
94 @export("___chkstk_ms", ___chkstk_ms, linkage);
95 }
96 @export("__divti3", @import("divti3.zig").__divti3_windows_x86_64, linkage);
97 @export("__multi3", @import("multi3.zig").__multi3_windows_x86_64, linkage);
98 @export("__muloti4", @import("muloti4.zig").__muloti4_windows_x86_64, linkage);
99 @export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage);
100 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
101 @export("__umodti3", @import("umodti3.zig").__umodti3_windows_x86_64, linkage);
102 },
103 else => {},
104 }
105 } else {
106 @export("__divti3", @import("divti3.zig").__divti3, linkage);
107 @export("__multi3", @import("multi3.zig").__multi3, linkage);
108 @export("__muloti4", @import("muloti4.zig").__muloti4, linkage);
109 @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
110 @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
111 @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
112 }
113}
114
115const std = @import("std");
116const assert = std.debug.assert;
117const testing = std.testing;
118
119const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
120
121// Avoid dragging in the runtime safety mechanisms into this .o file,
122// unless we're trying to test this file.
123pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
124 @setCold(true);
125 if (is_test) {
126 std.debug.panic("{}", msg);
127 } else {
128 unreachable;
129 }
130}
131
132pub fn setXmm0(comptime T: type, value: T) void {
133 comptime assert(builtin.arch == builtin.Arch.x86_64);
134 const aligned_value: T align(16) = value;
135 asm volatile (
136 \\movaps (%[ptr]), %%xmm0
137 :
138 : [ptr] "r" (&aligned_value)
139 : "xmm0"
140 );
141}
142
143extern fn __udivdi3(a: u64, b: u64) u64 {
144 @setRuntimeSafety(is_test);
145 return __udivmoddi4(a, b, null);
146}
147
148extern fn __umoddi3(a: u64, b: u64) u64 {
149 @setRuntimeSafety(is_test);
150
151 var r: u64 = undefined;
152 _ = __udivmoddi4(a, b, &r);
153 return r;
154}
155
156const AeabiUlDivModResult = extern struct {
157 quot: u64,
158 rem: u64,
159};
160extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult {
161 @setRuntimeSafety(is_test);
162 var result: AeabiUlDivModResult = undefined;
163 result.quot = __udivmoddi4(numerator, denominator, &result.rem);
164 return result;
165}
166
167const is_arm_64 = switch (builtin.arch) {
168 builtin.Arch.aarch64v8_3a,
169 builtin.Arch.aarch64v8_2a,
170 builtin.Arch.aarch64v8_1a,
171 builtin.Arch.aarch64v8,
172 builtin.Arch.aarch64v8r,
173 builtin.Arch.aarch64v8m_baseline,
174 builtin.Arch.aarch64v8m_mainline,
175 builtin.Arch.aarch64_bev8_3a,
176 builtin.Arch.aarch64_bev8_2a,
177 builtin.Arch.aarch64_bev8_1a,
178 builtin.Arch.aarch64_bev8,
179 builtin.Arch.aarch64_bev8r,
180 builtin.Arch.aarch64_bev8m_baseline,
181 builtin.Arch.aarch64_bev8m_mainline,
182 => true,
183 else => false,
184};
185
186const is_arm_arch = switch (builtin.arch) {
187 builtin.Arch.arm,
188 builtin.Arch.armeb,
189 builtin.Arch.aarch64,
190 builtin.Arch.aarch64_be,
191 builtin.Arch.thumb,
192 builtin.Arch.thumbeb,
193 => true,
194 else => false,
195};
196
197nakedcc fn __aeabi_uidivmod() void {
198 @setRuntimeSafety(false);
199 asm volatile (
200 \\ push { lr }
201 \\ sub sp, sp, #4
202 \\ mov r2, sp
203 \\ bl __udivmodsi4
204 \\ ldr r1, [sp]
205 \\ add sp, sp, #4
206 \\ pop { pc }
207 :
208 :
209 : "r2", "r1"
210 );
211}
212
213// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
214// then decrement %esp by %eax. Preserves all registers except %esp and flags.
215// This routine is windows specific
216// http://msdn.microsoft.com/en-us/library/ms648426.aspx
217nakedcc fn _chkstk() align(4) void {
218 @setRuntimeSafety(false);
219
220 asm volatile (
221 \\ push %%ecx
222 \\ push %%eax
223 \\ cmp $0x1000,%%eax
224 \\ lea 12(%%esp),%%ecx
225 \\ jb 1f
226 \\ 2:
227 \\ sub $0x1000,%%ecx
228 \\ test %%ecx,(%%ecx)
229 \\ sub $0x1000,%%eax
230 \\ cmp $0x1000,%%eax
231 \\ ja 2b
232 \\ 1:
233 \\ sub %%eax,%%ecx
234 \\ test %%ecx,(%%ecx)
235 \\ pop %%eax
236 \\ pop %%ecx
237 \\ ret
238 );
239}
240
241nakedcc fn __chkstk() align(4) void {
242 @setRuntimeSafety(false);
243
244 asm volatile (
245 \\ push %%rcx
246 \\ push %%rax
247 \\ cmp $0x1000,%%rax
248 \\ lea 24(%%rsp),%%rcx
249 \\ jb 1f
250 \\2:
251 \\ sub $0x1000,%%rcx
252 \\ test %%rcx,(%%rcx)
253 \\ sub $0x1000,%%rax
254 \\ cmp $0x1000,%%rax
255 \\ ja 2b
256 \\1:
257 \\ sub %%rax,%%rcx
258 \\ test %%rcx,(%%rcx)
259 \\ pop %%rax
260 \\ pop %%rcx
261 \\ ret
262 );
263}
264
265// _chkstk routine
266// This routine is windows specific
267// http://msdn.microsoft.com/en-us/library/ms648426.aspx
268nakedcc fn __chkstk_ms() align(4) void {
269 @setRuntimeSafety(false);
270
271 asm volatile (
272 \\ push %%ecx
273 \\ push %%eax
274 \\ cmp $0x1000,%%eax
275 \\ lea 12(%%esp),%%ecx
276 \\ jb 1f
277 \\ 2:
278 \\ sub $0x1000,%%ecx
279 \\ test %%ecx,(%%ecx)
280 \\ sub $0x1000,%%eax
281 \\ cmp $0x1000,%%eax
282 \\ ja 2b
283 \\ 1:
284 \\ sub %%eax,%%ecx
285 \\ test %%ecx,(%%ecx)
286 \\ pop %%eax
287 \\ pop %%ecx
288 \\ ret
289 );
290}
291
292nakedcc fn ___chkstk_ms() align(4) void {
293 @setRuntimeSafety(false);
294
295 asm volatile (
296 \\ push %%rcx
297 \\ push %%rax
298 \\ cmp $0x1000,%%rax
299 \\ lea 24(%%rsp),%%rcx
300 \\ jb 1f
301 \\2:
302 \\ sub $0x1000,%%rcx
303 \\ test %%rcx,(%%rcx)
304 \\ sub $0x1000,%%rax
305 \\ cmp $0x1000,%%rax
306 \\ ja 2b
307 \\1:
308 \\ sub %%rax,%%rcx
309 \\ test %%rcx,(%%rcx)
310 \\ pop %%rax
311 \\ pop %%rcx
312 \\ ret
313 );
314}
315
316extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 {
317 @setRuntimeSafety(is_test);
318
319 const d = __udivsi3(a, b);
320 rem.* = @bitCast(u32, @bitCast(i32, a) -% (@bitCast(i32, d) * @bitCast(i32, b)));
321 return d;
322}
323
324extern fn __udivsi3(n: u32, d: u32) u32 {
325 @setRuntimeSafety(is_test);
326
327 const n_uword_bits: c_uint = u32.bit_count;
328 // special cases
329 if (d == 0) return 0; // ?!
330 if (n == 0) return 0;
331 var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
332 // 0 <= sr <= n_uword_bits - 1 or sr large
333 if (sr > n_uword_bits - 1) {
334 // d > r
335 return 0;
336 }
337 if (sr == n_uword_bits - 1) {
338 // d == 1
339 return n;
340 }
341 sr += 1;
342 // 1 <= sr <= n_uword_bits - 1
343 // Not a special case
344 var q: u32 = n << @intCast(u5, n_uword_bits - sr);
345 var r: u32 = n >> @intCast(u5, sr);
346 var carry: u32 = 0;
347 while (sr > 0) : (sr -= 1) {
348 // r:q = ((r:q) << 1) | carry
349 r = (r << 1) | (q >> @intCast(u5, n_uword_bits - 1));
350 q = (q << 1) | carry;
351 // carry = 0;
352 // if (r.all >= d.all)
353 // {
354 // r.all -= d.all;
355 // carry = 1;
356 // }
357 const s = @intCast(i32, d -% r -% 1) >> @intCast(u5, n_uword_bits - 1);
358 carry = @intCast(u32, s & 1);
359 r -= d & @bitCast(u32, s);
360 }
361 q = (q << 1) | carry;
362 return q;
363}
364
365test "test_umoddi3" {
366 test_one_umoddi3(0, 1, 0);
367 test_one_umoddi3(2, 1, 0);
368 test_one_umoddi3(0x8000000000000000, 1, 0x0);
369 test_one_umoddi3(0x8000000000000000, 2, 0x0);
370 test_one_umoddi3(0xFFFFFFFFFFFFFFFF, 2, 0x1);
371}
372
373fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
374 const r = __umoddi3(a, b);
375 testing.expect(r == expected_r);
376}
377
378test "test_udivsi3" {
379 const cases = [][3]u32{
380 []u32{
381 0x00000000,
382 0x00000001,
383 0x00000000,
384 },
385 []u32{
386 0x00000000,
387 0x00000002,
388 0x00000000,
389 },
390 []u32{
391 0x00000000,
392 0x00000003,
393 0x00000000,
394 },
395 []u32{
396 0x00000000,
397 0x00000010,
398 0x00000000,
399 },
400 []u32{
401 0x00000000,
402 0x078644FA,
403 0x00000000,
404 },
405 []u32{
406 0x00000000,
407 0x0747AE14,
408 0x00000000,
409 },
410 []u32{
411 0x00000000,
412 0x7FFFFFFF,
413 0x00000000,
414 },
415 []u32{
416 0x00000000,
417 0x80000000,
418 0x00000000,
419 },
420 []u32{
421 0x00000000,
422 0xFFFFFFFD,
423 0x00000000,
424 },
425 []u32{
426 0x00000000,
427 0xFFFFFFFE,
428 0x00000000,
429 },
430 []u32{
431 0x00000000,
432 0xFFFFFFFF,
433 0x00000000,
434 },
435 []u32{
436 0x00000001,
437 0x00000001,
438 0x00000001,
439 },
440 []u32{
441 0x00000001,
442 0x00000002,
443 0x00000000,
444 },
445 []u32{
446 0x00000001,
447 0x00000003,
448 0x00000000,
449 },
450 []u32{
451 0x00000001,
452 0x00000010,
453 0x00000000,
454 },
455 []u32{
456 0x00000001,
457 0x078644FA,
458 0x00000000,
459 },
460 []u32{
461 0x00000001,
462 0x0747AE14,
463 0x00000000,
464 },
465 []u32{
466 0x00000001,
467 0x7FFFFFFF,
468 0x00000000,
469 },
470 []u32{
471 0x00000001,
472 0x80000000,
473 0x00000000,
474 },
475 []u32{
476 0x00000001,
477 0xFFFFFFFD,
478 0x00000000,
479 },
480 []u32{
481 0x00000001,
482 0xFFFFFFFE,
483 0x00000000,
484 },
485 []u32{
486 0x00000001,
487 0xFFFFFFFF,
488 0x00000000,
489 },
490 []u32{
491 0x00000002,
492 0x00000001,
493 0x00000002,
494 },
495 []u32{
496 0x00000002,
497 0x00000002,
498 0x00000001,
499 },
500 []u32{
501 0x00000002,
502 0x00000003,
503 0x00000000,
504 },
505 []u32{
506 0x00000002,
507 0x00000010,
508 0x00000000,
509 },
510 []u32{
511 0x00000002,
512 0x078644FA,
513 0x00000000,
514 },
515 []u32{
516 0x00000002,
517 0x0747AE14,
518 0x00000000,
519 },
520 []u32{
521 0x00000002,
522 0x7FFFFFFF,
523 0x00000000,
524 },
525 []u32{
526 0x00000002,
527 0x80000000,
528 0x00000000,
529 },
530 []u32{
531 0x00000002,
532 0xFFFFFFFD,
533 0x00000000,
534 },
535 []u32{
536 0x00000002,
537 0xFFFFFFFE,
538 0x00000000,
539 },
540 []u32{
541 0x00000002,
542 0xFFFFFFFF,
543 0x00000000,
544 },
545 []u32{
546 0x00000003,
547 0x00000001,
548 0x00000003,
549 },
550 []u32{
551 0x00000003,
552 0x00000002,
553 0x00000001,
554 },
555 []u32{
556 0x00000003,
557 0x00000003,
558 0x00000001,
559 },
560 []u32{
561 0x00000003,
562 0x00000010,
563 0x00000000,
564 },
565 []u32{
566 0x00000003,
567 0x078644FA,
568 0x00000000,
569 },
570 []u32{
571 0x00000003,
572 0x0747AE14,
573 0x00000000,
574 },
575 []u32{
576 0x00000003,
577 0x7FFFFFFF,
578 0x00000000,
579 },
580 []u32{
581 0x00000003,
582 0x80000000,
583 0x00000000,
584 },
585 []u32{
586 0x00000003,
587 0xFFFFFFFD,
588 0x00000000,
589 },
590 []u32{
591 0x00000003,
592 0xFFFFFFFE,
593 0x00000000,
594 },
595 []u32{
596 0x00000003,
597 0xFFFFFFFF,
598 0x00000000,
599 },
600 []u32{
601 0x00000010,
602 0x00000001,
603 0x00000010,
604 },
605 []u32{
606 0x00000010,
607 0x00000002,
608 0x00000008,
609 },
610 []u32{
611 0x00000010,
612 0x00000003,
613 0x00000005,
614 },
615 []u32{
616 0x00000010,
617 0x00000010,
618 0x00000001,
619 },
620 []u32{
621 0x00000010,
622 0x078644FA,
623 0x00000000,
624 },
625 []u32{
626 0x00000010,
627 0x0747AE14,
628 0x00000000,
629 },
630 []u32{
631 0x00000010,
632 0x7FFFFFFF,
633 0x00000000,
634 },
635 []u32{
636 0x00000010,
637 0x80000000,
638 0x00000000,
639 },
640 []u32{
641 0x00000010,
642 0xFFFFFFFD,
643 0x00000000,
644 },
645 []u32{
646 0x00000010,
647 0xFFFFFFFE,
648 0x00000000,
649 },
650 []u32{
651 0x00000010,
652 0xFFFFFFFF,
653 0x00000000,
654 },
655 []u32{
656 0x078644FA,
657 0x00000001,
658 0x078644FA,
659 },
660 []u32{
661 0x078644FA,
662 0x00000002,
663 0x03C3227D,
664 },
665 []u32{
666 0x078644FA,
667 0x00000003,
668 0x028216FE,
669 },
670 []u32{
671 0x078644FA,
672 0x00000010,
673 0x0078644F,
674 },
675 []u32{
676 0x078644FA,
677 0x078644FA,
678 0x00000001,
679 },
680 []u32{
681 0x078644FA,
682 0x0747AE14,
683 0x00000001,
684 },
685 []u32{
686 0x078644FA,
687 0x7FFFFFFF,
688 0x00000000,
689 },
690 []u32{
691 0x078644FA,
692 0x80000000,
693 0x00000000,
694 },
695 []u32{
696 0x078644FA,
697 0xFFFFFFFD,
698 0x00000000,
699 },
700 []u32{
701 0x078644FA,
702 0xFFFFFFFE,
703 0x00000000,
704 },
705 []u32{
706 0x078644FA,
707 0xFFFFFFFF,
708 0x00000000,
709 },
710 []u32{
711 0x0747AE14,
712 0x00000001,
713 0x0747AE14,
714 },
715 []u32{
716 0x0747AE14,
717 0x00000002,
718 0x03A3D70A,
719 },
720 []u32{
721 0x0747AE14,
722 0x00000003,
723 0x026D3A06,
724 },
725 []u32{
726 0x0747AE14,
727 0x00000010,
728 0x00747AE1,
729 },
730 []u32{
731 0x0747AE14,
732 0x078644FA,
733 0x00000000,
734 },
735 []u32{
736 0x0747AE14,
737 0x0747AE14,
738 0x00000001,
739 },
740 []u32{
741 0x0747AE14,
742 0x7FFFFFFF,
743 0x00000000,
744 },
745 []u32{
746 0x0747AE14,
747 0x80000000,
748 0x00000000,
749 },
750 []u32{
751 0x0747AE14,
752 0xFFFFFFFD,
753 0x00000000,
754 },
755 []u32{
756 0x0747AE14,
757 0xFFFFFFFE,
758 0x00000000,
759 },
760 []u32{
761 0x0747AE14,
762 0xFFFFFFFF,
763 0x00000000,
764 },
765 []u32{
766 0x7FFFFFFF,
767 0x00000001,
768 0x7FFFFFFF,
769 },
770 []u32{
771 0x7FFFFFFF,
772 0x00000002,
773 0x3FFFFFFF,
774 },
775 []u32{
776 0x7FFFFFFF,
777 0x00000003,
778 0x2AAAAAAA,
779 },
780 []u32{
781 0x7FFFFFFF,
782 0x00000010,
783 0x07FFFFFF,
784 },
785 []u32{
786 0x7FFFFFFF,
787 0x078644FA,
788 0x00000011,
789 },
790 []u32{
791 0x7FFFFFFF,
792 0x0747AE14,
793 0x00000011,
794 },
795 []u32{
796 0x7FFFFFFF,
797 0x7FFFFFFF,
798 0x00000001,
799 },
800 []u32{
801 0x7FFFFFFF,
802 0x80000000,
803 0x00000000,
804 },
805 []u32{
806 0x7FFFFFFF,
807 0xFFFFFFFD,
808 0x00000000,
809 },
810 []u32{
811 0x7FFFFFFF,
812 0xFFFFFFFE,
813 0x00000000,
814 },
815 []u32{
816 0x7FFFFFFF,
817 0xFFFFFFFF,
818 0x00000000,
819 },
820 []u32{
821 0x80000000,
822 0x00000001,
823 0x80000000,
824 },
825 []u32{
826 0x80000000,
827 0x00000002,
828 0x40000000,
829 },
830 []u32{
831 0x80000000,
832 0x00000003,
833 0x2AAAAAAA,
834 },
835 []u32{
836 0x80000000,
837 0x00000010,
838 0x08000000,
839 },
840 []u32{
841 0x80000000,
842 0x078644FA,
843 0x00000011,
844 },
845 []u32{
846 0x80000000,
847 0x0747AE14,
848 0x00000011,
849 },
850 []u32{
851 0x80000000,
852 0x7FFFFFFF,
853 0x00000001,
854 },
855 []u32{
856 0x80000000,
857 0x80000000,
858 0x00000001,
859 },
860 []u32{
861 0x80000000,
862 0xFFFFFFFD,
863 0x00000000,
864 },
865 []u32{
866 0x80000000,
867 0xFFFFFFFE,
868 0x00000000,
869 },
870 []u32{
871 0x80000000,
872 0xFFFFFFFF,
873 0x00000000,
874 },
875 []u32{
876 0xFFFFFFFD,
877 0x00000001,
878 0xFFFFFFFD,
879 },
880 []u32{
881 0xFFFFFFFD,
882 0x00000002,
883 0x7FFFFFFE,
884 },
885 []u32{
886 0xFFFFFFFD,
887 0x00000003,
888 0x55555554,
889 },
890 []u32{
891 0xFFFFFFFD,
892 0x00000010,
893 0x0FFFFFFF,
894 },
895 []u32{
896 0xFFFFFFFD,
897 0x078644FA,
898 0x00000022,
899 },
900 []u32{
901 0xFFFFFFFD,
902 0x0747AE14,
903 0x00000023,
904 },
905 []u32{
906 0xFFFFFFFD,
907 0x7FFFFFFF,
908 0x00000001,
909 },
910 []u32{
911 0xFFFFFFFD,
912 0x80000000,
913 0x00000001,
914 },
915 []u32{
916 0xFFFFFFFD,
917 0xFFFFFFFD,
918 0x00000001,
919 },
920 []u32{
921 0xFFFFFFFD,
922 0xFFFFFFFE,
923 0x00000000,
924 },
925 []u32{
926 0xFFFFFFFD,
927 0xFFFFFFFF,
928 0x00000000,
929 },
930 []u32{
931 0xFFFFFFFE,
932 0x00000001,
933 0xFFFFFFFE,
934 },
935 []u32{
936 0xFFFFFFFE,
937 0x00000002,
938 0x7FFFFFFF,
939 },
940 []u32{
941 0xFFFFFFFE,
942 0x00000003,
943 0x55555554,
944 },
945 []u32{
946 0xFFFFFFFE,
947 0x00000010,
948 0x0FFFFFFF,
949 },
950 []u32{
951 0xFFFFFFFE,
952 0x078644FA,
953 0x00000022,
954 },
955 []u32{
956 0xFFFFFFFE,
957 0x0747AE14,
958 0x00000023,
959 },
960 []u32{
961 0xFFFFFFFE,
962 0x7FFFFFFF,
963 0x00000002,
964 },
965 []u32{
966 0xFFFFFFFE,
967 0x80000000,
968 0x00000001,
969 },
970 []u32{
971 0xFFFFFFFE,
972 0xFFFFFFFD,
973 0x00000001,
974 },
975 []u32{
976 0xFFFFFFFE,
977 0xFFFFFFFE,
978 0x00000001,
979 },
980 []u32{
981 0xFFFFFFFE,
982 0xFFFFFFFF,
983 0x00000000,
984 },
985 []u32{
986 0xFFFFFFFF,
987 0x00000001,
988 0xFFFFFFFF,
989 },
990 []u32{
991 0xFFFFFFFF,
992 0x00000002,
993 0x7FFFFFFF,
994 },
995 []u32{
996 0xFFFFFFFF,
997 0x00000003,
998 0x55555555,
999 },
1000 []u32{
1001 0xFFFFFFFF,
1002 0x00000010,
1003 0x0FFFFFFF,
1004 },
1005 []u32{
1006 0xFFFFFFFF,
1007 0x078644FA,
1008 0x00000022,
1009 },
1010 []u32{
1011 0xFFFFFFFF,
1012 0x0747AE14,
1013 0x00000023,
1014 },
1015 []u32{
1016 0xFFFFFFFF,
1017 0x7FFFFFFF,
1018 0x00000002,
1019 },
1020 []u32{
1021 0xFFFFFFFF,
1022 0x80000000,
1023 0x00000001,
1024 },
1025 []u32{
1026 0xFFFFFFFF,
1027 0xFFFFFFFD,
1028 0x00000001,
1029 },
1030 []u32{
1031 0xFFFFFFFF,
1032 0xFFFFFFFE,
1033 0x00000001,
1034 },
1035 []u32{
1036 0xFFFFFFFF,
1037 0xFFFFFFFF,
1038 0x00000001,
1039 },
1040 };
1041
1042 for (cases) |case| {
1043 test_one_udivsi3(case[0], case[1], case[2]);
1044 }
1045}
1046
1047fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void {
1048 const q: u32 = __udivsi3(a, b);
1049 testing.expect(q == expected_q);
1050}
std/special/compiler_rt/muloti4.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const udivmod = @import("udivmod.zig").udivmod;1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");3const compiler_rt = @import("../compiler_rt.zig");
44
5pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {5pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {
6 @setRuntimeSafety(builtin.is_test);6 @setRuntimeSafety(builtin.is_test);
std/special/compiler_rt/multi3.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const compiler_rt = @import("index.zig");2const compiler_rt = @import("../compiler_rt.zig");
33
4// Ported from git@github.com:llvm-project/llvm-project-20170507.git4// Ported from git@github.com:llvm-project/llvm-project-20170507.git
5// ae684fad6d34858c014c94da69c15e7774a633c35// ae684fad6d34858c014c94da69c15e7774a633c3
std/special/compiler_rt/udivmodti4.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const udivmod = @import("udivmod.zig").udivmod;1const udivmod = @import("udivmod.zig").udivmod;
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");3const compiler_rt = @import("../compiler_rt.zig");
44
5pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) u128 {5pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) u128 {
6 @setRuntimeSafety(builtin.is_test);6 @setRuntimeSafety(builtin.is_test);
std/special/compiler_rt/umodti3.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const udivmodti4 = @import("udivmodti4.zig");1const udivmodti4 = @import("udivmodti4.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");3const compiler_rt = @import("../compiler_rt.zig");
44
5pub extern fn __umodti3(a: u128, b: u128) u128 {5pub extern fn __umodti3(a: u128, b: u128) u128 {
6 @setRuntimeSafety(builtin.is_test);6 @setRuntimeSafety(builtin.is_test);
std/special/panic.zig+1-1
...@@ -18,7 +18,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn...@@ -18,7 +18,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
18 std.os.abort();18 std.os.abort();
19 },19 },
20 else => {20 else => {
21 const first_trace_addr = @ptrToInt(@returnAddress());21 const first_trace_addr = @returnAddress();
22 std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);22 std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
23 },23 },
24 }24 }
std/spinlock.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;3const AtomicOrder = builtin.AtomicOrder;
4const AtomicRmwOp = builtin.AtomicRmwOp;4const AtomicRmwOp = builtin.AtomicRmwOp;
std/statically_initialized_mutex.zig+5-8
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("index.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;3const AtomicOrder = builtin.AtomicOrder;
4const AtomicRmwOp = builtin.AtomicRmwOp;4const AtomicRmwOp = builtin.AtomicRmwOp;
...@@ -13,7 +13,7 @@ const windows = std.os.windows;...@@ -13,7 +13,7 @@ const windows = std.os.windows;
13/// On Windows, this mutex allocates resources when it is13/// On Windows, this mutex allocates resources when it is
14/// first used, and the resources cannot be freed.14/// first used, and the resources cannot be freed.
15/// On Linux, this is an alias of std.Mutex.15/// On Linux, this is an alias of std.Mutex.
16pub const StaticallyInitializedMutex = switch(builtin.os) {16pub const StaticallyInitializedMutex = switch (builtin.os) {
17 builtin.Os.linux => std.Mutex,17 builtin.Os.linux => std.Mutex,
18 builtin.Os.windows => struct {18 builtin.Os.windows => struct {
19 lock: windows.CRITICAL_SECTION,19 lock: windows.CRITICAL_SECTION,
...@@ -28,7 +28,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {...@@ -28,7 +28,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {
28 };28 };
2929
30 pub fn init() StaticallyInitializedMutex {30 pub fn init() StaticallyInitializedMutex {
31 return StaticallyInitializedMutex {31 return StaticallyInitializedMutex{
32 .lock = undefined,32 .lock = undefined,
33 .init_once = windows.INIT_ONCE_STATIC_INIT,33 .init_once = windows.INIT_ONCE_STATIC_INIT,
34 };34 };
...@@ -54,7 +54,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {...@@ -54,7 +54,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {
54 pub fn acquire(self: *StaticallyInitializedMutex) Held {54 pub fn acquire(self: *StaticallyInitializedMutex) Held {
55 assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);55 assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
56 windows.EnterCriticalSection(&self.lock);56 windows.EnterCriticalSection(&self.lock);
57 return Held { .mutex = self };57 return Held{ .mutex = self };
58 }58 }
59 },59 },
60 else => std.Mutex,60 else => std.Mutex,
...@@ -89,10 +89,7 @@ test "std.StaticallyInitializedMutex" {...@@ -89,10 +89,7 @@ test "std.StaticallyInitializedMutex" {
89 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);89 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
90 var a = &fixed_buffer_allocator.allocator;90 var a = &fixed_buffer_allocator.allocator;
9191
9292 var context = TestContext{ .data = 0 };
93 var context = TestContext{
94 .data = 0,
95 };
9693
97 if (builtin.single_threaded) {94 if (builtin.single_threaded) {
98 TestContext.worker(&context);95 TestContext.worker(&context);
std/std.zig created+95
...@@ -0,0 +1,95 @@
1pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
2pub const ArrayList = @import("array_list.zig").ArrayList;
3pub const AutoHashMap = @import("hash_map.zig").AutoHashMap;
4pub const BufMap = @import("buf_map.zig").BufMap;
5pub const BufSet = @import("buf_set.zig").BufSet;
6pub const Buffer = @import("buffer.zig").Buffer;
7pub const BufferOutStream = @import("io.zig").BufferOutStream;
8pub const DynLib = @import("dynamic_library.zig").DynLib;
9pub const HashMap = @import("hash_map.zig").HashMap;
10pub const LinkedList = @import("linked_list.zig").LinkedList;
11pub const Mutex = @import("mutex.zig").Mutex;
12pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
13pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
14pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
15pub const SpinLock = @import("spinlock.zig").SpinLock;
16
17pub const atomic = @import("atomic.zig");
18pub const base64 = @import("base64.zig");
19pub const build = @import("build.zig");
20pub const c = @import("c.zig");
21pub const coff = @import("coff.zig");
22pub const crypto = @import("crypto.zig");
23pub const cstr = @import("cstr.zig");
24pub const debug = @import("debug.zig");
25pub const dwarf = @import("dwarf.zig");
26pub const elf = @import("elf.zig");
27pub const empty_import = @import("empty.zig");
28pub const event = @import("event.zig");
29pub const fmt = @import("fmt.zig");
30pub const hash = @import("hash.zig");
31pub const hash_map = @import("hash_map.zig");
32pub const heap = @import("heap.zig");
33pub const io = @import("io.zig");
34pub const json = @import("json.zig");
35pub const lazyInit = @import("lazy_init.zig").lazyInit;
36pub const macho = @import("macho.zig");
37pub const math = @import("math.zig");
38pub const mem = @import("mem.zig");
39pub const meta = @import("meta.zig");
40pub const net = @import("net.zig");
41pub const os = @import("os.zig");
42pub const pdb = @import("pdb.zig");
43pub const rand = @import("rand.zig");
44pub const rb = @import("rb.zig");
45pub const sort = @import("sort.zig");
46pub const testing = @import("testing.zig");
47pub const unicode = @import("unicode.zig");
48pub const zig = @import("zig.zig");
49
50test "std" {
51 // run tests from these
52 _ = @import("array_list.zig");
53 _ = @import("atomic.zig");
54 _ = @import("buf_map.zig");
55 _ = @import("buf_set.zig");
56 _ = @import("buffer.zig");
57 _ = @import("hash_map.zig");
58 _ = @import("linked_list.zig");
59 _ = @import("mutex.zig");
60 _ = @import("statically_initialized_mutex.zig");
61 _ = @import("segmented_list.zig");
62 _ = @import("spinlock.zig");
63
64 _ = @import("base64.zig");
65 _ = @import("build.zig");
66 _ = @import("c.zig");
67 _ = @import("coff.zig");
68 _ = @import("crypto.zig");
69 _ = @import("cstr.zig");
70 _ = @import("debug.zig");
71 _ = @import("dwarf.zig");
72 _ = @import("dynamic_library.zig");
73 _ = @import("elf.zig");
74 _ = @import("empty.zig");
75 _ = @import("event.zig");
76 _ = @import("fmt.zig");
77 _ = @import("hash.zig");
78 _ = @import("heap.zig");
79 _ = @import("io.zig");
80 _ = @import("json.zig");
81 _ = @import("lazy_init.zig");
82 _ = @import("macho.zig");
83 _ = @import("math.zig");
84 _ = @import("mem.zig");
85 _ = @import("meta.zig");
86 _ = @import("net.zig");
87 _ = @import("os.zig");
88 _ = @import("pdb.zig");
89 _ = @import("priority_queue.zig");
90 _ = @import("rand.zig");
91 _ = @import("sort.zig");
92 _ = @import("testing.zig");
93 _ = @import("unicode.zig");
94 _ = @import("zig.zig");
95}
std/testing.zig+1-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const TypeId = builtin.TypeId;2const TypeId = builtin.TypeId;
3const std = @import("index.zig");3const std = @import("std.zig");
44
5/// This function is intended to be used only in tests. It prints diagnostics to stderr5/// This function is intended to be used only in tests. It prints diagnostics to stderr
6/// and then aborts when actual_error_union is not expected_error.6/// and then aborts when actual_error_union is not expected_error.
...@@ -44,7 +44,6 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -44,7 +44,6 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
44 TypeId.ComptimeFloat,44 TypeId.ComptimeFloat,
45 TypeId.ComptimeInt,45 TypeId.ComptimeInt,
46 TypeId.Enum,46 TypeId.Enum,
47 TypeId.Namespace,
48 TypeId.Fn,47 TypeId.Fn,
49 TypeId.Promise,48 TypeId.Promise,
50 TypeId.Vector,49 TypeId.Vector,
std/unicode.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("./index.zig");1const std = @import("./std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
std/zig.zig created+16
...@@ -0,0 +1,16 @@
1const tokenizer = @import("zig/tokenizer.zig");
2pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;
4pub const parse = @import("zig/parse.zig").parse;
5pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStringLiteral;
6pub const render = @import("zig/render.zig").render;
7pub const ast = @import("zig/ast.zig");
8
9test "std.zig tests" {
10 _ = @import("zig/ast.zig");
11 _ = @import("zig/parse.zig");
12 _ = @import("zig/render.zig");
13 _ = @import("zig/tokenizer.zig");
14 _ = @import("zig/parse_string_literal.zig");
15}
16
std/zig/ast.zig+7-7
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const SegmentedList = std.SegmentedList;4const SegmentedList = std.SegmentedList;
...@@ -617,7 +617,7 @@ pub const Node = struct {...@@ -617,7 +617,7 @@ pub const Node = struct {
617617
618 pub const DeclList = Root.DeclList;618 pub const DeclList = Root.DeclList;
619619
620 const InitArg = union(enum) {620 pub const InitArg = union(enum) {
621 None,621 None,
622 Enum: ?*Node,622 Enum: ?*Node,
623 Type: *Node,623 Type: *Node,
...@@ -1744,7 +1744,7 @@ pub const Node = struct {...@@ -1744,7 +1744,7 @@ pub const Node = struct {
1744 kind: Kind,1744 kind: Kind,
1745 rhs: ?*Node,1745 rhs: ?*Node,
17461746
1747 const Kind = union(enum) {1747 pub const Kind = union(enum) {
1748 Break: ?*Node,1748 Break: ?*Node,
1749 Continue: ?*Node,1749 Continue: ?*Node,
1750 Return,1750 Return,
...@@ -2022,7 +2022,7 @@ pub const Node = struct {...@@ -2022,7 +2022,7 @@ pub const Node = struct {
2022 kind: Kind,2022 kind: Kind,
2023 rparen: TokenIndex,2023 rparen: TokenIndex,
20242024
2025 const Kind = union(enum) {2025 pub const Kind = union(enum) {
2026 Variable: *Identifier,2026 Variable: *Identifier,
2027 Return: *Node,2027 Return: *Node,
2028 };2028 };
...@@ -2101,9 +2101,9 @@ pub const Node = struct {...@@ -2101,9 +2101,9 @@ pub const Node = struct {
2101 clobbers: ClobberList,2101 clobbers: ClobberList,
2102 rparen: TokenIndex,2102 rparen: TokenIndex,
21032103
2104 const OutputList = SegmentedList(*AsmOutput, 2);2104 pub const OutputList = SegmentedList(*AsmOutput, 2);
2105 const InputList = SegmentedList(*AsmInput, 2);2105 pub const InputList = SegmentedList(*AsmInput, 2);
2106 const ClobberList = SegmentedList(TokenIndex, 2);2106 pub const ClobberList = SegmentedList(TokenIndex, 2);
21072107
2108 pub fn iterate(self: *Asm, index: usize) ?*Node {2108 pub fn iterate(self: *Asm, index: usize) ?*Node {
2109 var i = index;2109 var i = index;
std/zig/bench.zig+1-1
...@@ -5,7 +5,7 @@ const Tokenizer = std.zig.Tokenizer;...@@ -5,7 +5,7 @@ const Tokenizer = std.zig.Tokenizer;
5const Parser = std.zig.Parser;5const Parser = std.zig.Parser;
6const io = std.io;6const io = std.io;
77
8const source = @embedFile("../os/index.zig");8const source = @embedFile("../os.zig");
9var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;9var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
1010
11pub fn main() !void {11pub fn main() !void {
std/zig/index.zig deleted-16
...@@ -1,16 +0,0 @@
1const tokenizer = @import("tokenizer.zig");
2pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;
4pub const parse = @import("parse.zig").parse;
5pub const parseStringLiteral = @import("parse_string_literal.zig").parseStringLiteral;
6pub const render = @import("render.zig").render;
7pub const ast = @import("ast.zig");
8
9test "std.zig tests" {
10 _ = @import("ast.zig");
11 _ = @import("parse.zig");
12 _ = @import("render.zig");
13 _ = @import("tokenizer.zig");
14 _ = @import("parse_string_literal.zig");
15}
16
std/zig/parse.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const mem = std.mem;3const mem = std.mem;
4const ast = std.zig.ast;4const ast = std.zig.ast;
std/zig/parse_string_literal.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
33
4const State = enum {4const State = enum {
std/zig/render.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const mem = std.mem;4const mem = std.mem;
std/zig/tokenizer.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1const std = @import("../index.zig");1const std = @import("../std.zig");
2const mem = std.mem;2const mem = std.mem;
33
4pub const Token = struct {4pub const Token = struct {
test/build_examples.zig+2
...@@ -7,8 +7,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {...@@ -7,8 +7,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
7 cases.addC("example/hello_world/hello_libc.zig");7 cases.addC("example/hello_world/hello_libc.zig");
8 cases.add("example/cat/main.zig");8 cases.add("example/cat/main.zig");
9 cases.add("example/guess_number/main.zig");9 cases.add("example/guess_number/main.zig");
10 cases.addBuildFile("test/standalone/main_pkg_path/build.zig");
10 cases.addBuildFile("example/shared_library/build.zig");11 cases.addBuildFile("example/shared_library/build.zig");
11 cases.addBuildFile("example/mix_o_files/build.zig");12 cases.addBuildFile("example/mix_o_files/build.zig");
13 cases.addBuildFile("test/standalone/static_c_lib/build.zig");
12 if (builtin.os != builtin.Os.macosx) {14 if (builtin.os != builtin.Os.macosx) {
13 // TODO https://github.com/ziglang/zig/issues/112615 // TODO https://github.com/ziglang/zig/issues/1126
14 cases.addBuildFile("test/standalone/issue_339/build.zig");16 cases.addBuildFile("test/standalone/issue_339/build.zig");
test/compile_errors.zig+701-690
...@@ -2,6 +2,122 @@ const tests = @import("tests.zig");...@@ -2,6 +2,122 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "import outside package path",
7 \\comptime{
8 \\ _ = @import("../a.zig");
9 \\}
10 ,
11 "tmp.zig:2:9: error: import of file outside package path: '../a.zig'",
12 );
13
14 cases.add(
15 "bogus compile var",
16 \\const x = @import("builtin").bogus;
17 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
18 ,
19 "tmp.zig:1:29: error: container 'builtin' has no member called 'bogus'",
20 );
21
22 cases.add(
23 "wrong panic signature, runtime function",
24 \\test "" {}
25 \\
26 \\pub fn panic() void {}
27 \\
28 ,
29 "tmp.zig:3:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() void'",
30 );
31
32 cases.add(
33 "wrong panic signature, generic function",
34 \\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
35 \\ while (true) {}
36 \\}
37 ,
38 "tmp.zig:1:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn([]const u8,var)var'",
39 "tmp.zig:1:5: note: only one of the functions is generic",
40 );
41
42 cases.add(
43 "direct struct loop",
44 \\const A = struct { a : A, };
45 \\export fn entry() usize { return @sizeOf(A); }
46 ,
47 "tmp.zig:1:11: error: struct 'A' contains itself",
48 );
49
50 cases.add(
51 "indirect struct loop",
52 \\const A = struct { b : B, };
53 \\const B = struct { c : C, };
54 \\const C = struct { a : A, };
55 \\export fn entry() usize { return @sizeOf(A); }
56 ,
57 "tmp.zig:1:11: error: struct 'A' contains itself",
58 );
59
60 cases.add(
61 "instantiating an undefined value for an invalid struct that contains itself",
62 \\const Foo = struct {
63 \\ x: Foo,
64 \\};
65 \\
66 \\var foo: Foo = undefined;
67 \\
68 \\export fn entry() usize {
69 \\ return @sizeOf(@typeOf(foo.x));
70 \\}
71 ,
72 "tmp.zig:1:13: error: struct 'Foo' contains itself",
73 "tmp.zig:8:28: note: referenced here",
74 );
75
76 cases.add(
77 "@typeInfo causing depend on itself compile error",
78 \\const start = struct {
79 \\ fn crash() bug() {
80 \\ return bug;
81 \\ }
82 \\};
83 \\fn bug() void {
84 \\ _ = @typeInfo(start).Struct;
85 \\}
86 \\export fn entry() void {
87 \\ var boom = start.crash();
88 \\}
89 ,
90 "tmp.zig:7:9: error: dependency loop detected",
91 "tmp.zig:2:19: note: called from here",
92 "tmp.zig:10:21: note: referenced here",
93 );
94
95 cases.add(
96 "enum field value references enum",
97 \\pub const Foo = extern enum {
98 \\ A = Foo.B,
99 \\ C = D,
100 \\};
101 \\export fn entry() void {
102 \\ var s: Foo = Foo.E;
103 \\}
104 ,
105 "tmp.zig:1:17: error: 'Foo' depends on itself",
106 );
107
108 cases.add(
109 "top level decl dependency loop",
110 \\const a : @typeOf(b) = 0;
111 \\const b : @typeOf(a) = 0;
112 \\export fn entry() void {
113 \\ const c = a + b;
114 \\}
115 ,
116 "tmp.zig:2:19: error: dependency loop detected",
117 "tmp.zig:1:19: note: referenced here",
118 "tmp.zig:4:15: note: referenced here",
119 );
120
5 cases.addTest(121 cases.addTest(
6 "not an enum type",122 "not an enum type",
7 \\export fn entry() void {123 \\export fn entry() void {
...@@ -18,7 +134,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -18,7 +134,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18 \\const InvalidToken = struct {};134 \\const InvalidToken = struct {};
19 \\const ExpectedVarDeclOrFn = struct {};135 \\const ExpectedVarDeclOrFn = struct {};
20 ,136 ,
21 ".tmp_source.zig:4:9: error: not an enum type",137 "tmp.zig:4:9: error: not an enum type",
22 );138 );
23139
24 cases.addTest(140 cases.addTest(
...@@ -29,7 +145,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -29,7 +145,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29 \\ var x: AB = undefined;145 \\ var x: AB = undefined;
30 \\}146 \\}
31 ,147 ,
32 ".tmp_source.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",148 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
33 );149 );
34150
35 if (builtin.os == builtin.Os.linux) {151 if (builtin.os == builtin.Os.linux) {
...@@ -40,7 +156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -40,7 +156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40 \\ exit(0);156 \\ exit(0);
41 \\}157 \\}
42 ,158 ,
43 ".tmp_source.zig:3:5: error: dependency on library c must be explicitly specified in the build command",159 "tmp.zig:3:5: error: dependency on library c must be explicitly specified in the build command",
44 );160 );
45161
46 cases.addTest(162 cases.addTest(
...@@ -50,8 +166,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -50,8 +166,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50 \\ _ = c.printf(c"hello, world!\n");166 \\ _ = c.printf(c"hello, world!\n");
51 \\}167 \\}
52 ,168 ,
53 ".tmp_source.zig:1:11: error: C import failed",169 "tmp.zig:1:11: error: C import failed",
54 ".tmp_source.zig:1:11: note: libc headers not available; compilation does not link against libc",170 "tmp.zig:1:11: note: libc headers not available; compilation does not link against libc",
55 );171 );
56 }172 }
57173
...@@ -63,8 +179,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -63,8 +179,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
63 \\ var x = a + b;179 \\ var x = a + b;
64 \\}180 \\}
65 ,181 ,
66 ".tmp_source.zig:4:15: error: operation caused overflow",182 "tmp.zig:4:15: error: operation caused overflow",
67 ".tmp_source.zig:4:15: note: when computing vector element at index 2",183 "tmp.zig:4:15: note: when computing vector element at index 2",
68 );184 );
69185
70 cases.addTest(186 cases.addTest(
...@@ -111,14 +227,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -111,14 +227,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
111 \\ B,227 \\ B,
112 \\};228 \\};
113 ,229 ,
114 ".tmp_source.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",230 "tmp.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
115 ".tmp_source.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",231 "tmp.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",
116 ".tmp_source.zig:8:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",232 "tmp.zig:8:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
117 ".tmp_source.zig:11:5: error: non-packed, non-extern struct 'S' not allowed in packed struct; no guaranteed in-memory representation",233 "tmp.zig:11:5: error: non-packed, non-extern struct 'S' not allowed in packed struct; no guaranteed in-memory representation",
118 ".tmp_source.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",234 "tmp.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
119 ".tmp_source.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",235 "tmp.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
120 ".tmp_source.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",236 "tmp.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
121 ".tmp_source.zig:38:14: note: enum declaration does not specify an integer tag type",237 "tmp.zig:38:14: note: enum declaration does not specify an integer tag type",
122 );238 );
123239
124 cases.addCase(x: {240 cases.addCase(x: {
...@@ -131,7 +247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -131,7 +247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
131 \\ x += 1;247 \\ x += 1;
132 \\}248 \\}
133 ,249 ,
134 ".tmp_source.zig:2:5: error: use of undeclared identifier 'x'",250 "tmp.zig:2:5: error: use of undeclared identifier 'x'",
135 );251 );
136 tc.expect_exact = true;252 tc.expect_exact = true;
137 break :x tc;253 break :x tc;
...@@ -143,7 +259,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -143,7 +259,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
143 \\ return 0;259 \\ return 0;
144 \\}260 \\}
145 ,261 ,
146 ".tmp_source.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'",262 "tmp.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'",
147 );263 );
148264
149 cases.addTest(265 cases.addTest(
...@@ -153,7 +269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -153,7 +269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
153 \\ var y: [*c]c_void = x;269 \\ var y: [*c]c_void = x;
154 \\}270 \\}
155 ,271 ,
156 ".tmp_source.zig:3:12: error: C pointers cannot point opaque types",272 "tmp.zig:3:12: error: C pointers cannot point opaque types",
157 );273 );
158274
159 cases.addTest(275 cases.addTest(
...@@ -173,8 +289,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -173,8 +289,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
173 \\ var bar: Bar = undefined;289 \\ var bar: Bar = undefined;
174 \\}290 \\}
175 ,291 ,
176 ".tmp_source.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",292 "tmp.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
177 ".tmp_source.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",293 "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
178 );294 );
179295
180 cases.addTest(296 cases.addTest(
...@@ -204,13 +320,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -204,13 +320,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
204 \\ var x: [*c]u32 = y;320 \\ var x: [*c]u32 = y;
205 \\}321 \\}
206 ,322 ,
207 ".tmp_source.zig:3:27: error: cast increases pointer alignment",323 "tmp.zig:3:27: error: cast increases pointer alignment",
208 ".tmp_source.zig:7:18: error: cast discards const qualifier",324 "tmp.zig:7:18: error: cast discards const qualifier",
209 ".tmp_source.zig:11:19: error: expected type '*u32', found '[*c]u8'",325 "tmp.zig:11:19: error: expected type '*u32', found '[*c]u8'",
210 ".tmp_source.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",326 "tmp.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
211 ".tmp_source.zig:15:22: error: cast increases pointer alignment",327 "tmp.zig:15:22: error: cast increases pointer alignment",
212 ".tmp_source.zig:19:21: error: cast discards const qualifier",328 "tmp.zig:19:21: error: cast discards const qualifier",
213 ".tmp_source.zig:23:22: error: expected type '[*c]u32', found '*u8'",329 "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'",
214 );330 );
215331
216 cases.addTest(332 cases.addTest(
...@@ -220,7 +336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -220,7 +336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
220 \\ var zig_ptr: *u8 = c_ptr;336 \\ var zig_ptr: *u8 = c_ptr;
221 \\}337 \\}
222 ,338 ,
223 ".tmp_source.zig:3:24: error: null pointer casted to type '*u8'",339 "tmp.zig:3:24: error: null pointer casted to type '*u8'",
224 );340 );
225341
226 cases.addTest(342 cases.addTest(
...@@ -230,7 +346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -230,7 +346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
230 \\ var zig_ptr: *u8 = c_ptr;346 \\ var zig_ptr: *u8 = c_ptr;
231 \\}347 \\}
232 ,348 ,
233 ".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior",349 "tmp.zig:3:24: error: use of undefined value here causes undefined behavior",
234 );350 );
235351
236 cases.addTest(352 cases.addTest(
...@@ -250,12 +366,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -250,12 +366,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
250 \\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;366 \\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
251 \\}367 \\}
252 ,368 ,
253 ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",369 "tmp.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
254 ".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",370 "tmp.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
255 ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",371 "tmp.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
256 ".tmp_source.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",372 "tmp.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
257 ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",373 "tmp.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
258 ".tmp_source.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",374 "tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
259 );375 );
260376
261 cases.addTest(377 cases.addTest(
...@@ -268,8 +384,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -268,8 +384,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
268 \\ var ptr: [*c]u8 = x;384 \\ var ptr: [*c]u8 = x;
269 \\}385 \\}
270 ,386 ,
271 ".tmp_source.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",387 "tmp.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",
272 ".tmp_source.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",388 "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
273 );389 );
274390
275 cases.addTest(391 cases.addTest(
...@@ -279,7 +395,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -279,7 +395,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
279 \\ const T = [*c]Foo;395 \\ const T = [*c]Foo;
280 \\}396 \\}
281 ,397 ,
282 ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",398 "tmp.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
283 );399 );
284400
285 cases.addCase(x: {401 cases.addCase(x: {
...@@ -294,7 +410,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -294,7 +410,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
294 \\ inline while (i < n) : (i += 1) { @compileLog("!@#$"); }410 \\ inline while (i < n) : (i += 1) { @compileLog("!@#$"); }
295 \\}411 \\}
296 ,412 ,
297 ".tmp_source.zig:7:39: error: found compile log statement",413 "tmp.zig:7:39: error: found compile log statement",
298 );414 );
299 tc.expect_exact = true;415 tc.expect_exact = true;
300 break :x tc;416 break :x tc;
...@@ -306,7 +422,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -306,7 +422,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
306 \\ 'a'.* = 1;422 \\ 'a'.* = 1;
307 \\}423 \\}
308 ,424 ,
309 ".tmp_source.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",425 "tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",
310 );426 );
311427
312 cases.addTest(428 cases.addTest(
...@@ -315,7 +431,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -315,7 +431,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
315 \\ const x = 'a'.*[0..];431 \\ const x = 'a'.*[0..];
316 \\}432 \\}
317 ,433 ,
318 ".tmp_source.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",434 "tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",
319 );435 );
320436
321 cases.addTest(437 cases.addTest(
...@@ -324,14 +440,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -324,14 +440,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
324 \\ var z = @truncate(u8, u16(undefined));440 \\ var z = @truncate(u8, u16(undefined));
325 \\}441 \\}
326 ,442 ,
327 ".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior",443 "tmp.zig:2:30: error: use of undefined value here causes undefined behavior",
328 );444 );
329445
330 cases.addTest(446 cases.addTest(
331 "return invalid type from test",447 "return invalid type from test",
332 \\test "example" { return 1; }448 \\test "example" { return 1; }
333 ,449 ,
334 ".tmp_source.zig:1:25: error: integer value 1 cannot be implicitly casted to type 'void'",450 "tmp.zig:1:25: error: integer value 1 cannot be implicitly casted to type 'void'",
335 );451 );
336452
337 cases.add(453 cases.add(
...@@ -341,7 +457,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -341,7 +457,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
341 \\ return x;457 \\ return x;
342 \\}458 \\}
343 ,459 ,
344 ".tmp_source.zig:1:13: error: threadlocal variable cannot be constant",460 "tmp.zig:1:13: error: threadlocal variable cannot be constant",
345 );461 );
346462
347 cases.add(463 cases.add(
...@@ -350,7 +466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -350,7 +466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
350 \\ threadlocal var x: i32 = 1234;466 \\ threadlocal var x: i32 = 1234;
351 \\}467 \\}
352 ,468 ,
353 ".tmp_source.zig:2:5: error: function-local variable 'x' cannot be threadlocal",469 "tmp.zig:2:5: error: function-local variable 'x' cannot be threadlocal",
354 );470 );
355471
356 cases.add(472 cases.add(
...@@ -359,7 +475,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -359,7 +475,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
359 \\ var oops = @bitCast(u7, byte);475 \\ var oops = @bitCast(u7, byte);
360 \\}476 \\}
361 ,477 ,
362 ".tmp_source.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",478 "tmp.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
363 );479 );
364480
365 cases.add(481 cases.add(
...@@ -371,7 +487,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -371,7 +487,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
371 \\ return 5678;487 \\ return 5678;
372 \\}488 \\}
373 ,489 ,
374 ".tmp_source.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.",490 "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.",
375 );491 );
376492
377 cases.add(493 cases.add(
...@@ -383,8 +499,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -383,8 +499,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
383 \\ return 5678;499 \\ return 5678;
384 \\}500 \\}
385 ,501 ,
386 ".tmp_source.zig:2:9: error: expected error set type, found 'bool'",502 "tmp.zig:2:9: error: expected error set type, found 'bool'",
387 ".tmp_source.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",503 "tmp.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
388 );504 );
389505
390 cases.add(506 cases.add(
...@@ -393,7 +509,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -393,7 +509,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
393 \\ @compileLog(@ptrCast(*const c_void, &entry));509 \\ @compileLog(@ptrCast(*const c_void, &entry));
394 \\}510 \\}
395 ,511 ,
396 ".tmp_source.zig:2:5: error: found compile log statement",512 "tmp.zig:2:5: error: found compile log statement",
397 );513 );
398514
399 cases.add(515 cases.add(
...@@ -413,8 +529,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -413,8 +529,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
413 \\ };529 \\ };
414 \\}530 \\}
415 ,531 ,
416 ".tmp_source.zig:5:9: error: duplicate switch value",532 "tmp.zig:5:9: error: duplicate switch value",
417 ".tmp_source.zig:12:9: error: duplicate switch value",533 "tmp.zig:12:9: error: duplicate switch value",
418 );534 );
419535
420 cases.add(536 cases.add(
...@@ -430,8 +546,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -430,8 +546,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
430 \\ };546 \\ };
431 \\}547 \\}
432 ,548 ,
433 ".tmp_source.zig:2:15: error: switch must handle all possibilities",549 "tmp.zig:2:15: error: switch must handle all possibilities",
434 ".tmp_source.zig:7:15: error: switch must handle all possibilities",550 "tmp.zig:7:15: error: switch must handle all possibilities",
435 );551 );
436552
437 cases.add(553 cases.add(
...@@ -443,7 +559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -443,7 +559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
443 \\ const deref = int_ptr.*;559 \\ const deref = int_ptr.*;
444 \\}560 \\}
445 ,561 ,
446 ".tmp_source.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",562 "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
447 );563 );
448564
449 cases.add(565 cases.add(
...@@ -454,8 +570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -454,8 +570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
454 \\ do_the_thing(bar);570 \\ do_the_thing(bar);
455 \\}571 \\}
456 ,572 ,
457 ".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",573 "tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
458 ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",574 "tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
459 );575 );
460576
461 cases.add(577 cases.add(
...@@ -469,8 +585,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -469,8 +585,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
469 \\ const unsigned: u32 = value;585 \\ const unsigned: u32 = value;
470 \\}586 \\}
471 ,587 ,
472 ".tmp_source.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'",588 "tmp.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'",
473 ".tmp_source.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",589 "tmp.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
474 );590 );
475591
476 cases.add(592 cases.add(
...@@ -488,9 +604,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -488,9 +604,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
488 \\ var byte: u8 = spartan_count;604 \\ var byte: u8 = spartan_count;
489 \\}605 \\}
490 ,606 ,
491 ".tmp_source.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'",607 "tmp.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'",
492 ".tmp_source.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'",608 "tmp.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'",
493 ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'",609 "tmp.zig:11:20: error: expected type 'u8', found 'u16'",
494 );610 );
495611
496 cases.add(612 cases.add(
...@@ -500,7 +616,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -500,7 +616,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
500 \\ const y: f32 = x;616 \\ const y: f32 = x;
501 \\}617 \\}
502 ,618 ,
503 ".tmp_source.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information",619 "tmp.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information",
504 );620 );
505621
506 cases.add(622 cases.add(
...@@ -510,7 +626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -510,7 +626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
510 \\626 \\
511 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }627 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
512 ,628 ,
513 ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'",629 "tmp.zig:2:14: error: expected type 'f32', found 'f64'",
514 );630 );
515631
516 cases.add(632 cases.add(
...@@ -522,28 +638,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -522,28 +638,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
522 \\ var x: i65536 = 1;638 \\ var x: i65536 = 1;
523 \\}639 \\}
524 ,640 ,
525 ".tmp_source.zig:2:31: error: integer value 65536 cannot be implicitly casted to type 'u16'",641 "tmp.zig:2:31: error: integer value 65536 cannot be implicitly casted to type 'u16'",
526 ".tmp_source.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",642 "tmp.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",
527 );
528
529 cases.add(
530 "wrong panic signature, runtime function",
531 \\test "" {}
532 \\
533 \\pub fn panic() void {}
534 \\
535 ,
536 ".tmp_source.zig:3:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn() void'",
537 );
538
539 cases.add(
540 "wrong panic signature, generic function",
541 \\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
542 \\ while (true) {}
543 \\}
544 ,
545 ".tmp_source.zig:1:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn([]const u8,var)var'",
546 ".tmp_source.zig:1:5: note: only one of the functions is generic",
547 );643 );
548644
549 cases.add(645 cases.add(
...@@ -556,7 +652,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -556,7 +652,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
556 \\ const car = Car.init();652 \\ const car = Car.init();
557 \\}653 \\}
558 ,654 ,
559 ".tmp_source.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",655 "tmp.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",
560 );656 );
561657
562 cases.add(658 cases.add(
...@@ -568,7 +664,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -568,7 +664,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
568 \\ var ptr2: *c_void = &b;664 \\ var ptr2: *c_void = &b;
569 \\}665 \\}
570 ,666 ,
571 ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'",667 "tmp.zig:5:26: error: expected type '*c_void', found '**u32'",
572 );668 );
573669
574 cases.add(670 cases.add(
...@@ -584,7 +680,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -584,7 +680,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
584 \\ const field = @typeInfo(Struct).Struct.fields[index];680 \\ const field = @typeInfo(Struct).Struct.fields[index];
585 \\}681 \\}
586 ,682 ,
587 ".tmp_source.zig:9:51: error: values of type 'StructField' must be comptime known, but index value is runtime known",683 "tmp.zig:9:51: error: values of type 'builtin.StructField' must be comptime known, but index value is runtime known",
588 );684 );
589685
590 cases.add(686 cases.add(
...@@ -598,7 +694,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -598,7 +694,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
598 \\ _ = @typeName(Foo(i32));694 \\ _ = @typeName(Foo(i32));
599 \\}695 \\}
600 ,696 ,
601 ".tmp_source.zig:2:5: error: found compile log statement",697 "tmp.zig:2:5: error: found compile log statement",
602 );698 );
603699
604 cases.add(700 cases.add(
...@@ -608,7 +704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -608,7 +704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
608 \\ var b = a[0..10];704 \\ var b = a[0..10];
609 \\}705 \\}
610 ,706 ,
611 ".tmp_source.zig:3:14: error: slice of undefined",707 "tmp.zig:3:14: error: slice of undefined",
612 );708 );
613709
614 cases.add(710 cases.add(
...@@ -618,7 +714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -618,7 +714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
618 \\ const sliceA: []u8 = &buffer;714 \\ const sliceA: []u8 = &buffer;
619 \\}715 \\}
620 ,716 ,
621 ".tmp_source.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",717 "tmp.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",
622 );718 );
623719
624 cases.add(720 cases.add(
...@@ -628,7 +724,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -628,7 +724,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
628 \\ _ = a.*.len;724 \\ _ = a.*.len;
629 \\}725 \\}
630 ,726 ,
631 ".tmp_source.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",727 "tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",
632 );728 );
633729
634 cases.add(730 cases.add(
...@@ -639,9 +735,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -639,9 +735,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
639 \\ return p == null;735 \\ return p == null;
640 \\}736 \\}
641 ,737 ,
642 ".tmp_source.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation",738 "tmp.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation",
643 ".tmp_source.zig:3:31: note: '*u0' has no in-memory bits",739 "tmp.zig:3:31: note: '*u0' has no in-memory bits",
644 ".tmp_source.zig:3:24: note: '?*u0' has in-memory bits",740 "tmp.zig:3:24: note: '?*u0' has in-memory bits",
645 );741 );
646742
647 cases.add(743 cases.add(
...@@ -651,7 +747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -651,7 +747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
651 \\ _ = &x == null;747 \\ _ = &x == null;
652 \\}748 \\}
653 ,749 ,
654 ".tmp_source.zig:3:12: error: comparison against null can only be done with optionals",750 "tmp.zig:3:12: error: comparison against null can only be done with optionals",
655 );751 );
656752
657 cases.add(753 cases.add(
...@@ -663,10 +759,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -663,10 +759,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
663 \\ const Errors = error{} || u16;759 \\ const Errors = error{} || u16;
664 \\}760 \\}
665 ,761 ,
666 ".tmp_source.zig:2:20: error: expected error set type, found type 'u8'",762 "tmp.zig:2:20: error: expected error set type, found type 'u8'",
667 ".tmp_source.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",763 "tmp.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",
668 ".tmp_source.zig:5:31: error: expected error set type, found type 'u16'",764 "tmp.zig:5:31: error: expected error set type, found type 'u16'",
669 ".tmp_source.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",765 "tmp.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",
670 );766 );
671767
672 cases.add(768 cases.add(
...@@ -684,7 +780,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -684,7 +780,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
684 \\ const S = Gen();780 \\ const S = Gen();
685 \\}781 \\}
686 ,782 ,
687 ".tmp_source.zig:2:12: error: use of undeclared identifier 'T'",783 "tmp.zig:2:12: error: use of undeclared identifier 'T'",
688 );784 );
689785
690 cases.add(786 cases.add(
...@@ -695,7 +791,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -695,7 +791,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
695 \\ f(i32);791 \\ f(i32);
696 \\}792 \\}
697 ,793 ,
698 ".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior",794 "tmp.zig:4:5: error: use of undefined value here causes undefined behavior",
699 );795 );
700796
701 cases.add(797 cases.add(
...@@ -713,9 +809,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -713,9 +809,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
713 \\ var x = func(3);809 \\ var x = func(3);
714 \\}810 \\}
715 ,811 ,
716 ".tmp_source.zig:4:24: error: 'y' not accessible from inner function",812 "tmp.zig:4:24: error: 'y' not accessible from inner function",
717 ".tmp_source.zig:3:28: note: crossed function definition here",813 "tmp.zig:3:28: note: crossed function definition here",
718 ".tmp_source.zig:1:10: note: declared here",814 "tmp.zig:1:10: note: declared here",
719 );815 );
720816
721 cases.add(817 cases.add(
...@@ -724,7 +820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -724,7 +820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
724 \\ const x = @intToFloat(f32, 1.1);820 \\ const x = @intToFloat(f32, 1.1);
725 \\}821 \\}
726 ,822 ,
727 ".tmp_source.zig:2:32: error: expected int type, found 'comptime_float'",823 "tmp.zig:2:32: error: expected int type, found 'comptime_float'",
728 );824 );
729825
730 cases.add(826 cases.add(
...@@ -733,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -733,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
733 \\ const x = @floatToInt(i32, i32(54));829 \\ const x = @floatToInt(i32, i32(54));
734 \\}830 \\}
735 ,831 ,
736 ".tmp_source.zig:2:35: error: expected float type, found 'i32'",832 "tmp.zig:2:35: error: expected float type, found 'i32'",
737 );833 );
738834
739 cases.add(835 cases.add(
...@@ -742,7 +838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -742,7 +838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
742 \\ const x = @floatToInt(i8, 200);838 \\ const x = @floatToInt(i8, 200);
743 \\}839 \\}
744 ,840 ,
745 ".tmp_source.zig:2:31: error: integer value 200 cannot be implicitly casted to type 'i8'",841 "tmp.zig:2:31: error: integer value 200 cannot be implicitly casted to type 'i8'",
746 );842 );
747843
748 cases.add(844 cases.add(
...@@ -754,7 +850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -754,7 +850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
754 \\ const int_val = int_ptr.*;850 \\ const int_val = int_ptr.*;
755 \\}851 \\}
756 ,852 ,
757 ".tmp_source.zig:5:28: error: attempt to read 8 bytes from pointer to f32 which is 4 bytes",853 "tmp.zig:5:28: error: attempt to read 8 bytes from pointer to f32 which is 4 bytes",
758 );854 );
759855
760 cases.add(856 cases.add(
...@@ -767,7 +863,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -767,7 +863,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
767 \\ const a = items[0];863 \\ const a = items[0];
768 \\}864 \\}
769 ,865 ,
770 ".tmp_source.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",866 "tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
771 );867 );
772868
773 cases.add(869 cases.add(
...@@ -778,7 +874,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -778,7 +874,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
778 \\ @noInlineCall(foo);874 \\ @noInlineCall(foo);
779 \\}875 \\}
780 ,876 ,
781 ".tmp_source.zig:4:5: error: no-inline call of inline function",877 "tmp.zig:4:5: error: no-inline call of inline function",
782 );878 );
783879
784 cases.add(880 cases.add(
...@@ -795,8 +891,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -795,8 +891,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
795 \\ }891 \\ }
796 \\}892 \\}
797 ,893 ,
798 ".tmp_source.zig:6:19: error: comptime control flow inside runtime block",894 "tmp.zig:6:19: error: comptime control flow inside runtime block",
799 ".tmp_source.zig:5:9: note: runtime block created here",895 "tmp.zig:5:9: note: runtime block created here",
800 );896 );
801897
802 cases.add(898 cases.add(
...@@ -812,8 +908,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -812,8 +908,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
812 \\ }908 \\ }
813 \\}909 \\}
814 ,910 ,
815 ".tmp_source.zig:6:13: error: comptime control flow inside runtime block",911 "tmp.zig:6:13: error: comptime control flow inside runtime block",
816 ".tmp_source.zig:5:9: note: runtime block created here",912 "tmp.zig:5:9: note: runtime block created here",
817 );913 );
818914
819 cases.add(915 cases.add(
...@@ -827,8 +923,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -827,8 +923,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
827 \\ }923 \\ }
828 \\}924 \\}
829 ,925 ,
830 ".tmp_source.zig:5:23: error: comptime control flow inside runtime block",926 "tmp.zig:5:23: error: comptime control flow inside runtime block",
831 ".tmp_source.zig:5:9: note: runtime block created here",927 "tmp.zig:5:9: note: runtime block created here",
832 );928 );
833929
834 cases.add(930 cases.add(
...@@ -842,8 +938,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -842,8 +938,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
842 \\ }938 \\ }
843 \\}939 \\}
844 ,940 ,
845 ".tmp_source.zig:5:25: error: comptime control flow inside runtime block",941 "tmp.zig:5:25: error: comptime control flow inside runtime block",
846 ".tmp_source.zig:5:9: note: runtime block created here",942 "tmp.zig:5:9: note: runtime block created here",
847 );943 );
848944
849 cases.add(945 cases.add(
...@@ -857,8 +953,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -857,8 +953,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
857 \\ }953 \\ }
858 \\}954 \\}
859 ,955 ,
860 ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",956 "tmp.zig:5:20: error: comptime control flow inside runtime block",
861 ".tmp_source.zig:5:9: note: runtime block created here",957 "tmp.zig:5:9: note: runtime block created here",
862 );958 );
863959
864 cases.add(960 cases.add(
...@@ -872,8 +968,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -872,8 +968,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
872 \\ }968 \\ }
873 \\}969 \\}
874 ,970 ,
875 ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",971 "tmp.zig:5:20: error: comptime control flow inside runtime block",
876 ".tmp_source.zig:5:9: note: runtime block created here",972 "tmp.zig:5:9: note: runtime block created here",
877 );973 );
878974
879 cases.add(975 cases.add(
...@@ -887,8 +983,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -887,8 +983,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
887 \\ }983 \\ }
888 \\}984 \\}
889 ,985 ,
890 ".tmp_source.zig:5:22: error: comptime control flow inside runtime block",986 "tmp.zig:5:22: error: comptime control flow inside runtime block",
891 ".tmp_source.zig:5:9: note: runtime block created here",987 "tmp.zig:5:9: note: runtime block created here",
892 );988 );
893989
894 cases.add(990 cases.add(
...@@ -904,7 +1000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -904,7 +1000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
904 \\ };1000 \\ };
905 \\}1001 \\}
906 ,1002 ,
907 ".tmp_source.zig:7:17: error: switch on type 'type' provides no expression parameter",1003 "tmp.zig:7:17: error: switch on type 'type' provides no expression parameter",
908 );1004 );
9091005
910 cases.add(1006 cases.add(
...@@ -914,24 +1010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -914,24 +1010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
914 \\ foo();1010 \\ foo();
915 \\}1011 \\}
916 ,1012 ,
917 ".tmp_source.zig:1:1: error: non-extern function has no body",1013 "tmp.zig:1:1: error: non-extern function has no body",
918 );
919
920 cases.add(
921 "@typeInfo causing depend on itself compile error",
922 \\const start = struct {
923 \\ fn crash() bug() {
924 \\ return bug;
925 \\ }
926 \\};
927 \\fn bug() void {
928 \\ _ = @typeInfo(start).Struct;
929 \\}
930 \\export fn entry() void {
931 \\ var boom = start.crash();
932 \\}
933 ,
934 ".tmp_source.zig:2:5: error: 'crash' depends on itself",
935 );1014 );
9361015
937 cases.add(1016 cases.add(
...@@ -942,7 +1021,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -942,7 +1021,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
942 \\ return handle_undef == handle_dummy;1021 \\ return handle_undef == handle_dummy;
943 \\}1022 \\}
944 ,1023 ,
945 ".tmp_source.zig:2:29: error: @handle() called outside of function definition",1024 "tmp.zig:2:29: error: @handle() called outside of function definition",
946 );1025 );
9471026
948 cases.add(1027 cases.add(
...@@ -952,7 +1031,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -952,7 +1031,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
952 \\ return handle_undef == @handle();1031 \\ return handle_undef == @handle();
953 \\}1032 \\}
954 ,1033 ,
955 ".tmp_source.zig:3:28: error: @handle() in non-async function",1034 "tmp.zig:3:28: error: @handle() in non-async function",
956 );1035 );
9571036
958 cases.add(1037 cases.add(
...@@ -962,8 +1041,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -962,8 +1041,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
962 \\ return _;1041 \\ return _;
963 \\}1042 \\}
964 ,1043 ,
965 ".tmp_source.zig:2:5: error: `_` is not a declarable symbol",1044 "tmp.zig:2:5: error: `_` is not a declarable symbol",
966 ".tmp_source.zig:3:12: error: use of undeclared identifier '_'",1045 "tmp.zig:3:12: error: use of undeclared identifier '_'",
967 );1046 );
9681047
969 cases.add(1048 cases.add(
...@@ -976,7 +1055,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -976,7 +1055,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
976 \\ }1055 \\ }
977 \\}1056 \\}
978 ,1057 ,
979 ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",1058 "tmp.zig:4:20: error: use of undeclared identifier '_'",
980 );1059 );
9811060
982 cases.add(1061 cases.add(
...@@ -992,7 +1071,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -992,7 +1071,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
992 \\ return 1;1071 \\ return 1;
993 \\}1072 \\}
994 ,1073 ,
995 ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",1074 "tmp.zig:4:20: error: use of undeclared identifier '_'",
996 );1075 );
9971076
998 cases.add(1077 cases.add(
...@@ -1010,7 +1089,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1010,7 +1089,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1010 \\ return error.optionalReturnError;1089 \\ return error.optionalReturnError;
1011 \\}1090 \\}
1012 ,1091 ,
1013 ".tmp_source.zig:6:17: error: use of undeclared identifier '_'",1092 "tmp.zig:6:17: error: use of undeclared identifier '_'",
1014 );1093 );
10151094
1016 cases.add(1095 cases.add(
...@@ -1030,9 +1109,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1030,9 +1109,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1030 \\ while (x) |_| returns() else |_| unreachable;1109 \\ while (x) |_| returns() else |_| unreachable;
1031 \\}1110 \\}
1032 ,1111 ,
1033 ".tmp_source.zig:5:25: error: expression value is ignored",1112 "tmp.zig:5:25: error: expression value is ignored",
1034 ".tmp_source.zig:9:26: error: expression value is ignored",1113 "tmp.zig:9:26: error: expression value is ignored",
1035 ".tmp_source.zig:13:26: error: expression value is ignored",1114 "tmp.zig:13:26: error: expression value is ignored",
1036 );1115 );
10371116
1038 cases.add(1117 cases.add(
...@@ -1043,7 +1122,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1043,7 +1122,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1043 \\ dump(a);1122 \\ dump(a);
1044 \\}1123 \\}
1045 ,1124 ,
1046 ".tmp_source.zig:1:9: error: missing parameter name",1125 "tmp.zig:1:9: error: missing parameter name",
1047 );1126 );
10481127
1049 cases.add(1128 cases.add(
...@@ -1057,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1057,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1057 \\ for (xx) |f| {}1136 \\ for (xx) |f| {}
1058 \\}1137 \\}
1059 ,1138 ,
1060 ".tmp_source.zig:7:15: error: variable of type 'Foo' must be const or comptime",1139 "tmp.zig:7:15: error: variable of type 'Foo' must be const or comptime",
1061 );1140 );
10621141
1063 cases.add(1142 cases.add(
...@@ -1068,7 +1147,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1068,7 +1147,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1068 \\ f(g);1147 \\ f(g);
1069 \\}1148 \\}
1070 ,1149 ,
1071 ".tmp_source.zig:1:9: error: parameter of type 'fn(var)var' must be declared comptime",1150 "tmp.zig:1:9: error: parameter of type 'fn(var)var' must be declared comptime",
1072 );1151 );
10731152
1074 cases.add(1153 cases.add(
...@@ -1082,7 +1161,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1082,7 +1161,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1082 \\};1161 \\};
1083 \\export fn entry(bar: *Bar) void {}1162 \\export fn entry(bar: *Bar) void {}
1084 ,1163 ,
1085 ".tmp_source.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",1164 "tmp.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
1086 );1165 );
10871166
1088 cases.add(1167 cases.add(
...@@ -1095,7 +1174,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1095,7 +1174,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1095 \\ command.exec();1174 \\ command.exec();
1096 \\}1175 \\}
1097 ,1176 ,
1098 ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",1177 "tmp.zig:6:12: error: use of undefined value here causes undefined behavior",
1099 );1178 );
11001179
1101 cases.add(1180 cases.add(
...@@ -1108,7 +1187,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1108,7 +1187,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1108 \\ command.exec();1187 \\ command.exec();
1109 \\}1188 \\}
1110 ,1189 ,
1111 ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",1190 "tmp.zig:6:12: error: use of undefined value here causes undefined behavior",
1112 );1191 );
11131192
1114 cases.add(1193 cases.add(
...@@ -1118,7 +1197,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1118,7 +1197,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1118 \\ const aligned = @alignCast(4, ptr);1197 \\ const aligned = @alignCast(4, ptr);
1119 \\}1198 \\}
1120 ,1199 ,
1121 ".tmp_source.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",1200 "tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",
1122 );1201 );
11231202
1124 cases.add(1203 cases.add(
...@@ -1127,7 +1206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1127,7 +1206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1127 \\ return @ptrToInt(&{}) == @ptrToInt(&{});1206 \\ return @ptrToInt(&{}) == @ptrToInt(&{});
1128 \\}1207 \\}
1129 ,1208 ,
1130 ".tmp_source.zig:2:23: error: pointer to size 0 type has no address",1209 "tmp.zig:2:23: error: pointer to size 0 type has no address",
1131 );1210 );
11321211
1133 cases.add(1212 cases.add(
...@@ -1136,7 +1215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1136,7 +1215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1136 \\ return @popCount(x);1215 \\ return @popCount(x);
1137 \\}1216 \\}
1138 ,1217 ,
1139 ".tmp_source.zig:2:22: error: expected integer type, found 'f32'",1218 "tmp.zig:2:22: error: expected integer type, found 'f32'",
1140 );1219 );
11411220
1142 cases.add(1221 cases.add(
...@@ -1145,7 +1224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1145,7 +1224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1145 \\ _ = @popCount(-1);1224 \\ _ = @popCount(-1);
1146 \\}1225 \\}
1147 ,1226 ,
1148 ".tmp_source.zig:2:9: error: @popCount on negative comptime_int value -1",1227 "tmp.zig:2:9: error: @popCount on negative comptime_int value -1",
1149 );1228 );
11501229
1151 cases.addCase(x: {1230 cases.addCase(x: {
...@@ -1161,10 +1240,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1161,10 +1240,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1161 \\1240 \\
1162 \\fn bar(x: *b.Foo) void {}1241 \\fn bar(x: *b.Foo) void {}
1163 ,1242 ,
1164 ".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'",1243 "tmp.zig:6:10: error: expected type '*b.Foo', found '*a.Foo'",
1165 ".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'",1244 "tmp.zig:6:10: note: pointer type child 'a.Foo' cannot cast into pointer type child 'b.Foo'",
1166 "a.zig:1:17: note: Foo declared here",1245 "a.zig:1:17: note: a.Foo declared here",
1167 "b.zig:1:17: note: Foo declared here",1246 "b.zig:1:17: note: b.Foo declared here",
1168 );1247 );
11691248
1170 tc.addSourceFile("a.zig",1249 tc.addSourceFile("a.zig",
...@@ -1182,19 +1261,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1182,19 +1261,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1182 break :x tc;1261 break :x tc;
1183 });1262 });
11841263
1185 cases.add(
1186 "enum field value references enum",
1187 \\pub const Foo = extern enum {
1188 \\ A = Foo.B,
1189 \\ C = D,
1190 \\};
1191 \\export fn entry() void {
1192 \\ var s: Foo = Foo.E;
1193 \\}
1194 ,
1195 ".tmp_source.zig:1:17: error: 'Foo' depends on itself",
1196 );
1197
1198 cases.add(1264 cases.add(
1199 "@floatToInt comptime safety",1265 "@floatToInt comptime safety",
1200 \\comptime {1266 \\comptime {
...@@ -1207,9 +1273,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1207,9 +1273,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1207 \\ _ = @floatToInt(u8, f32(256.1));1273 \\ _ = @floatToInt(u8, f32(256.1));
1208 \\}1274 \\}
1209 ,1275 ,
1210 ".tmp_source.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",1276 "tmp.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",
1211 ".tmp_source.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",1277 "tmp.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",
1212 ".tmp_source.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",1278 "tmp.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
1213 );1279 );
12141280
1215 cases.add(1281 cases.add(
...@@ -1218,7 +1284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1218,7 +1284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1218 \\ const a: fn () c_void = undefined;1284 \\ const a: fn () c_void = undefined;
1219 \\}1285 \\}
1220 ,1286 ,
1221 ".tmp_source.zig:2:20: error: return type cannot be opaque",1287 "tmp.zig:2:20: error: return type cannot be opaque",
1222 );1288 );
12231289
1224 cases.add(1290 cases.add(
...@@ -1231,7 +1297,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1231,7 +1297,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1231 \\ var y = p.*;1297 \\ var y = p.*;
1232 \\}1298 \\}
1233 ,1299 ,
1234 ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'",1300 "tmp.zig:4:23: error: expected type '*?*i32', found '**i32'",
1235 );1301 );
12361302
1237 cases.add(1303 cases.add(
...@@ -1240,7 +1306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1240,7 +1306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1240 \\ const x: [*]const bool = true;1306 \\ const x: [*]const bool = true;
1241 \\}1307 \\}
1242 ,1308 ,
1243 ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'",1309 "tmp.zig:2:30: error: expected type '[*]const bool', found 'bool'",
1244 );1310 );
12451311
1246 cases.add(1312 cases.add(
...@@ -1249,7 +1315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1249,7 +1315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1249 \\ return x.*;1315 \\ return x.*;
1250 \\}1316 \\}
1251 ,1317 ,
1252 ".tmp_source.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",1318 "tmp.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
1253 );1319 );
12541320
1255 cases.add(1321 cases.add(
...@@ -1262,14 +1328,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1262,14 +1328,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1262 \\ foo.a += 1;1328 \\ foo.a += 1;
1263 \\}1329 \\}
1264 ,1330 ,
1265 ".tmp_source.zig:6:8: error: type '[*]Foo' does not support field access",1331 "tmp.zig:6:8: error: type '[*]Foo' does not support field access",
1266 );1332 );
12671333
1268 cases.add(1334 cases.add(
1269 "unknown length pointer to opaque",1335 "unknown length pointer to opaque",
1270 \\export const T = [*]@OpaqueType();1336 \\export const T = [*]@OpaqueType();
1271 ,1337 ,
1272 ".tmp_source.zig:1:18: error: unknown-length pointer to opaque",1338 "tmp.zig:1:18: error: unknown-length pointer to opaque",
1273 );1339 );
12741340
1275 cases.add(1341 cases.add(
...@@ -1285,7 +1351,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1285,7 +1351,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1285 \\ var rule_set = try Foo.init();1351 \\ var rule_set = try Foo.init();
1286 \\}1352 \\}
1287 ,1353 ,
1288 ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'",1354 "tmp.zig:2:13: error: expected type 'i32', found 'type'",
1289 );1355 );
12901356
1291 cases.add(1357 cases.add(
...@@ -1294,7 +1360,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1294,7 +1360,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1294 \\ const slice = ptr[0..2];1360 \\ const slice = ptr[0..2];
1295 \\}1361 \\}
1296 ,1362 ,
1297 ".tmp_source.zig:2:22: error: slice of single-item pointer",1363 "tmp.zig:2:22: error: slice of single-item pointer",
1298 );1364 );
12991365
1300 cases.add(1366 cases.add(
...@@ -1303,7 +1369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1303,7 +1369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1303 \\ return ptr[1];1369 \\ return ptr[1];
1304 \\}1370 \\}
1305 ,1371 ,
1306 ".tmp_source.zig:2:15: error: index of single-item pointer",1372 "tmp.zig:2:15: error: index of single-item pointer",
1307 );1373 );
13081374
1309 cases.add(1375 cases.add(
...@@ -1319,10 +1385,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1319,10 +1385,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1319 \\ return null;1385 \\ return null;
1320 \\}1386 \\}
1321 ,1387 ,
1322 ".tmp_source.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",1388 "tmp.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",
1323 ".tmp_source.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",1389 "tmp.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",
1324 ".tmp_source.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",1390 "tmp.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",
1325 ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",1391 "tmp.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
1326 );1392 );
13271393
1328 cases.add(1394 cases.add(
...@@ -1339,14 +1405,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1339,14 +1405,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1339 \\ Filled,1405 \\ Filled,
1340 \\};1406 \\};
1341 ,1407 ,
1342 ".tmp_source.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",1408 "tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",
1343 );1409 );
13441410
1345 cases.add(1411 cases.add(
1346 "invalid field access in comptime",1412 "invalid field access in comptime",
1347 \\comptime { var x = doesnt_exist.whatever; }1413 \\comptime { var x = doesnt_exist.whatever; }
1348 ,1414 ,
1349 ".tmp_source.zig:1:20: error: use of undeclared identifier 'doesnt_exist'",1415 "tmp.zig:1:20: error: use of undeclared identifier 'doesnt_exist'",
1350 );1416 );
13511417
1352 cases.add(1418 cases.add(
...@@ -1367,8 +1433,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1367,8 +1433,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1367 \\ }1433 \\ }
1368 \\}1434 \\}
1369 ,1435 ,
1370 ".tmp_source.zig:12:9: error: cannot suspend inside suspend block",1436 "tmp.zig:12:9: error: cannot suspend inside suspend block",
1371 ".tmp_source.zig:11:5: note: other suspend block here",1437 "tmp.zig:11:5: note: other suspend block here",
1372 );1438 );
13731439
1374 cases.add(1440 cases.add(
...@@ -1378,8 +1444,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1378,8 +1444,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1378 \\}1444 \\}
1379 \\inline fn b() void { }1445 \\inline fn b() void { }
1380 ,1446 ,
1381 ".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",1447 "tmp.zig:2:5: error: functions marked inline must be stored in const or comptime var",
1382 ".tmp_source.zig:4:1: note: declared here",1448 "tmp.zig:4:1: note: declared here",
1383 );1449 );
13841450
1385 cases.add(1451 cases.add(
...@@ -1389,7 +1455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1389,7 +1455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1389 \\ @panic(e);1455 \\ @panic(e);
1390 \\}1456 \\}
1391 ,1457 ,
1392 ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'",1458 "tmp.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'",
1393 );1459 );
13941460
1395 cases.add(1461 cases.add(
...@@ -1403,8 +1469,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1403,8 +1469,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1403 \\ var tagName = @tagName(fi);1469 \\ var tagName = @tagName(fi);
1404 \\}1470 \\}
1405 ,1471 ,
1406 ".tmp_source.zig:7:19: error: union has no associated enum",1472 "tmp.zig:7:19: error: union has no associated enum",
1407 ".tmp_source.zig:1:18: note: declared here",1473 "tmp.zig:1:18: note: declared here",
1408 );1474 );
14091475
1410 cases.add(1476 cases.add(
...@@ -1417,7 +1483,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1417,7 +1483,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1417 \\ return error.ShouldBeCompileError;1483 \\ return error.ShouldBeCompileError;
1418 \\}1484 \\}
1419 ,1485 ,
1420 ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",1486 "tmp.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
1421 );1487 );
14221488
1423 cases.add(1489 cases.add(
...@@ -1426,7 +1492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1426,7 +1492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1426 \\ var s = (struct{v: var}){.v=i32(10)};1492 \\ var s = (struct{v: var}){.v=i32(10)};
1427 \\}1493 \\}
1428 ,1494 ,
1429 ".tmp_source.zig:2:23: error: invalid token: 'var'",1495 "tmp.zig:2:23: error: invalid token: 'var'",
1430 );1496 );
14311497
1432 cases.add(1498 cases.add(
...@@ -1436,7 +1502,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1436,7 +1502,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1436 \\ const y = @ptrCast(*i32, &x);1502 \\ const y = @ptrCast(*i32, &x);
1437 \\}1503 \\}
1438 ,1504 ,
1439 ".tmp_source.zig:3:15: error: cast discards const qualifier",1505 "tmp.zig:3:15: error: cast discards const qualifier",
1440 );1506 );
14411507
1442 cases.add(1508 cases.add(
...@@ -1445,7 +1511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1445,7 +1511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1445 \\ const slice = ([*]i32)(undefined)[0..1];1511 \\ const slice = ([*]i32)(undefined)[0..1];
1446 \\}1512 \\}
1447 ,1513 ,
1448 ".tmp_source.zig:2:38: error: non-zero length slice of undefined pointer",1514 "tmp.zig:2:38: error: non-zero length slice of undefined pointer",
1449 );1515 );
14501516
1451 cases.add(1517 cases.add(
...@@ -1460,7 +1526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1460,7 +1526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1460 \\ a(c);1526 \\ a(c);
1461 \\}1527 \\}
1462 ,1528 ,
1463 ".tmp_source.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'",1529 "tmp.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'",
1464 );1530 );
14651531
1466 cases.add(1532 cases.add(
...@@ -1474,7 +1540,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1474,7 +1540,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1474 \\ }1540 \\ }
1475 \\}1541 \\}
1476 ,1542 ,
1477 ".tmp_source.zig:5:5: error: else prong required when switching on type 'anyerror'",1543 "tmp.zig:5:5: error: else prong required when switching on type 'anyerror'",
1478 );1544 );
14791545
1480 cases.add(1546 cases.add(
...@@ -1485,7 +1551,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1485,7 +1551,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1485 \\fn foo() !void {1551 \\fn foo() !void {
1486 \\}1552 \\}
1487 ,1553 ,
1488 ".tmp_source.zig:4:11: error: function with inferred error set must return at least one possible error",1554 "tmp.zig:4:11: error: function with inferred error set must return at least one possible error",
1489 );1555 );
14901556
1491 cases.add(1557 cases.add(
...@@ -1504,8 +1570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1504,8 +1570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1504 \\ }1570 \\ }
1505 \\}1571 \\}
1506 ,1572 ,
1507 ".tmp_source.zig:2:26: error: error.Baz not handled in switch",1573 "tmp.zig:2:26: error: error.Baz not handled in switch",
1508 ".tmp_source.zig:2:26: error: error.Bar not handled in switch",1574 "tmp.zig:2:26: error: error.Bar not handled in switch",
1509 );1575 );
15101576
1511 cases.add(1577 cases.add(
...@@ -1526,8 +1592,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1526,8 +1592,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1526 \\ }1592 \\ }
1527 \\}1593 \\}
1528 ,1594 ,
1529 ".tmp_source.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",1595 "tmp.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
1530 ".tmp_source.zig:3:14: note: other value is here",1596 "tmp.zig:3:14: note: other value is here",
1531 );1597 );
15321598
1533 cases.add("invalid cast from integral type to enum",1599 cases.add("invalid cast from integral type to enum",
...@@ -1542,7 +1608,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1542,7 +1608,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1542 \\ E.One => {},1608 \\ E.One => {},
1543 \\ }1609 \\ }
1544 \\}1610 \\}
1545 , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'");1611 , "tmp.zig:9:10: error: expected type 'usize', found 'E'");
15461612
1547 cases.add(1613 cases.add(
1548 "range operator in switch used on error set",1614 "range operator in switch used on error set",
...@@ -1560,7 +1626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1560,7 +1626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1560 \\ }1626 \\ }
1561 \\}1627 \\}
1562 ,1628 ,
1563 ".tmp_source.zig:3:17: error: operator not allowed for errors",1629 "tmp.zig:3:17: error: operator not allowed for errors",
1564 );1630 );
15651631
1566 cases.add(1632 cases.add(
...@@ -1569,7 +1635,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1569,7 +1635,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1569 \\ const z: ?fn()!void = null;1635 \\ const z: ?fn()!void = null;
1570 \\}1636 \\}
1571 ,1637 ,
1572 ".tmp_source.zig:2:15: error: inferring error set of return type valid only for function definitions",1638 "tmp.zig:2:15: error: inferring error set of return type valid only for function definitions",
1573 );1639 );
15741640
1575 cases.add(1641 cases.add(
...@@ -1579,7 +1645,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1579,7 +1645,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1579 \\ const z = Foo.Bar;1645 \\ const z = Foo.Bar;
1580 \\}1646 \\}
1581 ,1647 ,
1582 ".tmp_source.zig:3:18: error: no error named 'Bar' in 'Foo'",1648 "tmp.zig:3:18: error: no error named 'Bar' in 'Foo'",
1583 );1649 );
15841650
1585 cases.add(1651 cases.add(
...@@ -1588,7 +1654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1588,7 +1654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1588 \\ const z = i32!i32;1654 \\ const z = i32!i32;
1589 \\}1655 \\}
1590 ,1656 ,
1591 ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'",1657 "tmp.zig:2:15: error: expected error set type, found type 'i32'",
1592 );1658 );
15931659
1594 cases.add(1660 cases.add(
...@@ -1604,7 +1670,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1604,7 +1670,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1604 \\ }1670 \\ }
1605 \\}1671 \\}
1606 ,1672 ,
1607 ".tmp_source.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors",1673 "tmp.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors",
1608 );1674 );
16091675
1610 cases.add(1676 cases.add(
...@@ -1613,7 +1679,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1613,7 +1679,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1613 \\ const z = error.A > error.B;1679 \\ const z = error.A > error.B;
1614 \\}1680 \\}
1615 ,1681 ,
1616 ".tmp_source.zig:2:23: error: operator not allowed for errors",1682 "tmp.zig:2:23: error: operator not allowed for errors",
1617 );1683 );
16181684
1619 cases.add(1685 cases.add(
...@@ -1625,7 +1691,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1625,7 +1691,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1625 \\ var y = @errSetCast(Set2, x);1691 \\ var y = @errSetCast(Set2, x);
1626 \\}1692 \\}
1627 ,1693 ,
1628 ".tmp_source.zig:5:13: error: error.B not a member of error set 'Set2'",1694 "tmp.zig:5:13: error: error.B not a member of error set 'Set2'",
1629 );1695 );
16301696
1631 cases.add(1697 cases.add(
...@@ -1638,9 +1704,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1638,9 +1704,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1638 \\ return error.B;1704 \\ return error.B;
1639 \\}1705 \\}
1640 ,1706 ,
1641 ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'",1707 "tmp.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'",
1642 ".tmp_source.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'",1708 "tmp.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'",
1643 ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set",1709 "tmp.zig:3:35: note: cannot cast global error set into smaller set",
1644 );1710 );
16451711
1646 cases.add(1712 cases.add(
...@@ -1653,10 +1719,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1653,10 +1719,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1653 \\ return error.B;1719 \\ return error.B;
1654 \\}1720 \\}
1655 ,1721 ,
1656 ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",1722 "tmp.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",
1657 ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set",1723 "tmp.zig:3:31: note: cannot cast global error set into smaller set",
1658 );1724 );
1659
1660 cases.add(1725 cases.add(
1661 "recursive inferred error set",1726 "recursive inferred error set",
1662 \\export fn entry() void {1727 \\export fn entry() void {
...@@ -1666,7 +1731,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1666,7 +1731,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1666 \\ try foo();1731 \\ try foo();
1667 \\}1732 \\}
1668 ,1733 ,
1669 ".tmp_source.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet",1734 "tmp.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet",
1670 );1735 );
16711736
1672 cases.add(1737 cases.add(
...@@ -1680,8 +1745,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1680,8 +1745,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1680 \\ var x: Set2 = set1;1745 \\ var x: Set2 = set1;
1681 \\}1746 \\}
1682 ,1747 ,
1683 ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'",1748 "tmp.zig:7:19: error: expected type 'Set2', found 'Set1'",
1684 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set",1749 "tmp.zig:1:23: note: 'error.B' not a member of destination error set",
1685 );1750 );
16861751
1687 cases.add(1752 cases.add(
...@@ -1695,7 +1760,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1695,7 +1760,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1695 \\ var y = @intToError(x);1760 \\ var y = @intToError(x);
1696 \\}1761 \\}
1697 ,1762 ,
1698 ".tmp_source.zig:7:13: error: integer value 3 represents no error",1763 "tmp.zig:7:13: error: integer value 3 represents no error",
1699 );1764 );
17001765
1701 cases.add(1766 cases.add(
...@@ -1713,7 +1778,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1713,7 +1778,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1713 \\ var y = @errSetCast(Set2, @intToError(x));1778 \\ var y = @errSetCast(Set2, @intToError(x));
1714 \\}1779 \\}
1715 ,1780 ,
1716 ".tmp_source.zig:11:13: error: error.B not a member of error set 'Set2'",1781 "tmp.zig:11:13: error: error.B not a member of error set 'Set2'",
1717 );1782 );
17181783
1719 cases.add(1784 cases.add(
...@@ -1722,7 +1787,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1722,7 +1787,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1722 \\ _ = @memberCount(anyerror);1787 \\ _ = @memberCount(anyerror);
1723 \\}1788 \\}
1724 ,1789 ,
1725 ".tmp_source.zig:2:9: error: global error set member count not available at comptime",1790 "tmp.zig:2:9: error: global error set member count not available at comptime",
1726 );1791 );
17271792
1728 cases.add(1793 cases.add(
...@@ -1735,8 +1800,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1735,8 +1800,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1735 \\ const a: Foo = undefined;1800 \\ const a: Foo = undefined;
1736 \\}1801 \\}
1737 ,1802 ,
1738 ".tmp_source.zig:3:5: error: duplicate error: 'Bar'",1803 "tmp.zig:3:5: error: duplicate error: 'Bar'",
1739 ".tmp_source.zig:2:5: note: other error here",1804 "tmp.zig:2:5: note: other error here",
1740 );1805 );
17411806
1742 cases.add(1807 cases.add(
...@@ -1745,7 +1810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1745,7 +1810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1745 \\ const x = usize(-10);1810 \\ const x = usize(-10);
1746 \\}1811 \\}
1747 ,1812 ,
1748 ".tmp_source.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'",1813 "tmp.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'",
1749 );1814 );
17501815
1751 cases.add(1816 cases.add(
...@@ -1755,7 +1820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1755,7 +1820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1755 \\ var arr: [v]u8 = undefined;1820 \\ var arr: [v]u8 = undefined;
1756 \\}1821 \\}
1757 ,1822 ,
1758 ".tmp_source.zig:1:1: error: unable to infer variable type",1823 "tmp.zig:1:1: error: unable to infer variable type",
1759 );1824 );
17601825
1761 cases.add(1826 cases.add(
...@@ -1768,8 +1833,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1768,8 +1833,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1768 \\ const a: Foo = undefined;1833 \\ const a: Foo = undefined;
1769 \\}1834 \\}
1770 ,1835 ,
1771 ".tmp_source.zig:3:5: error: duplicate struct field: 'Bar'",1836 "tmp.zig:3:5: error: duplicate struct field: 'Bar'",
1772 ".tmp_source.zig:2:5: note: other field here",1837 "tmp.zig:2:5: note: other field here",
1773 );1838 );
17741839
1775 cases.add(1840 cases.add(
...@@ -1782,8 +1847,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1782,8 +1847,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1782 \\ const a: Foo = undefined;1847 \\ const a: Foo = undefined;
1783 \\}1848 \\}
1784 ,1849 ,
1785 ".tmp_source.zig:3:5: error: duplicate union field: 'Bar'",1850 "tmp.zig:3:5: error: duplicate union field: 'Bar'",
1786 ".tmp_source.zig:2:5: note: other field here",1851 "tmp.zig:2:5: note: other field here",
1787 );1852 );
17881853
1789 cases.add(1854 cases.add(
...@@ -1797,8 +1862,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1797,8 +1862,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1797 \\ const a: Foo = undefined;1862 \\ const a: Foo = undefined;
1798 \\}1863 \\}
1799 ,1864 ,
1800 ".tmp_source.zig:3:5: error: duplicate enum field: 'Bar'",1865 "tmp.zig:3:5: error: duplicate enum field: 'Bar'",
1801 ".tmp_source.zig:2:5: note: other field here",1866 "tmp.zig:2:5: note: other field here",
1802 );1867 );
18031868
1804 cases.add(1869 cases.add(
...@@ -1808,15 +1873,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1808,15 +1873,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1808 \\}1873 \\}
1809 \\nakedcc fn foo() void { }1874 \\nakedcc fn foo() void { }
1810 ,1875 ,
1811 ".tmp_source.zig:2:5: error: unable to call function with naked calling convention",1876 "tmp.zig:2:5: error: unable to call function with naked calling convention",
1812 ".tmp_source.zig:4:1: note: declared here",1877 "tmp.zig:4:1: note: declared here",
1813 );1878 );
18141879
1815 cases.add(1880 cases.add(
1816 "function with invalid return type",1881 "function with invalid return type",
1817 \\export fn foo() boid {}1882 \\export fn foo() boid {}
1818 ,1883 ,
1819 ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'",1884 "tmp.zig:1:17: error: use of undeclared identifier 'boid'",
1820 );1885 );
18211886
1822 cases.add(1887 cases.add(
...@@ -1824,7 +1889,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1824,7 +1889,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1824 \\const Foo = enum { A, B, C };1889 \\const Foo = enum { A, B, C };
1825 \\export fn entry(foo: Foo) void { }1890 \\export fn entry(foo: Foo) void { }
1826 ,1891 ,
1827 ".tmp_source.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",1892 "tmp.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
1828 );1893 );
18291894
1830 cases.add(1895 cases.add(
...@@ -1836,7 +1901,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1836,7 +1901,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1836 \\};1901 \\};
1837 \\export fn entry(foo: Foo) void { }1902 \\export fn entry(foo: Foo) void { }
1838 ,1903 ,
1839 ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",1904 "tmp.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
1840 );1905 );
18411906
1842 cases.add(1907 cases.add(
...@@ -1848,7 +1913,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1848,7 +1913,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1848 \\};1913 \\};
1849 \\export fn entry(foo: Foo) void { }1914 \\export fn entry(foo: Foo) void { }
1850 ,1915 ,
1851 ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",1916 "tmp.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
1852 );1917 );
18531918
1854 cases.add(1919 cases.add(
...@@ -1860,7 +1925,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1860,7 +1925,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1860 \\ switch (f) {}1925 \\ switch (f) {}
1861 \\}1926 \\}
1862 ,1927 ,
1863 ".tmp_source.zig:5:5: error: enumeration value 'Foo.M' not handled in switch",1928 "tmp.zig:5:5: error: enumeration value 'Foo.M' not handled in switch",
1864 );1929 );
18651930
1866 cases.add(1931 cases.add(
...@@ -1869,7 +1934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1869,7 +1934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1869 \\ var a = 1 >> -1;1934 \\ var a = 1 >> -1;
1870 \\}1935 \\}
1871 ,1936 ,
1872 ".tmp_source.zig:2:18: error: shift by negative value -1",1937 "tmp.zig:2:18: error: shift by negative value -1",
1873 );1938 );
18741939
1875 cases.add(1940 cases.add(
...@@ -1880,7 +1945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1880,7 +1945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1880 \\ }1945 \\ }
1881 \\}1946 \\}
1882 ,1947 ,
1883 ".tmp_source.zig:3:9: error: encountered @panic at compile-time",1948 "tmp.zig:3:9: error: encountered @panic at compile-time",
1884 );1949 );
18851950
1886 cases.add(1951 cases.add(
...@@ -1910,7 +1975,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1910,7 +1975,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1910 \\ bogus;1975 \\ bogus;
1911 \\}1976 \\}
1912 ,1977 ,
1913 ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'",1978 "tmp.zig:8:5: error: use of undeclared identifier 'bogus'",
1914 );1979 );
19151980
1916 cases.add(1981 cases.add(
...@@ -1923,7 +1988,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1923,7 +1988,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1923 \\ }1988 \\ }
1924 \\}1989 \\}
1925 ,1990 ,
1926 ".tmp_source.zig:4:13: error: label not found: 'outer'",1991 "tmp.zig:4:13: error: label not found: 'outer'",
1927 );1992 );
19281993
1929 cases.add(1994 cases.add(
...@@ -1937,7 +2002,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1937,7 +2002,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1937 \\ }2002 \\ }
1938 \\}2003 \\}
1939 ,2004 ,
1940 ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'",2005 "tmp.zig:5:13: error: labeled loop not found: 'outer'",
1941 );2006 );
19422007
1943 cases.add(2008 cases.add(
...@@ -1950,8 +2015,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1950,8 +2015,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1950 \\2015 \\
1951 \\extern fn bar(x: *void) void { }2016 \\extern fn bar(x: *void) void { }
1952 ,2017 ,
1953 ".tmp_source.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",2018 "tmp.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
1954 ".tmp_source.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",2019 "tmp.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
1955 );2020 );
19562021
1957 cases.add(2022 cases.add(
...@@ -1963,7 +2028,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1963,7 +2028,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1963 \\ var bad = {};2028 \\ var bad = {};
1964 \\}2029 \\}
1965 ,2030 ,
1966 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2031 "tmp.zig:5:5: error: expected token ';', found 'var'",
1967 );2032 );
19682033
1969 cases.add(2034 cases.add(
...@@ -1975,7 +2040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1975,7 +2040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1975 \\ var bad = {};2040 \\ var bad = {};
1976 \\}2041 \\}
1977 ,2042 ,
1978 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2043 "tmp.zig:5:5: error: expected token ';', found 'var'",
1979 );2044 );
19802045
1981 cases.add(2046 cases.add(
...@@ -1987,7 +2052,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1987,7 +2052,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1987 \\ var bad = {};2052 \\ var bad = {};
1988 \\}2053 \\}
1989 ,2054 ,
1990 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2055 "tmp.zig:5:5: error: expected token ';', found 'var'",
1991 );2056 );
19922057
1993 cases.add(2058 cases.add(
...@@ -1999,7 +2064,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1999,7 +2064,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1999 \\ var bad = {};2064 \\ var bad = {};
2000 \\}2065 \\}
2001 ,2066 ,
2002 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2067 "tmp.zig:5:5: error: expected token ';', found 'var'",
2003 );2068 );
20042069
2005 cases.add(2070 cases.add(
...@@ -2011,7 +2076,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2011,7 +2076,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2011 \\ var bad = {};2076 \\ var bad = {};
2012 \\}2077 \\}
2013 ,2078 ,
2014 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2079 "tmp.zig:5:5: error: expected token ';', found 'var'",
2015 );2080 );
20162081
2017 cases.add(2082 cases.add(
...@@ -2023,7 +2088,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2023,7 +2088,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2023 \\ var bad = {};2088 \\ var bad = {};
2024 \\}2089 \\}
2025 ,2090 ,
2026 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2091 "tmp.zig:5:5: error: expected token ';', found 'var'",
2027 );2092 );
20282093
2029 cases.add(2094 cases.add(
...@@ -2035,7 +2100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2035,7 +2100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2035 \\ var bad = {};2100 \\ var bad = {};
2036 \\}2101 \\}
2037 ,2102 ,
2038 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2103 "tmp.zig:5:5: error: expected token ';', found 'var'",
2039 );2104 );
20402105
2041 cases.add(2106 cases.add(
...@@ -2047,7 +2112,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2047,7 +2112,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2047 \\ var bad = {};2112 \\ var bad = {};
2048 \\}2113 \\}
2049 ,2114 ,
2050 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2115 "tmp.zig:5:5: error: expected token ';', found 'var'",
2051 );2116 );
20522117
2053 cases.add(2118 cases.add(
...@@ -2059,7 +2124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2059,7 +2124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2059 \\ var bad = {};2124 \\ var bad = {};
2060 \\}2125 \\}
2061 ,2126 ,
2062 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2127 "tmp.zig:5:5: error: expected token ';', found 'var'",
2063 );2128 );
20642129
2065 cases.add(2130 cases.add(
...@@ -2071,7 +2136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2071,7 +2136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2071 \\ var bad = {};2136 \\ var bad = {};
2072 \\}2137 \\}
2073 ,2138 ,
2074 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2139 "tmp.zig:5:5: error: expected token ';', found 'var'",
2075 );2140 );
20762141
2077 cases.add(2142 cases.add(
...@@ -2083,7 +2148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2083,7 +2148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2083 \\ var bad = {};2148 \\ var bad = {};
2084 \\}2149 \\}
2085 ,2150 ,
2086 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2151 "tmp.zig:5:5: error: expected token ';', found 'var'",
2087 );2152 );
20882153
2089 cases.add(2154 cases.add(
...@@ -2095,7 +2160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2095,7 +2160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2095 \\ var bad = {};2160 \\ var bad = {};
2096 \\}2161 \\}
2097 ,2162 ,
2098 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2163 "tmp.zig:5:5: error: expected token ';', found 'var'",
2099 );2164 );
21002165
2101 cases.add(2166 cases.add(
...@@ -2107,7 +2172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2107,7 +2172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2107 \\ var bad = {};2172 \\ var bad = {};
2108 \\}2173 \\}
2109 ,2174 ,
2110 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2175 "tmp.zig:5:5: error: expected token ';', found 'var'",
2111 );2176 );
21122177
2113 cases.add(2178 cases.add(
...@@ -2119,7 +2184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2119,7 +2184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2119 \\ var bad = {};2184 \\ var bad = {};
2120 \\}2185 \\}
2121 ,2186 ,
2122 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2187 "tmp.zig:5:5: error: expected token ';', found 'var'",
2123 );2188 );
21242189
2125 cases.add(2190 cases.add(
...@@ -2131,7 +2196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2131,7 +2196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2131 \\ var bad = {};2196 \\ var bad = {};
2132 \\}2197 \\}
2133 ,2198 ,
2134 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2199 "tmp.zig:5:5: error: expected token ';', found 'var'",
2135 );2200 );
21362201
2137 cases.add(2202 cases.add(
...@@ -2143,7 +2208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2143,7 +2208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2143 \\ var bad = {};2208 \\ var bad = {};
2144 \\}2209 \\}
2145 ,2210 ,
2146 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2211 "tmp.zig:5:5: error: expected token ';', found 'var'",
2147 );2212 );
21482213
2149 cases.add(2214 cases.add(
...@@ -2155,7 +2220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2155,7 +2220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2155 \\ var bad = {};2220 \\ var bad = {};
2156 \\}2221 \\}
2157 ,2222 ,
2158 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2223 "tmp.zig:5:5: error: expected token ';', found 'var'",
2159 );2224 );
21602225
2161 cases.add(2226 cases.add(
...@@ -2167,7 +2232,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2167,7 +2232,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2167 \\ var bad = {};2232 \\ var bad = {};
2168 \\}2233 \\}
2169 ,2234 ,
2170 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2235 "tmp.zig:5:5: error: expected token ';', found 'var'",
2171 );2236 );
21722237
2173 cases.add(2238 cases.add(
...@@ -2179,7 +2244,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2179,7 +2244,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2179 \\ var bad = {};2244 \\ var bad = {};
2180 \\}2245 \\}
2181 ,2246 ,
2182 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2247 "tmp.zig:5:5: error: expected token ';', found 'var'",
2183 );2248 );
21842249
2185 cases.add(2250 cases.add(
...@@ -2191,7 +2256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2191,7 +2256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2191 \\ var bad = {};2256 \\ var bad = {};
2192 \\}2257 \\}
2193 ,2258 ,
2194 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2259 "tmp.zig:5:5: error: expected token ';', found 'var'",
2195 );2260 );
21962261
2197 cases.add(2262 cases.add(
...@@ -2203,7 +2268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2203,7 +2268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2203 \\ var bad = {};2268 \\ var bad = {};
2204 \\}2269 \\}
2205 ,2270 ,
2206 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",2271 "tmp.zig:5:5: error: expected token ';', found 'var'",
2207 );2272 );
22082273
2209 cases.add(2274 cases.add(
...@@ -2212,7 +2277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2212,7 +2277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2212 \\fn a() void {}2277 \\fn a() void {}
2213 \\export fn entry() void { a(); }2278 \\export fn entry() void { a(); }
2214 ,2279 ,
2215 ".tmp_source.zig:2:1: error: redefinition of 'a'",2280 "tmp.zig:2:1: error: redefinition of 'a'",
2216 );2281 );
22172282
2218 cases.add(2283 cases.add(
...@@ -2220,7 +2285,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2220,7 +2285,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2220 \\fn a() noreturn {return;}2285 \\fn a() noreturn {return;}
2221 \\export fn entry() void { a(); }2286 \\export fn entry() void { a(); }
2222 ,2287 ,
2223 ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'",2288 "tmp.zig:1:18: error: expected type 'noreturn', found 'void'",
2224 );2289 );
22252290
2226 cases.add(2291 cases.add(
...@@ -2228,7 +2293,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2228,7 +2293,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2228 \\fn a() i32 {}2293 \\fn a() i32 {}
2229 \\export fn entry() void { _ = a(); }2294 \\export fn entry() void { _ = a(); }
2230 ,2295 ,
2231 ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'",2296 "tmp.zig:1:12: error: expected type 'i32', found 'void'",
2232 );2297 );
22332298
2234 cases.add(2299 cases.add(
...@@ -2237,7 +2302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2237,7 +2302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2237 \\ b();2302 \\ b();
2238 \\}2303 \\}
2239 ,2304 ,
2240 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",2305 "tmp.zig:2:5: error: use of undeclared identifier 'b'",
2241 );2306 );
22422307
2243 cases.add(2308 cases.add(
...@@ -2247,7 +2312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2247,7 +2312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2247 \\}2312 \\}
2248 \\fn b(a: i32, b: i32, c: i32) void { }2313 \\fn b(a: i32, b: i32, c: i32) void { }
2249 ,2314 ,
2250 ".tmp_source.zig:2:6: error: expected 3 arguments, found 1",2315 "tmp.zig:2:6: error: expected 3 arguments, found 1",
2251 );2316 );
22522317
2253 cases.add(2318 cases.add(
...@@ -2255,7 +2320,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2255,7 +2320,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2255 \\fn a() bogus {}2320 \\fn a() bogus {}
2256 \\export fn entry() void { _ = a(); }2321 \\export fn entry() void { _ = a(); }
2257 ,2322 ,
2258 ".tmp_source.zig:1:8: error: use of undeclared identifier 'bogus'",2323 "tmp.zig:1:8: error: use of undeclared identifier 'bogus'",
2259 );2324 );
22602325
2261 cases.add(2326 cases.add(
...@@ -2263,7 +2328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2263,7 +2328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2263 \\fn a() *noreturn {}2328 \\fn a() *noreturn {}
2264 \\export fn entry() void { _ = a(); }2329 \\export fn entry() void { _ = a(); }
2265 ,2330 ,
2266 ".tmp_source.zig:1:8: error: pointer to noreturn not allowed",2331 "tmp.zig:1:8: error: pointer to noreturn not allowed",
2267 );2332 );
22682333
2269 cases.add(2334 cases.add(
...@@ -2275,7 +2340,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2275,7 +2340,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2275 \\2340 \\
2276 \\fn b() void {}2341 \\fn b() void {}
2277 ,2342 ,
2278 ".tmp_source.zig:3:5: error: unreachable code",2343 "tmp.zig:3:5: error: unreachable code",
2279 );2344 );
22802345
2281 cases.add(2346 cases.add(
...@@ -2283,7 +2348,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2283,7 +2348,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2283 \\const bogus = @import("bogus-does-not-exist.zig",);2348 \\const bogus = @import("bogus-does-not-exist.zig",);
2284 \\export fn entry() void { bogus.bogo(); }2349 \\export fn entry() void { bogus.bogo(); }
2285 ,2350 ,
2286 ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",2351 "tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
2287 );2352 );
22882353
2289 cases.add(2354 cases.add(
...@@ -2294,8 +2359,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2294,8 +2359,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2294 \\ c;2359 \\ c;
2295 \\}2360 \\}
2296 ,2361 ,
2297 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",2362 "tmp.zig:3:5: error: use of undeclared identifier 'b'",
2298 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'",2363 "tmp.zig:4:5: error: use of undeclared identifier 'c'",
2299 );2364 );
23002365
2301 cases.add(2366 cases.add(
...@@ -2304,7 +2369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2304,7 +2369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2304 \\}2369 \\}
2305 \\export fn entry() void { f(1, 2); }2370 \\export fn entry() void { f(1, 2); }
2306 ,2371 ,
2307 ".tmp_source.zig:1:15: error: redeclaration of variable 'a'",2372 "tmp.zig:1:15: error: redeclaration of variable 'a'",
2308 );2373 );
23092374
2310 cases.add(2375 cases.add(
...@@ -2314,7 +2379,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2314,7 +2379,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2314 \\ const a = 0;2379 \\ const a = 0;
2315 \\}2380 \\}
2316 ,2381 ,
2317 ".tmp_source.zig:3:5: error: redeclaration of variable 'a'",2382 "tmp.zig:3:5: error: redeclaration of variable 'a'",
2318 );2383 );
23192384
2320 cases.add(2385 cases.add(
...@@ -2324,7 +2389,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2324,7 +2389,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2324 \\}2389 \\}
2325 \\export fn entry() void { f(1); }2390 \\export fn entry() void { f(1); }
2326 ,2391 ,
2327 ".tmp_source.zig:2:5: error: redeclaration of variable 'a'",2392 "tmp.zig:2:5: error: redeclaration of variable 'a'",
2328 );2393 );
23292394
2330 cases.add(2395 cases.add(
...@@ -2334,7 +2399,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2334,7 +2399,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2334 \\ return a;2399 \\ return a;
2335 \\}2400 \\}
2336 ,2401 ,
2337 ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'",2402 "tmp.zig:3:12: error: expected type 'i32', found '[*]const u8'",
2338 );2403 );
23392404
2340 cases.add(2405 cases.add(
...@@ -2343,7 +2408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2343,7 +2408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2343 \\ if (0) {}2408 \\ if (0) {}
2344 \\}2409 \\}
2345 ,2410 ,
2346 ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'",2411 "tmp.zig:2:9: error: expected type 'bool', found 'comptime_int'",
2347 );2412 );
23482413
2349 cases.add(2414 cases.add(
...@@ -2352,7 +2417,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2352,7 +2417,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2352 \\ const a = return;2417 \\ const a = return;
2353 \\}2418 \\}
2354 ,2419 ,
2355 ".tmp_source.zig:2:5: error: unreachable code",2420 "tmp.zig:2:5: error: unreachable code",
2356 );2421 );
23572422
2358 cases.add(2423 cases.add(
...@@ -2361,7 +2426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2361,7 +2426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2361 \\ const a: noreturn = {};2426 \\ const a: noreturn = {};
2362 \\}2427 \\}
2363 ,2428 ,
2364 ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed",2429 "tmp.zig:2:14: error: variable of type 'noreturn' not allowed",
2365 );2430 );
23662431
2367 cases.add(2432 cases.add(
...@@ -2369,7 +2434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2369,7 +2434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2369 \\fn f(a: noreturn) void {}2434 \\fn f(a: noreturn) void {}
2370 \\export fn entry() void { f(); }2435 \\export fn entry() void { f(); }
2371 ,2436 ,
2372 ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed",2437 "tmp.zig:1:9: error: parameter of type 'noreturn' not allowed",
2373 );2438 );
23742439
2375 cases.add(2440 cases.add(
...@@ -2378,7 +2443,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2378,7 +2443,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2378 \\ 3 = 3;2443 \\ 3 = 3;
2379 \\}2444 \\}
2380 ,2445 ,
2381 ".tmp_source.zig:2:7: error: cannot assign to constant",2446 "tmp.zig:2:7: error: cannot assign to constant",
2382 );2447 );
23832448
2384 cases.add(2449 cases.add(
...@@ -2388,7 +2453,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2388,7 +2453,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2388 \\ a = 4;2453 \\ a = 4;
2389 \\}2454 \\}
2390 ,2455 ,
2391 ".tmp_source.zig:3:7: error: cannot assign to constant",2456 "tmp.zig:3:7: error: cannot assign to constant",
2392 );2457 );
23932458
2394 cases.add(2459 cases.add(
...@@ -2397,7 +2462,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2397,7 +2462,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2397 \\ b = 3;2462 \\ b = 3;
2398 \\}2463 \\}
2399 ,2464 ,
2400 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",2465 "tmp.zig:2:5: error: use of undeclared identifier 'b'",
2401 );2466 );
24022467
2403 cases.add(2468 cases.add(
...@@ -2406,7 +2471,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2406,7 +2471,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2406 \\ (const a = 0);2471 \\ (const a = 0);
2407 \\}2472 \\}
2408 ,2473 ,
2409 ".tmp_source.zig:2:6: error: invalid token: 'const'",2474 "tmp.zig:2:6: error: invalid token: 'const'",
2410 );2475 );
24112476
2412 cases.add(2477 cases.add(
...@@ -2415,7 +2480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2415,7 +2480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2415 \\ i[i] = i[i];2480 \\ i[i] = i[i];
2416 \\}2481 \\}
2417 ,2482 ,
2418 ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",2483 "tmp.zig:2:5: error: use of undeclared identifier 'i'",
2419 );2484 );
24202485
2421 cases.add(2486 cases.add(
...@@ -2425,8 +2490,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2425,8 +2490,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2425 \\ bad[bad] = bad[bad];2490 \\ bad[bad] = bad[bad];
2426 \\}2491 \\}
2427 ,2492 ,
2428 ".tmp_source.zig:3:8: error: array access of non-array type 'bool'",2493 "tmp.zig:3:8: error: array access of non-array type 'bool'",
2429 ".tmp_source.zig:3:19: error: array access of non-array type 'bool'",2494 "tmp.zig:3:19: error: array access of non-array type 'bool'",
2430 );2495 );
24312496
2432 cases.add(2497 cases.add(
...@@ -2437,8 +2502,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2437,8 +2502,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2437 \\ array[bad] = array[bad];2502 \\ array[bad] = array[bad];
2438 \\}2503 \\}
2439 ,2504 ,
2440 ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'",2505 "tmp.zig:4:11: error: expected type 'usize', found 'bool'",
2441 ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'",2506 "tmp.zig:4:24: error: expected type 'usize', found 'bool'",
2442 );2507 );
24432508
2444 cases.add(2509 cases.add(
...@@ -2449,7 +2514,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2449,7 +2514,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2449 \\}2514 \\}
2450 \\export fn entry() void { f(); }2515 \\export fn entry() void { f(); }
2451 ,2516 ,
2452 ".tmp_source.zig:3:7: error: cannot assign to constant",2517 "tmp.zig:3:7: error: cannot assign to constant",
2453 );2518 );
24542519
2455 cases.add(2520 cases.add(
...@@ -2460,26 +2525,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2460,26 +2525,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2460 \\}2525 \\}
2461 \\export fn entry() void { f(true); }2526 \\export fn entry() void { f(true); }
2462 ,2527 ,
2463 ".tmp_source.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",2528 "tmp.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
2464 ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'",2529 "tmp.zig:3:15: error: incompatible types: 'i32' and 'void'",
2465 );
2466
2467 cases.add(
2468 "direct struct loop",
2469 \\const A = struct { a : A, };
2470 \\export fn entry() usize { return @sizeOf(A); }
2471 ,
2472 ".tmp_source.zig:1:11: error: struct 'A' contains itself",
2473 );
2474
2475 cases.add(
2476 "indirect struct loop",
2477 \\const A = struct { b : B, };
2478 \\const B = struct { c : C, };
2479 \\const C = struct { a : A, };
2480 \\export fn entry() usize { return @sizeOf(A); }
2481 ,
2482 ".tmp_source.zig:1:11: error: struct 'A' contains itself",
2483 );2530 );
24842531
2485 cases.add(2532 cases.add(
...@@ -2491,8 +2538,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2491,8 +2538,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2491 \\ const y = a.bar;2538 \\ const y = a.bar;
2492 \\}2539 \\}
2493 ,2540 ,
2494 ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",2541 "tmp.zig:4:6: error: no member named 'foo' in struct 'A'",
2495 ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'",2542 "tmp.zig:5:16: error: no member named 'bar' in struct 'A'",
2496 );2543 );
24972544
2498 cases.add(2545 cases.add(
...@@ -2500,7 +2547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2500,7 +2547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2500 \\const A = struct { x : i32, };2547 \\const A = struct { x : i32, };
2501 \\const A = struct { y : i32, };2548 \\const A = struct { y : i32, };
2502 ,2549 ,
2503 ".tmp_source.zig:2:1: error: redefinition of 'A'",2550 "tmp.zig:2:1: error: redefinition of 'A'",
2504 );2551 );
25052552
2506 cases.add(2553 cases.add(
...@@ -2508,7 +2555,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2508,7 +2555,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2508 \\const A = enum {};2555 \\const A = enum {};
2509 \\const A = enum {};2556 \\const A = enum {};
2510 ,2557 ,
2511 ".tmp_source.zig:2:1: error: redefinition of 'A'",2558 "tmp.zig:2:1: error: redefinition of 'A'",
2512 );2559 );
25132560
2514 cases.add(2561 cases.add(
...@@ -2516,8 +2563,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2516,8 +2563,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2516 \\var a : i32 = 1;2563 \\var a : i32 = 1;
2517 \\var a : i32 = 2;2564 \\var a : i32 = 2;
2518 ,2565 ,
2519 ".tmp_source.zig:2:1: error: redefinition of 'a'",2566 "tmp.zig:2:1: error: redefinition of 'a'",
2520 ".tmp_source.zig:1:1: note: previous definition is here",2567 "tmp.zig:1:1: note: previous definition is here",
2521 );2568 );
25222569
2523 cases.add(2570 cases.add(
...@@ -2536,7 +2583,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2536,7 +2583,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2536 \\ };2583 \\ };
2537 \\}2584 \\}
2538 ,2585 ,
2539 ".tmp_source.zig:11:9: error: duplicate field",2586 "tmp.zig:11:9: error: duplicate field",
2540 );2587 );
25412588
2542 cases.add(2589 cases.add(
...@@ -2555,7 +2602,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2555,7 +2602,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2555 \\ };2602 \\ };
2556 \\}2603 \\}
2557 ,2604 ,
2558 ".tmp_source.zig:9:17: error: missing field: 'x'",2605 "tmp.zig:9:17: error: missing field: 'x'",
2559 );2606 );
25602607
2561 cases.add(2608 cases.add(
...@@ -2573,7 +2620,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2573,7 +2620,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2573 \\ };2620 \\ };
2574 \\}2621 \\}
2575 ,2622 ,
2576 ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'",2623 "tmp.zig:10:9: error: no member named 'foo' in struct 'A'",
2577 );2624 );
25782625
2579 cases.add(2626 cases.add(
...@@ -2582,7 +2629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2582,7 +2629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2582 \\ break;2629 \\ break;
2583 \\}2630 \\}
2584 ,2631 ,
2585 ".tmp_source.zig:2:5: error: break expression outside loop",2632 "tmp.zig:2:5: error: break expression outside loop",
2586 );2633 );
25872634
2588 cases.add(2635 cases.add(
...@@ -2591,7 +2638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2591,7 +2638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2591 \\ continue;2638 \\ continue;
2592 \\}2639 \\}
2593 ,2640 ,
2594 ".tmp_source.zig:2:5: error: continue expression outside loop",2641 "tmp.zig:2:5: error: continue expression outside loop",
2595 );2642 );
25962643
2597 cases.add(2644 cases.add(
...@@ -2600,7 +2647,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2600,7 +2647,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2600 \\ if (true) |x| { }2647 \\ if (true) |x| { }
2601 \\}2648 \\}
2602 ,2649 ,
2603 ".tmp_source.zig:2:9: error: expected optional type, found 'bool'",2650 "tmp.zig:2:9: error: expected optional type, found 'bool'",
2604 );2651 );
26052652
2606 cases.add(2653 cases.add(
...@@ -2610,7 +2657,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2610,7 +2657,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2610 \\}2657 \\}
2611 \\export fn entry() void { _ = f(); }2658 \\export fn entry() void { _ = f(); }
2612 ,2659 ,
2613 ".tmp_source.zig:2:15: error: unreachable code",2660 "tmp.zig:2:15: error: unreachable code",
2614 );2661 );
26152662
2616 cases.add(2663 cases.add(
...@@ -2619,18 +2666,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2619,18 +2666,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2619 \\}2666 \\}
2620 \\export fn entry() void { _ = f(); }2667 \\export fn entry() void { _ = f(); }
2621 ,2668 ,
2622 ".tmp_source.zig:1:8: error: invalid builtin function: 'bogus'",2669 "tmp.zig:1:8: error: invalid builtin function: 'bogus'",
2623 );
2624
2625 cases.add(
2626 "top level decl dependency loop",
2627 \\const a : @typeOf(b) = 0;
2628 \\const b : @typeOf(a) = 0;
2629 \\export fn entry() void {
2630 \\ const c = a + b;
2631 \\}
2632 ,
2633 ".tmp_source.zig:1:1: error: 'a' depends on itself",
2634 );2670 );
26352671
2636 cases.add(2672 cases.add(
...@@ -2638,7 +2674,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2638,7 +2674,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2638 \\fn f(noalias x: i32) void {}2674 \\fn f(noalias x: i32) void {}
2639 \\export fn entry() void { f(1234); }2675 \\export fn entry() void { f(1234); }
2640 ,2676 ,
2641 ".tmp_source.zig:1:6: error: noalias on non-pointer parameter",2677 "tmp.zig:1:6: error: noalias on non-pointer parameter",
2642 );2678 );
26432679
2644 cases.add(2680 cases.add(
...@@ -2646,7 +2682,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2646,7 +2682,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2646 \\const foo = []u16{.x = 1024,};2682 \\const foo = []u16{.x = 1024,};
2647 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }2683 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2648 ,2684 ,
2649 ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax",2685 "tmp.zig:1:18: error: type '[]u16' does not support struct initialization syntax",
2650 );2686 );
26512687
2652 cases.add(2688 cases.add(
...@@ -2656,7 +2692,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2656,7 +2692,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2656 \\ return 1;2692 \\ return 1;
2657 \\}2693 \\}
2658 ,2694 ,
2659 ".tmp_source.zig:1:1: error: variable of type 'type' must be constant",2695 "tmp.zig:1:1: error: variable of type 'type' must be constant",
2660 );2696 );
26612697
2662 cases.add(2698 cases.add(
...@@ -2672,10 +2708,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2672,10 +2708,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2672 \\ f(1234);2708 \\ f(1234);
2673 \\}2709 \\}
2674 ,2710 ,
2675 ".tmp_source.zig:4:6: error: redefinition of 'Foo'",2711 "tmp.zig:4:6: error: redefinition of 'Foo'",
2676 ".tmp_source.zig:1:1: note: previous definition is here",2712 "tmp.zig:1:1: note: previous definition is here",
2677 ".tmp_source.zig:5:5: error: redefinition of 'Bar'",2713 "tmp.zig:5:5: error: redefinition of 'Bar'",
2678 ".tmp_source.zig:2:1: note: previous definition is here",2714 "tmp.zig:2:1: note: previous definition is here",
2679 );2715 );
26802716
2681 cases.add(2717 cases.add(
...@@ -2696,7 +2732,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2696,7 +2732,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2696 \\2732 \\
2697 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }2733 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2698 ,2734 ,
2699 ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch",2735 "tmp.zig:8:5: error: enumeration value 'Number.Four' not handled in switch",
2700 );2736 );
27012737
2702 cases.add(2738 cases.add(
...@@ -2719,8 +2755,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2719,8 +2755,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2719 \\2755 \\
2720 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }2756 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2721 ,2757 ,
2722 ".tmp_source.zig:13:15: error: duplicate switch value",2758 "tmp.zig:13:15: error: duplicate switch value",
2723 ".tmp_source.zig:10:15: note: other value is here",2759 "tmp.zig:10:15: note: other value is here",
2724 );2760 );
27252761
2726 cases.add(2762 cases.add(
...@@ -2744,8 +2780,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2744,8 +2780,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2744 \\2780 \\
2745 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }2781 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2746 ,2782 ,
2747 ".tmp_source.zig:13:15: error: duplicate switch value",2783 "tmp.zig:13:15: error: duplicate switch value",
2748 ".tmp_source.zig:10:15: note: other value is here",2784 "tmp.zig:10:15: note: other value is here",
2749 );2785 );
27502786
2751 cases.add(2787 cases.add(
...@@ -2761,7 +2797,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2761,7 +2797,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2761 \\ f(1234);2797 \\ f(1234);
2762 \\}2798 \\}
2763 ,2799 ,
2764 ".tmp_source.zig:5:9: error: multiple else prongs in switch expression",2800 "tmp.zig:5:9: error: multiple else prongs in switch expression",
2765 );2801 );
27662802
2767 cases.add(2803 cases.add(
...@@ -2773,7 +2809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2773,7 +2809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2773 \\}2809 \\}
2774 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }2810 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2775 ,2811 ,
2776 ".tmp_source.zig:2:5: error: switch must handle all possibilities",2812 "tmp.zig:2:5: error: switch must handle all possibilities",
2777 );2813 );
27782814
2779 cases.add(2815 cases.add(
...@@ -2788,8 +2824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2788,8 +2824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2788 \\}2824 \\}
2789 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }2825 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2790 ,2826 ,
2791 ".tmp_source.zig:6:9: error: duplicate switch value",2827 "tmp.zig:6:9: error: duplicate switch value",
2792 ".tmp_source.zig:5:14: note: previous value is here",2828 "tmp.zig:5:14: note: previous value is here",
2793 );2829 );
27942830
2795 cases.add(2831 cases.add(
...@@ -2802,7 +2838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2802,7 +2838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2802 \\const y: u8 = 100;2838 \\const y: u8 = 100;
2803 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }2839 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2804 ,2840 ,
2805 ".tmp_source.zig:2:5: error: else prong required when switching on type '*u8'",2841 "tmp.zig:2:5: error: else prong required when switching on type '*u8'",
2806 );2842 );
28072843
2808 cases.add(2844 cases.add(
...@@ -2811,7 +2847,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2811,7 +2847,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2811 \\const x = foo();2847 \\const x = foo();
2812 \\export fn entry() i32 { return x; }2848 \\export fn entry() i32 { return x; }
2813 ,2849 ,
2814 ".tmp_source.zig:2:11: error: unable to evaluate constant expression",2850 "tmp.zig:2:11: error: unable to evaluate constant expression",
2815 );2851 );
28162852
2817 cases.add(2853 cases.add(
...@@ -2822,7 +2858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2822,7 +2858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2822 \\2858 \\
2823 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }2859 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
2824 ,2860 ,
2825 ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'",2861 "tmp.zig:3:11: error: expected array or C string literal, found 'usize'",
2826 );2862 );
28272863
2828 cases.add(2864 cases.add(
...@@ -2833,7 +2869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2833,7 +2869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2833 \\var s: [10]u8 = undefined;2869 \\var s: [10]u8 = undefined;
2834 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }2870 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2835 ,2871 ,
2836 ".tmp_source.zig:2:12: error: unable to evaluate constant expression",2872 "tmp.zig:2:12: error: unable to evaluate constant expression",
2837 );2873 );
28382874
2839 cases.add(2875 cases.add(
...@@ -2841,7 +2877,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2841,7 +2877,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2841 \\const c = @cImport(@cInclude("bogus.h"));2877 \\const c = @cImport(@cInclude("bogus.h"));
2842 \\export fn entry() usize { return @sizeOf(@typeOf(c.bogo)); }2878 \\export fn entry() usize { return @sizeOf(@typeOf(c.bogo)); }
2843 ,2879 ,
2844 ".tmp_source.zig:1:11: error: C import failed",2880 "tmp.zig:1:11: error: C import failed",
2845 ".h:1:10: note: 'bogus.h' file not found",2881 ".h:1:10: note: 'bogus.h' file not found",
2846 );2882 );
28472883
...@@ -2852,7 +2888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2852,7 +2888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2852 \\fn foo() *const i32 { return y; }2888 \\fn foo() *const i32 { return y; }
2853 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }2889 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2854 ,2890 ,
2855 ".tmp_source.zig:3:30: error: expected type '*const i32', found '*const comptime_int'",2891 "tmp.zig:3:30: error: expected type '*const i32', found '*const comptime_int'",
2856 );2892 );
28572893
2858 cases.add(2894 cases.add(
...@@ -2860,7 +2896,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2860,7 +2896,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2860 \\const x : u8 = 300;2896 \\const x : u8 = 300;
2861 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }2897 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2862 ,2898 ,
2863 ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",2899 "tmp.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",
2864 );2900 );
28652901
2866 cases.add(2902 cases.add(
...@@ -2871,8 +2907,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2871,8 +2907,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2871 \\}2907 \\}
2872 \\export fn entry() u16 { return f(); }2908 \\export fn entry() u16 { return f(); }
2873 ,2909 ,
2874 ".tmp_source.zig:3:14: error: RHS of shift is too large for LHS type",2910 "tmp.zig:3:14: error: RHS of shift is too large for LHS type",
2875 ".tmp_source.zig:3:17: note: value 8 cannot fit into type u3",2911 "tmp.zig:3:17: note: value 8 cannot fit into type u3",
2876 );2912 );
28772913
2878 cases.add(2914 cases.add(
...@@ -2880,7 +2916,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2880,7 +2916,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2880 \\const x = 2 == 2.0;2916 \\const x = 2 == 2.0;
2881 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }2917 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2882 ,2918 ,
2883 ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type 'comptime_float'",2919 "tmp.zig:1:11: error: integer value 2 cannot be implicitly casted to type 'comptime_float'",
2884 );2920 );
28852921
2886 cases.add(2922 cases.add(
...@@ -2909,7 +2945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2909,7 +2945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2909 \\2945 \\
2910 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }2946 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2911 ,2947 ,
2912 ".tmp_source.zig:20:34: error: expected 1 arguments, found 0",2948 "tmp.zig:20:34: error: expected 1 arguments, found 0",
2913 );2949 );
29142950
2915 cases.add(2951 cases.add(
...@@ -2918,8 +2954,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2918,8 +2954,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2918 \\fn f(i32) void {}2954 \\fn f(i32) void {}
2919 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }2955 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
2920 ,2956 ,
2921 ".tmp_source.zig:1:1: error: missing function name",2957 "tmp.zig:1:1: error: missing function name",
2922 ".tmp_source.zig:2:6: error: missing parameter name",2958 "tmp.zig:2:6: error: missing parameter name",
2923 );2959 );
29242960
2925 cases.add(2961 cases.add(
...@@ -2930,7 +2966,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2930,7 +2966,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2930 \\fn c() i32 {return 2;}2966 \\fn c() i32 {return 2;}
2931 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }2967 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
2932 ,2968 ,
2933 ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'",2969 "tmp.zig:1:27: error: expected type 'fn() void', found 'fn() i32'",
2934 );2970 );
29352971
2936 cases.add(2972 cases.add(
...@@ -2942,7 +2978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2942,7 +2978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2942 \\2978 \\
2943 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }2979 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
2944 ,2980 ,
2945 ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'",2981 "tmp.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'",
2946 );2982 );
29472983
2948 cases.add(2984 cases.add(
...@@ -2951,16 +2987,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2951,16 +2987,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2951 \\fn func() bogus {}2987 \\fn func() bogus {}
2952 \\export fn entry() usize { return @sizeOf(@typeOf(func)); }2988 \\export fn entry() usize { return @sizeOf(@typeOf(func)); }
2953 ,2989 ,
2954 ".tmp_source.zig:2:1: error: redefinition of 'func'",2990 "tmp.zig:2:1: error: redefinition of 'func'",
2955 ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'",2991 "tmp.zig:1:11: error: use of undeclared identifier 'bogus'",
2956 );
2957
2958 cases.add(
2959 "bogus compile var",
2960 \\const x = @import("builtin").bogus;
2961 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2962 ,
2963 ".tmp_source.zig:1:29: error: no member named 'bogus' in '",
2964 );2992 );
29652993
2966 cases.add(2994 cases.add(
...@@ -2973,9 +3001,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2973,9 +3001,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2973 \\3001 \\
2974 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }3002 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
2975 ,3003 ,
2976 ".tmp_source.zig:5:25: error: unable to evaluate constant expression",3004 "tmp.zig:5:25: error: unable to evaluate constant expression",
2977 ".tmp_source.zig:2:12: note: called from here",3005 "tmp.zig:2:12: note: called from here",
2978 ".tmp_source.zig:2:8: note: called from here",3006 "tmp.zig:2:8: note: called from here",
2979 );3007 );
29803008
2981 cases.add(3009 cases.add(
...@@ -2987,7 +3015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2987,7 +3015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2987 \\3015 \\
2988 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }3016 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
2989 ,3017 ,
2990 ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'",3018 "tmp.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'",
2991 );3019 );
29923020
2993 cases.add(3021 cases.add(
...@@ -3002,10 +3030,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3002,10 +3030,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3002 \\export fn entry3() usize { return @sizeOf(@typeOf(int_x)); }3030 \\export fn entry3() usize { return @sizeOf(@typeOf(int_x)); }
3003 \\export fn entry4() usize { return @sizeOf(@typeOf(float_x)); }3031 \\export fn entry4() usize { return @sizeOf(@typeOf(float_x)); }
3004 ,3032 ,
3005 ".tmp_source.zig:1:21: error: division by zero",3033 "tmp.zig:1:21: error: division by zero",
3006 ".tmp_source.zig:2:25: error: division by zero",3034 "tmp.zig:2:25: error: division by zero",
3007 ".tmp_source.zig:3:22: error: division by zero",3035 "tmp.zig:3:22: error: division by zero",
3008 ".tmp_source.zig:4:26: error: division by zero",3036 "tmp.zig:4:26: error: division by zero",
3009 );3037 );
30103038
3011 cases.add(3039 cases.add(
...@@ -3015,7 +3043,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3015,7 +3043,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3015 \\3043 \\
3016 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }3044 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
3017 ,3045 ,
3018 ".tmp_source.zig:1:15: error: newline not allowed in string literal",3046 "tmp.zig:1:15: error: newline not allowed in string literal",
3019 );3047 );
30203048
3021 cases.add(3049 cases.add(
...@@ -3025,7 +3053,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3025,7 +3053,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3025 \\3053 \\
3026 \\export fn entry() usize { return @sizeOf(@typeOf(invalid)); }3054 \\export fn entry() usize { return @sizeOf(@typeOf(invalid)); }
3027 ,3055 ,
3028 ".tmp_source.zig:2:21: error: operator not allowed for type 'fn() void'",3056 "tmp.zig:2:21: error: operator not allowed for type 'fn() void'",
3029 );3057 );
30303058
3031 cases.add(3059 cases.add(
...@@ -3037,7 +3065,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3037,7 +3065,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3037 \\3065 \\
3038 \\export fn entry() usize { return @sizeOf(@typeOf(test1)); }3066 \\export fn entry() usize { return @sizeOf(@typeOf(test1)); }
3039 ,3067 ,
3040 ".tmp_source.zig:3:16: error: unable to evaluate constant expression",3068 "tmp.zig:3:16: error: unable to evaluate constant expression",
3041 );3069 );
30423070
3043 cases.add(3071 cases.add(
...@@ -3046,7 +3074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3046,7 +3074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3046 \\3074 \\
3047 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }3075 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
3048 ,3076 ,
3049 ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'",3077 "tmp.zig:1:16: error: expected type '*u8', found '(null)'",
3050 );3078 );
30513079
3052 cases.add(3080 cases.add(
...@@ -3056,7 +3084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3056,7 +3084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3056 \\ const pointer = &array[0];3084 \\ const pointer = &array[0];
3057 \\}3085 \\}
3058 ,3086 ,
3059 ".tmp_source.zig:3:27: error: index 0 outside array of size 0",3087 "tmp.zig:3:27: error: index 0 outside array of size 0",
3060 );3088 );
30613089
3062 cases.add(3090 cases.add(
...@@ -3068,8 +3096,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3068,8 +3096,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3068 \\3096 \\
3069 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }3097 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
3070 ,3098 ,
3071 ".tmp_source.zig:3:14: error: division by zero",3099 "tmp.zig:3:14: error: division by zero",
3072 ".tmp_source.zig:1:14: note: called from here",3100 "tmp.zig:1:14: note: called from here",
3073 );3101 );
30743102
3075 cases.add(3103 cases.add(
...@@ -3078,7 +3106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3078,7 +3106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3078 \\3106 \\
3079 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }3107 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
3080 ,3108 ,
3081 ".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior",3109 "tmp.zig:1:15: error: use of undefined value here causes undefined behavior",
3082 );3110 );
30833111
3084 cases.add(3112 cases.add(
...@@ -3088,7 +3116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3088,7 +3116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3088 \\ _ = a / a;3116 \\ _ = a / a;
3089 \\}3117 \\}
3090 ,3118 ,
3091 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3119 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3092 );3120 );
30933121
3094 cases.add(3122 cases.add(
...@@ -3098,7 +3126,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3098,7 +3126,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3098 \\ a /= a;3126 \\ a /= a;
3099 \\}3127 \\}
3100 ,3128 ,
3101 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3129 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3102 );3130 );
31033131
3104 cases.add(3132 cases.add(
...@@ -3108,7 +3136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3108,7 +3136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3108 \\ _ = a % a;3136 \\ _ = a % a;
3109 \\}3137 \\}
3110 ,3138 ,
3111 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3139 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3112 );3140 );
31133141
3114 cases.add(3142 cases.add(
...@@ -3118,7 +3146,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3118,7 +3146,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3118 \\ a %= a;3146 \\ a %= a;
3119 \\}3147 \\}
3120 ,3148 ,
3121 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3149 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3122 );3150 );
31233151
3124 cases.add(3152 cases.add(
...@@ -3128,7 +3156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3128,7 +3156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3128 \\ _ = a + a;3156 \\ _ = a + a;
3129 \\}3157 \\}
3130 ,3158 ,
3131 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3159 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3132 );3160 );
31333161
3134 cases.add(3162 cases.add(
...@@ -3138,7 +3166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3138,7 +3166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3138 \\ a += a;3166 \\ a += a;
3139 \\}3167 \\}
3140 ,3168 ,
3141 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3169 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3142 );3170 );
31433171
3144 cases.add(3172 cases.add(
...@@ -3148,7 +3176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3148,7 +3176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3148 \\ _ = a +% a;3176 \\ _ = a +% a;
3149 \\}3177 \\}
3150 ,3178 ,
3151 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3179 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3152 );3180 );
31533181
3154 cases.add(3182 cases.add(
...@@ -3158,7 +3186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3158,7 +3186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3158 \\ a +%= a;3186 \\ a +%= a;
3159 \\}3187 \\}
3160 ,3188 ,
3161 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3189 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3162 );3190 );
31633191
3164 cases.add(3192 cases.add(
...@@ -3168,7 +3196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3168,7 +3196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3168 \\ _ = a - a;3196 \\ _ = a - a;
3169 \\}3197 \\}
3170 ,3198 ,
3171 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3199 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3172 );3200 );
31733201
3174 cases.add(3202 cases.add(
...@@ -3178,7 +3206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3178,7 +3206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3178 \\ a -= a;3206 \\ a -= a;
3179 \\}3207 \\}
3180 ,3208 ,
3181 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3209 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3182 );3210 );
31833211
3184 cases.add(3212 cases.add(
...@@ -3188,7 +3216,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3188,7 +3216,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3188 \\ _ = a -% a;3216 \\ _ = a -% a;
3189 \\}3217 \\}
3190 ,3218 ,
3191 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3219 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3192 );3220 );
31933221
3194 cases.add(3222 cases.add(
...@@ -3198,7 +3226,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3198,7 +3226,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3198 \\ a -%= a;3226 \\ a -%= a;
3199 \\}3227 \\}
3200 ,3228 ,
3201 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3229 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3202 );3230 );
32033231
3204 cases.add(3232 cases.add(
...@@ -3208,7 +3236,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3208,7 +3236,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3208 \\ _ = a * a;3236 \\ _ = a * a;
3209 \\}3237 \\}
3210 ,3238 ,
3211 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3239 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3212 );3240 );
32133241
3214 cases.add(3242 cases.add(
...@@ -3218,7 +3246,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3218,7 +3246,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3218 \\ a *= a;3246 \\ a *= a;
3219 \\}3247 \\}
3220 ,3248 ,
3221 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3249 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3222 );3250 );
32233251
3224 cases.add(3252 cases.add(
...@@ -3228,7 +3256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3228,7 +3256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3228 \\ _ = a *% a;3256 \\ _ = a *% a;
3229 \\}3257 \\}
3230 ,3258 ,
3231 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3259 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3232 );3260 );
32333261
3234 cases.add(3262 cases.add(
...@@ -3238,7 +3266,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3238,7 +3266,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3238 \\ a *%= a;3266 \\ a *%= a;
3239 \\}3267 \\}
3240 ,3268 ,
3241 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3269 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3242 );3270 );
32433271
3244 cases.add(3272 cases.add(
...@@ -3248,7 +3276,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3248,7 +3276,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3248 \\ _ = a << 2;3276 \\ _ = a << 2;
3249 \\}3277 \\}
3250 ,3278 ,
3251 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3279 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3252 );3280 );
32533281
3254 cases.add(3282 cases.add(
...@@ -3258,7 +3286,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3258,7 +3286,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3258 \\ a <<= 2;3286 \\ a <<= 2;
3259 \\}3287 \\}
3260 ,3288 ,
3261 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3289 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3262 );3290 );
32633291
3264 cases.add(3292 cases.add(
...@@ -3268,7 +3296,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3268,7 +3296,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3268 \\ _ = a >> 2;3296 \\ _ = a >> 2;
3269 \\}3297 \\}
3270 ,3298 ,
3271 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3299 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3272 );3300 );
32733301
3274 cases.add(3302 cases.add(
...@@ -3278,7 +3306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3278,7 +3306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3278 \\ a >>= 2;3306 \\ a >>= 2;
3279 \\}3307 \\}
3280 ,3308 ,
3281 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3309 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3282 );3310 );
32833311
3284 cases.add(3312 cases.add(
...@@ -3288,7 +3316,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3288,7 +3316,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3288 \\ _ = a & a;3316 \\ _ = a & a;
3289 \\}3317 \\}
3290 ,3318 ,
3291 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3319 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3292 );3320 );
32933321
3294 cases.add(3322 cases.add(
...@@ -3298,7 +3326,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3298,7 +3326,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3298 \\ a &= a;3326 \\ a &= a;
3299 \\}3327 \\}
3300 ,3328 ,
3301 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3329 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3302 );3330 );
33033331
3304 cases.add(3332 cases.add(
...@@ -3308,7 +3336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3308,7 +3336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3308 \\ _ = a | a;3336 \\ _ = a | a;
3309 \\}3337 \\}
3310 ,3338 ,
3311 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3339 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3312 );3340 );
33133341
3314 cases.add(3342 cases.add(
...@@ -3318,7 +3346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3318,7 +3346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3318 \\ a |= a;3346 \\ a |= a;
3319 \\}3347 \\}
3320 ,3348 ,
3321 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3349 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3322 );3350 );
33233351
3324 cases.add(3352 cases.add(
...@@ -3328,7 +3356,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3328,7 +3356,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3328 \\ _ = a ^ a;3356 \\ _ = a ^ a;
3329 \\}3357 \\}
3330 ,3358 ,
3331 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3359 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3332 );3360 );
33333361
3334 cases.add(3362 cases.add(
...@@ -3338,7 +3366,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3338,7 +3366,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3338 \\ a ^= a;3366 \\ a ^= a;
3339 \\}3367 \\}
3340 ,3368 ,
3341 ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",3369 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
3342 );3370 );
33433371
3344 cases.add(3372 cases.add(
...@@ -3348,7 +3376,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3348,7 +3376,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3348 \\ _ = a == a;3376 \\ _ = a == a;
3349 \\}3377 \\}
3350 ,3378 ,
3351 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3379 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3352 );3380 );
33533381
3354 cases.add(3382 cases.add(
...@@ -3358,7 +3386,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3358,7 +3386,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3358 \\ _ = a != a;3386 \\ _ = a != a;
3359 \\}3387 \\}
3360 ,3388 ,
3361 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3389 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3362 );3390 );
33633391
3364 cases.add(3392 cases.add(
...@@ -3368,7 +3396,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3368,7 +3396,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3368 \\ _ = a > a;3396 \\ _ = a > a;
3369 \\}3397 \\}
3370 ,3398 ,
3371 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3399 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3372 );3400 );
33733401
3374 cases.add(3402 cases.add(
...@@ -3378,7 +3406,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3378,7 +3406,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3378 \\ _ = a >= a;3406 \\ _ = a >= a;
3379 \\}3407 \\}
3380 ,3408 ,
3381 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3409 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3382 );3410 );
33833411
3384 cases.add(3412 cases.add(
...@@ -3388,7 +3416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3388,7 +3416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3388 \\ _ = a < a;3416 \\ _ = a < a;
3389 \\}3417 \\}
3390 ,3418 ,
3391 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3419 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3392 );3420 );
33933421
3394 cases.add(3422 cases.add(
...@@ -3398,7 +3426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3398,7 +3426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3398 \\ _ = a <= a;3426 \\ _ = a <= a;
3399 \\}3427 \\}
3400 ,3428 ,
3401 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3429 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3402 );3430 );
34033431
3404 cases.add(3432 cases.add(
...@@ -3408,7 +3436,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3408,7 +3436,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3408 \\ _ = a and a;3436 \\ _ = a and a;
3409 \\}3437 \\}
3410 ,3438 ,
3411 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3439 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3412 );3440 );
34133441
3414 cases.add(3442 cases.add(
...@@ -3418,7 +3446,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3418,7 +3446,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3418 \\ _ = a or a;3446 \\ _ = a or a;
3419 \\}3447 \\}
3420 ,3448 ,
3421 ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",3449 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
3422 );3450 );
34233451
3424 cases.add(3452 cases.add(
...@@ -3428,7 +3456,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3428,7 +3456,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3428 \\ _ = -a;3456 \\ _ = -a;
3429 \\}3457 \\}
3430 ,3458 ,
3431 ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",3459 "tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
3432 );3460 );
34333461
3434 cases.add(3462 cases.add(
...@@ -3438,7 +3466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3438,7 +3466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3438 \\ _ = -%a;3466 \\ _ = -%a;
3439 \\}3467 \\}
3440 ,3468 ,
3441 ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",3469 "tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
3442 );3470 );
34433471
3444 cases.add(3472 cases.add(
...@@ -3448,7 +3476,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3448,7 +3476,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3448 \\ _ = ~a;3476 \\ _ = ~a;
3449 \\}3477 \\}
3450 ,3478 ,
3451 ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",3479 "tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
3452 );3480 );
34533481
3454 cases.add(3482 cases.add(
...@@ -3458,7 +3486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3458,7 +3486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3458 \\ _ = !a;3486 \\ _ = !a;
3459 \\}3487 \\}
3460 ,3488 ,
3461 ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",3489 "tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
3462 );3490 );
34633491
3464 cases.add(3492 cases.add(
...@@ -3468,7 +3496,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3468,7 +3496,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3468 \\ _ = a orelse false;3496 \\ _ = a orelse false;
3469 \\}3497 \\}
3470 ,3498 ,
3471 ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",3499 "tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
3472 );3500 );
34733501
3474 cases.add(3502 cases.add(
...@@ -3478,7 +3506,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3478,7 +3506,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3478 \\ _ = a catch |err| false;3506 \\ _ = a catch |err| false;
3479 \\}3507 \\}
3480 ,3508 ,
3481 ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",3509 "tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
3482 );3510 );
34833511
3484 cases.add(3512 cases.add(
...@@ -3488,7 +3516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3488,7 +3516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3488 \\ _ = a.*;3516 \\ _ = a.*;
3489 \\}3517 \\}
3490 ,3518 ,
3491 ".tmp_source.zig:3:9: error: attempt to dereference undefined value",3519 "tmp.zig:3:9: error: attempt to dereference undefined value",
3492 );3520 );
34933521
3494 cases.add(3522 cases.add(
...@@ -3500,8 +3528,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3500,8 +3528,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3500 \\3528 \\
3501 \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); }3529 \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); }
3502 ,3530 ,
3503 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",3531 "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches",
3504 ".tmp_source.zig:3:21: note: called from here",3532 "tmp.zig:3:21: note: called from here",
3505 );3533 );
35063534
3507 cases.add(3535 cases.add(
...@@ -3510,7 +3538,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3510,7 +3538,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3510 \\3538 \\
3511 \\export fn entry() usize { return @sizeOf(@typeOf(resource)); }3539 \\export fn entry() usize { return @sizeOf(@typeOf(resource)); }
3512 ,3540 ,
3513 ".tmp_source.zig:1:29: error: unable to find '",3541 "tmp.zig:1:29: error: unable to find '",
3514 "bogus.txt'",3542 "bogus.txt'",
3515 );3543 );
35163544
...@@ -3524,7 +3552,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3524,7 +3552,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3524 \\3552 \\
3525 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }3553 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
3526 ,3554 ,
3527 ".tmp_source.zig:4:21: error: unable to evaluate constant expression",3555 "tmp.zig:4:21: error: unable to evaluate constant expression",
3528 );3556 );
35293557
3530 cases.add(3558 cases.add(
...@@ -3541,8 +3569,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3541,8 +3569,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3541 \\3569 \\
3542 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }3570 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
3543 ,3571 ,
3544 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",3572 "tmp.zig:6:24: error: unable to evaluate constant expression",
3545 ".tmp_source.zig:4:17: note: called from here",3573 "tmp.zig:4:17: note: called from here",
3546 );3574 );
35473575
3548 cases.add(3576 cases.add(
...@@ -3554,7 +3582,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3554,7 +3582,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3554 \\ bad_fn_call();3582 \\ bad_fn_call();
3555 \\}3583 \\}
3556 ,3584 ,
3557 ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'",3585 "tmp.zig:5:5: error: use of undeclared identifier 'bad_fn_call'",
3558 );3586 );
35593587
3560 cases.add(3588 cases.add(
...@@ -3573,8 +3601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3573,8 +3601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3573 \\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }3601 \\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }
3574 \\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }3602 \\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }
3575 ,3603 ,
3576 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",3604 "tmp.zig:2:14: error: operator not allowed for type '[]u8'",
3577 ".tmp_source.zig:9:16: error: operator not allowed for type 'EnumWithData'",3605 "tmp.zig:9:16: error: operator not allowed for type 'EnumWithData'",
3578 );3606 );
35793607
3580 cases.add(3608 cases.add(
...@@ -3590,7 +3618,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3590,7 +3618,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3590 \\ return 2;3618 \\ return 2;
3591 \\}3619 \\}
3592 ,3620 ,
3593 ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known",3621 "tmp.zig:2:15: error: values of type 'comptime_int' must be comptime known",
3594 );3622 );
35953623
3596 cases.add(3624 cases.add(
...@@ -3601,7 +3629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3601,7 +3629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3601 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}3629 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
3602 \\}3630 \\}
3603 ,3631 ,
3604 ".tmp_source.zig:4:81: error: failure atomic ordering must be no stricter than success",3632 "tmp.zig:4:81: error: failure atomic ordering must be no stricter than success",
3605 );3633 );
36063634
3607 cases.add(3635 cases.add(
...@@ -3612,7 +3640,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3612,7 +3640,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3612 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}3640 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
3613 \\}3641 \\}
3614 ,3642 ,
3615 ".tmp_source.zig:4:58: error: success atomic ordering must be Monotonic or stricter",3643 "tmp.zig:4:58: error: success atomic ordering must be Monotonic or stricter",
3616 );3644 );
36173645
3618 cases.add(3646 cases.add(
...@@ -3624,8 +3652,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3624,8 +3652,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3624 \\3652 \\
3625 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }3653 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
3626 ,3654 ,
3627 ".tmp_source.zig:3:12: error: negation caused overflow",3655 "tmp.zig:3:12: error: negation caused overflow",
3628 ".tmp_source.zig:1:14: note: called from here",3656 "tmp.zig:1:14: note: called from here",
3629 );3657 );
36303658
3631 cases.add(3659 cases.add(
...@@ -3637,8 +3665,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3637,8 +3665,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3637 \\3665 \\
3638 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }3666 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
3639 ,3667 ,
3640 ".tmp_source.zig:3:14: error: operation caused overflow",3668 "tmp.zig:3:14: error: operation caused overflow",
3641 ".tmp_source.zig:1:14: note: called from here",3669 "tmp.zig:1:14: note: called from here",
3642 );3670 );
36433671
3644 cases.add(3672 cases.add(
...@@ -3650,8 +3678,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3650,8 +3678,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3650 \\3678 \\
3651 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }3679 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
3652 ,3680 ,
3653 ".tmp_source.zig:3:14: error: operation caused overflow",3681 "tmp.zig:3:14: error: operation caused overflow",
3654 ".tmp_source.zig:1:14: note: called from here",3682 "tmp.zig:1:14: note: called from here",
3655 );3683 );
36563684
3657 cases.add(3685 cases.add(
...@@ -3663,8 +3691,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3663,8 +3691,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3663 \\3691 \\
3664 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }3692 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
3665 ,3693 ,
3666 ".tmp_source.zig:3:14: error: operation caused overflow",3694 "tmp.zig:3:14: error: operation caused overflow",
3667 ".tmp_source.zig:1:14: note: called from here",3695 "tmp.zig:1:14: note: called from here",
3668 );3696 );
36693697
3670 cases.add(3698 cases.add(
...@@ -3676,7 +3704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3676,7 +3704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3676 \\3704 \\
3677 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }3705 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
3678 ,3706 ,
3679 ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'",3707 "tmp.zig:3:26: error: expected signed integer type, found 'u32'",
3680 );3708 );
36813709
3682 cases.add(3710 cases.add(
...@@ -3686,8 +3714,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3686,8 +3714,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3686 \\}3714 \\}
3687 \\fn something() anyerror!void { }3715 \\fn something() anyerror!void { }
3688 ,3716 ,
3689 ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'",3717 "tmp.zig:2:5: error: expected type 'void', found 'anyerror'",
3690 ".tmp_source.zig:1:15: note: return type declared here",3718 "tmp.zig:1:15: note: return type declared here",
3691 );3719 );
36923720
3693 cases.add(3721 cases.add(
...@@ -3700,7 +3728,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3700,7 +3728,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3700 \\ }3728 \\ }
3701 \\}3729 \\}
3702 ,3730 ,
3703 ".tmp_source.zig:2:13: error: unable to evaluate constant expression",3731 "tmp.zig:2:13: error: unable to evaluate constant expression",
3704 );3732 );
37053733
3706 cases.add(3734 cases.add(
...@@ -3709,7 +3737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3709,7 +3737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3709 \\ return x + y;3737 \\ return x + y;
3710 \\}3738 \\}
3711 ,3739 ,
3712 ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",3740 "tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
3713 );3741 );
37143742
3715 cases.add(3743 cases.add(
...@@ -3720,7 +3748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3720,7 +3748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3720 \\}3748 \\}
3721 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }3749 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
3722 ,3750 ,
3723 ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",3751 "tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
3724 );3752 );
37253753
3726 cases.add(3754 cases.add(
...@@ -3730,8 +3758,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3730,8 +3758,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3730 \\ var foo = @bytesToSlice(u32, array)[0];3758 \\ var foo = @bytesToSlice(u32, array)[0];
3731 \\}3759 \\}
3732 ,3760 ,
3733 ".tmp_source.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",3761 "tmp.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
3734 ".tmp_source.zig:3:29: note: u32 has size 4; remaining bytes: 1",3762 "tmp.zig:3:29: note: u32 has size 4; remaining bytes: 1",
3735 );3763 );
37363764
3737 cases.add(3765 cases.add(
...@@ -3755,8 +3783,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3755,8 +3783,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3755 \\ list.length = 10;3783 \\ list.length = 10;
3756 \\}3784 \\}
3757 ,3785 ,
3758 ".tmp_source.zig:3:7: error: unable to evaluate constant expression",3786 "tmp.zig:3:7: error: unable to evaluate constant expression",
3759 ".tmp_source.zig:16:19: note: called from here",3787 "tmp.zig:16:19: note: called from here",
3760 );3788 );
37613789
3762 cases.add(3790 cases.add(
...@@ -3767,7 +3795,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3767,7 +3795,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3767 \\}3795 \\}
3768 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }3796 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
3769 ,3797 ,
3770 ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'",3798 "tmp.zig:3:6: error: no member named 'copy' in '[]const u8'",
3771 );3799 );
37723800
3773 cases.add(3801 cases.add(
...@@ -3781,7 +3809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3781,7 +3809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3781 \\}3809 \\}
3782 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }3810 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
3783 ,3811 ,
3784 ".tmp_source.zig:6:15: error: expected 2 arguments, found 3",3812 "tmp.zig:6:15: error: expected 2 arguments, found 3",
3785 );3813 );
37863814
3787 cases.add(3815 cases.add(
...@@ -3791,7 +3819,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3791,7 +3819,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3791 \\ cstr[0] = 'W';3819 \\ cstr[0] = 'W';
3792 \\}3820 \\}
3793 ,3821 ,
3794 ".tmp_source.zig:3:11: error: cannot assign to constant",3822 "tmp.zig:3:11: error: cannot assign to constant",
3795 );3823 );
37963824
3797 cases.add(3825 cases.add(
...@@ -3801,14 +3829,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3801,14 +3829,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3801 \\ cstr[0] = 'W';3829 \\ cstr[0] = 'W';
3802 \\}3830 \\}
3803 ,3831 ,
3804 ".tmp_source.zig:3:11: error: cannot assign to constant",3832 "tmp.zig:3:11: error: cannot assign to constant",
3805 );3833 );
38063834
3807 cases.add(3835 cases.add(
3808 "main function with bogus args type",3836 "main function with bogus args type",
3809 \\pub fn main(args: [][]bogus) !void {}3837 \\pub fn main(args: [][]bogus) !void {}
3810 ,3838 ,
3811 ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'",3839 "tmp.zig:1:23: error: use of undeclared identifier 'bogus'",
3812 );3840 );
38133841
3814 cases.add(3842 cases.add(
...@@ -3844,7 +3872,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3844,7 +3872,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3844 \\3872 \\
3845 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }3873 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
3846 ,3874 ,
3847 ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'",3875 "tmp.zig:5:16: error: use of undeclared identifier 'JsonList'",
3848 );3876 );
38493877
3850 cases.add(3878 cases.add(
...@@ -3865,7 +3893,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3865,7 +3893,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3865 \\ derp.init();3893 \\ derp.init();
3866 \\}3894 \\}
3867 ,3895 ,
3868 ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",3896 "tmp.zig:14:5: error: expected type 'i32', found 'Foo'",
3869 );3897 );
38703898
3871 cases.add(3899 cases.add(
...@@ -3895,7 +3923,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3895,7 +3923,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3895 \\ x.init();3923 \\ x.init();
3896 \\}3924 \\}
3897 ,3925 ,
3898 ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'",3926 "tmp.zig:23:5: error: expected type '*Allocator', found '*List'",
3899 );3927 );
39003928
3901 cases.add(3929 cases.add(
...@@ -3906,7 +3934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3906,7 +3934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3906 \\3934 \\
3907 \\export fn entry() usize { return @sizeOf(@typeOf(block_aligned_stuff)); }3935 \\export fn entry() usize { return @sizeOf(@typeOf(block_aligned_stuff)); }
3908 ,3936 ,
3909 ".tmp_source.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'",3937 "tmp.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'",
3910 );3938 );
39113939
3912 cases.addCase(x: {3940 cases.addCase(x: {
...@@ -3918,7 +3946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3918,7 +3946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3918 \\ foo.privateFunction();3946 \\ foo.privateFunction();
3919 \\}3947 \\}
3920 ,3948 ,
3921 ".tmp_source.zig:4:8: error: 'privateFunction' is private",3949 "tmp.zig:4:8: error: 'privateFunction' is private",
3922 "foo.zig:1:1: note: declared here",3950 "foo.zig:1:1: note: declared here",
3923 );3951 );
39243952
...@@ -3936,7 +3964,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3936,7 +3964,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3936 \\3964 \\
3937 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }3965 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
3938 ,3966 ,
3939 ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'",3967 "tmp.zig:2:11: error: expected type 'type', found 'i32'",
3940 );3968 );
39413969
3942 cases.add(3970 cases.add(
...@@ -3949,7 +3977,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3949,7 +3977,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3949 \\ f.field = 0;3977 \\ f.field = 0;
3950 \\}3978 \\}
3951 ,3979 ,
3952 ".tmp_source.zig:6:13: error: cannot assign to constant",3980 "tmp.zig:6:13: error: cannot assign to constant",
3953 );3981 );
39543982
3955 cases.add(3983 cases.add(
...@@ -3970,7 +3998,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3970,7 +3998,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3970 \\3998 \\
3971 \\export fn entry() usize { return @sizeOf(@typeOf(testTrickyDefer)); }3999 \\export fn entry() usize { return @sizeOf(@typeOf(testTrickyDefer)); }
3972 ,4000 ,
3973 ".tmp_source.zig:4:11: error: cannot return from defer expression",4001 "tmp.zig:4:11: error: cannot return from defer expression",
3974 );4002 );
39754003
3976 cases.add(4004 cases.add(
...@@ -3985,8 +4013,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3985,8 +4013,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3985 \\4013 \\
3986 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }4014 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
3987 ,4015 ,
3988 ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",4016 "tmp.zig:2:26: error: index 1 outside argument list of size 1",
3989 ".tmp_source.zig:6:15: note: called from here",4017 "tmp.zig:6:15: note: called from here",
3990 );4018 );
39914019
3992 cases.add(4020 cases.add(
...@@ -4005,7 +4033,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4005,7 +4033,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4005 \\4033 \\
4006 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }4034 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
4007 ,4035 ,
4008 ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted",4036 "tmp.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted",
4009 );4037 );
40104038
4011 cases.add(4039 cases.add(
...@@ -4014,7 +4042,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4014,7 +4042,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4014 \\ var vga_mem: u16 = 0xB8000;4042 \\ var vga_mem: u16 = 0xB8000;
4015 \\}4043 \\}
4016 ,4044 ,
4017 ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'",4045 "tmp.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'",
4018 );4046 );
40194047
4020 cases.add(4048 cases.add(
...@@ -4022,7 +4050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4022,7 +4050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4022 \\const some_data: [100]u8 align(3) = undefined;4050 \\const some_data: [100]u8 align(3) = undefined;
4023 \\export fn entry() usize { return @sizeOf(@typeOf(some_data)); }4051 \\export fn entry() usize { return @sizeOf(@typeOf(some_data)); }
4024 ,4052 ,
4025 ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2",4053 "tmp.zig:1:32: error: alignment value 3 is not a power of 2",
4026 );4054 );
40274055
4028 cases.add(4056 cases.add(
...@@ -4030,7 +4058,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4030,7 +4058,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4030 \\extern fn foo() align(3) void;4058 \\extern fn foo() align(3) void;
4031 \\export fn entry() void { return foo(); }4059 \\export fn entry() void { return foo(); }
4032 ,4060 ,
4033 ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2",4061 "tmp.zig:1:23: error: alignment value 3 is not a power of 2",
4034 );4062 );
40354063
4036 cases.add(4064 cases.add(
...@@ -4044,9 +4072,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4044,9 +4072,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4044 \\ @compileLog("end",);4072 \\ @compileLog("end",);
4045 \\}4073 \\}
4046 ,4074 ,
4047 ".tmp_source.zig:5:5: error: found compile log statement",4075 "tmp.zig:5:5: error: found compile log statement",
4048 ".tmp_source.zig:6:5: error: found compile log statement",4076 "tmp.zig:6:5: error: found compile log statement",
4049 ".tmp_source.zig:7:5: error: found compile log statement",4077 "tmp.zig:7:5: error: found compile log statement",
4050 );4078 );
40514079
4052 cases.add(4080 cases.add(
...@@ -4067,7 +4095,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4067,7 +4095,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4067 \\4095 \\
4068 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }4096 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
4069 ,4097 ,
4070 ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'",4098 "tmp.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'",
4071 );4099 );
40724100
4073 cases.add(4101 cases.add(
...@@ -4084,8 +4112,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4084,8 +4112,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4084 \\ if (!ok) unreachable;4112 \\ if (!ok) unreachable;
4085 \\}4113 \\}
4086 ,4114 ,
4087 ".tmp_source.zig:10:14: error: unable to evaluate constant expression",4115 "tmp.zig:10:14: error: unable to evaluate constant expression",
4088 ".tmp_source.zig:6:20: note: called from here",4116 "tmp.zig:6:20: note: called from here",
4089 );4117 );
40904118
4091 cases.add(4119 cases.add(
...@@ -4099,8 +4127,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4099,8 +4127,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4099 \\4127 \\
4100 \\fn bar() void { }4128 \\fn bar() void { }
4101 ,4129 ,
4102 ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime",4130 "tmp.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
4103 ".tmp_source.zig:3:24: note: compile-time variable assigned here",4131 "tmp.zig:3:24: note: compile-time variable assigned here",
4104 );4132 );
41054133
4106 cases.add(4134 cases.add(
...@@ -4110,7 +4138,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4110,7 +4138,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4110 \\}4138 \\}
4111 \\fn bar() i32 { return 0; }4139 \\fn bar() i32 { return 0; }
4112 ,4140 ,
4113 ".tmp_source.zig:2:8: error: expression value is ignored",4141 "tmp.zig:2:8: error: expression value is ignored",
4114 );4142 );
41154143
4116 cases.add(4144 cases.add(
...@@ -4120,7 +4148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4120,7 +4148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4120 \\}4148 \\}
4121 \\fn bar() anyerror!i32 { return 0; }4149 \\fn bar() anyerror!i32 { return 0; }
4122 ,4150 ,
4123 ".tmp_source.zig:2:11: error: expression value is ignored",4151 "tmp.zig:2:11: error: expression value is ignored",
4124 );4152 );
41254153
4126 cases.add(4154 cases.add(
...@@ -4129,7 +4157,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4129,7 +4157,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4129 \\ 1;4157 \\ 1;
4130 \\}4158 \\}
4131 ,4159 ,
4132 ".tmp_source.zig:2:5: error: expression value is ignored",4160 "tmp.zig:2:5: error: expression value is ignored",
4133 );4161 );
41344162
4135 cases.add(4163 cases.add(
...@@ -4138,7 +4166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4138,7 +4166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4138 \\ comptime {1;}4166 \\ comptime {1;}
4139 \\}4167 \\}
4140 ,4168 ,
4141 ".tmp_source.zig:2:15: error: expression value is ignored",4169 "tmp.zig:2:15: error: expression value is ignored",
4142 );4170 );
41434171
4144 cases.add(4172 cases.add(
...@@ -4147,7 +4175,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4147,7 +4175,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4147 \\ comptime 1;4175 \\ comptime 1;
4148 \\}4176 \\}
4149 ,4177 ,
4150 ".tmp_source.zig:2:5: error: expression value is ignored",4178 "tmp.zig:2:5: error: expression value is ignored",
4151 );4179 );
41524180
4153 cases.add(4181 cases.add(
...@@ -4156,7 +4184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4156,7 +4184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4156 \\ defer {1;}4184 \\ defer {1;}
4157 \\}4185 \\}
4158 ,4186 ,
4159 ".tmp_source.zig:2:12: error: expression value is ignored",4187 "tmp.zig:2:12: error: expression value is ignored",
4160 );4188 );
41614189
4162 cases.add(4190 cases.add(
...@@ -4166,7 +4194,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4166,7 +4194,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4166 \\}4194 \\}
4167 \\fn bar() anyerror!i32 { return 0; }4195 \\fn bar() anyerror!i32 { return 0; }
4168 ,4196 ,
4169 ".tmp_source.zig:2:14: error: expression value is ignored",4197 "tmp.zig:2:14: error: expression value is ignored",
4170 );4198 );
41714199
4172 cases.add(4200 cases.add(
...@@ -4180,7 +4208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4180,7 +4208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4180 \\4208 \\
4181 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }4209 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
4182 ,4210 ,
4183 ".tmp_source.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",4211 "tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",
4184 );4212 );
41854213
4186 cases.add(4214 cases.add(
...@@ -4196,7 +4224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4196,7 +4224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4196 \\4224 \\
4197 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }4225 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
4198 ,4226 ,
4199 ".tmp_source.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'",4227 "tmp.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'",
4200 );4228 );
42014229
4202 cases.addCase(x: {4230 cases.addCase(x: {
...@@ -4209,7 +4237,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4209,7 +4237,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4209 \\}4237 \\}
4210 ,4238 ,
4211 "foo.zig:1:1: error: exported symbol collision: 'bar'",4239 "foo.zig:1:1: error: exported symbol collision: 'bar'",
4212 ".tmp_source.zig:3:1: note: other symbol here",4240 "tmp.zig:3:1: note: other symbol here",
4213 );4241 );
42144242
4215 tc.addSourceFile("foo.zig",4243 tc.addSourceFile("foo.zig",
...@@ -4228,7 +4256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4228,7 +4256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4228 \\ foo(global_array);4256 \\ foo(global_array);
4229 \\}4257 \\}
4230 ,4258 ,
4231 ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'",4259 "tmp.zig:4:9: error: expected type '[]i32', found '[10]i32'",
4232 );4260 );
42334261
4234 cases.add(4262 cases.add(
...@@ -4237,7 +4265,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4237,7 +4265,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4237 \\ return @ptrCast(usize, a);4265 \\ return @ptrCast(usize, a);
4238 \\}4266 \\}
4239 ,4267 ,
4240 ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",4268 "tmp.zig:2:21: error: expected pointer, found 'usize'",
4241 );4269 );
42424270
4243 cases.add(4271 cases.add(
...@@ -4254,7 +4282,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4254,7 +4282,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4254 \\ );4282 \\ );
4255 \\}4283 \\}
4256 ,4284 ,
4257 ".tmp_source.zig:6:5: error: unable to evaluate constant expression",4285 "tmp.zig:6:5: error: unable to evaluate constant expression",
4258 );4286 );
42594287
4260 cases.add(4288 cases.add(
...@@ -4264,7 +4292,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4264,7 +4292,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4264 \\ const foo = builtin.Arch.x86;4292 \\ const foo = builtin.Arch.x86;
4265 \\}4293 \\}
4266 ,4294 ,
4267 ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'",4295 "tmp.zig:3:29: error: container 'builtin.Arch' has no member called 'x86'",
4268 );4296 );
42694297
4270 cases.add(4298 cases.add(
...@@ -4274,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4274,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4274 \\ var y: *void = @intToPtr(*void, x);4302 \\ var y: *void = @intToPtr(*void, x);
4275 \\}4303 \\}
4276 ,4304 ,
4277 ".tmp_source.zig:3:30: error: type '*void' has 0 bits and cannot store information",4305 "tmp.zig:3:30: error: type '*void' has 0 bits and cannot store information",
4278 );4306 );
42794307
4280 cases.add(4308 cases.add(
...@@ -4284,7 +4312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4284,7 +4312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4284 \\ return @fieldParentPtr(Foo, "a", a);4312 \\ return @fieldParentPtr(Foo, "a", a);
4285 \\}4313 \\}
4286 ,4314 ,
4287 ".tmp_source.zig:3:28: error: expected struct type, found 'i32'",4315 "tmp.zig:3:28: error: expected struct type, found 'i32'",
4288 );4316 );
42894317
4290 cases.add(4318 cases.add(
...@@ -4296,7 +4324,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4296,7 +4324,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4296 \\ return @fieldParentPtr(Foo, "a", a);4324 \\ return @fieldParentPtr(Foo, "a", a);
4297 \\}4325 \\}
4298 ,4326 ,
4299 ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'",4327 "tmp.zig:5:33: error: struct 'Foo' has no field 'a'",
4300 );4328 );
43014329
4302 cases.add(4330 cases.add(
...@@ -4308,7 +4336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4308,7 +4336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4308 \\ return @fieldParentPtr(Foo, "a", a);4336 \\ return @fieldParentPtr(Foo, "a", a);
4309 \\}4337 \\}
4310 ,4338 ,
4311 ".tmp_source.zig:5:38: error: expected pointer, found 'i32'",4339 "tmp.zig:5:38: error: expected pointer, found 'i32'",
4312 );4340 );
43134341
4314 cases.add(4342 cases.add(
...@@ -4324,7 +4352,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4324,7 +4352,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4324 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);4352 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
4325 \\}4353 \\}
4326 ,4354 ,
4327 ".tmp_source.zig:9:55: error: pointer value not based on parent struct",4355 "tmp.zig:9:55: error: pointer value not based on parent struct",
4328 );4356 );
43294357
4330 cases.add(4358 cases.add(
...@@ -4339,7 +4367,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4339,7 +4367,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4339 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);4367 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
4340 \\}4368 \\}
4341 ,4369 ,
4342 ".tmp_source.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'",4370 "tmp.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'",
4343 );4371 );
43444372
4345 cases.add(4373 cases.add(
...@@ -4349,7 +4377,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4349,7 +4377,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4349 \\ return @byteOffsetOf(Foo, "a",);4377 \\ return @byteOffsetOf(Foo, "a",);
4350 \\}4378 \\}
4351 ,4379 ,
4352 ".tmp_source.zig:3:26: error: expected struct type, found 'i32'",4380 "tmp.zig:3:26: error: expected struct type, found 'i32'",
4353 );4381 );
43544382
4355 cases.add(4383 cases.add(
...@@ -4361,14 +4389,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4361,14 +4389,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4361 \\ return @byteOffsetOf(Foo, "a",);4389 \\ return @byteOffsetOf(Foo, "a",);
4362 \\}4390 \\}
4363 ,4391 ,
4364 ".tmp_source.zig:5:31: error: struct 'Foo' has no field 'a'",4392 "tmp.zig:5:31: error: struct 'Foo' has no field 'a'",
4365 );4393 );
43664394
4367 cases.addExe(4395 cases.addExe(
4368 "missing main fn in executable",4396 "missing main fn in executable",
4369 \\4397 \\
4370 ,4398 ,
4371 "error: no member named 'main' in '",4399 "error: root source file has no member called 'main'",
4372 );4400 );
43734401
4374 cases.addExe(4402 cases.addExe(
...@@ -4376,7 +4404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4376,7 +4404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4376 \\fn main() void {}4404 \\fn main() void {}
4377 ,4405 ,
4378 "error: 'main' is private",4406 "error: 'main' is private",
4379 ".tmp_source.zig:1:1: note: declared here",4407 "tmp.zig:1:1: note: declared here",
4380 );4408 );
43814409
4382 cases.add(4410 cases.add(
...@@ -4386,7 +4414,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4386,7 +4414,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4386 \\ return foo;4414 \\ return foo;
4387 \\}4415 \\}
4388 ,4416 ,
4389 ".tmp_source.zig:1:33: error: cannot set section of external variable 'foo'",4417 "tmp.zig:1:33: error: cannot set section of external variable 'foo'",
4390 );4418 );
43914419
4392 cases.add(4420 cases.add(
...@@ -4396,7 +4424,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4396,7 +4424,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4396 \\ return foo;4424 \\ return foo;
4397 \\}4425 \\}
4398 ,4426 ,
4399 ".tmp_source.zig:2:30: error: cannot set section of local variable 'foo'",4427 "tmp.zig:2:30: error: cannot set section of local variable 'foo'",
4400 );4428 );
44014429
4402 cases.add(4430 cases.add(
...@@ -4406,7 +4434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4406,7 +4434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4406 \\ foo();4434 \\ foo();
4407 \\}4435 \\}
4408 ,4436 ,
4409 ".tmp_source.zig:1:29: error: cannot set section of external function 'foo'",4437 "tmp.zig:1:29: error: cannot set section of external function 'foo'",
4410 );4438 );
44114439
4412 cases.add(4440 cases.add(
...@@ -4416,7 +4444,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4416,7 +4444,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4416 \\ return &a;4444 \\ return &a;
4417 \\}4445 \\}
4418 ,4446 ,
4419 ".tmp_source.zig:3:13: error: function returns address of local variable",4447 "tmp.zig:3:13: error: function returns address of local variable",
4420 );4448 );
44214449
4422 cases.add(4450 cases.add(
...@@ -4427,7 +4455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4427,7 +4455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4427 \\ return if (c) &a else &b;4455 \\ return if (c) &a else &b;
4428 \\}4456 \\}
4429 ,4457 ,
4430 ".tmp_source.zig:4:12: error: function returns address of local variable",4458 "tmp.zig:4:12: error: function returns address of local variable",
4431 );4459 );
44324460
4433 cases.add(4461 cases.add(
...@@ -4452,8 +4480,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4452,8 +4480,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4452 \\ if (!ok) unreachable;4480 \\ if (!ok) unreachable;
4453 \\}4481 \\}
4454 ,4482 ,
4455 ".tmp_source.zig:9:17: error: redefinition of 'Self'",4483 "tmp.zig:9:17: error: redefinition of 'Self'",
4456 ".tmp_source.zig:5:9: note: previous definition is here",4484 "tmp.zig:5:9: note: previous definition is here",
4457 );4485 );
44584486
4459 cases.add(4487 cases.add(
...@@ -4463,7 +4491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4463,7 +4491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4463 \\}4491 \\}
4464 \\fn bar() ?i32 { return 1; }4492 \\fn bar() ?i32 { return 1; }
4465 ,4493 ,
4466 ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'",4494 "tmp.zig:2:15: error: expected type 'bool', found '?i32'",
4467 );4495 );
44684496
4469 cases.add(4497 cases.add(
...@@ -4473,7 +4501,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4473,7 +4501,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4473 \\}4501 \\}
4474 \\fn bar() anyerror!i32 { return 1; }4502 \\fn bar() anyerror!i32 { return 1; }
4475 ,4503 ,
4476 ".tmp_source.zig:2:15: error: expected type 'bool', found 'anyerror!i32'",4504 "tmp.zig:2:15: error: expected type 'bool', found 'anyerror!i32'",
4477 );4505 );
44784506
4479 cases.add(4507 cases.add(
...@@ -4483,7 +4511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4483,7 +4511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4483 \\}4511 \\}
4484 \\fn bar() bool { return true; }4512 \\fn bar() bool { return true; }
4485 ,4513 ,
4486 ".tmp_source.zig:2:15: error: expected optional type, found 'bool'",4514 "tmp.zig:2:15: error: expected optional type, found 'bool'",
4487 );4515 );
44884516
4489 cases.add(4517 cases.add(
...@@ -4493,7 +4521,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4493,7 +4521,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4493 \\}4521 \\}
4494 \\fn bar() anyerror!i32 { return 1; }4522 \\fn bar() anyerror!i32 { return 1; }
4495 ,4523 ,
4496 ".tmp_source.zig:2:15: error: expected optional type, found 'anyerror!i32'",4524 "tmp.zig:2:15: error: expected optional type, found 'anyerror!i32'",
4497 );4525 );
44984526
4499 cases.add(4527 cases.add(
...@@ -4503,7 +4531,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4503,7 +4531,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4503 \\}4531 \\}
4504 \\fn bar() bool { return true; }4532 \\fn bar() bool { return true; }
4505 ,4533 ,
4506 ".tmp_source.zig:2:15: error: expected error union type, found 'bool'",4534 "tmp.zig:2:15: error: expected error union type, found 'bool'",
4507 );4535 );
45084536
4509 cases.add(4537 cases.add(
...@@ -4513,7 +4541,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4513,7 +4541,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4513 \\}4541 \\}
4514 \\fn bar() ?i32 { return 1; }4542 \\fn bar() ?i32 { return 1; }
4515 ,4543 ,
4516 ".tmp_source.zig:2:15: error: expected error union type, found '?i32'",4544 "tmp.zig:2:15: error: expected error union type, found '?i32'",
4517 );4545 );
45184546
4519 cases.add(4547 cases.add(
...@@ -4531,7 +4559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4531,7 +4559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4531 \\}4559 \\}
4532 \\extern fn quux() void;4560 \\extern fn quux() void;
4533 ,4561 ,
4534 ".tmp_source.zig:4:1: error: unable to inline function",4562 "tmp.zig:4:1: error: unable to inline function",
4535 );4563 );
45364564
4537 cases.add(4565 cases.add(
...@@ -4542,7 +4570,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4542,7 +4570,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4542 \\inline fn bar() void { }4570 \\inline fn bar() void { }
4543 \\extern fn quux(usize) void;4571 \\extern fn quux(usize) void;
4544 ,4572 ,
4545 ".tmp_source.zig:4:1: error: unable to inline function",4573 "tmp.zig:4:1: error: unable to inline function",
4546 );4574 );
45474575
4548 cases.add(4576 cases.add(
...@@ -4551,7 +4579,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4551,7 +4579,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4551 \\ return a / b;4579 \\ return a / b;
4552 \\}4580 \\}
4553 ,4581 ,
4554 ".tmp_source.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact",4582 "tmp.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact",
4555 );4583 );
45564584
4557 cases.add(4585 cases.add(
...@@ -4560,7 +4588,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4560,7 +4588,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4560 \\ return a % b;4588 \\ return a % b;
4561 \\}4589 \\}
4562 ,4590 ,
4563 ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",4591 "tmp.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",
4564 );4592 );
45654593
4566 cases.add(4594 cases.add(
...@@ -4571,7 +4599,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4571,7 +4599,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4571 \\ const c = a / b;4599 \\ const c = a / b;
4572 \\}4600 \\}
4573 ,4601 ,
4574 ".tmp_source.zig:4:17: error: division by zero",4602 "tmp.zig:4:17: error: division by zero",
4575 );4603 );
45764604
4577 cases.add(4605 cases.add(
...@@ -4582,7 +4610,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4582,7 +4610,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4582 \\ const c = a % b;4610 \\ const c = a % b;
4583 \\}4611 \\}
4584 ,4612 ,
4585 ".tmp_source.zig:4:17: error: division by zero",4613 "tmp.zig:4:17: error: division by zero",
4586 );4614 );
45874615
4588 cases.add(4616 cases.add(
...@@ -4592,8 +4620,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4592,8 +4620,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4592 \\ @setRuntimeSafety(false);4620 \\ @setRuntimeSafety(false);
4593 \\}4621 \\}
4594 ,4622 ,
4595 ".tmp_source.zig:3:5: error: runtime safety set twice for same scope",4623 "tmp.zig:3:5: error: runtime safety set twice for same scope",
4596 ".tmp_source.zig:2:5: note: first set here",4624 "tmp.zig:2:5: note: first set here",
4597 );4625 );
45984626
4599 cases.add(4627 cases.add(
...@@ -4603,8 +4631,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4603,8 +4631,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4603 \\ @setFloatMode(@import("builtin").FloatMode.Optimized);4631 \\ @setFloatMode(@import("builtin").FloatMode.Optimized);
4604 \\}4632 \\}
4605 ,4633 ,
4606 ".tmp_source.zig:3:5: error: float mode set twice for same scope",4634 "tmp.zig:3:5: error: float mode set twice for same scope",
4607 ".tmp_source.zig:2:5: note: first set here",4635 "tmp.zig:2:5: note: first set here",
4608 );4636 );
46094637
4610 cases.add(4638 cases.add(
...@@ -4613,7 +4641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4613,7 +4641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4613 \\ var b: u8[40] = undefined;4641 \\ var b: u8[40] = undefined;
4614 \\}4642 \\}
4615 ,4643 ,
4616 ".tmp_source.zig:2:14: error: array access of non-array type 'type'",4644 "tmp.zig:2:14: error: array access of non-array type 'type'",
4617 );4645 );
46184646
4619 cases.add(4647 cases.add(
...@@ -4626,7 +4654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4626,7 +4654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4626 \\ }4654 \\ }
4627 \\}4655 \\}
4628 ,4656 ,
4629 ".tmp_source.zig:4:13: error: cannot break out of defer expression",4657 "tmp.zig:4:13: error: cannot break out of defer expression",
4630 );4658 );
46314659
4632 cases.add(4660 cases.add(
...@@ -4639,7 +4667,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4639,7 +4667,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4639 \\ }4667 \\ }
4640 \\}4668 \\}
4641 ,4669 ,
4642 ".tmp_source.zig:4:13: error: cannot continue out of defer expression",4670 "tmp.zig:4:13: error: cannot continue out of defer expression",
4643 );4671 );
46444672
4645 cases.add(4673 cases.add(
...@@ -4653,7 +4681,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4653,7 +4681,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4653 \\ foos[0]();4681 \\ foos[0]();
4654 \\}4682 \\}
4655 ,4683 ,
4656 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value",4684 "tmp.zig:7:9: error: calling a generic function requires compile-time known function value",
4657 );4685 );
46584686
4659 cases.add(4687 cases.add(
...@@ -4667,7 +4695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4667,7 +4695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4667 \\ foos[0](true);4695 \\ foos[0](true);
4668 \\}4696 \\}
4669 ,4697 ,
4670 ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value",4698 "tmp.zig:7:9: error: calling a generic function requires compile-time known function value",
4671 );4699 );
46724700
4673 cases.add(4701 cases.add(
...@@ -4681,24 +4709,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4681,24 +4709,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4681 \\ return bar;4709 \\ return bar;
4682 \\}4710 \\}
4683 ,4711 ,
4684 ".tmp_source.zig:1:13: error: aoeu",4712 "tmp.zig:1:13: error: aoeu",
4685 ".tmp_source.zig:3:19: note: referenced here",4713 "tmp.zig:3:19: note: referenced here",
4686 ".tmp_source.zig:7:12: note: referenced here",4714 "tmp.zig:7:12: note: referenced here",
4687 );
4688
4689 cases.add(
4690 "instantiating an undefined value for an invalid struct that contains itself",
4691 \\const Foo = struct {
4692 \\ x: Foo,
4693 \\};
4694 \\
4695 \\var foo: Foo = undefined;
4696 \\
4697 \\export fn entry() usize {
4698 \\ return @sizeOf(@typeOf(foo.x));
4699 \\}
4700 ,
4701 ".tmp_source.zig:1:13: error: struct 'Foo' contains itself",
4702 );4715 );
47034716
4704 cases.add(4717 cases.add(
...@@ -4707,7 +4720,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4707,7 +4720,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4707 \\ const a = 0x1.0p16384;4720 \\ const a = 0x1.0p16384;
4708 \\}4721 \\}
4709 ,4722 ,
4710 ".tmp_source.zig:2:15: error: float literal out of range of any type",4723 "tmp.zig:2:15: error: float literal out of range of any type",
4711 );4724 );
47124725
4713 cases.add(4726 cases.add(
...@@ -4716,7 +4729,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4716,7 +4729,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4716 \\ const a = 0x1.0p-16384;4729 \\ const a = 0x1.0p-16384;
4717 \\}4730 \\}
4718 ,4731 ,
4719 ".tmp_source.zig:2:15: error: float literal out of range of any type",4732 "tmp.zig:2:15: error: float literal out of range of any type",
4720 );4733 );
47214734
4722 cases.add(4735 cases.add(
...@@ -4725,7 +4738,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4725,7 +4738,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4725 \\ return i32(12.34);4738 \\ return i32(12.34);
4726 \\}4739 \\}
4727 ,4740 ,
4728 ".tmp_source.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'",4741 "tmp.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'",
4729 );4742 );
47304743
4731 cases.add(4744 cases.add(
...@@ -4734,7 +4747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4734,7 +4747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4734 \\ return @ptrToInt(x);4747 \\ return @ptrToInt(x);
4735 \\}4748 \\}
4736 ,4749 ,
4737 ".tmp_source.zig:2:22: error: expected pointer, found 'i32'",4750 "tmp.zig:2:22: error: expected pointer, found 'i32'",
4738 );4751 );
47394752
4740 cases.add(4753 cases.add(
...@@ -4743,7 +4756,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4743,7 +4756,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4743 \\ const x = @shlExact(u8(0b01010101), 2);4756 \\ const x = @shlExact(u8(0b01010101), 2);
4744 \\}4757 \\}
4745 ,4758 ,
4746 ".tmp_source.zig:2:15: error: operation caused overflow",4759 "tmp.zig:2:15: error: operation caused overflow",
4747 );4760 );
47484761
4749 cases.add(4762 cases.add(
...@@ -4752,7 +4765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4752,7 +4765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4752 \\ const x = @shrExact(u8(0b10101010), 2);4765 \\ const x = @shrExact(u8(0b10101010), 2);
4753 \\}4766 \\}
4754 ,4767 ,
4755 ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits",4768 "tmp.zig:2:15: error: exact shift shifted out 1 bits",
4756 );4769 );
47574770
4758 cases.add(4771 cases.add(
...@@ -4761,7 +4774,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4761,7 +4774,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4761 \\ return 0x11 << x;4774 \\ return 0x11 << x;
4762 \\}4775 \\}
4763 ,4776 ,
4764 ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known",4777 "tmp.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known",
4765 );4778 );
47664779
4767 cases.add(4780 cases.add(
...@@ -4770,7 +4783,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4770,7 +4783,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4770 \\ return x << y;4783 \\ return x << y;
4771 \\}4784 \\}
4772 ,4785 ,
4773 ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'",4786 "tmp.zig:2:17: error: expected type 'u3', found 'u8'",
4774 );4787 );
47754788
4776 cases.add(4789 cases.add(
...@@ -4780,7 +4793,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4780,7 +4793,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4780 \\ const a: u16 = 300;4793 \\ const a: u16 = 300;
4781 \\}4794 \\}
4782 ,4795 ,
4783 ".tmp_source.zig:1:1: error: declaration shadows primitive type 'u16'",4796 "tmp.zig:1:1: error: declaration shadows primitive type 'u16'",
4784 );4797 );
47854798
4786 cases.add(4799 cases.add(
...@@ -4799,7 +4812,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4799,7 +4812,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4799 \\ x.* += 1;4812 \\ x.* += 1;
4800 \\}4813 \\}
4801 ,4814 ,
4802 ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'",4815 "tmp.zig:8:13: error: expected type '*u32', found '*align(1) u32'",
4803 );4816 );
48044817
4805 cases.add(4818 cases.add(
...@@ -4819,9 +4832,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4819,9 +4832,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4819 \\ x[0] += 1;4832 \\ x[0] += 1;
4820 \\}4833 \\}
4821 ,4834 ,
4822 ".tmp_source.zig:9:18: error: cast increases pointer alignment",4835 "tmp.zig:9:18: error: cast increases pointer alignment",
4823 ".tmp_source.zig:9:23: note: '*align(1) u32' has alignment 1",4836 "tmp.zig:9:23: note: '*align(1) u32' has alignment 1",
4824 ".tmp_source.zig:9:18: note: '*[1]u32' has alignment 4",4837 "tmp.zig:9:18: note: '*[1]u32' has alignment 4",
4825 );4838 );
48264839
4827 cases.add(4840 cases.add(
...@@ -4832,9 +4845,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4832,9 +4845,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4832 \\ return ptr.*;4845 \\ return ptr.*;
4833 \\}4846 \\}
4834 ,4847 ,
4835 ".tmp_source.zig:3:17: error: cast increases pointer alignment",4848 "tmp.zig:3:17: error: cast increases pointer alignment",
4836 ".tmp_source.zig:3:38: note: '*u8' has alignment 1",4849 "tmp.zig:3:38: note: '*u8' has alignment 1",
4837 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",4850 "tmp.zig:3:26: note: '*u32' has alignment 4",
4838 );4851 );
48394852
4840 cases.add(4853 cases.add(
...@@ -4843,7 +4856,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4843,7 +4856,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4843 \\ @alignCast(4, u32(3));4856 \\ @alignCast(4, u32(3));
4844 \\}4857 \\}
4845 ,4858 ,
4846 ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'",4859 "tmp.zig:2:22: error: expected pointer or slice, found 'u32'",
4847 );4860 );
48484861
4849 cases.add(4862 cases.add(
...@@ -4856,7 +4869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4856,7 +4869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4856 \\}4869 \\}
4857 \\fn alignedSmall() align(4) i32 { return 1234; }4870 \\fn alignedSmall() align(4) i32 { return 1234; }
4858 ,4871 ,
4859 ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'",4872 "tmp.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'",
4860 );4873 );
48614874
4862 cases.add(4875 cases.add(
...@@ -4868,7 +4881,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4868,7 +4881,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4868 \\ return x == 5678;4881 \\ return x == 5678;
4869 \\}4882 \\}
4870 ,4883 ,
4871 ".tmp_source.zig:4:32: error: expected type '*i32', found '*align(1) i32'",4884 "tmp.zig:4:32: error: expected type '*i32', found '*align(1) i32'",
4872 );4885 );
48734886
4874 cases.add(4887 cases.add(
...@@ -4877,7 +4890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4877,7 +4890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4877 \\ const array = [2]u8{1, 2, 3};4890 \\ const array = [2]u8{1, 2, 3};
4878 \\}4891 \\}
4879 ,4892 ,
4880 ".tmp_source.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal",4893 "tmp.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal",
4881 );4894 );
48824895
4883 cases.add(4896 cases.add(
...@@ -4889,7 +4902,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4889,7 +4902,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4889 \\ bar(@ptrCast(*c_void, &x));4902 \\ bar(@ptrCast(*c_void, &x));
4890 \\}4903 \\}
4891 ,4904 ,
4892 ".tmp_source.zig:5:9: error: expected type '*Derp', found '*c_void'",4905 "tmp.zig:5:9: error: expected type '*Derp', found '*c_void'",
4893 );4906 );
48944907
4895 cases.add(4908 cases.add(
...@@ -4906,7 +4919,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4906,7 +4919,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4906 \\ var d = null;4919 \\ var d = null;
4907 \\ var e = opaque.*;4920 \\ var e = opaque.*;
4908 \\ var f = i32;4921 \\ var f = i32;
4909 \\ var g = @import("std",);
4910 \\ var h = (Foo {}).bar;4922 \\ var h = (Foo {}).bar;
4911 \\4923 \\
4912 \\ var z: noreturn = return;4924 \\ var z: noreturn = return;
...@@ -4916,16 +4928,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4916,16 +4928,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4916 \\ fn bar(self: *const Foo) void {}4928 \\ fn bar(self: *const Foo) void {}
4917 \\};4929 \\};
4918 ,4930 ,
4919 ".tmp_source.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",4931 "tmp.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",
4920 ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime",4932 "tmp.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
4921 ".tmp_source.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",4933 "tmp.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
4922 ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",4934 "tmp.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
4923 ".tmp_source.zig:10:4: error: variable of type '(null)' must be const or comptime",4935 "tmp.zig:10:4: error: variable of type '(null)' must be const or comptime",
4924 ".tmp_source.zig:11:4: error: variable of type 'Opaque' not allowed",4936 "tmp.zig:11:4: error: variable of type 'Opaque' not allowed",
4925 ".tmp_source.zig:12:4: error: variable of type 'type' must be const or comptime",4937 "tmp.zig:12:4: error: variable of type 'type' must be const or comptime",
4926 ".tmp_source.zig:13:4: error: variable of type '(namespace)' must be const or comptime",4938 "tmp.zig:13:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
4927 ".tmp_source.zig:14:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",4939 "tmp.zig:15:4: error: unreachable code",
4928 ".tmp_source.zig:16:4: error: unreachable code",
4929 );4940 );
49304941
4931 cases.add(4942 cases.add(
...@@ -4935,7 +4946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4935,7 +4946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4935 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}4946 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}
4936 \\}4947 \\}
4937 ,4948 ,
4938 ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'",4949 "tmp.zig:3:50: error: expected type 'builtin.AtomicOrder', found 'u32'",
4939 );4950 );
49404951
4941 cases.add(4952 cases.add(
...@@ -4945,7 +4956,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4945,7 +4956,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4945 \\ @export("entry", entry, u32(1234));4956 \\ @export("entry", entry, u32(1234));
4946 \\}4957 \\}
4947 ,4958 ,
4948 ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'",4959 "tmp.zig:3:32: error: expected type 'builtin.GlobalLinkage', found 'u32'",
4949 );4960 );
49504961
4951 cases.add(4962 cases.add(
...@@ -4974,7 +4985,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4974,7 +4985,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4974 \\ };4985 \\ };
4975 \\}4986 \\}
4976 ,4987 ,
4977 ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'",4988 "tmp.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
4978 );4989 );
49794990
4980 cases.add(4991 cases.add(
...@@ -4983,7 +4994,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4983,7 +4994,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4983 \\ @setAlignStack(16);4994 \\ @setAlignStack(16);
4984 \\}4995 \\}
4985 ,4996 ,
4986 ".tmp_source.zig:2:5: error: @setAlignStack outside function",4997 "tmp.zig:2:5: error: @setAlignStack outside function",
4987 );4998 );
49884999
4989 cases.add(5000 cases.add(
...@@ -4992,7 +5003,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4992,7 +5003,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4992 \\ @setAlignStack(16);5003 \\ @setAlignStack(16);
4993 \\}5004 \\}
4994 ,5005 ,
4995 ".tmp_source.zig:2:5: error: @setAlignStack in naked function",5006 "tmp.zig:2:5: error: @setAlignStack in naked function",
4996 );5007 );
49975008
4998 cases.add(5009 cases.add(
...@@ -5004,7 +5015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5004,7 +5015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5004 \\ @setAlignStack(16);5015 \\ @setAlignStack(16);
5005 \\}5016 \\}
5006 ,5017 ,
5007 ".tmp_source.zig:5:5: error: @setAlignStack in inline function",5018 "tmp.zig:5:5: error: @setAlignStack in inline function",
5008 );5019 );
50095020
5010 cases.add(5021 cases.add(
...@@ -5014,8 +5025,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5014,8 +5025,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5014 \\ @setAlignStack(16);5025 \\ @setAlignStack(16);
5015 \\}5026 \\}
5016 ,5027 ,
5017 ".tmp_source.zig:3:5: error: alignstack set twice",5028 "tmp.zig:3:5: error: alignstack set twice",
5018 ".tmp_source.zig:2:5: note: first set here",5029 "tmp.zig:2:5: note: first set here",
5019 );5030 );
50205031
5021 cases.add(5032 cases.add(
...@@ -5024,7 +5035,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5024,7 +5035,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5024 \\ @setAlignStack(511 + 1);5035 \\ @setAlignStack(511 + 1);
5025 \\}5036 \\}
5026 ,5037 ,
5027 ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256",5038 "tmp.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256",
5028 );5039 );
50295040
5030 cases.add(5041 cases.add(
...@@ -5071,7 +5082,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5071,7 +5082,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5071 \\ }5082 \\ }
5072 \\}5083 \\}
5073 ,5084 ,
5074 ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable",5085 "tmp.zig:37:16: error: cannot store runtime value in compile time variable",
5075 );5086 );
50765087
5077 cases.add(5088 cases.add(
...@@ -5087,7 +5098,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5087,7 +5098,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5087 \\ return x.blah;5098 \\ return x.blah;
5088 \\}5099 \\}
5089 ,5100 ,
5090 ".tmp_source.zig:9:13: error: type '*MyType' does not support field access",5101 "tmp.zig:9:13: error: type '*MyType' does not support field access",
5091 );5102 );
50925103
5093 cases.add(5104 cases.add(
...@@ -5095,7 +5106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5095,7 +5106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5095 "fn test() bool {\r\n" ++5106 "fn test() bool {\r\n" ++
5096 " true\r\n" ++5107 " true\r\n" ++
5097 "}\r\n",5108 "}\r\n",
5098 ".tmp_source.zig:1:17: error: invalid carriage return, only '\\n' line endings are supported",5109 "tmp.zig:1:17: error: invalid carriage return, only '\\n' line endings are supported",
5099 );5110 );
51005111
5101 cases.add(5112 cases.add(
...@@ -5105,7 +5116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5105,7 +5116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5105 \\ true\r5116 \\ true\r
5106 \\}5117 \\}
5107 ,5118 ,
5108 ".tmp_source.zig:1:1: error: invalid character: '\\xff'",5119 "tmp.zig:1:1: error: invalid character: '\\xff'",
5109 );5120 );
51105121
5111 cases.add(5122 cases.add(
...@@ -5113,7 +5124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5113,7 +5124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5113 "fn test() bool {\n" ++5124 "fn test() bool {\n" ++
5114 "\ttrue\n" ++5125 "\ttrue\n" ++
5115 "}\n",5126 "}\n",
5116 ".tmp_source.zig:2:1: error: invalid character: '\\t'",5127 "tmp.zig:2:1: error: invalid character: '\\t'",
5117 );5128 );
51185129
5119 cases.add(5130 cases.add(
...@@ -5122,7 +5133,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5122,7 +5133,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5122 \\ _ = @ArgType(i32, 3);5133 \\ _ = @ArgType(i32, 3);
5123 \\}5134 \\}
5124 ,5135 ,
5125 ".tmp_source.zig:2:18: error: expected function, found 'i32'",5136 "tmp.zig:2:18: error: expected function, found 'i32'",
5126 );5137 );
51275138
5128 cases.add(5139 cases.add(
...@@ -5132,7 +5143,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5132,7 +5143,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5132 \\}5143 \\}
5133 \\fn add(a: i32, b: i32) i32 { return a + b; }5144 \\fn add(a: i32, b: i32) i32 { return a + b; }
5134 ,5145 ,
5135 ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments",5146 "tmp.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments",
5136 );5147 );
51375148
5138 cases.add(5149 cases.add(
...@@ -5141,7 +5152,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5141,7 +5152,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5141 \\ _ = @memberType(i32, 0);5152 \\ _ = @memberType(i32, 0);
5142 \\}5153 \\}
5143 ,5154 ,
5144 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType",5155 "tmp.zig:2:21: error: type 'i32' does not support @memberType",
5145 );5156 );
51465157
5147 cases.add(5158 cases.add(
...@@ -5151,7 +5162,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5151,7 +5162,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5151 \\}5162 \\}
5152 \\const Foo = enum {A,};5163 \\const Foo = enum {A,};
5153 ,5164 ,
5154 ".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType",5165 "tmp.zig:2:21: error: type 'Foo' does not support @memberType",
5155 );5166 );
51565167
5157 cases.add(5168 cases.add(
...@@ -5161,7 +5172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5161,7 +5172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5161 \\}5172 \\}
5162 \\const Foo = struct {};5173 \\const Foo = struct {};
5163 ,5174 ,
5164 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",5175 "tmp.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
5165 );5176 );
51665177
5167 cases.add(5178 cases.add(
...@@ -5171,7 +5182,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5171,7 +5182,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5171 \\}5182 \\}
5172 \\const Foo = union {A: void,};5183 \\const Foo = union {A: void,};
5173 ,5184 ,
5174 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",5185 "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
5175 );5186 );
51765187
5177 cases.add(5188 cases.add(
...@@ -5180,7 +5191,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5180,7 +5191,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5180 \\ _ = @memberName(i32, 0);5191 \\ _ = @memberName(i32, 0);
5181 \\}5192 \\}
5182 ,5193 ,
5183 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName",5194 "tmp.zig:2:21: error: type 'i32' does not support @memberName",
5184 );5195 );
51855196
5186 cases.add(5197 cases.add(
...@@ -5190,7 +5201,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5190,7 +5201,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5190 \\}5201 \\}
5191 \\const Foo = struct {};5202 \\const Foo = struct {};
5192 ,5203 ,
5193 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",5204 "tmp.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
5194 );5205 );
51955206
5196 cases.add(5207 cases.add(
...@@ -5200,7 +5211,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5200,7 +5211,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5200 \\}5211 \\}
5201 \\const Foo = enum {A,};5212 \\const Foo = enum {A,};
5202 ,5213 ,
5203 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",5214 "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
5204 );5215 );
52055216
5206 cases.add(5217 cases.add(
...@@ -5210,7 +5221,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5210,7 +5221,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5210 \\}5221 \\}
5211 \\const Foo = union {A:i32,};5222 \\const Foo = union {A:i32,};
5212 ,5223 ,
5213 ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",5224 "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
5214 );5225 );
52155226
5216 cases.add(5227 cases.add(
...@@ -5220,7 +5231,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5220,7 +5231,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5220 \\}5231 \\}
5221 \\pub extern fn foo(format: *const u8, ...) void;5232 \\pub extern fn foo(format: *const u8, ...) void;
5222 ,5233 ,
5223 ".tmp_source.zig:2:9: error: expected type '*const u8', found '[5]u8'",5234 "tmp.zig:2:9: error: expected type '*const u8', found '[5]u8'",
5224 );5235 );
52255236
5226 cases.add(5237 cases.add(
...@@ -5239,9 +5250,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5239,9 +5250,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5239 \\ var allocator: ContextAllocator = undefined;5250 \\ var allocator: ContextAllocator = undefined;
5240 \\}5251 \\}
5241 ,5252 ,
5242 ".tmp_source.zig:4:25: error: aoeu",5253 "tmp.zig:4:25: error: aoeu",
5243 ".tmp_source.zig:1:36: note: called from here",5254 "tmp.zig:1:36: note: called from here",
5244 ".tmp_source.zig:12:20: note: referenced here",5255 "tmp.zig:12:20: note: referenced here",
5245 );5256 );
52465257
5247 cases.add(5258 cases.add(
...@@ -5258,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5258,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5258 \\ var x = Small.One;5269 \\ var x = Small.One;
5259 \\}5270 \\}
5260 ,5271 ,
5261 ".tmp_source.zig:1:21: error: 'u2' too small to hold all bits; must be at least 'u3'",5272 "tmp.zig:1:21: error: 'u2' too small to hold all bits; must be at least 'u3'",
5262 );5273 );
52635274
5264 cases.add(5275 cases.add(
...@@ -5273,7 +5284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5273,7 +5284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5273 \\ var x = Small.One;5284 \\ var x = Small.One;
5274 \\}5285 \\}
5275 ,5286 ,
5276 ".tmp_source.zig:1:21: error: expected integer, found 'f32'",5287 "tmp.zig:1:21: error: expected integer, found 'f32'",
5277 );5288 );
52785289
5279 cases.add(5290 cases.add(
...@@ -5289,7 +5300,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5289,7 +5300,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5289 \\ var x: u2 = Small.Two;5300 \\ var x: u2 = Small.Two;
5290 \\}5301 \\}
5291 ,5302 ,
5292 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",5303 "tmp.zig:9:22: error: expected type 'u2', found 'Small'",
5293 );5304 );
52945305
5295 cases.add(5306 cases.add(
...@@ -5306,7 +5317,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5306,7 +5317,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5306 \\ var x = @intToEnum(Small, y);5317 \\ var x = @intToEnum(Small, y);
5307 \\}5318 \\}
5308 ,5319 ,
5309 ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'",5320 "tmp.zig:10:31: error: expected type 'u2', found 'u3'",
5310 );5321 );
53115322
5312 cases.add(5323 cases.add(
...@@ -5322,7 +5333,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5322,7 +5333,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5322 \\ var y = Small.Two;5333 \\ var y = Small.Two;
5323 \\}5334 \\}
5324 ,5335 ,
5325 ".tmp_source.zig:1:20: error: expected unsigned integer, found 'i2'",5336 "tmp.zig:1:20: error: expected unsigned integer, found 'i2'",
5326 );5337 );
53275338
5328 cases.add(5339 cases.add(
...@@ -5334,7 +5345,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5334,7 +5345,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5334 \\ var x: MultipleChoice = undefined;5345 \\ var x: MultipleChoice = undefined;
5335 \\}5346 \\}
5336 ,5347 ,
5337 ".tmp_source.zig:2:14: error: enums, not structs, support field assignment",5348 "tmp.zig:2:14: error: enums, not structs, support field assignment",
5338 );5349 );
53395350
5340 cases.add(5351 cases.add(
...@@ -5346,8 +5357,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5346,8 +5357,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5346 \\ var x: MultipleChoice = undefined;5357 \\ var x: MultipleChoice = undefined;
5347 \\}5358 \\}
5348 ,5359 ,
5349 ".tmp_source.zig:2:14: error: non-enum union field assignment",5360 "tmp.zig:2:14: error: non-enum union field assignment",
5350 ".tmp_source.zig:1:24: note: consider 'union(enum)' here",5361 "tmp.zig:1:24: note: consider 'union(enum)' here",
5351 );5362 );
53525363
5353 cases.add(5364 cases.add(
...@@ -5357,7 +5368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5357,7 +5368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5357 \\ return @sizeOf(Foo);5368 \\ return @sizeOf(Foo);
5358 \\}5369 \\}
5359 ,5370 ,
5360 ".tmp_source.zig:1:13: error: enums must have 1 or more fields",5371 "tmp.zig:1:13: error: enums must have 1 or more fields",
5361 );5372 );
53625373
5363 cases.add(5374 cases.add(
...@@ -5367,7 +5378,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5367,7 +5378,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5367 \\ return @sizeOf(Foo);5378 \\ return @sizeOf(Foo);
5368 \\}5379 \\}
5369 ,5380 ,
5370 ".tmp_source.zig:1:13: error: unions must have 1 or more fields",5381 "tmp.zig:1:13: error: unions must have 1 or more fields",
5371 );5382 );
53725383
5373 cases.add(5384 cases.add(
...@@ -5383,8 +5394,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5383,8 +5394,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5383 \\ var x = MultipleChoice.C;5394 \\ var x = MultipleChoice.C;
5384 \\}5395 \\}
5385 ,5396 ,
5386 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",5397 "tmp.zig:6:9: error: enum tag value 60 already taken",
5387 ".tmp_source.zig:4:9: note: other occurrence here",5398 "tmp.zig:4:9: note: other occurrence here",
5388 );5399 );
53895400
5390 cases.add(5401 cases.add(
...@@ -5402,8 +5413,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5402,8 +5413,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5402 \\ return @sizeOf(Payload);5413 \\ return @sizeOf(Payload);
5403 \\}5414 \\}
5404 ,5415 ,
5405 ".tmp_source.zig:6:17: error: enum field missing: 'C'",5416 "tmp.zig:6:17: error: enum field missing: 'C'",
5406 ".tmp_source.zig:4:5: note: declared here",5417 "tmp.zig:4:5: note: declared here",
5407 );5418 );
54085419
5409 cases.add(5420 cases.add(
...@@ -5415,8 +5426,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5415,8 +5426,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5415 \\ const x = @TagType(Foo);5426 \\ const x = @TagType(Foo);
5416 \\}5427 \\}
5417 ,5428 ,
5418 ".tmp_source.zig:5:24: error: union 'Foo' has no tag",5429 "tmp.zig:5:24: error: union 'Foo' has no tag",
5419 ".tmp_source.zig:1:13: note: consider 'union(enum)' here",5430 "tmp.zig:1:13: note: consider 'union(enum)' here",
5420 );5431 );
54215432
5422 cases.add(5433 cases.add(
...@@ -5428,7 +5439,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5428,7 +5439,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5428 \\ const x = @TagType(Foo);5439 \\ const x = @TagType(Foo);
5429 \\}5440 \\}
5430 ,5441 ,
5431 ".tmp_source.zig:1:24: error: expected integer tag type, found 'f32'",5442 "tmp.zig:1:24: error: expected integer tag type, found 'f32'",
5432 );5443 );
54335444
5434 cases.add(5445 cases.add(
...@@ -5440,7 +5451,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5440,7 +5451,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5440 \\ const x = @TagType(Foo);5451 \\ const x = @TagType(Foo);
5441 \\}5452 \\}
5442 ,5453 ,
5443 ".tmp_source.zig:1:19: error: expected enum tag type, found 'u32'",5454 "tmp.zig:1:19: error: expected enum tag type, found 'u32'",
5444 );5455 );
54455456
5446 cases.add(5457 cases.add(
...@@ -5456,8 +5467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5456,8 +5467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5456 \\ var x = MultipleChoice { .C = {} };5467 \\ var x = MultipleChoice { .C = {} };
5457 \\}5468 \\}
5458 ,5469 ,
5459 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",5470 "tmp.zig:6:9: error: enum tag value 60 already taken",
5460 ".tmp_source.zig:4:9: note: other occurrence here",5471 "tmp.zig:4:9: note: other occurrence here",
5461 );5472 );
54625473
5463 cases.add(5474 cases.add(
...@@ -5477,8 +5488,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5477,8 +5488,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5477 \\ var a = Payload {.A = 1234};5488 \\ var a = Payload {.A = 1234};
5478 \\}5489 \\}
5479 ,5490 ,
5480 ".tmp_source.zig:10:5: error: enum field not found: 'D'",5491 "tmp.zig:10:5: error: enum field not found: 'D'",
5481 ".tmp_source.zig:1:16: note: enum declared here",5492 "tmp.zig:1:16: note: enum declared here",
5482 );5493 );
54835494
5484 cases.add(5495 cases.add(
...@@ -5492,8 +5503,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5492,8 +5503,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5492 \\ var b = Letter.B;5503 \\ var b = Letter.B;
5493 \\}5504 \\}
5494 ,5505 ,
5495 ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types",5506 "tmp.zig:2:8: error: structs and unions, not enums, support field types",
5496 ".tmp_source.zig:1:16: note: consider 'union(enum)' here",5507 "tmp.zig:1:16: note: consider 'union(enum)' here",
5497 );5508 );
54985509
5499 cases.add(5510 cases.add(
...@@ -5505,7 +5516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5505,7 +5516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5505 \\ var a = Letter { .A = {} };5516 \\ var a = Letter { .A = {} };
5506 \\}5517 \\}
5507 ,5518 ,
5508 ".tmp_source.zig:2:5: error: struct field missing type",5519 "tmp.zig:2:5: error: struct field missing type",
5509 );5520 );
55105521
5511 cases.add(5522 cases.add(
...@@ -5517,7 +5528,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5517,7 +5528,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5517 \\ var a = Letter { .A = {} };5528 \\ var a = Letter { .A = {} };
5518 \\}5529 \\}
5519 ,5530 ,
5520 ".tmp_source.zig:2:5: error: union field missing type",5531 "tmp.zig:2:5: error: union field missing type",
5521 );5532 );
55225533
5523 cases.add(5534 cases.add(
...@@ -5536,7 +5547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5536,7 +5547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5536 \\ var a = Payload { .A = 1234 };5547 \\ var a = Payload { .A = 1234 };
5537 \\}5548 \\}
5538 ,5549 ,
5539 ".tmp_source.zig:6:30: error: extern union does not support enum tag type",5550 "tmp.zig:6:30: error: extern union does not support enum tag type",
5540 );5551 );
55415552
5542 cases.add(5553 cases.add(
...@@ -5555,7 +5566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5555,7 +5566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5555 \\ var a = Payload { .A = 1234 };5566 \\ var a = Payload { .A = 1234 };
5556 \\}5567 \\}
5557 ,5568 ,
5558 ".tmp_source.zig:6:30: error: packed union does not support enum tag type",5569 "tmp.zig:6:30: error: packed union does not support enum tag type",
5559 );5570 );
55605571
5561 cases.add(5572 cases.add(
...@@ -5576,8 +5587,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5576,8 +5587,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5576 \\ }5587 \\ }
5577 \\}5588 \\}
5578 ,5589 ,
5579 ".tmp_source.zig:11:14: error: switch on union which has no attached enum",5590 "tmp.zig:11:14: error: switch on union which has no attached enum",
5580 ".tmp_source.zig:1:17: note: consider 'union(enum)' here",5591 "tmp.zig:1:17: note: consider 'union(enum)' here",
5581 );5592 );
55825593
5583 cases.add(5594 cases.add(
...@@ -5590,8 +5601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5590,8 +5601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5590 \\ var x = @intToEnum(Foo, 0);5601 \\ var x = @intToEnum(Foo, 0);
5591 \\}5602 \\}
5592 ,5603 ,
5593 ".tmp_source.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",5604 "tmp.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
5594 ".tmp_source.zig:1:13: note: 'Foo' declared here",5605 "tmp.zig:1:13: note: 'Foo' declared here",
5595 );5606 );
55965607
5597 cases.add(5608 cases.add(
...@@ -5606,8 +5617,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5606,8 +5617,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5606 \\ var x: Value = Letter.A;5617 \\ var x: Value = Letter.A;
5607 \\}5618 \\}
5608 ,5619 ,
5609 ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",5620 "tmp.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
5610 ".tmp_source.zig:3:5: note: field 'A' declared here",5621 "tmp.zig:3:5: note: field 'A' declared here",
5611 );5622 );
56125623
5613 cases.add(5624 cases.add(
...@@ -5625,8 +5636,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5625,8 +5636,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5625 \\ var x: Value = l;5636 \\ var x: Value = l;
5626 \\}5637 \\}
5627 ,5638 ,
5628 ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",5639 "tmp.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
5629 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'",5640 "tmp.zig:3:5: note: field 'A' has type 'i32'",
5630 );5641 );
56315642
5632 cases.add(5643 cases.add(
...@@ -5638,7 +5649,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5638,7 +5649,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5638 \\ const fieldOffset = @byteOffsetOf(Empty, "val",);5649 \\ const fieldOffset = @byteOffsetOf(Empty, "val",);
5639 \\}5650 \\}
5640 ,5651 ,
5641 ".tmp_source.zig:5:46: error: zero-bit field 'val' in struct 'Empty' has no offset",5652 "tmp.zig:5:46: error: zero-bit field 'val' in struct 'Empty' has no offset",
5642 );5653 );
56435654
5644 cases.add(5655 cases.add(
...@@ -5650,7 +5661,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5650,7 +5661,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5650 \\ const fieldOffset = @bitOffsetOf(Empty, "val",);5661 \\ const fieldOffset = @bitOffsetOf(Empty, "val",);
5651 \\}5662 \\}
5652 ,5663 ,
5653 ".tmp_source.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",5664 "tmp.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
5654 );5665 );
56555666
5656 cases.add(5667 cases.add(
...@@ -5664,7 +5675,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5664,7 +5675,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5664 \\ const bar_val = foo.Bar;5675 \\ const bar_val = foo.Bar;
5665 \\}5676 \\}
5666 ,5677 ,
5667 ".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",5678 "tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",
5668 );5679 );
56695680
5670 cases.add(5681 cases.add(
...@@ -5674,7 +5685,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5674,7 +5685,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5674 \\ _ = @typeOf(generic).ReturnType;5685 \\ _ = @typeOf(generic).ReturnType;
5675 \\}5686 \\}
5676 ,5687 ,
5677 ".tmp_source.zig:3:25: error: ReturnType has not been resolved because 'fn(var)var' is generic",5688 "tmp.zig:3:25: error: ReturnType has not been resolved because 'fn(var)var' is generic",
5678 );5689 );
56795690
5680 cases.add(5691 cases.add(
...@@ -5684,7 +5695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5684,7 +5695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5684 \\ _ = @ArgType(@typeOf(generic), 0);5695 \\ _ = @ArgType(@typeOf(generic), 0);
5685 \\}5696 \\}
5686 ,5697 ,
5687 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",5698 "tmp.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
5688 );5699 );
56895700
5690 cases.add(5701 cases.add(
...@@ -5694,7 +5705,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5694,7 +5705,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5694 \\ asm volatile ("" : [baz]"+r"(bar) : : "");5705 \\ asm volatile ("" : [baz]"+r"(bar) : : "");
5695 \\}5706 \\}
5696 ,5707 ,
5697 ".tmp_source.zig:3:5: error: invalid modifier starting output constraint for 'baz': '+', only '=' is supported. Compiler TODO: see https://github.com/ziglang/zig/issues/215",5708 "tmp.zig:3:5: error: invalid modifier starting output constraint for 'baz': '+', only '=' is supported. Compiler TODO: see https://github.com/ziglang/zig/issues/215",
5698 );5709 );
56995710
5700 cases.add(5711 cases.add(
...@@ -5703,7 +5714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5703,7 +5714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5703 \\ asm volatile ("" : : [bar]"r"(3) : "");5714 \\ asm volatile ("" : : [bar]"r"(3) : "");
5704 \\}5715 \\}
5705 ,5716 ,
5706 ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int",5717 "tmp.zig:2:35: error: expected sized integer or sized float, found comptime_int",
5707 );5718 );
57085719
5709 cases.add(5720 cases.add(
...@@ -5712,7 +5723,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5712,7 +5723,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5712 \\ asm volatile ("" : : [bar]"r"(3.17) : "");5723 \\ asm volatile ("" : : [bar]"r"(3.17) : "");
5713 \\}5724 \\}
5714 ,5725 ,
5715 ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float",5726 "tmp.zig:2:35: error: expected sized integer or sized float, found comptime_float",
5716 );5727 );
57175728
5718 cases.add(5729 cases.add(
...@@ -5726,7 +5737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5726,7 +5737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5726 \\ const foo = Foo { .Bar = x, .Baz = u8 };5737 \\ const foo = Foo { .Bar = x, .Baz = u8 };
5727 \\}5738 \\}
5728 ,5739 ,
5729 ".tmp_source.zig:7:30: error: unable to evaluate constant expression",5740 "tmp.zig:7:30: error: unable to evaluate constant expression",
5730 );5741 );
57315742
5732 cases.add(5743 cases.add(
...@@ -5740,7 +5751,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5740,7 +5751,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5740 \\ const foo = Foo { .Bar = x };5751 \\ const foo = Foo { .Bar = x };
5741 \\}5752 \\}
5742 ,5753 ,
5743 ".tmp_source.zig:7:30: error: unable to evaluate constant expression",5754 "tmp.zig:7:30: error: unable to evaluate constant expression",
5744 );5755 );
57455756
5746 cases.addTest(5757 cases.addTest(
...@@ -5750,7 +5761,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5750,7 +5761,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5750 \\ var v: V = undefined;5761 \\ var v: V = undefined;
5751 \\}5762 \\}
5752 ,5763 ,
5753 ".tmp_source.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",5764 "tmp.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
5754 );5765 );
57555766
5756 cases.add("compileLog of tagged enum doesn't crash the compiler",5767 cases.add("compileLog of tagged enum doesn't crash the compiler",
...@@ -5765,5 +5776,5 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5765,5 +5776,5 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5765 \\pub fn main () void {5776 \\pub fn main () void {
5766 \\ comptime testCompileLog(Bar{.X = 123});5777 \\ comptime testCompileLog(Bar{.X = 123});
5767 \\}5778 \\}
5768 , ".tmp_source.zig:6:5: error: found compile log statement");5779 , "tmp.zig:6:5: error: found compile log statement");
5769}5780}
test/stage1/behavior.zig+5-2
...@@ -18,6 +18,7 @@ comptime {...@@ -18,6 +18,7 @@ comptime {
18 _ = @import("behavior/bugs/1421.zig");18 _ = @import("behavior/bugs/1421.zig");
19 _ = @import("behavior/bugs/1442.zig");19 _ = @import("behavior/bugs/1442.zig");
20 _ = @import("behavior/bugs/1486.zig");20 _ = @import("behavior/bugs/1486.zig");
21 _ = @import("behavior/bugs/1500.zig");
21 _ = @import("behavior/bugs/1851.zig");22 _ = @import("behavior/bugs/1851.zig");
22 _ = @import("behavior/bugs/2006.zig");23 _ = @import("behavior/bugs/2006.zig");
23 _ = @import("behavior/bugs/394.zig");24 _ = @import("behavior/bugs/394.zig");
...@@ -25,6 +26,7 @@ comptime {...@@ -25,6 +26,7 @@ comptime {
25 _ = @import("behavior/bugs/529.zig");26 _ = @import("behavior/bugs/529.zig");
26 _ = @import("behavior/bugs/655.zig");27 _ = @import("behavior/bugs/655.zig");
27 _ = @import("behavior/bugs/656.zig");28 _ = @import("behavior/bugs/656.zig");
29 _ = @import("behavior/bugs/679.zig");
28 _ = @import("behavior/bugs/704.zig");30 _ = @import("behavior/bugs/704.zig");
29 _ = @import("behavior/bugs/718.zig");31 _ = @import("behavior/bugs/718.zig");
30 _ = @import("behavior/bugs/726.zig");32 _ = @import("behavior/bugs/726.zig");
...@@ -54,14 +56,14 @@ comptime {...@@ -54,14 +56,14 @@ comptime {
54 _ = @import("behavior/math.zig");56 _ = @import("behavior/math.zig");
55 _ = @import("behavior/merge_error_sets.zig");57 _ = @import("behavior/merge_error_sets.zig");
56 _ = @import("behavior/misc.zig");58 _ = @import("behavior/misc.zig");
57 _ = @import("behavior/namespace_depends_on_compile_var/index.zig");59 _ = @import("behavior/namespace_depends_on_compile_var.zig");
58 _ = @import("behavior/new_stack_call.zig");60 _ = @import("behavior/new_stack_call.zig");
59 _ = @import("behavior/null.zig");61 _ = @import("behavior/null.zig");
60 _ = @import("behavior/optional.zig");62 _ = @import("behavior/optional.zig");
61 _ = @import("behavior/pointers.zig");63 _ = @import("behavior/pointers.zig");
62 _ = @import("behavior/popcount.zig");64 _ = @import("behavior/popcount.zig");
63 _ = @import("behavior/ptrcast.zig");65 _ = @import("behavior/ptrcast.zig");
64 _ = @import("behavior/pub_enum/index.zig");66 _ = @import("behavior/pub_enum.zig");
65 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");67 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
66 _ = @import("behavior/reflection.zig");68 _ = @import("behavior/reflection.zig");
67 _ = @import("behavior/sizeof_and_typeof.zig");69 _ = @import("behavior/sizeof_and_typeof.zig");
...@@ -78,6 +80,7 @@ comptime {...@@ -78,6 +80,7 @@ comptime {
78 _ = @import("behavior/truncate.zig");80 _ = @import("behavior/truncate.zig");
79 _ = @import("behavior/try.zig");81 _ = @import("behavior/try.zig");
80 _ = @import("behavior/type_info.zig");82 _ = @import("behavior/type_info.zig");
83 _ = @import("behavior/typename.zig");
81 _ = @import("behavior/undefined.zig");84 _ = @import("behavior/undefined.zig");
82 _ = @import("behavior/underscore.zig");85 _ = @import("behavior/underscore.zig");
83 _ = @import("behavior/union.zig");86 _ = @import("behavior/union.zig");
test/stage1/behavior/asm.zig+5-5
...@@ -4,16 +4,16 @@ const expect = @import("std").testing.expect;...@@ -4,16 +4,16 @@ const expect = @import("std").testing.expect;
4comptime {4comptime {
5 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {5 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
6 asm volatile (6 asm volatile (
7 \\.globl aoeu;7 \\.globl this_is_my_alias;
8 \\.type aoeu, @function;8 \\.type this_is_my_alias, @function;
9 \\.set aoeu, derp;9 \\.set this_is_my_alias, derp;
10 );10 );
11 }11 }
12}12}
1313
14test "module level assembly" {14test "module level assembly" {
15 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {15 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
16 expect(aoeu() == 1234);16 expect(this_is_my_alias() == 1234);
17 }17 }
18}18}
1919
...@@ -85,7 +85,7 @@ test "sized integer/float in asm input" {...@@ -85,7 +85,7 @@ test "sized integer/float in asm input" {
85 );85 );
86}86}
8787
88extern fn aoeu() i32;88extern fn this_is_my_alias() i32;
8989
90export fn derp() i32 {90export fn derp() i32 {
91 return 1234;91 return 1234;
test/stage1/behavior/bugs/1500.zig created+10
...@@ -0,0 +1,10 @@
1const A = struct {
2 b: B,
3};
4
5const B = fn (A) void;
6
7test "allow these dependencies" {
8 var a: A = undefined;
9 var b: B = undefined;
10}
test/stage1/behavior/bugs/679.zig created+17
...@@ -0,0 +1,17 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4pub fn List(comptime T: type) type {
5 return u32;
6}
7
8const ElementList = List(Element);
9const Element = struct {
10 link: ElementList,
11};
12
13test "false dependency loop in struct definition" {
14 const listType = ElementList;
15 var x: listType = 42;
16 expect(x == 42);
17}
test/stage1/behavior/misc.zig+3-2
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
3const mem = std.mem;4const mem = std.mem;
4const cstr = std.cstr;5const cstr = std.cstr;
5const builtin = @import("builtin");6const builtin = @import("builtin");
...@@ -469,7 +470,7 @@ test "@typeId" {...@@ -469,7 +470,7 @@ test "@typeId" {
469 expect(@typeId(AUnionEnum) == Tid.Union);470 expect(@typeId(AUnionEnum) == Tid.Union);
470 expect(@typeId(AUnion) == Tid.Union);471 expect(@typeId(AUnion) == Tid.Union);
471 expect(@typeId(fn () void) == Tid.Fn);472 expect(@typeId(fn () void) == Tid.Fn);
472 expect(@typeId(@typeOf(builtin)) == Tid.Namespace);473 expect(@typeId(@typeOf(builtin)) == Tid.Type);
473 // TODO bound fn474 // TODO bound fn
474 // TODO arg tuple475 // TODO arg tuple
475 // TODO opaque476 // TODO opaque
...@@ -488,7 +489,7 @@ test "@typeName" {...@@ -488,7 +489,7 @@ test "@typeName" {
488 expect(mem.eql(u8, @typeName(i64), "i64"));489 expect(mem.eql(u8, @typeName(i64), "i64"));
489 expect(mem.eql(u8, @typeName(*usize), "*usize"));490 expect(mem.eql(u8, @typeName(*usize), "*usize"));
490 // https://github.com/ziglang/zig/issues/675491 // https://github.com/ziglang/zig/issues/675
491 expect(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));492 expectEqualSlices(u8, "behavior.misc.TypeFromFn(u8)", @typeName(TypeFromFn(u8)));
492 expect(mem.eql(u8, @typeName(Struct), "Struct"));493 expect(mem.eql(u8, @typeName(Struct), "Struct"));
493 expect(mem.eql(u8, @typeName(Union), "Union"));494 expect(mem.eql(u8, @typeName(Union), "Union"));
494 expect(mem.eql(u8, @typeName(Enum), "Enum"));495 expect(mem.eql(u8, @typeName(Enum), "Enum"));
test/stage1/behavior/namespace_depends_on_compile_var.zig created+14
...@@ -0,0 +1,14 @@
1const builtin = @import("builtin");
2const expect = @import("std").testing.expect;
3
4test "namespace depends on compile var" {
5 if (some_namespace.a_bool) {
6 expect(some_namespace.a_bool);
7 } else {
8 expect(!some_namespace.a_bool);
9 }
10}
11const some_namespace = switch (builtin.os) {
12 builtin.Os.linux => @import("namespace_depends_on_compile_var/a.zig"),
13 else => @import("namespace_depends_on_compile_var/b.zig"),
14};
test/stage1/behavior/namespace_depends_on_compile_var/index.zig deleted-14
...@@ -1,14 +0,0 @@
1const builtin = @import("builtin");
2const expect = @import("std").testing.expect;
3
4test "namespace depends on compile var" {
5 if (some_namespace.a_bool) {
6 expect(some_namespace.a_bool);
7 } else {
8 expect(!some_namespace.a_bool);
9 }
10}
11const some_namespace = switch (builtin.os) {
12 builtin.Os.linux => @import("a.zig"),
13 else => @import("b.zig"),
14};
test/stage1/behavior/pointers.zig+6
...@@ -124,3 +124,9 @@ test "implicit cast error unions with non-optional to optional pointer" {...@@ -124,3 +124,9 @@ test "implicit cast error unions with non-optional to optional pointer" {
124 S.doTheTest();124 S.doTheTest();
125 comptime S.doTheTest();125 comptime S.doTheTest();
126}126}
127
128test "initialize const optional C pointer to null" {
129 const a: ?[*c]i32 = null;
130 expect(a == null);
131 comptime expect(a == null);
132}
test/stage1/behavior/pub_enum.zig created+13
...@@ -0,0 +1,13 @@
1const other = @import("pub_enum/other.zig");
2const expect = @import("std").testing.expect;
3
4test "pub enum" {
5 pubEnumTest(other.APubEnum.Two);
6}
7fn pubEnumTest(foo: other.APubEnum) void {
8 expect(foo == other.APubEnum.Two);
9}
10
11test "cast with imported symbol" {
12 expect(other.size_t(42) == 42);
13}
test/stage1/behavior/pub_enum/index.zig deleted-13
...@@ -1,13 +0,0 @@
1const other = @import("other.zig");
2const expect = @import("std").testing.expect;
3
4test "pub enum" {
5 pubEnumTest(other.APubEnum.Two);
6}
7fn pubEnumTest(foo: other.APubEnum) void {
8 expect(foo == other.APubEnum.Two);
9}
10
11test "cast with imported symbol" {
12 expect(other.size_t(42) == 42);
13}
test/stage1/behavior/slice.zig+11-2
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const mem = @import("std").mem;2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
4const mem = std.mem;
35
4const x = @intToPtr([*]i32, 0x1000)[0..0x500];6const x = @intToPtr([*]i32, 0x1000)[0..0x500];
5const y = x[0x100..];7const y = x[0x100..];
...@@ -38,3 +40,10 @@ test "implicitly cast array of size 0 to slice" {...@@ -38,3 +40,10 @@ test "implicitly cast array of size 0 to slice" {
38fn assertLenIsZero(msg: []const u8) void {40fn assertLenIsZero(msg: []const u8) void {
39 expect(msg.len == 0);41 expect(msg.len == 0);
40}42}
43
44test "C pointer" {
45 var buf: [*c]const u8 = c"kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf";
46 var len: u32 = 10;
47 var slice = buf[0..len];
48 expectEqualSlices(u8, "kjdhfkjdhf", slice);
49}
test/stage1/behavior/type_info.zig+1-1
...@@ -186,7 +186,7 @@ fn testUnion() void {...@@ -186,7 +186,7 @@ fn testUnion() void {
186 expect(TypeId(typeinfo_info) == TypeId.Union);186 expect(TypeId(typeinfo_info) == TypeId.Union);
187 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);187 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
188 expect(typeinfo_info.Union.tag_type.? == TypeId);188 expect(typeinfo_info.Union.tag_type.? == TypeId);
189 expect(typeinfo_info.Union.fields.len == 25);189 expect(typeinfo_info.Union.fields.len == 24);
190 expect(typeinfo_info.Union.fields[4].enum_field != null);190 expect(typeinfo_info.Union.fields[4].enum_field != null);
191 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);191 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
192 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));192 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
test/stage1/behavior/typename.zig created+7
...@@ -0,0 +1,7 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
4
5test "slice" {
6 expectEqualSlices(u8, "[]u8", @typeName([]u8));
7}
test/standalone/main_pkg_path/a/test.zig created+5
...@@ -0,0 +1,5 @@
1const b = @import("../b.zig");
2
3test "main pkg path" {
4 b.foo();
5}
test/standalone/main_pkg_path/b.zig created+1
...@@ -0,0 +1 @@
1pub fn foo() void {}
test/standalone/main_pkg_path/build.zig created+9
...@@ -0,0 +1,9 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const test_exe = b.addTest("a/test.zig");
5 test_exe.setMainPkgPath(".");
6
7 const test_step = b.step("test", "Test the program");
8 test_step.dependOn(&test_exe.step);
9}
test/standalone/static_c_lib/build.zig created+18
...@@ -0,0 +1,18 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const mode = b.standardReleaseOptions();
5
6 const foo = b.addStaticLibrary("foo", null);
7 foo.addCSourceFile("foo.c", [][]const u8{});
8 foo.setBuildMode(mode);
9 foo.addIncludeDir(".");
10
11 const test_exe = b.addTest("foo.zig");
12 test_exe.setBuildMode(mode);
13 test_exe.linkLibrary(foo);
14 test_exe.addIncludeDir(".");
15
16 const test_step = b.step("test", "Test it");
17 test_step.dependOn(&test_exe.step);
18}
test/standalone/static_c_lib/foo.c created+4
...@@ -0,0 +1,4 @@
1#include "foo.h"
2uint32_t add(uint32_t a, uint32_t b) {
3 return a + b;
4}
test/standalone/static_c_lib/foo.h created+2
...@@ -0,0 +1,2 @@
1#include <stdint.h>
2uint32_t add(uint32_t a, uint32_t b);
test/standalone/static_c_lib/foo.zig created+8
...@@ -0,0 +1,8 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const c = @cImport(@cInclude("foo.h"));
4
5test "C add" {
6 const result = c.add(1, 2);
7 expect(result == 3);
8}
test/tests.zig+5-2
...@@ -569,7 +569,7 @@ pub const CompileErrorContext = struct {...@@ -569,7 +569,7 @@ pub const CompileErrorContext = struct {
569 const ErrLineIter = struct {569 const ErrLineIter = struct {
570 lines: mem.SplitIterator,570 lines: mem.SplitIterator,
571571
572 const source_file = ".tmp_source.zig";572 const source_file = "tmp.zig";
573573
574 fn init(input: []const u8) ErrLineIter {574 fn init(input: []const u8) ErrLineIter {
575 return ErrLineIter{ .lines = mem.separate(input, "\n") };575 return ErrLineIter{ .lines = mem.separate(input, "\n") };
...@@ -759,7 +759,7 @@ pub const CompileErrorContext = struct {...@@ -759,7 +759,7 @@ pub const CompileErrorContext = struct {
759 .is_test = false,759 .is_test = false,
760 };760 };
761761
762 tc.addSourceFile(".tmp_source.zig", source);762 tc.addSourceFile("tmp.zig", source);
763 comptime var arg_i = 0;763 comptime var arg_i = 0;
764 inline while (arg_i < expected_lines.len) : (arg_i += 1) {764 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
765 tc.addExpectedError(expected_lines[arg_i]);765 tc.addExpectedError(expected_lines[arg_i]);
...@@ -980,15 +980,18 @@ pub const TranslateCContext = struct {...@@ -980,15 +980,18 @@ pub const TranslateCContext = struct {
980 Term.Exited => |code| {980 Term.Exited => |code| {
981 if (code != 0) {981 if (code != 0) {
982 warn("Compilation failed with exit code {}\n", code);982 warn("Compilation failed with exit code {}\n", code);
983 printInvocation(zig_args.toSliceConst());
983 return error.TestFailed;984 return error.TestFailed;
984 }985 }
985 },986 },
986 Term.Signal => |code| {987 Term.Signal => |code| {
987 warn("Compilation failed with signal {}\n", code);988 warn("Compilation failed with signal {}\n", code);
989 printInvocation(zig_args.toSliceConst());
988 return error.TestFailed;990 return error.TestFailed;
989 },991 },
990 else => {992 else => {
991 warn("Compilation terminated unexpectedly\n");993 warn("Compilation terminated unexpectedly\n");
994 printInvocation(zig_args.toSliceConst());
992 return error.TestFailed;995 return error.TestFailed;
993 },996 },
994 }997 }