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
signature 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:
1313 - test: |
1414 cd zig/build
1515 bin/zig test ../test/stage1/behavior.zig
16 bin/zig test ../std/special/compiler_rt/index.zig
16 bin/zig test ../std/special/compiler_rt.zig
1717
1818 bin/zig test ../test/stage1/behavior.zig --library c
19 bin/zig test ../std/special/compiler_rt/index.zig --library c
19 bin/zig test ../std/special/compiler_rt.zig --library c
2020
2121 bin/zig test ../test/stage1/behavior.zig --release-fast
22 bin/zig test ../std/special/compiler_rt/index.zig --release-fast
22 bin/zig test ../std/special/compiler_rt.zig --release-fast
2323
2424 bin/zig test ../test/stage1/behavior.zig --release-fast --library c
25 bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c
25 bin/zig test ../std/special/compiler_rt.zig --release-fast --library c
2626
2727 bin/zig test ../test/stage1/behavior.zig --release-small --library c
28 bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c
28 bin/zig test ../std/special/compiler_rt.zig --release-small --library c
2929
3030 bin/zig test ../test/stage1/behavior.zig --release-small
31 bin/zig test ../std/special/compiler_rt/index.zig --release-small
31 bin/zig test ../std/special/compiler_rt.zig --release-small
3232
3333 bin/zig test ../test/stage1/behavior.zig --release-safe
34 bin/zig test ../std/special/compiler_rt/index.zig --release-safe
34 bin/zig test ../std/special/compiler_rt.zig --release-safe
3535
3636 bin/zig test ../test/stage1/behavior.zig --release-safe --library c
37 bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c
37 bin/zig test ../std/special/compiler_rt.zig --release-safe --library c
3838 # TODO enable all tests
3939 #bin/zig build --build-file ../build.zig test
4040 # TODO integrate with the download page updater and make a
CMakeLists.txt+21-21
......@@ -442,7 +442,7 @@ set(ZIG_CPP_SOURCES
442442
443443set(ZIG_STD_FILES
444444 "array_list.zig"
445 "atomic/index.zig"
445 "atomic.zig"
446446 "atomic/int.zig"
447447 "atomic/queue.zig"
448448 "atomic/stack.zig"
......@@ -452,17 +452,17 @@ set(ZIG_STD_FILES
452452 "buffer.zig"
453453 "build.zig"
454454 "build/fmt.zig"
455 "c.zig"
455456 "c/darwin.zig"
456457 "c/freebsd.zig"
457 "c/index.zig"
458458 "c/linux.zig"
459459 "c/netbsd.zig"
460460 "c/windows.zig"
461461 "coff.zig"
462 "crypto.zig"
462463 "crypto/blake2.zig"
463464 "crypto/chacha20.zig"
464465 "crypto/hmac.zig"
465 "crypto/index.zig"
466466 "crypto/md5.zig"
467467 "crypto/poly1305.zig"
468468 "crypto/sha1.zig"
......@@ -470,8 +470,8 @@ set(ZIG_STD_FILES
470470 "crypto/sha3.zig"
471471 "crypto/x25519.zig"
472472 "cstr.zig"
473 "debug.zig"
473474 "debug/failing_allocator.zig"
474 "debug/index.zig"
475475 "dwarf.zig"
476476 "dynamic_library.zig"
477477 "elf.zig"
......@@ -488,25 +488,25 @@ set(ZIG_STD_FILES
488488 "event/net.zig"
489489 "event/rwlock.zig"
490490 "event/rwlocked.zig"
491 "fmt.zig"
492 "fmt/errol.zig"
491493 "fmt/errol/enum3.zig"
492 "fmt/errol/index.zig"
493494 "fmt/errol/lookup.zig"
494 "fmt/index.zig"
495495 "fmt/parse_float.zig"
496 "hash.zig"
496497 "hash/adler.zig"
497498 "hash/crc.zig"
498499 "hash/fnv.zig"
499 "hash/index.zig"
500500 "hash/siphash.zig"
501501 "hash_map.zig"
502502 "heap.zig"
503 "index.zig"
504503 "io.zig"
505504 "io/seekable_stream.zig"
506505 "json.zig"
507506 "lazy_init.zig"
508507 "linked_list.zig"
509508 "macho.zig"
509 "math.zig"
510510 "math/acos.zig"
511511 "math/acosh.zig"
512512 "math/asin.zig"
......@@ -514,10 +514,11 @@ set(ZIG_STD_FILES
514514 "math/atan.zig"
515515 "math/atan2.zig"
516516 "math/atanh.zig"
517 "math/big/index.zig"
517 "math/big.zig"
518518 "math/big/int.zig"
519519 "math/cbrt.zig"
520520 "math/ceil.zig"
521 "math/complex.zig"
521522 "math/complex/abs.zig"
522523 "math/complex/acos.zig"
523524 "math/complex/acosh.zig"
......@@ -530,7 +531,6 @@ set(ZIG_STD_FILES
530531 "math/complex/cos.zig"
531532 "math/complex/cosh.zig"
532533 "math/complex/exp.zig"
533 "math/complex/index.zig"
534534 "math/complex/ldexp.zig"
535535 "math/complex/log.zig"
536536 "math/complex/pow.zig"
......@@ -553,7 +553,6 @@ set(ZIG_STD_FILES
553553 "math/frexp.zig"
554554 "math/hypot.zig"
555555 "math/ilogb.zig"
556 "math/index.zig"
557556 "math/inf.zig"
558557 "math/isfinite.zig"
559558 "math/isinf.zig"
......@@ -578,50 +577,51 @@ set(ZIG_STD_FILES
578577 "math/tanh.zig"
579578 "math/trunc.zig"
580579 "mem.zig"
581 "meta/index.zig"
580 "meta.zig"
582581 "meta/trait.zig"
583582 "mutex.zig"
584583 "net.zig"
584 "os.zig"
585585 "os/child_process.zig"
586586 "os/darwin.zig"
587587 "os/darwin/errno.zig"
588588 "os/epoch.zig"
589589 "os/file.zig"
590 "os/freebsd.zig"
590591 "os/freebsd/errno.zig"
591 "os/freebsd/index.zig"
592592 "os/get_app_data_dir.zig"
593593 "os/get_user_id.zig"
594 "os/index.zig"
594 "os/linux.zig"
595595 "os/linux/arm64.zig"
596596 "os/linux/errno.zig"
597 "os/linux/index.zig"
598597 "os/linux/vdso.zig"
599598 "os/linux/x86_64.zig"
599 "os/netbsd.zig"
600600 "os/netbsd/errno.zig"
601 "os/netbsd/index.zig"
602601 "os/path.zig"
603602 "os/time.zig"
604603 "os/uefi.zig"
604 "os/windows.zig"
605605 "os/windows/advapi32.zig"
606606 "os/windows/error.zig"
607 "os/windows/index.zig"
608607 "os/windows/kernel32.zig"
609608 "os/windows/ntdll.zig"
610609 "os/windows/ole32.zig"
611610 "os/windows/shell32.zig"
612 "os/windows/tls.zig"
613611 "os/windows/util.zig"
614612 "os/zen.zig"
615613 "pdb.zig"
616614 "priority_queue.zig"
617 "rand/index.zig"
615 "rand.zig"
618616 "rand/ziggurat.zig"
619617 "segmented_list.zig"
620618 "sort.zig"
621619 "special/bootstrap.zig"
622620 "special/bootstrap_lib.zig"
621 "special/bootstrap_windows_tls.zig"
623622 "special/build_runner.zig"
624623 "special/builtin.zig"
624 "special/compiler_rt.zig"
625625 "special/compiler_rt/addXf3.zig"
626626 "special/compiler_rt/aulldiv.zig"
627627 "special/compiler_rt/aullrem.zig"
......@@ -656,7 +656,6 @@ set(ZIG_STD_FILES
656656 "special/compiler_rt/floatuntidf.zig"
657657 "special/compiler_rt/floatuntisf.zig"
658658 "special/compiler_rt/floatuntitf.zig"
659 "special/compiler_rt/index.zig"
660659 "special/compiler_rt/muloti4.zig"
661660 "special/compiler_rt/multi3.zig"
662661 "special/compiler_rt/truncXfYf2.zig"
......@@ -674,10 +673,11 @@ set(ZIG_STD_FILES
674673 "special/test_runner.zig"
675674 "spinlock.zig"
676675 "statically_initialized_mutex.zig"
676 "std.zig"
677677 "testing.zig"
678678 "unicode.zig"
679 "zig.zig"
679680 "zig/ast.zig"
680 "zig/index.zig"
681681 "zig/parse.zig"
682682 "zig/parse_string_literal.zig"
683683 "zig/render.zig"
build.zig+2-2
......@@ -115,9 +115,9 @@ pub fn build(b: *Builder) !void {
115115
116116 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
122122 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
123123 test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes));
doc/langref.html.in+27-23
......@@ -6116,7 +6116,7 @@ test "main" {
61166116 {#header_close#}
61176117
61186118 {#header_open|@frameAddress#}
6119 <pre>{#syntax#}@frameAddress(){#endsyntax#}</pre>
6119 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>
61206120 <p>
61216121 This function returns the base pointer of the current stack frame.
61226122 </p>
......@@ -6482,17 +6482,18 @@ test "call foo" {
64826482 {#header_close#}
64836483
64846484 {#header_open|@returnAddress#}
6485 <pre>{#syntax#}@returnAddress(){#endsyntax#}</pre>
6485 <pre>{#syntax#}@returnAddress() usize{#endsyntax#}</pre>
64866486 <p>
6487 This function returns a pointer to the return address of the current stack
6488 frame.
6487 This function returns the address of the next machine code instruction that will be executed
6488 when the current function returns.
64896489 </p>
64906490 <p>
64916491 The implications of this are target specific and not consistent across
64926492 all platforms.
64936493 </p>
64946494 <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.
64966497 </p>
64976498 {#header_close#}
64986499 {#header_open|@setAlignStack#}
......@@ -6785,7 +6786,6 @@ pub const TypeId = enum {
67856786 Enum,
67866787 Union,
67876788 Fn,
6788 Namespace,
67896789 Block,
67906790 BoundFn,
67916791 ArgTuple,
......@@ -6820,7 +6820,6 @@ pub const TypeInfo = union(TypeId) {
68206820 Enum: Enum,
68216821 Union: Union,
68226822 Fn: Fn,
6823 Namespace: void,
68246823 BoundFn: Fn,
68256824 ArgTuple: void,
68266825 Opaque: void,
......@@ -6829,18 +6828,18 @@ pub const TypeInfo = union(TypeId) {
68296828
68306829 pub const Int = struct {
68316830 is_signed: bool,
6832 bits: u8,
6831 bits: comptime_int,
68336832 };
68346833
68356834 pub const Float = struct {
6836 bits: u8,
6835 bits: comptime_int,
68376836 };
68386837
68396838 pub const Pointer = struct {
68406839 size: Size,
68416840 is_const: bool,
68426841 is_volatile: bool,
6843 alignment: u32,
6842 alignment: comptime_int,
68446843 child: type,
68456844
68466845 pub const Size = enum {
......@@ -6851,7 +6850,7 @@ pub const TypeInfo = union(TypeId) {
68516850 };
68526851
68536852 pub const Array = struct {
6854 len: usize,
6853 len: comptime_int,
68556854 child: type,
68566855 };
68576856
......@@ -6863,7 +6862,7 @@ pub const TypeInfo = union(TypeId) {
68636862
68646863 pub const StructField = struct {
68656864 name: []const u8,
6866 offset: ?usize,
6865 offset: ?comptime_int,
68676866 field_type: type,
68686867 };
68696868
......@@ -6884,7 +6883,7 @@ pub const TypeInfo = union(TypeId) {
68846883
68856884 pub const Error = struct {
68866885 name: []const u8,
6887 value: usize,
6886 value: comptime_int,
68886887 };
68896888
68906889 pub const ErrorSet = struct {
......@@ -6893,7 +6892,7 @@ pub const TypeInfo = union(TypeId) {
68936892
68946893 pub const EnumField = struct {
68956894 name: []const u8,
6896 value: usize,
6895 value: comptime_int,
68976896 };
68986897
68996898 pub const Enum = struct {
......@@ -8167,17 +8166,18 @@ coding style.
81678166 </p>
81688167 <ul>
81698168 <li>
8170 If {#syntax#}x{#endsyntax#} is a {#syntax#}struct{#endsyntax#} (or an alias of a {#syntax#}struct{#endsyntax#}),
8171 then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.
8172 </li>
8173 <li>
8174 If {#syntax#}x{#endsyntax#} otherwise identifies a type, {#syntax#}x{#endsyntax#} should have {#syntax#}snake_case{#endsyntax#}.
8169 If {#syntax#}x{#endsyntax#} is a {#syntax#}type{#endsyntax#}
8170 then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}, unless it
8171 is a {#syntax#}struct{#endsyntax#} with 0 fields and is never meant to be instantiated,
8172 in which case it is considered to be a "namespace" and uses {#syntax#}snake_case{#endsyntax#}.
81758173 </li>
81768174 <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#}.
81788177 </li>
81798178 <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#}.
81818181 </li>
81828182 <li>
81838183 Otherwise, {#syntax#}x{#endsyntax#} should be {#syntax#}snake_case{#endsyntax#}.
......@@ -8203,7 +8203,9 @@ const const_name = 42;
82038203const primitive_type_alias = f32;
82048204const string_alias = []u8;
82058205
8206const StructName = struct {};
8206const StructName = struct {
8207 field: i32,
8208};
82078209const StructAlias = StructName;
82088210
82098211fn functionName(param_name: TypeName) void {
......@@ -8231,7 +8233,9 @@ const xml_document =
82318233 \\<document>
82328234 \\</document>
82338235;
8234const XmlParser = struct {};
8236const XmlParser = struct {
8237 field: i32,
8238};
82358239
82368240// The initials BE (Big Endian) are just another word in Zig identifier names.
82378241fn readU32Be() u32 {}
src-self-hosted/compilation.zig+2-2
......@@ -47,7 +47,7 @@ pub const ZigCompiler = struct {
4747
4848 var lazy_init_targets = std.lazyInit(void);
4949
50 fn init(loop: *event.Loop) !ZigCompiler {
50 pub fn init(loop: *event.Loop) !ZigCompiler {
5151 lazy_init_targets.get() orelse {
5252 Target.initializeAll();
5353 lazy_init_targets.resolve();
......@@ -533,7 +533,7 @@ pub const Compilation = struct {
533533 const basename = std.os.path.basename(root_src);
534534
535535 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");
537537 try comp.root_package.add("std", comp.std_package);
538538 } else {
539539 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) ![
1111 const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });
1212 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" });
1515 defer allocator.free(test_index_file);
1616
1717 var file = try os.File.openRead(test_index_file);
src-self-hosted/type.zig-12
......@@ -39,7 +39,6 @@ pub const Type = struct {
3939 Id.ErrorSet => @fieldParentPtr(ErrorSet, "base", base).destroy(comp),
4040 Id.Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),
4141 Id.Union => @fieldParentPtr(Union, "base", base).destroy(comp),
42 Id.Namespace => @fieldParentPtr(Namespace, "base", base).destroy(comp),
4342 Id.BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),
4443 Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
4544 Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
......@@ -73,7 +72,6 @@ pub const Type = struct {
7372 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
7473 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
7574 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
76 Id.Namespace => unreachable,
7775 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
7876 Id.ArgTuple => unreachable,
7977 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
......@@ -89,7 +87,6 @@ pub const Type = struct {
8987 Id.ComptimeInt,
9088 Id.Undefined,
9189 Id.Null,
92 Id.Namespace,
9390 Id.BoundFn,
9491 Id.ArgTuple,
9592 Id.Opaque,
......@@ -123,7 +120,6 @@ pub const Type = struct {
123120 Id.ComptimeInt,
124121 Id.Undefined,
125122 Id.Null,
126 Id.Namespace,
127123 Id.BoundFn,
128124 Id.ArgTuple,
129125 Id.Opaque,
......@@ -1020,14 +1016,6 @@ pub const Type = struct {
10201016 }
10211017 };
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
10311019 pub const BoundFn = struct {
10321020 base: Type,
10331021
src/all_types.hpp+51-49
......@@ -21,7 +21,6 @@
2121#include "libc_installation.hpp"
2222
2323struct AstNode;
24struct ImportTableEntry;
2524struct ZigFn;
2625struct Scope;
2726struct ScopeBlock;
......@@ -317,7 +316,6 @@ struct ConstExprValue {
317316 ConstUnionValue x_union;
318317 ConstArrayValue x_array;
319318 ConstPtrValue x_ptr;
320 ImportTableEntry *x_import;
321319 ConstArgTuple x_arg_tuple;
322320
323321 // populated if special == ConstValSpecialRuntime
......@@ -369,10 +367,8 @@ struct Tld {
369367 VisibMod visib_mod;
370368 AstNode *source_node;
371369
372 ImportTableEntry *import;
370 ZigType *import;
373371 Scope *parent_scope;
374 // set this flag temporarily to detect infinite loops
375 bool dep_loop_flag;
376372 TldResolution resolution;
377373};
378374
......@@ -382,6 +378,7 @@ struct TldVar {
382378 ZigVar *var;
383379 Buf *extern_lib_name;
384380 Buf *section_name;
381 bool analyzing_type; // flag to detect dependency loops
385382};
386383
387384struct TldFn {
......@@ -700,7 +697,7 @@ struct AstNodeUse {
700697 AstNode *expr;
701698
702699 TldResolution resolution;
703 ConstExprValue *value;
700 ConstExprValue *using_namespace_value;
704701};
705702
706703struct AstNodeIfBoolExpr {
......@@ -937,7 +934,7 @@ struct AstNode {
937934 enum NodeType type;
938935 size_t line;
939936 size_t column;
940 ImportTableEntry *owner;
937 ZigType *owner;
941938 union {
942939 AstNodeFnDef fn_def;
943940 AstNodeFnProto fn_proto;
......@@ -1075,12 +1072,32 @@ enum ResolveStatus {
10751072 ResolveStatusSizeKnown,
10761073};
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
10781094struct ZigTypeStruct {
10791095 AstNode *decl_node;
10801096 TypeStructField *fields;
10811097 ScopeDecls *decls_scope;
10821098 uint64_t size_bytes;
10831099 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
1100 RootStruct *root_struct;
10841101
10851102 uint32_t src_field_count;
10861103 uint32_t gen_field_count;
......@@ -1232,7 +1249,6 @@ enum ZigTypeId {
12321249 ZigTypeIdEnum,
12331250 ZigTypeIdUnion,
12341251 ZigTypeIdFn,
1235 ZigTypeIdNamespace,
12361252 ZigTypeIdBoundFn,
12371253 ZigTypeIdArgTuple,
12381254 ZigTypeIdOpaque,
......@@ -1246,6 +1262,10 @@ enum OnePossibleValue {
12461262 OnePossibleValueYes,
12471263};
12481264
1265struct ZigTypeOpaque {
1266 Buf *bare_name;
1267};
1268
12491269struct ZigType {
12501270 ZigTypeId id;
12511271 Buf name;
......@@ -1268,6 +1288,7 @@ struct ZigType {
12681288 ZigTypeBoundFn bound_fn;
12691289 ZigTypePromise promise;
12701290 ZigTypeVector vector;
1291 ZigTypeOpaque opaque;
12711292 } data;
12721293
12731294 // use these fields to make sure we don't duplicate type table entries for the same type
......@@ -1285,29 +1306,6 @@ struct ZigType {
12851306 bool gen_h_loop_flag;
12861307};
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
13111309enum FnAnalState {
13121310 FnAnalStateReady,
13131311 FnAnalStateProbing,
......@@ -1670,7 +1668,7 @@ struct CodeGen {
16701668 LLVMValueRef return_err_fn;
16711669
16721670 // 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;
16741672 HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
16751673 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> primitive_type_table;
16761674 HashMap<TypeId, ZigType *, type_id_hash, type_id_eql> type_table;
......@@ -1684,8 +1682,6 @@ struct CodeGen {
16841682 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
16851683 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;
16891685 ZigList<Tld *> resolve_queue;
16901686 size_t resolve_queue_index;
16911687 ZigList<AstNode *> use_queue;
......@@ -1699,14 +1695,14 @@ struct CodeGen {
16991695 ZigList<ErrorTableEntry *> errors_by_index;
17001696 size_t largest_err_name_len;
17011697
1702 PackageTableEntry *std_package;
1703 PackageTableEntry *panic_package;
1704 PackageTableEntry *test_runner_package;
1705 PackageTableEntry *compile_var_package;
1706 ImportTableEntry *compile_var_import;
1707 ImportTableEntry *root_import;
1708 ImportTableEntry *bootstrap_import;
1709 ImportTableEntry *test_runner_import;
1698 ZigPackage *std_package;
1699 ZigPackage *panic_package;
1700 ZigPackage *test_runner_package;
1701 ZigPackage *compile_var_package;
1702 ZigType *compile_var_import;
1703 ZigType *root_import;
1704 ZigType *bootstrap_import;
1705 ZigType *test_runner_import;
17101706
17111707 struct {
17121708 ZigType *entry_bool;
......@@ -1731,7 +1727,6 @@ struct CodeGen {
17311727 ZigType *entry_unreachable;
17321728 ZigType *entry_type;
17331729 ZigType *entry_invalid;
1734 ZigType *entry_namespace;
17351730 ZigType *entry_block;
17361731 ZigType *entry_num_lit_int;
17371732 ZigType *entry_num_lit_float;
......@@ -1851,7 +1846,7 @@ struct CodeGen {
18511846 Buf *root_out_name;
18521847 Buf *test_filter;
18531848 Buf *test_name_prefix;
1854 PackageTableEntry *root_package;
1849 ZigPackage *root_package;
18551850 Buf *zig_lib_dir;
18561851 Buf *zig_std_dir;
18571852
......@@ -1945,13 +1940,17 @@ struct ScopeDecls {
19451940 Scope base;
19461941
19471942 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
1948 bool safety_off;
1943 ZigList<AstNode *> use_decls;
19491944 AstNode *safety_set_node;
1950 bool fast_math_on;
19511945 AstNode *fast_math_set_node;
1952 ImportTableEntry *import;
1946 ZigType *import;
19531947 // If this is a scope from a container, this is the type entry, otherwise null
19541948 ZigType *container_type;
1949 Buf *bare_name;
1950
1951 bool safety_off;
1952 bool fast_math_on;
1953 bool any_imports_failed;
19551954};
19561955
19571956// This scope comes from a block expression in user code.
......@@ -3463,7 +3462,8 @@ static const size_t err_union_err_index = 0;
34633462static const size_t err_union_payload_index = 1;
34643463
34653464// 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
34683468// these belong to the async function
34693469#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
......@@ -3476,6 +3476,8 @@ static const size_t stack_trace_ptr_count = 30;
34763476#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
34773477#define RESULT_PTR_FIELD_NAME "result_ptr"
34783478
3479#define NAMESPACE_SEP_CHAR '.'
3480#define NAMESPACE_SEP_STR "."
34793481
34803482enum FloatMode {
34813483 FloatModeStrict,
......@@ -3507,7 +3509,7 @@ struct FnWalkTypes {
35073509};
35083510
35093511struct FnWalkVars {
3510 ImportTableEntry *import;
3512 ZigType *import;
35113513 LLVMValueRef llvm_fn;
35123514 ZigFn *fn;
35133515 ZigVar *var;
src/analyze.cpp+295-234
......@@ -28,10 +28,14 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum
2828static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
2929static 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,
32 Buf *msg)
33{
34 if (owner->c_import_node != nullptr) {
31static bool is_top_level_struct(ZigType *import) {
32 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
33}
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) {
3539 // if this happens, then translate_c generated code that
3640 // 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
4650 return note;
4751 }
4852
49 ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,
50 owner->source_code, owner->line_offsets, msg);
53 ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
54 root_struct->source_code, root_struct->line_offsets, msg);
5155
5256 err_msg_add_note(parent_msg, err);
5357 return err;
5458}
5559
56ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg) {
57 if (owner->c_import_node != nullptr) {
60ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
61 assert(is_top_level_struct(owner));
62 RootStruct *root_struct = owner->data.structure.root_struct;
63 if (root_struct->c_import_node != nullptr) {
5864 // if this happens, then translate_c generated code that
5965 // 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,
6167 buf_sprintf("compiler bug: @cImport generated invalid zig code"));
6268
6369 add_error_note_token(g, err, owner, token, msg);
......@@ -65,8 +71,8 @@ ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf
6571 g->errors.append(err);
6672 return err;
6773 }
68 ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,
69 owner->source_code, owner->line_offsets, msg);
74 ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
75 root_struct->source_code, root_struct->line_offsets, msg);
7076
7177 g->errors.append(err);
7278 return err;
......@@ -114,13 +120,16 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope
114120 dest->parent = parent;
115121}
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{
118126 assert(node == nullptr || node->type == NodeTypeContainerDecl || node->type == NodeTypeFnCallExpr);
119127 ScopeDecls *scope = allocate<ScopeDecls>(1);
120128 init_scope(g, &scope->base, ScopeIdDecls, node, parent);
121129 scope->decl_table.init(4);
122130 scope->container_type = container_type;
123131 scope->import = import;
132 scope->bare_name = bare_name;
124133 return scope;
125134}
126135
......@@ -207,11 +216,11 @@ Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {
207216 return &scope->base;
208217}
209218
210ImportTableEntry *get_scope_import(Scope *scope) {
219ZigType *get_scope_import(Scope *scope) {
211220 while (scope) {
212221 if (scope->id == ScopeIdDecls) {
213222 ScopeDecls *decls_scope = (ScopeDecls *)scope;
214 assert(decls_scope->import);
223 assert(is_top_level_struct(decls_scope->import));
215224 return decls_scope->import;
216225 }
217226 scope = scope->parent;
......@@ -219,9 +228,12 @@ ImportTableEntry *get_scope_import(Scope *scope) {
219228 zig_unreachable();
220229}
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{
223234 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);
225237 return entry;
226238}
227239
......@@ -261,7 +273,6 @@ AstNode *type_decl_node(ZigType *type_entry) {
261273 case ZigTypeIdErrorUnion:
262274 case ZigTypeIdErrorSet:
263275 case ZigTypeIdFn:
264 case ZigTypeIdNamespace:
265276 case ZigTypeIdBoundFn:
266277 case ZigTypeIdArgTuple:
267278 case ZigTypeIdPromise:
......@@ -323,7 +334,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
323334 case ZigTypeIdErrorUnion:
324335 case ZigTypeIdErrorSet:
325336 case ZigTypeIdFn:
326 case ZigTypeIdNamespace:
327337 case ZigTypeIdBoundFn:
328338 case ZigTypeIdArgTuple:
329339 case ZigTypeIdPromise:
......@@ -616,7 +626,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
616626 if (child_type->zero_bits) {
617627 entry->type_ref = LLVMInt1Type();
618628 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) {
620630 assert(child_type->di_type);
621631 // this is an optimization but also is necessary for calling C
622632 // functions where all pointers are maybe pointers
......@@ -1005,21 +1015,22 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
10051015 return entry;
10061016}
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) {
10091019 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;
10141024 unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
10151025
10161026 entry->type_ref = LLVMInt8Type();
10171027 entry->di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
1018 ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
1019 import ? ZigLLVMFileToScope(import->di_file) : nullptr,
1020 import ? import->di_file : nullptr,
1028 ZigLLVMTag_DW_structure_type(), full_name,
1029 import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
1030 import ? import->data.structure.root_struct->di_file : nullptr,
10211031 line);
10221032 entry->zero_bits = false;
1033 entry->data.opaque.bare_name = bare_name;
10231034
10241035 return entry;
10251036}
......@@ -1288,11 +1299,32 @@ static ZigTypeId container_to_type(ContainerKind kind) {
12881299 zig_unreachable();
12891300}
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
12911323ZigType *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)
12931325{
12941326 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
12971329 switch (kind) {
12981330 case ContainerKindStruct:
......@@ -1312,13 +1344,14 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
13121344 size_t line = decl_node ? decl_node->line : 0;
13131345 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
13141346
1315 ImportTableEntry *import = get_scope_import(scope);
1316 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
1347 ZigType *import = get_scope_import(scope);
1348 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
13171349 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
1318 dwarf_kind, name,
1319 ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));
1350 dwarf_kind, full_name,
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
13231356 return entry;
13241357}
......@@ -1459,7 +1492,6 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
14591492 case ZigTypeIdNull:
14601493 case ZigTypeIdErrorUnion:
14611494 case ZigTypeIdErrorSet:
1462 case ZigTypeIdNamespace:
14631495 case ZigTypeIdBoundFn:
14641496 case ZigTypeIdArgTuple:
14651497 case ZigTypeIdOpaque:
......@@ -1547,7 +1579,6 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
15471579 case ZigTypeIdNull:
15481580 case ZigTypeIdErrorUnion:
15491581 case ZigTypeIdErrorSet:
1550 case ZigTypeIdNamespace:
15511582 case ZigTypeIdBoundFn:
15521583 case ZigTypeIdArgTuple:
15531584 case ZigTypeIdPromise:
......@@ -1706,7 +1737,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
17061737 return g->builtin_types.entry_invalid;
17071738 case ZigTypeIdComptimeFloat:
17081739 case ZigTypeIdComptimeInt:
1709 case ZigTypeIdNamespace:
17101740 case ZigTypeIdBoundFn:
17111741 case ZigTypeIdMetaType:
17121742 case ZigTypeIdVoid:
......@@ -1801,7 +1831,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
18011831
18021832 case ZigTypeIdComptimeFloat:
18031833 case ZigTypeIdComptimeInt:
1804 case ZigTypeIdNamespace:
18051834 case ZigTypeIdBoundFn:
18061835 case ZigTypeIdMetaType:
18071836 case ZigTypeIdUnreachable:
......@@ -1880,7 +1909,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
18801909 if (!enum_type->data.enumeration.reported_infinite_err) {
18811910 enum_type->data.enumeration.is_invalid = true;
18821911 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);
18841915 }
18851916 return ErrorSemanticAnalyzeFail;
18861917 }
......@@ -1895,7 +1926,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
18951926 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
18961927
18971928 Scope *scope = &enum_type->data.enumeration.decls_scope->base;
1898 ImportTableEntry *import = get_scope_import(scope);
1929 ZigType *import = get_scope_import(scope);
18991930
19001931 // set temporary flag
19011932 enum_type->data.enumeration.embedded_in_current = true;
......@@ -1924,9 +1955,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
19241955 ZigLLVMDIType **di_root_members = nullptr;
19251956 size_t debug_member_count = 0;
19261957 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1927 ZigLLVMFileToScope(import->di_file),
1958 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
19281959 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),
19301961 debug_size_in_bits,
19311962 debug_align_in_bits,
19321963 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) {
19421973 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);
19431974 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
19441975 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1945 ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
1946 import->di_file, (unsigned)(decl_node->line + 1),
1976 ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name),
1977 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
19471978 tag_debug_size_in_bits,
19481979 tag_debug_align_in_bits,
19491980 di_enumerators, field_count,
......@@ -2051,8 +2082,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
20512082 if (struct_type->data.structure.resolve_loop_flag) {
20522083 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
20532084 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2054 add_node_error(g, decl_node,
2085 ErrorMsg *msg = add_node_error(g, decl_node,
20552086 buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
2087 emit_error_notes_for_ref_stack(g, msg);
20562088 }
20572089 return ErrorSemanticAnalyzeFail;
20582090 }
......@@ -2159,15 +2191,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
21592191 if (struct_type->zero_bits) {
21602192 struct_type->type_ref = LLVMVoidType();
21612193
2162 ImportTableEntry *import = get_scope_import(scope);
2194 ZigType *import = get_scope_import(scope);
21632195 uint64_t debug_size_in_bits = 0;
21642196 uint64_t debug_align_in_bits = 0;
21652197 ZigLLVMDIType **di_element_types = nullptr;
21662198 size_t debug_field_count = 0;
21672199 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2168 ZigLLVMFileToScope(import->di_file),
2200 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
21692201 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),
21712203 debug_size_in_bits,
21722204 debug_align_in_bits,
21732205 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) {
21912223
21922224 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
21932225
2194 ImportTableEntry *import = get_scope_import(scope);
2226 ZigType *import = get_scope_import(scope);
21952227 size_t debug_field_index = 0;
21962228 for (size_t i = 0; i < field_count; i += 1) {
21972229 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) {
22342266 }
22352267 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
22362268 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),
22382270 debug_size_in_bits,
22392271 debug_align_in_bits,
22402272 debug_offset_in_bits,
......@@ -2247,9 +2279,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
22472279 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);
22482280 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
22492281 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2250 ZigLLVMFileToScope(import->di_file),
2282 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
22512283 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),
22532285 debug_size_in_bits,
22542286 debug_align_in_bits,
22552287 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) {
22762308 if (!union_type->data.unionation.reported_infinite_err) {
22772309 union_type->data.unionation.reported_infinite_err = true;
22782310 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);
22802314 }
22812315 return ErrorSemanticAnalyzeFail;
22822316 }
......@@ -2298,7 +2332,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
22982332 uint64_t biggest_size_in_bits = 0;
22992333
23002334 Scope *scope = &union_type->data.unionation.decls_scope->base;
2301 ImportTableEntry *import = get_scope_import(scope);
2335 ZigType *import = get_scope_import(scope);
23022336
23032337 // set temporary flag
23042338 union_type->data.unionation.embedded_in_current = true;
......@@ -2325,7 +2359,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
23252359
23262360 union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
23272361 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),
23292363 store_size_in_bits,
23302364 abi_align_in_bits,
23312365 0,
......@@ -2358,9 +2392,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
23582392 ZigLLVMDIType **di_root_members = nullptr;
23592393 size_t debug_member_count = 0;
23602394 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
2361 ZigLLVMFileToScope(import->di_file),
2395 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
23622396 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),
23642398 debug_size_in_bits,
23652399 debug_align_in_bits,
23662400 0, di_root_members, (int)debug_member_count, 0, "");
......@@ -2396,8 +2430,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
23962430
23972431 // create debug type for union
23982432 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
2399 ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),
2400 import->di_file, (unsigned)(decl_node->line + 1),
2433 ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name),
2434 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
24012435 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
24022436 gen_field_count, 0, "");
24032437
......@@ -2452,7 +2486,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24522486 // create debug type for union
24532487 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
24542488 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),
24562490 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
24572491 gen_field_count, 0, "");
24582492
......@@ -2463,7 +2497,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24632497
24642498 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
24652499 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),
24672501 biggest_size_in_bits,
24682502 biggest_align_in_bits,
24692503 union_offset_in_bits,
......@@ -2474,7 +2508,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24742508
24752509 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
24762510 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),
24782512 tag_debug_size_in_bits,
24792513 tag_debug_align_in_bits,
24802514 tag_offset_in_bits,
......@@ -2487,9 +2521,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24872521 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);
24882522 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);
24892523 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2490 ZigLLVMFileToScope(import->di_file),
2524 ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
24912525 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),
24932527 debug_size_in_bits,
24942528 debug_align_in_bits,
24952529 0, nullptr, di_root_members, 2, 0, nullptr, "");
......@@ -2507,8 +2541,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
25072541 return ErrorNone;
25082542
25092543 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,
25112545 buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
2546 emit_error_notes_for_ref_stack(g, msg);
25122547 enum_type->data.enumeration.is_invalid = true;
25132548 return ErrorSemanticAnalyzeFail;
25142549 }
......@@ -2780,8 +2815,9 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
27802815 if (struct_type->data.structure.resolve_loop_flag) {
27812816 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
27822817 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2783 add_node_error(g, decl_node,
2818 ErrorMsg *msg = add_node_error(g, decl_node,
27842819 buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
2820 emit_error_notes_for_ref_stack(g, msg);
27852821 }
27862822 return ErrorSemanticAnalyzeFail;
27872823 }
......@@ -3185,15 +3221,15 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
31853221 }
31863222
31873223 if (create_enum_type) {
3188 ImportTableEntry *import = get_scope_import(scope);
3224 ZigType *import = get_scope_import(scope);
31893225 uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 :
31903226 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
31913227 uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 :
31923228 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
31933229 // TODO get a more accurate debug scope
31943230 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
3195 ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),
3196 import->di_file, (unsigned)(decl_node->line + 1),
3231 ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&tag_type->name),
3232 import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
31973233 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
31983234 tag_type->di_type, "");
31993235 tag_type->di_type = tag_di_type;
......@@ -3210,27 +3246,16 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
32103246 return ErrorNone;
32113247}
32123248
3213static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
3214 if (!scope)
3215 return;
3216
3217 if (scope->id == ScopeIdDecls) {
3218 get_fully_qualified_decl_name_internal(buf, scope->parent, sep);
3249static void get_fully_qualified_decl_name(Buf *buf, Tld *tld) {
3250 buf_resize(buf, 0);
32193251
3220 ScopeDecls *scope_decls = (ScopeDecls *)scope;
3221 if (scope_decls->container_type) {
3222 buf_append_buf(buf, &scope_decls->container_type->name);
3223 buf_append_char(buf, sep);
3224 }
3225 return;
3252 Scope *scope = tld->parent_scope;
3253 while (scope->id != ScopeIdDecls) {
3254 scope = scope->parent;
32263255 }
3227
3228 get_fully_qualified_decl_name_internal(buf, scope->parent, sep);
3229}
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);
3256 ScopeDecls *decls_scope = reinterpret_cast<ScopeDecls *>(scope);
3257 buf_append_buf(buf, &decls_scope->container_type->name);
3258 if (buf_len(buf) != 0) buf_append_char(buf, NAMESPACE_SEP_CHAR);
32343259 buf_append_buf(buf, tld->name);
32353260}
32363261
......@@ -3265,7 +3290,7 @@ static bool scope_is_root_decls(Scope *scope) {
32653290 while (scope) {
32663291 if (scope->id == ScopeIdDecls) {
32673292 ScopeDecls *scope_decls = (ScopeDecls *)scope;
3268 return (scope_decls->container_type == nullptr);
3293 return is_top_level_struct(scope_decls->container_type);
32693294 }
32703295 scope = scope->parent;
32713296 }
......@@ -3281,7 +3306,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {
32813306 AstNode *fake_decl = allocate<AstNode>(1);
32823307 *fake_decl = *panic_fn->proto_node;
32833308 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
32863311 // call this for the side effects of casting to panic_fn_type
32873312 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
33263351}
33273352
33283353static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3329 ImportTableEntry *import = tld_fn->base.import;
3354 ZigType *import = tld_fn->base.import;
33303355 AstNode *source_node = tld_fn->base.source_node;
33313356 if (source_node->type == NodeTypeFnProto) {
33323357 AstNodeFnProto *fn_proto = &source_node->data.fn_proto;
......@@ -3334,16 +3359,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
33343359 AstNode *fn_def_node = fn_proto->fn_def_node;
33353360
33363361 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
33393371 if (fn_proto->is_export) {
33403372 bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC);
33413373 add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc);
33423374 }
33433375
3344 tld_fn->fn_entry = fn_table_entry;
3345
3346 if (fn_table_entry->body_node) {
3376 if (!is_extern) {
33473377 fn_table_entry->fndef_scope = create_fndef_scope(g,
33483378 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) {
33823412 }
33833413
33843414 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))
33863416 {
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")) {
33883418 g->main_fn = fn_table_entry;
3389 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
3390 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
3419 } else if ((import->data.structure.root_struct->package == g->panic_package || g->have_pub_panic) &&
3420 buf_eql_str(tld_fn->base.name, "panic"))
33913421 {
33923422 g->panic_fn = fn_table_entry;
33933423 g->panic_tld_fn = tld_fn;
......@@ -3396,7 +3426,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
33963426 } else if (source_node->type == NodeTypeTestDecl) {
33973427 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
34013431 tld_fn->fn_entry = fn_table_entry;
34023432
......@@ -3473,8 +3503,8 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
34733503 if (!g->is_test_build)
34743504 return;
34753505
3476 ImportTableEntry *import = get_scope_import(&decls_scope->base);
3477 if (import->package != g->root_package)
3506 ZigType *import = get_scope_import(&decls_scope->base);
3507 if (import->data.structure.root_struct->package != g->root_package)
34783508 return;
34793509
34803510 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
35113541}
35123542
35133543void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
3514 Tld *tld = g->compile_var_import->decls_scope->decl_table.get(name);
3515 resolve_top_level_decl(g, tld, false, tld->source_node);
3544 Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name);
3545 resolve_top_level_decl(g, tld, tld->source_node);
35163546 assert(tld->id == TldIdVar);
35173547 TldVar *tld_var = (TldVar *)tld;
35183548 tld_var->var->const_value = value;
......@@ -3561,8 +3591,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
35613591 case NodeTypeUse:
35623592 {
35633593 g->use_queue.append(node);
3564 ImportTableEntry *import = get_scope_import(&decls_scope->base);
3565 import->use_decls.append(node);
3594 decls_scope->use_decls.append(node);
35663595 break;
35673596 }
35683597 case NodeTypeTestDecl:
......@@ -3654,7 +3683,6 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
36543683 return g->builtin_types.entry_invalid;
36553684 case ZigTypeIdComptimeFloat:
36563685 case ZigTypeIdComptimeInt:
3657 case ZigTypeIdNamespace:
36583686 case ZigTypeIdMetaType:
36593687 case ZigTypeIdVoid:
36603688 case ZigTypeIdBool:
......@@ -3763,8 +3791,16 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
37633791
37643792 ZigType *explicit_type = nullptr;
37653793 if (var_decl->type) {
3766 ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type);
3767 explicit_type = validate_var_type(g, var_decl->type, proposed_type);
3794 if (tld_var->analyzing_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 }
37683804 }
37693805
37703806 assert(!is_export || !is_extern);
......@@ -3847,17 +3883,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
38473883 g->global_vars.append(tld_var);
38483884}
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) {
38513887 if (tld->resolution != TldResolutionUnresolved)
38523888 return;
38533889
3854 if (tld->dep_loop_flag) {
3855 add_node_error(g, tld->source_node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name)));
3856 tld->resolution = TldResolutionInvalid;
3857 return;
3858 }
3859
3860 tld->dep_loop_flag = true;
3890 assert(tld->resolution != TldResolutionResolving);
3891 tld->resolution = TldResolutionResolving;
38613892 g->tld_ref_source_node_stack.append(source_node);
38623893
38633894 switch (tld->id) {
......@@ -3888,27 +3919,31 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
38883919 }
38893920
38903921 tld->resolution = TldResolutionOk;
3891 tld->dep_loop_flag = false;
38923922 g->tld_ref_source_node_stack.pop();
38933923}
38943924
3895Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
3896 // we must resolve all the use decls
3897 ImportTableEntry *import = get_scope_import(scope);
3898 for (size_t i = 0; i < import->use_decls.length; i += 1) {
3899 AstNode *use_decl_node = import->use_decls.at(i);
3925Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
3926 // resolve all the use decls
3927 for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
3928 AstNode *use_decl_node = decls_scope->use_decls.at(i);
39003929 if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {
39013930 preview_use_decl(g, use_decl_node);
39023931 resolve_use_decl(g, use_decl_node);
39033932 }
39043933 }
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) {
39063940 while (scope) {
39073941 if (scope->id == ScopeIdDecls) {
39083942 ScopeDecls *decls_scope = (ScopeDecls *)scope;
3909 auto entry = decls_scope->decl_table.maybe_get(name);
3910 if (entry)
3911 return entry->value;
3943
3944 Tld *result = find_container_decl(g, decls_scope, name);
3945 if (result != nullptr)
3946 return result;
39123947 }
39133948 scope = scope->parent;
39143949 }
......@@ -3959,6 +3994,12 @@ ZigFn *scope_fn_entry(Scope *scope) {
39593994 return nullptr;
39603995}
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
39624003TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {
39634004 assert(enum_type->id == ZigTypeIdEnum);
39644005 if (enum_type->data.enumeration.src_field_count == 0)
......@@ -4039,7 +4080,6 @@ static bool is_container(ZigType *type_entry) {
40394080 case ZigTypeIdErrorUnion:
40404081 case ZigTypeIdErrorSet:
40414082 case ZigTypeIdFn:
4042 case ZigTypeIdNamespace:
40434083 case ZigTypeIdBoundFn:
40444084 case ZigTypeIdArgTuple:
40454085 case ZigTypeIdOpaque:
......@@ -4098,7 +4138,6 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {
40984138 case ZigTypeIdErrorUnion:
40994139 case ZigTypeIdErrorSet:
41004140 case ZigTypeIdFn:
4101 case ZigTypeIdNamespace:
41024141 case ZigTypeIdBoundFn:
41034142 case ZigTypeIdInvalid:
41044143 case ZigTypeIdArgTuple:
......@@ -4131,10 +4170,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
41314170}
41324171
41334172bool 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);
41354174}
41364175
4137bool type_is_codegen_pointer(ZigType *type) {
4176bool type_is_non_optional_pointer(ZigType *type) {
41384177 return get_codegen_ptr_type(type) == type;
41394178}
41404179
......@@ -4342,9 +4381,9 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
43424381 preview_use_decl(g, src_use_node);
43434382 }
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;
43464385 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;
43484387 return;
43494388 }
43504389
......@@ -4352,14 +4391,14 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
43524391
43534392 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;
43564395 assert(target_import);
43574396
4358 if (target_import->any_imports_failed) {
4359 dst_use_node->owner->any_imports_failed = true;
4397 if (get_container_scope(target_import)->any_imports_failed) {
4398 get_container_scope(dst_use_node->owner)->any_imports_failed = true;
43604399 }
43614400
4362 auto it = target_import->decls_scope->decl_table.entry_iterator();
4401 auto it = get_container_scope(target_import)->decl_table.entry_iterator();
43634402 for (;;) {
43644403 auto *entry = it.next();
43654404 if (!entry)
......@@ -4374,7 +4413,7 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
43744413
43754414 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);
43784417 if (existing_entry) {
43794418 Tld *existing_decl = existing_entry->value;
43804419 if (existing_decl != target_tld) {
......@@ -4387,8 +4426,8 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
43874426 }
43884427 }
43894428
4390 for (size_t i = 0; i < target_import->use_decls.length; i += 1) {
4391 AstNode *use_decl_node = target_import->use_decls.at(i);
4429 for (size_t i = 0; i < get_container_scope(target_import)->use_decls.length; i += 1) {
4430 AstNode *use_decl_node = get_container_scope(target_import)->use_decls.at(i);
43924431 if (use_decl_node->data.use.visib_mod != VisibModPrivate)
43934432 add_symbols_from_import(g, use_decl_node, dst_use_node);
43944433 }
......@@ -4415,16 +4454,18 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
44154454 }
44164455
44174456 node->data.use.resolution = TldResolutionResolving;
4418 ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base,
4419 node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
4457 ConstExprValue *result = analyze_const_value(g, &get_container_scope(node->owner)->base,
4458 node->data.use.expr, g->builtin_types.entry_type, nullptr);
44204459
44214460 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;
44254464}
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{
44284469 if (g->verbose_tokenize) {
44294470 fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(resolved_path));
44304471 fprintf(stderr, "----------------\n");
......@@ -4452,87 +4493,102 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r
44524493 fprintf(stderr, "------\n");
44534494 }
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
44674496 Buf *src_dirname = buf_alloc();
44684497 Buf *src_basename = buf_alloc();
44694498 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));
4472 g->import_table.put(resolved_path, import_entry);
4473 g->import_queue.append(import_entry);
4474
4475 import_entry->decls_scope = create_decls_scope(g, import_entry->root, nullptr, nullptr, import_entry);
4500 Buf noextname = BUF_INIT;
4501 os_path_extname(resolved_path, &noextname, nullptr);
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);
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);
4506 assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir));
44814507
4482 if (top_level_decl->type == NodeTypeFnDef) {
4483 AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
4484 assert(proto_node->type == NodeTypeFnProto);
4485 Buf *proto_name = proto_node->data.fn_proto.name;
4508 Buf namespace_name = BUF_INIT;
4509 buf_init_from_buf(&namespace_name, &package->pkg_path);
4510 if (source_kind == SourceKindNonRoot) {
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);
4488 bool ok_cc = (proto_node->data.fn_proto.cc == CallingConventionUnspecified ||
4489 proto_node->data.fn_proto.cc == CallingConventionCold);
4519 RootStruct *root_struct = allocate<RootStruct>(1);
4520 root_struct->package = package;
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) {
4492 if (buf_eql_str(proto_name, "main")) {
4493 g->have_pub_main = true;
4494 g->subsystem = TargetSubsystemConsole;
4495 } else if (buf_eql_str(proto_name, "panic")) {
4496 g->have_pub_panic = true;
4532 AstNode *root_node = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
4533 assert(root_node != nullptr);
4534 assert(root_node->type == NodeTypeContainerDecl);
4535 import_entry->data.structure.decl_node = root_node;
4536 import_entry->data.structure.decls_scope->base.source_node = root_node;
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 }
44974559 }
44984560 }
44994561 }
45004562 }
45014563
4502 return import_entry;
4503}
4504
4505void scan_import(CodeGen *g, ImportTableEntry *import) {
4506 if (!import->scanned) {
4507 import->scanned = true;
4508 scan_decls(g, import->decls_scope, import->root);
4564 for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
4565 AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
4566 scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl);
45094567 }
4510}
45114568
4512void semantic_analyze(CodeGen *g) {
4513 for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) {
4514 ImportTableEntry *import = g->import_queue.at(g->import_queue_index);
4515 scan_import(g, import);
4516 }
4569 TldContainer *tld_container = allocate<TldContainer>(1);
4570 init_tld(&tld_container->base, TldIdContainer, &namespace_name, VisibModPub, root_node, nullptr);
4571 tld_container->type_entry = import_entry;
4572 tld_container->decls_scope = import_entry->data.structure.decls_scope;
4573 g->resolve_queue.append(&tld_container->base);
45174574
4518 for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
4519 AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
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 }
4575 return import_entry;
4576}
45274577
4578void semantic_analyze(CodeGen *g) {
45284579 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)
45304582 {
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 }
45314588 for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
45324589 Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
4533 bool pointer_only = false;
45344590 AstNode *source_node = nullptr;
4535 resolve_top_level_decl(g, tld, pointer_only, source_node);
4591 resolve_top_level_decl(g, tld, source_node);
45364592 }
45374593
45384594 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) {
46134669 case ZigTypeIdComptimeInt:
46144670 case ZigTypeIdUndefined:
46154671 case ZigTypeIdNull:
4616 case ZigTypeIdNamespace:
46174672 case ZigTypeIdBoundFn:
46184673 case ZigTypeIdArgTuple:
46194674 case ZigTypeIdOpaque:
......@@ -4637,7 +4692,7 @@ bool handle_is_ptr(ZigType *type_entry) {
46374692 return type_has_bits(type_entry->data.error_union.payload_type);
46384693 case ZigTypeIdOptional:
46394694 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) &&
46414696 type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
46424697 case ZigTypeIdUnion:
46434698 assert(type_entry->data.unionation.zero_bits_known);
......@@ -4880,8 +4935,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
48804935 return 3415065496;
48814936 case ZigTypeIdErrorSet:
48824937 return hash_const_val_error_set(const_val);
4883 case ZigTypeIdNamespace:
4884 return hash_ptr(const_val->data.x_import);
48854938 case ZigTypeIdVector:
48864939 // TODO better hashing algorithm
48874940 return 3647867726;
......@@ -4943,7 +4996,6 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
49434996 case ZigTypeIdComptimeInt:
49444997 case ZigTypeIdUndefined:
49454998 case ZigTypeIdNull:
4946 case ZigTypeIdNamespace:
49474999 case ZigTypeIdBoundFn:
49485000 case ZigTypeIdFn:
49495001 case ZigTypeIdOpaque:
......@@ -5013,7 +5065,6 @@ static bool return_type_is_cacheable(ZigType *return_type) {
50135065 case ZigTypeIdComptimeInt:
50145066 case ZigTypeIdUndefined:
50155067 case ZigTypeIdNull:
5016 case ZigTypeIdNamespace:
50175068 case ZigTypeIdBoundFn:
50185069 case ZigTypeIdFn:
50195070 case ZigTypeIdOpaque:
......@@ -5143,7 +5194,6 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
51435194 case ZigTypeIdComptimeFloat:
51445195 case ZigTypeIdComptimeInt:
51455196 case ZigTypeIdMetaType:
5146 case ZigTypeIdNamespace:
51475197 case ZigTypeIdBoundFn:
51485198 case ZigTypeIdArgTuple:
51495199 case ZigTypeIdOptional:
......@@ -5209,7 +5259,6 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
52095259 case ZigTypeIdUndefined:
52105260 case ZigTypeIdNull:
52115261 case ZigTypeIdMetaType:
5212 case ZigTypeIdNamespace:
52135262 case ZigTypeIdBoundFn:
52145263 case ZigTypeIdArgTuple:
52155264 return ReqCompTimeYes;
......@@ -5797,8 +5846,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
57975846 }
57985847 case ZigTypeIdErrorUnion:
57995848 zig_panic("TODO");
5800 case ZigTypeIdNamespace:
5801 return a->data.x_import == b->data.x_import;
58025849 case ZigTypeIdArgTuple:
58035850 return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
58045851 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) {
60726119 }
60736120 return;
60746121 }
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 }
60856122 case ZigTypeIdBoundFn:
60866123 {
60876124 ZigFn *fn_entry = const_val->data.x_bound_fn.fn;
......@@ -6203,7 +6240,6 @@ uint32_t type_id_hash(TypeId x) {
62036240 case ZigTypeIdEnum:
62046241 case ZigTypeIdUnion:
62056242 case ZigTypeIdFn:
6206 case ZigTypeIdNamespace:
62076243 case ZigTypeIdBoundFn:
62086244 case ZigTypeIdArgTuple:
62096245 case ZigTypeIdPromise:
......@@ -6252,7 +6288,6 @@ bool type_id_eql(TypeId a, TypeId b) {
62526288 case ZigTypeIdEnum:
62536289 case ZigTypeIdUnion:
62546290 case ZigTypeIdFn:
6255 case ZigTypeIdNamespace:
62566291 case ZigTypeIdBoundFn:
62576292 case ZigTypeIdArgTuple:
62586293 case ZigTypeIdOpaque:
......@@ -6419,7 +6454,6 @@ static const ZigTypeId all_type_ids[] = {
64196454 ZigTypeIdEnum,
64206455 ZigTypeIdUnion,
64216456 ZigTypeIdFn,
6422 ZigTypeIdNamespace,
64236457 ZigTypeIdBoundFn,
64246458 ZigTypeIdArgTuple,
64256459 ZigTypeIdOpaque,
......@@ -6480,18 +6514,16 @@ size_t type_id_index(ZigType *entry) {
64806514 return 17;
64816515 case ZigTypeIdFn:
64826516 return 18;
6483 case ZigTypeIdNamespace:
6484 return 19;
64856517 case ZigTypeIdBoundFn:
6486 return 20;
6518 return 19;
64876519 case ZigTypeIdArgTuple:
6488 return 21;
6520 return 20;
64896521 case ZigTypeIdOpaque:
6490 return 22;
6522 return 21;
64916523 case ZigTypeIdPromise:
6492 return 23;
6524 return 22;
64936525 case ZigTypeIdVector:
6494 return 24;
6526 return 23;
64956527 }
64966528 zig_unreachable();
64976529}
......@@ -6538,8 +6570,6 @@ const char *type_id_name(ZigTypeId id) {
65386570 return "Union";
65396571 case ZigTypeIdFn:
65406572 return "Fn";
6541 case ZigTypeIdNamespace:
6542 return "Namespace";
65436573 case ZigTypeIdBoundFn:
65446574 return "BoundFn";
65456575 case ZigTypeIdArgTuple:
......@@ -6619,8 +6649,8 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) {
66196649}
66206650
66216651ConstExprValue *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));
6623 resolve_top_level_decl(codegen, tld, false, nullptr);
6652 Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name));
6653 resolve_top_level_decl(codegen, tld, nullptr);
66246654 assert(tld->id == TldIdVar);
66256655 TldVar *tld_var = (TldVar *)tld;
66266656 ConstExprValue *var_value = tld_var->var->const_value;
......@@ -6812,3 +6842,34 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) {
68126842 }
68136843 return false;
68146844}
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 @@
1212
1313void semantic_analyze(CodeGen *g);
1414ErrorMsg *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);
1616ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
1718ZigType *new_type_table_entry(ZigTypeId id);
1819ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
1920ZigType *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);
2930ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);
3031ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
3132ZigType *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);
3336ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
3437ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
3538ZigType *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);
3740ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
3841 ZigType *field_types[], size_t field_count);
3942ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
......@@ -46,13 +49,19 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
4649bool ptr_allows_addr_zero(ZigType *ptr_type);
4750bool type_is_nonnull_ptr(ZigType *type);
4851
49ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
50
52enum SourceKind {
53 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
5260ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);
5361Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
54void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
55bool type_is_codegen_pointer(ZigType *type);
62Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name);
63void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node);
64bool type_is_non_optional_pointer(ZigType *type);
5665
5766ZigType *get_src_ptr_type(ZigType *type);
5867ZigType *get_codegen_ptr_type(ZigType *type);
......@@ -77,11 +86,11 @@ bool is_array_ref(ZigType *type_entry);
7786bool is_container_ref(ZigType *type_entry);
7887bool is_valid_vector_elem_type(ZigType *elem_type);
7988void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
80void scan_import(CodeGen *g, ImportTableEntry *import);
8189void preview_use_decl(CodeGen *g, AstNode *node);
8290void resolve_use_decl(CodeGen *g, AstNode *node);
8391ZigFn *scope_fn_entry(Scope *scope);
84ImportTableEntry *get_scope_import(Scope *scope);
92ZigPackage *scope_package(Scope *scope);
93ZigType *get_scope_import(Scope *scope);
8594void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
8695ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
8796 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);
109118ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
110119ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
111120ScopeFnDef *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);
113121Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
114122Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
115123Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
......@@ -186,7 +194,7 @@ LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
186194
187195uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry);
188196ZigType *get_align_amt_type(CodeGen *g);
189PackageTableEntry *new_anonymous_package(void);
197ZigPackage *new_anonymous_package(void);
190198
191199Buf *const_value_to_buffer(ConstExprValue *const_val);
192200void 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
232240 ConstExprValue *const_val, ZigType *wanted_type);
233241
234242void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
243Buf *type_bare_name(ZigType *t);
244Buf *type_h_name(ZigType *t);
235245#endif
src/buffer.hpp+3-3
......@@ -59,7 +59,7 @@ static inline void buf_deinit(Buf *buf) {
5959static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) {
6060 assert(len != SIZE_MAX);
6161 buf->list.resize(len + 1);
62 safe_memcpy(buf_ptr(buf), ptr, len);
62 memcpy(buf_ptr(buf), ptr, len);
6363 buf->list.at(buf_len(buf)) = 0;
6464}
6565
......@@ -98,7 +98,7 @@ static inline Buf *buf_slice(Buf *in_buf, size_t start, size_t end) {
9898 assert(end <= buf_len(in_buf));
9999 Buf *out_buf = allocate<Buf>(1);
100100 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);
102102 out_buf->list.at(buf_len(out_buf)) = 0;
103103 return out_buf;
104104}
......@@ -108,7 +108,7 @@ static inline void buf_append_mem(Buf *buf, const char *mem, size_t mem_len) {
108108 assert(mem_len != SIZE_MAX);
109109 size_t old_len = buf_len(buf);
110110 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);
112112 buf->list.at(buf_len(buf)) = 0;
113113}
114114
src/codegen.cpp+118-94
......@@ -48,16 +48,17 @@ static void init_darwin_native(CodeGen *g) {
4848 }
4949}
5050
51static PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) {
52 PackageTableEntry *entry = allocate<PackageTableEntry>(1);
51static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {
52 ZigPackage *entry = allocate<ZigPackage>(1);
5353 entry->package_table.init(4);
5454 buf_init_from_str(&entry->root_src_dir, root_src_dir);
5555 buf_init_from_str(&entry->root_src_path, root_src_path);
56 buf_init_from_str(&entry->pkg_path, pkg_path);
5657 return entry;
5758}
5859
59PackageTableEntry *new_anonymous_package(void) {
60 return new_package("", "");
60ZigPackage *new_anonymous_package() {
61 return new_package("", "", "");
6162}
6263
6364static const char *symbols_that_llvm_depends_on[] = {
......@@ -87,8 +88,8 @@ static const char *symbols_that_llvm_depends_on[] = {
8788 // TODO probably all of compiler-rt needs to go here
8889};
8990
90CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
91 Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc)
91CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
92 OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc)
9293{
9394 CodeGen *g = allocate<CodeGen>(1);
9495
......@@ -132,20 +133,39 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
132133 }
133134
134135 if (root_src_path) {
135 Buf *src_basename = buf_alloc();
136 Buf *src_dir = buf_alloc();
137 os_path_split(root_src_path, src_dir, src_basename);
136 Buf *root_pkg_path;
137 Buf *rel_root_src_path;
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) {
140 fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
141 exit(1);
153 if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
154 fprintf(stderr, "Root source path '%s' outside main package path '%s'",
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);
142162 }
143163
144 g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename));
145 g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig");
164 g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
165 g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
146166 g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
147167 } else {
148 g->root_package = new_package(".", "");
168 g->root_package = new_package(".", "", "");
149169 }
150170
151171 g->zig_std_special_dir = buf_alloc();
......@@ -621,7 +641,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
621641 if (scope->di_scope)
622642 return scope->di_scope;
623643
624 ImportTableEntry *import = get_scope_import(scope);
644 ZigType *import = get_scope_import(scope);
625645 switch (scope->id) {
626646 case ScopeIdCImport:
627647 zig_unreachable();
......@@ -644,7 +664,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
644664 assert(fn_di_scope != nullptr);
645665 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
646666 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,
648668 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,
649669 is_definition, scope_line, flags, is_optimized, nullptr);
650670
......@@ -658,7 +678,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
658678 assert(decls_scope->container_type);
659679 scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
660680 } else {
661 scope->di_scope = ZigLLVMFileToScope(import->di_file);
681 scope->di_scope = ZigLLVMFileToScope(import->data.structure.root_struct->di_file);
662682 }
663683 return scope->di_scope;
664684 case ScopeIdBlock:
......@@ -668,7 +688,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
668688 assert(scope->parent);
669689 ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
670690 get_di_scope(g, scope->parent),
671 import->di_file,
691 import->data.structure.root_struct->di_file,
672692 (unsigned)scope->source_node->line + 1,
673693 (unsigned)scope->source_node->column + 1);
674694 scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
......@@ -1236,7 +1256,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
12361256
12371257 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
12411261 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
12421262 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
......@@ -1254,9 +1274,10 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
12541274
12551275 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
12561276 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, "");
12581279 LLVMValueRef address_indices[] = {
1259 modded_val,
1280 masked_val,
12601281 };
12611282
12621283 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
......@@ -2196,7 +2217,7 @@ var_ok:
21962217 if (dest_ty != nullptr && var->decl_node) {
21972218 // arg index + 1 because the 0 index is return value
21982219 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,
22002221 (unsigned)(var->decl_node->line + 1),
22012222 dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
22022223 }
......@@ -3938,7 +3959,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
39383959 if (child_type->zero_bits) {
39393960 return maybe_handle;
39403961 } 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;
39423963 if (is_scalar) {
39433964 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
39443965 } else {
......@@ -3978,7 +3999,7 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec
39783999 if (child_type->zero_bits) {
39794000 return nullptr;
39804001 } 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;
39824003 if (is_scalar) {
39834004 return maybe_ptr;
39844005 } else {
......@@ -4549,7 +4570,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
45494570
45504571 return tmp_struct_ptr;
45514572 } else if (array_type->id == ZigTypeIdPointer) {
4552 assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
4573 assert(array_type->data.pointer.ptr_len != PtrLenSingle);
45534574 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
45544575 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
45554576
......@@ -4640,7 +4661,8 @@ static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executabl
46404661 IrInstructionReturnAddress *instruction)
46414662{
46424663 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, "");
46444666}
46454667
46464668static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {
......@@ -4661,7 +4683,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
46614683 IrInstructionFrameAddress *instruction)
46624684{
46634685 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, "");
46654688}
46664689
46674690static LLVMValueRef get_handle_fn_val(CodeGen *g) {
......@@ -4839,7 +4862,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
48394862 }
48404863
48414864 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) {
48434866 return payload_val;
48444867 }
48454868
......@@ -5800,7 +5823,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
58005823 case ZigTypeIdNull:
58015824 case ZigTypeIdErrorUnion:
58025825 case ZigTypeIdErrorSet:
5803 case ZigTypeIdNamespace:
58045826 case ZigTypeIdBoundFn:
58055827 case ZigTypeIdArgTuple:
58065828 case ZigTypeIdVoid:
......@@ -6077,9 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
60776099 case ZigTypeIdOptional:
60786100 {
60796101 ZigType *child_type = type_entry->data.maybe.child_type;
6080 if (child_type->zero_bits) {
6102 if (!type_has_bits(child_type)) {
60816103 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) {
60836105 return gen_const_val_ptr(g, const_val, name);
60846106 } else if (child_type->id == ZigTypeIdErrorSet) {
60856107 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
64006422 case ZigTypeIdComptimeInt:
64016423 case ZigTypeIdUndefined:
64026424 case ZigTypeIdNull:
6403 case ZigTypeIdNamespace:
64046425 case ZigTypeIdBoundFn:
64056426 case ZigTypeIdArgTuple:
64066427 case ZigTypeIdOpaque:
......@@ -6506,12 +6527,12 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
65066527 assert(var->gen_is_const);
65076528 assert(type_entry);
65086529
6509 ImportTableEntry *import = get_scope_import(var->parent_scope);
6530 ZigType *import = get_scope_import(var->parent_scope);
65106531 assert(import);
65116532
65126533 bool is_local_to_unit = true;
65136534 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,
65156536 (unsigned)(var->decl_node->line + 1),
65166537 type_entry->di_type, is_local_to_unit);
65176538
......@@ -6767,7 +6788,7 @@ static void do_code_gen(CodeGen *g) {
67676788 *slot = build_alloca(g, slot_type, "", alignment_bytes);
67686789 }
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
67726793 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) {
67996820 var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
68006821
68016822 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),
68036824 var->var_type->di_type, !g->strip_debug_symbols, 0);
68046825
68056826 } else if (is_c_abi) {
......@@ -6823,7 +6844,7 @@ static void do_code_gen(CodeGen *g) {
68236844 }
68246845 if (var->decl_node) {
68256846 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,
68276848 (unsigned)(var->decl_node->line + 1),
68286849 gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
68296850 }
......@@ -6971,12 +6992,6 @@ static void define_builtin_types(CodeGen *g) {
69716992 entry->zero_bits = true;
69726993 g->builtin_types.entry_invalid = entry;
69736994 }
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 }
69806995 {
69816996 ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);
69826997 buf_init_from_str(&entry->name, "comptime_float");
......@@ -7130,7 +7145,8 @@ static void define_builtin_types(CodeGen *g) {
71307145 g->builtin_types.entry_i64 = get_int_type(g, true, 64);
71317146
71327147 {
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"));
71347150 g->primitive_type_table.put(&g->builtin_types.entry_c_void->name, g->builtin_types.entry_c_void);
71357151 }
71367152
......@@ -7470,7 +7486,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
74707486 " Enum: Enum,\n"
74717487 " Union: Union,\n"
74727488 " Fn: Fn,\n"
7473 " Namespace: void,\n"
74747489 " BoundFn: Fn,\n"
74757490 " ArgTuple: void,\n"
74767491 " Opaque: void,\n"
......@@ -7479,18 +7494,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
74797494 "\n\n"
74807495 " pub const Int = struct {\n"
74817496 " is_signed: bool,\n"
7482 " bits: u8,\n"
7497 " bits: comptime_int,\n"
74837498 " };\n"
74847499 "\n"
74857500 " pub const Float = struct {\n"
7486 " bits: u8,\n"
7501 " bits: comptime_int,\n"
74877502 " };\n"
74887503 "\n"
74897504 " pub const Pointer = struct {\n"
74907505 " size: Size,\n"
74917506 " is_const: bool,\n"
74927507 " is_volatile: bool,\n"
7493 " alignment: u32,\n"
7508 " alignment: comptime_int,\n"
74947509 " child: type,\n"
74957510 "\n"
74967511 " pub const Size = enum {\n"
......@@ -7502,7 +7517,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75027517 " };\n"
75037518 "\n"
75047519 " pub const Array = struct {\n"
7505 " len: usize,\n"
7520 " len: comptime_int,\n"
75067521 " child: type,\n"
75077522 " };\n"
75087523 "\n"
......@@ -7514,7 +7529,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75147529 "\n"
75157530 " pub const StructField = struct {\n"
75167531 " name: []const u8,\n"
7517 " offset: ?usize,\n"
7532 " offset: ?comptime_int,\n"
75187533 " field_type: type,\n"
75197534 " };\n"
75207535 "\n"
......@@ -7535,7 +7550,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75357550 "\n"
75367551 " pub const Error = struct {\n"
75377552 " name: []const u8,\n"
7538 " value: usize,\n"
7553 " value: comptime_int,\n"
75397554 " };\n"
75407555 "\n"
75417556 " pub const ErrorSet = struct {\n"
......@@ -7544,7 +7559,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75447559 "\n"
75457560 " pub const EnumField = struct {\n"
75467561 " name: []const u8,\n"
7547 " value: usize,\n"
7562 " value: comptime_int,\n"
75487563 " };\n"
75497564 "\n"
75507565 " pub const Enum = struct {\n"
......@@ -7596,7 +7611,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75967611 " };\n"
75977612 "\n"
75987613 " pub const Vector = struct {\n"
7599 " len: u32,\n"
7614 " len: comptime_int,\n"
76007615 " child: type,\n"
76017616 " };\n"
76027617 "\n"
......@@ -7751,12 +7766,12 @@ static Error define_builtin_compile_vars(CodeGen *g) {
77517766
77527767 assert(g->root_package);
77537768 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");
77557770 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
77567771 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
77577772 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);
7759 scan_import(g, g->compile_var_import);
7773 g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents,
7774 SourceKindPkgMain);
77607775
77617776 return ErrorNone;
77627777}
......@@ -7948,17 +7963,20 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
79487963 Buf *src_dirname = buf_alloc();
79497964 os_path_split(full_path, src_dirname, src_basename);
79507965
7951 ImportTableEntry *import = allocate<ImportTableEntry>(1);
7952 import->source_code = nullptr;
7953 import->path = full_path;
7954 g->root_import = import;
7955 import->decls_scope = create_decls_scope(g, nullptr, nullptr, nullptr, import);
7966 Buf noextname = BUF_INIT;
7967 os_path_extname(src_basename, &noextname, nullptr);
79567968
79577969 detect_libc(g);
79587970
79597971 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
79637981 ZigList<ErrorMsg *> errors = {0};
79647982 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) {
79777995 }
79787996}
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) {
79817999 Buf *code_basename = buf_create_from_str(basename);
79828000 Buf path_to_code_src = BUF_INIT;
79838001 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
79918009 zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
79928010 }
79938011
7994 return add_source_file(g, package, resolved_path, import_code);
8012 return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain);
79958013}
79968014
7997static PackageTableEntry *create_bootstrap_pkg(CodeGen *g, PackageTableEntry *pkg_with_main) {
7998 PackageTableEntry *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig");
8015static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) {
8016 ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special");
79998017 package->package_table.put(buf_create_from_str("@root"), pkg_with_main);
80008018 return package;
80018019}
80028020
8003static PackageTableEntry *create_test_runner_pkg(CodeGen *g) {
8004 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig");
8021static ZigPackage *create_test_runner_pkg(CodeGen *g) {
8022 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
80058023}
80068024
8007static PackageTableEntry *create_panic_pkg(CodeGen *g) {
8008 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig");
8025static ZigPackage *create_panic_pkg(CodeGen *g) {
8026 return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
80098027}
80108028
80118029static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
......@@ -8089,24 +8107,24 @@ static void gen_root_source(CodeGen *g) {
80898107 exit(1);
80908108 }
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
80948113 assert(g->root_out_name);
80958114 assert(g->out_type != OutTypeUnknown);
80968115
80978116 {
80988117 // Zig has lazy top level definitions. Here we semantically analyze the panic function.
8099 ImportTableEntry *import_with_panic;
8118 ZigType *import_with_panic;
81008119 if (g->have_pub_panic) {
81018120 import_with_panic = g->root_import;
81028121 } else {
81038122 g->panic_package = create_panic_pkg(g);
81048123 import_with_panic = add_special_code(g, g->panic_package, "panic.zig");
81058124 }
8106 scan_import(g, import_with_panic);
8107 Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic"));
8125 Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic"));
81088126 assert(panic_tld != nullptr);
8109 resolve_top_level_decl(g, panic_tld, false, nullptr);
8127 resolve_top_level_decl(g, panic_tld, nullptr);
81108128 }
81118129
81128130
......@@ -8358,7 +8376,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
83588376 case ZigTypeIdComptimeInt:
83598377 case ZigTypeIdUndefined:
83608378 case ZigTypeIdNull:
8361 case ZigTypeIdNamespace:
83628379 case ZigTypeIdBoundFn:
83638380 case ZigTypeIdArgTuple:
83648381 case ZigTypeIdErrorUnion:
......@@ -8496,7 +8513,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
84968513 if (child_type->zero_bits) {
84978514 buf_init_from_str(out_buf, "bool");
84988515 return;
8499 } else if (type_is_codegen_pointer(child_type)) {
8516 } else if (type_is_non_optional_pointer(child_type)) {
85008517 return get_c_type(g, gen_h, child_type, out_buf);
85018518 } else {
85028519 zig_unreachable();
......@@ -8506,19 +8523,19 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
85068523 case ZigTypeIdOpaque:
85078524 {
85088525 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));
85108527 return;
85118528 }
85128529 case ZigTypeIdUnion:
85138530 {
85148531 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));
85168533 return;
85178534 }
85188535 case ZigTypeIdEnum:
85198536 {
85208537 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));
85228539 return;
85238540 }
85248541 case ZigTypeIdArray:
......@@ -8541,7 +8558,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
85418558 case ZigTypeIdInvalid:
85428559 case ZigTypeIdMetaType:
85438560 case ZigTypeIdBoundFn:
8544 case ZigTypeIdNamespace:
85458561 case ZigTypeIdComptimeFloat:
85468562 case ZigTypeIdComptimeInt:
85478563 case ZigTypeIdUndefined:
......@@ -8614,10 +8630,17 @@ static void gen_h_file(CodeGen *g) {
86148630 Buf return_type_c = BUF_INIT;
86158631 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 }
86178640 buf_appendf(&h_buf, "%s %s %s(",
86188641 buf_ptr(export_macro),
86198642 buf_ptr(&return_type_c),
8620 buf_ptr(&fn_table_entry->symbol_name));
8643 buf_ptr(symbol_name));
86218644
86228645 Buf param_type_c = BUF_INIT;
86238646 if (fn_type_id->param_count > 0) {
......@@ -8693,7 +8716,6 @@ static void gen_h_file(CodeGen *g) {
86938716 case ZigTypeIdNull:
86948717 case ZigTypeIdErrorUnion:
86958718 case ZigTypeIdErrorSet:
8696 case ZigTypeIdNamespace:
86978719 case ZigTypeIdBoundFn:
86988720 case ZigTypeIdArgTuple:
86998721 case ZigTypeIdOptional:
......@@ -8703,7 +8725,7 @@ static void gen_h_file(CodeGen *g) {
87038725 zig_unreachable();
87048726 case ZigTypeIdEnum:
87058727 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)));
87078729 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
87088730 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
87098731 Buf *value_buf = buf_alloc();
......@@ -8716,12 +8738,12 @@ static void gen_h_file(CodeGen *g) {
87168738 }
87178739 fprintf(out_h, "};\n\n");
87188740 } 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)));
87208742 }
87218743 break;
87228744 case ZigTypeIdStruct:
87238745 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)));
87258747 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
87268748 TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
87278749
......@@ -8739,12 +8761,12 @@ static void gen_h_file(CodeGen *g) {
87398761 }
87408762 fprintf(out_h, "};\n\n");
87418763 } 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)));
87438765 }
87448766 break;
87458767 case ZigTypeIdUnion:
87468768 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)));
87488770 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
87498771 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
87508772
......@@ -8754,11 +8776,11 @@ static void gen_h_file(CodeGen *g) {
87548776 }
87558777 fprintf(out_h, "};\n\n");
87568778 } 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)));
87588780 }
87598781 break;
87608782 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)));
87628784 break;
87638785 }
87648786 }
......@@ -8792,7 +8814,7 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
87928814 g->timing_events.append({os_get_time(), name});
87938815}
87948816
8795static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {
8817static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) {
87968818 if (buf_len(&pkg->root_src_path) == 0)
87978819 return;
87988820
......@@ -9046,9 +9068,11 @@ void codegen_build_and_link(CodeGen *g) {
90469068 codegen_add_time_event(g, "Done");
90479069}
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{
90509074 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);
90529076 if (g->std_package != nullptr) {
90539077 assert(g->compile_var_package != nullptr);
90549078 pkg->package_table.put(buf_create_from_str("std"), g->std_package);
src/codegen.hpp+4-3
......@@ -15,8 +15,8 @@
1515
1616#include <stdio.h>
1717
18CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
19 Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
18CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
19 OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
2020
2121void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
2222void 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);
4848void codegen_link(CodeGen *g);
4949void 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);
5253void codegen_add_assembly(CodeGen *g, Buf *path);
5354void 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) {
7878 Buf std_buf = BUF_INIT;
7979 buf_init_from_str(&std_buf, "std");
8080
81 Buf index_zig_buf = BUF_INIT;
82 buf_init_from_str(&index_zig_buf, "index.zig");
81 Buf std_zig_buf = BUF_INIT;
82 buf_init_from_str(&std_zig_buf, "std.zig");
8383
8484 Buf test_lib_dir = BUF_INIT;
8585 Buf test_zig_dir = BUF_INIT;
......@@ -89,7 +89,7 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
8989 os_path_join(test_path, &lib_buf, &test_lib_dir);
9090 os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir);
9191 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
9494 int err;
9595 bool exists;
src/ir.cpp+149-143
......@@ -258,7 +258,6 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
258258 case ZigTypeIdPointer:
259259 case ZigTypeIdUndefined:
260260 case ZigTypeIdNull:
261 case ZigTypeIdNamespace:
262261 case ZigTypeIdBoundFn:
263262 case ZigTypeIdErrorSet:
264263 case ZigTypeIdOpaque:
......@@ -1123,11 +1122,11 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *
11231122 return &const_instruction->base;
11241123}
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) {
11271126 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;
11291128 const_instruction->base.value.special = ConstValSpecialStatic;
1130 const_instruction->base.value.data.x_import = import;
1129 const_instruction->base.value.data.x_type = import;
11311130 return &const_instruction->base;
11321131}
11331132
......@@ -3824,7 +3823,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
38243823 if (tld)
38253824 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) {
38283827 // skip the error message since we had a failing import in this file
38293828 // if an import breaks we don't need redundant undeclared identifier errors
38303829 return irb->codegen->invalid_instruction;
......@@ -6609,20 +6608,32 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
66096608 return true;
66106609}
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{
66136614 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;
66156621 } else if (exec->name_fn != nullptr) {
66166622 Buf *name = buf_alloc();
66176623 buf_append_buf(name, &exec->name_fn->symbol_name);
66186624 buf_appendf(name, "(");
66196625 render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);
66206626 buf_appendf(name, ")");
6627 buf_init_from_buf(out_bare_name, name);
66216628 return name;
66226629 } else {
6623 //Note: C-imports do not have valid location information
6624 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
6625 (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
6630 ZigType *import = get_scope_import(scope);
6631 Buf *namespace_name = buf_create_from_buf(&import->name);
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;
66266637 }
66276638}
66286639
......@@ -6630,24 +6641,23 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
66306641 assert(node->type == NodeTypeContainerDecl);
66316642
66326643 ContainerKind kind = node->data.container_decl.kind;
6633 Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), node);
6634
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);
6644 Buf *bare_name = buf_alloc();
6645 Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), parent_scope, node, bare_name);
66386646
66396647 ContainerLayout layout = node->data.container_decl.layout;
66406648 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);
66426650 ScopeDecls *child_scope = get_container_scope(container_type);
66436651
6644 tld_container->type_entry = container_type;
6645 tld_container->decls_scope = child_scope;
6646
66476652 for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) {
66486653 AstNode *child_node = node->data.container_decl.decls.at(i);
66496654 scan_decls(irb->codegen, child_scope, child_node);
66506655 }
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;
66516661 irb->codegen->resolve_queue.append(&tld_container->base);
66526662
66536663 // 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
67326742
67336743 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);
67366747 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
67376748 buf_init_from_buf(&err_set_type->name, type_name);
67386749 err_set_type->data.error_set.err_count = err_count;
......@@ -12065,7 +12076,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1206512076 case ZigTypeIdErrorSet:
1206612077 case ZigTypeIdFn:
1206712078 case ZigTypeIdOpaque:
12068 case ZigTypeIdNamespace:
1206912079 case ZigTypeIdBoundFn:
1207012080 case ZigTypeIdArgTuple:
1207112081 case ZigTypeIdPromise:
......@@ -13407,7 +13417,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1340713417 case ZigTypeIdOptional:
1340813418 case ZigTypeIdErrorUnion:
1340913419 case ZigTypeIdErrorSet:
13410 case ZigTypeIdNamespace:
1341113420 case ZigTypeIdBoundFn:
1341213421 case ZigTypeIdArgTuple:
1341313422 case ZigTypeIdOpaque:
......@@ -13432,7 +13441,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1343213441 case ZigTypeIdErrorSet:
1343313442 case ZigTypeIdVector:
1343413443 zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
13435 case ZigTypeIdNamespace:
1343613444 case ZigTypeIdBoundFn:
1343713445 case ZigTypeIdArgTuple:
1343813446 case ZigTypeIdOpaque:
......@@ -14616,7 +14624,6 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
1461614624 case ZigTypeIdEnum:
1461714625 case ZigTypeIdUnion:
1461814626 case ZigTypeIdFn:
14619 case ZigTypeIdNamespace:
1462014627 case ZigTypeIdBoundFn:
1462114628 case ZigTypeIdArgTuple:
1462214629 case ZigTypeIdPromise:
......@@ -15368,7 +15375,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
1536815375 auto entry = container_scope->decl_table.maybe_get(field_name);
1536915376 Tld *tld = entry ? entry->value : nullptr;
1537015377 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);
1537215379 if (tld->resolution == TldResolutionInvalid)
1537315380 return ira->codegen->invalid_instruction;
1537415381 TldFn *tld_fn = (TldFn *)tld;
......@@ -15557,8 +15564,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name,
1555715564
1555815565
1555915566static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
15560 bool pointer_only = false;
15561 resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node);
15567 resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node);
1556215568 if (tld->resolution == TldResolutionInvalid)
1556315569 return ira->codegen->invalid_instruction;
1556415570
......@@ -15735,12 +15741,17 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
1573515741 }
1573615742 }
1573715743 ScopeDecls *container_scope = get_container_scope(child_type);
15738 if (container_scope != nullptr) {
15739 auto entry = container_scope->decl_table.maybe_get(field_name);
15740 Tld *tld = entry ? entry->value : nullptr;
15741 if (tld) {
15742 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
15744 Tld *tld = find_container_decl(ira->codegen, container_scope, field_name);
15745 if (tld) {
15746 if (tld->visib_mod == VisibModPrivate &&
15747 tld->import != get_scope_import(field_ptr_instruction->base.scope))
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;
1574315753 }
15754 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
1574415755 }
1574515756 if (child_type->id == ZigTypeIdUnion &&
1574615757 (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
1575815769 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);
1575915770 }
1576015771 }
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)));
1576115774 ir_add_error(ira, &field_ptr_instruction->base,
15762 buf_sprintf("container '%s' has no member called '%s'",
15763 buf_ptr(&child_type->name), buf_ptr(field_name)));
15775 buf_sprintf("%s has no member called '%s'",
15776 container_name, buf_ptr(field_name)));
1576415777 return ira->codegen->invalid_instruction;
1576515778 } else if (child_type->id == ZigTypeIdErrorSet) {
1576615779 ErrorTableEntry *err_entry;
......@@ -15971,37 +15984,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
1597115984 buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
1597215985 return ira->codegen->invalid_instruction;
1597315986 }
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 }
1600515987 } else {
1600615988 ir_add_error_node(ira, field_ptr_instruction->base.source_node,
1600715989 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,
1628116263 case ZigTypeIdEnum:
1628216264 case ZigTypeIdUnion:
1628316265 case ZigTypeIdFn:
16284 case ZigTypeIdNamespace:
1628516266 case ZigTypeIdBoundFn:
1628616267 case ZigTypeIdPromise:
1628716268 case ZigTypeIdVector:
......@@ -16402,7 +16383,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
1640216383 case ZigTypeIdEnum:
1640316384 case ZigTypeIdUnion:
1640416385 case ZigTypeIdFn:
16405 case ZigTypeIdNamespace:
1640616386 case ZigTypeIdBoundFn:
1640716387 case ZigTypeIdPromise:
1640816388 case ZigTypeIdVector:
......@@ -16452,7 +16432,6 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
1645216432 case ZigTypeIdComptimeInt:
1645316433 case ZigTypeIdBoundFn:
1645416434 case ZigTypeIdMetaType:
16455 case ZigTypeIdNamespace:
1645616435 case ZigTypeIdArgTuple:
1645716436 case ZigTypeIdOpaque:
1645816437 ir_add_error_node(ira, size_of_instruction->base.source_node,
......@@ -16860,7 +16839,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1686016839 case ZigTypeIdPointer:
1686116840 case ZigTypeIdPromise:
1686216841 case ZigTypeIdFn:
16863 case ZigTypeIdNamespace:
1686416842 case ZigTypeIdErrorSet: {
1686516843 if (pointee_val) {
1686616844 IrInstruction *result = ir_const(ira, &switch_target_instruction->base, nullptr);
......@@ -17009,25 +16987,29 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
1700916987 return ira->codegen->invalid_instruction;
1701016988
1701116989 AstNode *source_node = import_instruction->base.source_node;
17012 ImportTableEntry *import = source_node->owner;
16990 ZigType *import = source_node->owner;
1701316991
1701416992 Buf *import_target_path;
1701516993 Buf *search_dir;
17016 assert(import->package);
17017 PackageTableEntry *target_package;
17018 auto package_entry = import->package->package_table.maybe_get(import_target_str);
16994 assert(import->data.structure.root_struct->package);
16995 ZigPackage *target_package;
16996 auto package_entry = import->data.structure.root_struct->package->package_table.maybe_get(import_target_str);
16997 SourceKind source_kind;
1701916998 if (package_entry) {
1702016999 target_package = package_entry->value;
1702117000 import_target_path = &target_package->root_src_path;
1702217001 search_dir = &target_package->root_src_dir;
17002 source_kind = SourceKindPkgMain;
1702317003 } else {
1702417004 // try it as a filename
17025 target_package = import->package;
17005 target_package = import->data.structure.root_struct->package;
1702617006 import_target_path = import_target_str;
1702717007
1702817008 // search relative to importing file
1702917009 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;
1703117013 }
1703217014
1703317015 Buf full_path = BUF_INIT;
......@@ -17041,10 +17023,19 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
1704117023
1704217024 auto import_entry = ira->codegen->import_table.maybe_get(resolved_path);
1704317025 if (import_entry) {
17044 IrInstruction *result = ir_const(ira, &import_instruction->base,
17045 ira->codegen->builtin_types.entry_namespace);
17046 result->value.data.x_import = import_entry->value;
17047 return result;
17026 return ir_const_type(ira, &import_instruction->base, import_entry->value);
17027 }
17028
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 }
1704817039 }
1704917040
1705017041 if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {
......@@ -17059,13 +17050,9 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
1705917050 }
1706017051 }
1706117052
17062 ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code);
17063
17064 scan_import(ira->codegen, target_import);
17053 ZigType *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code, source_kind);
1706517054
17066 IrInstruction *result = ir_const(ira, &import_instruction->base, ira->codegen->builtin_types.entry_namespace);
17067 result->value.data.x_import = target_import;
17068 return result;
17055 return ir_const_type(ira, &import_instruction->base, target_import);
1706917056}
1707017057
1707117058static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) {
......@@ -17398,17 +17385,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,
1739817385 return ira->codegen->invalid_instruction;
1739917386
1740017387 ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf);
17401 size_t i = ira->codegen->tld_ref_source_node_stack.length;
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 }
17388 emit_error_notes_for_ref_stack(ira->codegen, msg);
1741217389
1741317390 return ira->codegen->invalid_instruction;
1741417391}
......@@ -17665,6 +17642,12 @@ static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
1766517642 return ir_const_unsigned(ira, &instruction->base, bit_offset);
1766617643}
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
1766817651static void ensure_field_index(ZigType *type, const char *field_name, size_t index) {
1766917652 Buf *field_name_buf;
1767017653
......@@ -17711,7 +17694,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
1771117694 return var->const_value->data.x_type;
1771217695}
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{
1771517700 Error err;
1771617701 ZigType *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr);
1771717702 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
1774117726 while ((curr_entry = decl_it.next()) != nullptr) {
1774217727 // If the definition is unresolved, force it to be resolved again.
1774317728 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);
1774517730 if (curr_entry->value->resolution != TldResolutionOk) {
1774617731 return ErrorSemanticAnalyzeFail;
1774717732 }
......@@ -17831,6 +17816,11 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
1783117816 ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
1783217817 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
1783417824 AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
1783517825
1783617826 ConstExprValue *fn_def_val = create_const_vals(1);
......@@ -18007,7 +17997,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
1800717997 // alignment: u32
1800817998 ensure_field_index(result->type, "alignment", 3);
1800917999 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;
1801118001 bigint_init_unsigned(&fields[3].data.x_bigint, get_ptr_align(ira->codegen, attrs_type));
1801218002 // child: type
1801318003 ensure_field_index(result->type, "child", 4);
......@@ -18026,7 +18016,7 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,
1802618016
1802718017 ConstExprValue *inner_fields = create_const_vals(2);
1802818018 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
1803118021 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
1803218022 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,
1803618026 enum_field_val->data.x_struct.fields = inner_fields;
1803718027}
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{
1804018032 Error err;
1804118033 assert(type_entry != nullptr);
1804218034 assert(!type_is_invalid(type_entry));
......@@ -18056,7 +18048,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1805618048 case ZigTypeIdComptimeInt:
1805718049 case ZigTypeIdUndefined:
1805818050 case ZigTypeIdNull:
18059 case ZigTypeIdNamespace:
1806018051 case ZigTypeIdArgTuple:
1806118052 case ZigTypeIdOpaque:
1806218053 *out = nullptr;
......@@ -18089,7 +18080,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1808918080 // bits: u8
1809018081 ensure_field_index(result->type, "bits", 1);
1809118082 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;
1809318084 bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count);
1809418085
1809518086 break;
......@@ -18106,7 +18097,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1810618097 // bits: u8
1810718098 ensure_field_index(result->type, "bits", 0);
1810818099 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;
1811018101 bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count);
1811118102
1811218103 break;
......@@ -18130,7 +18121,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1813018121 // len: usize
1813118122 ensure_field_index(result->type, "len", 0);
1813218123 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;
1813418125 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len);
1813518126 // child: type
1813618127 ensure_field_index(result->type, "child", 1);
......@@ -18151,7 +18142,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1815118142 // len: usize
1815218143 ensure_field_index(result->type, "len", 0);
1815318144 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;
1815518146 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len);
1815618147 // child: type
1815718148 ensure_field_index(result->type, "child", 1);
......@@ -18248,8 +18239,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1824818239 }
1824918240 // defs: []TypeInfo.Definition
1825018241 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 {
1825218245 return err;
18246 }
1825318247
1825418248 break;
1825518249 }
......@@ -18266,11 +18260,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1826618260 ensure_field_index(result->type, "errors", 0);
1826718261
1826818262 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)) {
1827018264 return ErrorSemanticAnalyzeFail;
1827118265 }
1827218266 if (type_is_global_error_set(type_entry)) {
18273 ir_add_error_node(ira, source_node,
18267 ir_add_error(ira, source_instr,
1827418268 buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936"));
1827518269 return ErrorSemanticAnalyzeFail;
1827618270 }
......@@ -18292,7 +18286,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1829218286
1829318287 ConstExprValue *inner_fields = create_const_vals(2);
1829418288 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
1829718291 ConstExprValue *name = nullptr;
1829818292 if (error->cached_error_name_val != nullptr)
......@@ -18412,8 +18406,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1841218406 }
1841318407 // defs: []TypeInfo.Definition
1841418408 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 {
1841618412 return err;
18413 }
1841718414
1841818415 break;
1841918416 }
......@@ -18461,7 +18458,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1846118458
1846218459 ConstExprValue *inner_fields = create_const_vals(3);
1846318460 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
1846618463 if (!type_has_bits(struct_field->type_entry)) {
1846718464 inner_fields[1].data.x_optional = nullptr;
......@@ -18487,8 +18484,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1848718484 }
1848818485 // defs: []TypeInfo.Definition
1848918486 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 {
1849118490 return err;
18491 }
1849218492
1849318493 break;
1849418494 }
......@@ -18600,7 +18600,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
1860018600 {
1860118601 ZigType *fn_type = type_entry->data.bound_fn.fn_type;
1860218602 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)))
1860418604 return err;
1860518605
1860618606 break;
......@@ -18625,7 +18625,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,
1862518625 ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr);
1862618626
1862718627 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)))
1862918629 return ira->codegen->invalid_instruction;
1863018630
1863118631 IrInstruction *result = ir_const(ira, &instruction->base, result_type);
......@@ -18680,7 +18680,7 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
1868018680 return ira->codegen->invalid_instruction;
1868118681
1868218682 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));
1868418684 }
1868518685 IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
1868618686 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
1870218702 if (type_is_invalid(cimport_result->type))
1870318703 return ira->codegen->invalid_instruction;
1870418704
18705 ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
18706 child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import);
18707 child_import->c_import_node = node;
18708 child_import->package = new_anonymous_package();
18709 child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);
18710 child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
18711 child_import->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,
18705 ZigPackage *cur_scope_pkg = scope_package(instruction->base.scope);
18706 Buf *namespace_name = buf_sprintf("%s.cimport:%" ZIG_PRI_usize ":%" ZIG_PRI_usize,
18707 buf_ptr(&cur_scope_pkg->pkg_path), node->line + 1, node->column + 1);
18708
18709 RootStruct *root_struct = allocate<RootStruct>(1);
18710 root_struct->package = new_anonymous_package();
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,
1871218717 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
1871418721 ZigList<ErrorMsg *> errors = {0};
1871518722
......@@ -18738,14 +18745,12 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
1873818745 if (ira->codegen->verbose_cimport) {
1873918746 fprintf(stderr, "\nC imports:\n");
1874018747 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);
1874218749 }
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);
18747 result->value.data.x_import = child_import;
18748 return result;
18753 return ir_const_type(ira, &instruction->base, child_import);
1874918754}
1875018755
1875118756static IrInstruction *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {
......@@ -18819,10 +18824,10 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
1881918824 if (!rel_file_path)
1882018825 return ira->codegen->invalid_instruction;
1882118826
18822 ImportTableEntry *import = get_scope_import(instruction->base.scope);
18827 ZigType *import = get_scope_import(instruction->base.scope);
1882318828 // figure out absolute path to resource
1882418829 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
1882718832 Buf *resolve_paths[] = {
1882818833 &source_dir_path,
......@@ -19752,6 +19757,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
1975219757 return ira->codegen->invalid_instruction;
1975319758 }
1975419759 } else {
19760 if (array_type->data.pointer.ptr_len == PtrLenC) {
19761 array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
19762 }
1975519763 return_type = get_slice_type(ira->codegen, array_type);
1975619764 if (!end) {
1975719765 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
2013720145static IrInstruction *ir_analyze_instruction_return_address(IrAnalyze *ira, IrInstructionReturnAddress *instruction) {
2013820146 IrInstruction *result = ir_build_return_address(&ira->new_irb,
2013920147 instruction->base.scope, instruction->base.source_node);
20140 ZigType *u8 = ira->codegen->builtin_types.entry_u8;
20141 ZigType *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
20142 result->value.type = u8_ptr_const;
20148 result->value.type = ira->codegen->builtin_types.entry_usize;
2014320149 return result;
2014420150}
2014520151
2014620152static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrInstructionFrameAddress *instruction) {
2014720153 IrInstruction *result = ir_build_frame_address(&ira->new_irb,
2014820154 instruction->base.scope, instruction->base.source_node);
20149 ZigType *u8 = ira->codegen->builtin_types.entry_u8;
20150 ZigType *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
20151 result->value.type = u8_ptr_const;
20155 result->value.type = ira->codegen->builtin_types.entry_usize;
2015220156 return result;
2015320157}
2015420158
......@@ -20179,7 +20183,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
2017920183 case ZigTypeIdComptimeInt:
2018020184 case ZigTypeIdUndefined:
2018120185 case ZigTypeIdNull:
20182 case ZigTypeIdNamespace:
2018320186 case ZigTypeIdBoundFn:
2018420187 case ZigTypeIdArgTuple:
2018520188 case ZigTypeIdVoid:
......@@ -21025,7 +21028,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2102521028 case ZigTypeIdOpaque:
2102621029 case ZigTypeIdBoundFn:
2102721030 case ZigTypeIdArgTuple:
21028 case ZigTypeIdNamespace:
2102921031 case ZigTypeIdUnreachable:
2103021032 case ZigTypeIdComptimeFloat:
2103121033 case ZigTypeIdComptimeInt:
......@@ -21185,7 +21187,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
2118521187 case ZigTypeIdOpaque:
2118621188 case ZigTypeIdBoundFn:
2118721189 case ZigTypeIdArgTuple:
21188 case ZigTypeIdNamespace:
2118921190 case ZigTypeIdUnreachable:
2119021191 case ZigTypeIdComptimeFloat:
2119121192 case ZigTypeIdComptimeInt:
......@@ -21343,7 +21344,6 @@ static bool type_can_bit_cast(ZigType *t) {
2134321344 case ZigTypeIdOpaque:
2134421345 case ZigTypeIdBoundFn:
2134521346 case ZigTypeIdArgTuple:
21346 case ZigTypeIdNamespace:
2134721347 case ZigTypeIdUnreachable:
2134821348 case ZigTypeIdComptimeFloat:
2134921349 case ZigTypeIdComptimeInt:
......@@ -21516,7 +21516,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
2151621516 Tld *tld = instruction->tld;
2151721517 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);
2152021520 if (tld->resolution == TldResolutionInvalid)
2152121521 return ira->codegen->invalid_instruction;
2152221522
......@@ -21528,6 +21528,10 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
2152821528 TldVar *tld_var = (TldVar *)tld;
2152921529 ZigVar *var = tld_var->var;
2153021530
21531 if (var == nullptr) {
21532 return ir_error_dependency_loop(ira, &instruction->base);
21533 }
21534
2153121535 IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);
2153221536 if (type_is_invalid(var_ptr->value.type))
2153321537 return ira->codegen->invalid_instruction;
......@@ -21664,9 +21668,11 @@ static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstru
2166421668}
2166521669
2166621670static 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);
2166821674 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);
2167021676 return ir_const_type(ira, &instruction->base, result_type);
2167121677}
2167221678
src/link.cpp+2-4
......@@ -41,7 +41,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
4141 child_out_type = OutTypeObj;
4242 }
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,
4545 parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir,
4646 parent_gen->libc);
4747
......@@ -87,10 +87,8 @@ static Buf *build_a(CodeGen *parent_gen, const char *aname) {
8787}
8888
8989static 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);
9290 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
9593 return build_a_raw(parent_gen, "compiler_rt", full_path);
9694}
src/main.cpp+19-15
......@@ -63,6 +63,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
6363 " --output-lib [file] override import library path\n"
6464 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
6565 " --pkg-end pop current pkg\n"
66 " --main-pkg-path set the directory of the root package\n"
6667 " --release-fast build with optimizations on and safety off\n"
6768 " --release-safe build with optimizations on and safety on\n"
6869 " --release-small build with size optimizations on and safety off\n"
......@@ -215,7 +216,7 @@ struct CliPkg {
215216 CliPkg *parent;
216217};
217218
218static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
219static void add_package(CodeGen *g, CliPkg *cli_pkg, ZigPackage *pkg) {
219220 for (size_t i = 0; i < cli_pkg->children.length; i += 1) {
220221 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) {
223224 Buf *basename = buf_alloc();
224225 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)));
227229 auto entry = pkg->package_table.put_unique(buf_create_from_str(child_cli_pkg->name), child_pkg);
228230 if (entry) {
229 PackageTableEntry *existing_pkg = entry->value;
231 ZigPackage *existing_pkg = entry->value;
230232 Buf *full_path = buf_alloc();
231233 os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path);
232234 fprintf(stderr, "Unable to add package '%s'->'%s': already exists as '%s'\n",
......@@ -437,6 +439,7 @@ int main(int argc, char **argv) {
437439 TargetSubsystem subsystem = TargetSubsystemAuto;
438440 bool is_single_threaded = false;
439441 Buf *override_std_dir = nullptr;
442 Buf *main_pkg_path = nullptr;
440443 ValgrindSupport valgrind_support = ValgrindSupportAuto;
441444
442445 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
......@@ -475,8 +478,8 @@ int main(int argc, char **argv) {
475478
476479 ZigTarget target;
477480 get_native_target(&target);
478 CodeGen *g = codegen_create(build_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
479 override_std_dir, nullptr);
481 CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe,
482 BuildModeDebug, get_zig_lib_dir(), override_std_dir, nullptr);
480483 g->valgrind_support = valgrind_support;
481484 g->enable_time_report = timing_info;
482485 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) {
543546 return EXIT_FAILURE;
544547 }
545548
546 PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
547 buf_ptr(&build_file_basename));
549 ZigPackage *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
550 buf_ptr(&build_file_basename), "std.special");
548551 g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
549552 g->enable_cache = get_cache_opt(enable_cache, true);
550553 codegen_build_and_link(g);
......@@ -566,8 +569,8 @@ int main(int argc, char **argv) {
566569 get_native_target(&target);
567570 Buf *fmt_runner_path = buf_alloc();
568571 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(),
570 nullptr, nullptr);
572 CodeGen *g = codegen_create(main_pkg_path, fmt_runner_path, &target, OutTypeExe,
573 BuildModeDebug, get_zig_lib_dir(), nullptr, nullptr);
571574 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
572575 g->valgrind_support = valgrind_support;
573576 g->is_single_threaded = true;
......@@ -728,6 +731,8 @@ int main(int argc, char **argv) {
728731 llvm_argv.append(argv[i]);
729732 } else if (strcmp(arg, "--override-std-dir") == 0) {
730733 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]);
731736 } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
732737 lib_dirs.append(argv[i]);
733738 } else if (strcmp(arg, "--library") == 0) {
......@@ -907,8 +912,8 @@ int main(int argc, char **argv) {
907912 return EXIT_SUCCESS;
908913 }
909914 case CmdBuiltin: {
910 CodeGen *g = codegen_create(nullptr, &target, out_type, build_mode, get_zig_lib_dir(), override_std_dir,
911 nullptr);
915 CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
916 out_type, build_mode, get_zig_lib_dir(), override_std_dir, nullptr);
912917 g->valgrind_support = valgrind_support;
913918 g->is_single_threaded = is_single_threaded;
914919 Buf *builtin_source = codegen_generate_builtin_source(g);
......@@ -1011,8 +1016,8 @@ int main(int argc, char **argv) {
10111016 return EXIT_FAILURE;
10121017 }
10131018 }
1014 CodeGen *g = codegen_create(zig_root_source_file, &target, out_type, build_mode, get_zig_lib_dir(),
1015 override_std_dir, libc);
1019 CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,
1020 get_zig_lib_dir(), override_std_dir, libc);
10161021 g->valgrind_support = valgrind_support;
10171022 g->subsystem = subsystem;
10181023
......@@ -1095,7 +1100,6 @@ int main(int argc, char **argv) {
10951100 if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
10961101 codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
10971102
1098
10991103 add_package(g, cur_pkg, g->root_package);
11001104
11011105 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
......@@ -1145,7 +1149,7 @@ int main(int argc, char **argv) {
11451149 }
11461150 } else if (cmd == CmdTranslateC) {
11471151 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);
11491153 if (timing_info)
11501154 codegen_print_timing_report(g, stdout);
11511155 return EXIT_SUCCESS;
src/os.cpp+1-1
......@@ -264,7 +264,7 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
264264 buf_append_buf(out_full_path, basename);
265265}
266266
267int os_path_real(Buf *rel_path, Buf *out_abs_path) {
267Error os_path_real(Buf *rel_path, Buf *out_abs_path) {
268268#if defined(ZIG_OS_WINDOWS)
269269 buf_resize(out_abs_path, 4096);
270270 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);
9696void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
9797void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
9898void 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);
100100Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
101101bool os_path_is_absolute(Buf *path);
102102
src/parser.cpp+10-8
......@@ -18,7 +18,7 @@ struct ParseContext {
1818 Buf *buf;
1919 size_t current_token;
2020 ZigList<Token> *tokens;
21 ImportTableEntry *owner;
21 ZigType *owner;
2222 ErrColor err_color;
2323};
2424
......@@ -130,8 +130,10 @@ static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
130130 va_end(ap);
131131
132132
133 ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column,
134 pc->owner->source_code, pc->owner->line_offsets, msg);
133 ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path,
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);
135137 err->line_start = token->start_line;
136138 err->column_start = token->start_column;
137139
......@@ -148,8 +150,10 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, size_t offset, const
148150 Buf *msg = buf_vprintf(format, ap);
149151 va_end(ap);
150152
151 ErrorMsg *err = err_msg_create_with_line(pc->owner->path, node->line, node->column,
152 pc->owner->source_code, pc->owner->line_offsets, msg);
153 ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path,
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
154158 print_err_msg(err, pc->err_color);
155159 exit(EXIT_FAILURE);
......@@ -570,9 +574,7 @@ static void ast_parse_asm_template(ParseContext *pc, AstNode *node) {
570574 }
571575}
572576
573AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
574 ErrColor err_color)
575{
577AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ZigType *owner, ErrColor err_color) {
576578 ParseContext pc = {};
577579 pc.err_color = err_color;
578580 pc.owner = owner;
src/parser.hpp+1-1
......@@ -16,7 +16,7 @@ ATTRIBUTE_PRINTF(2, 3)
1616void 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
2121void 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) {
676676 if (!opt_archsub.is_some)
677677 return ErrorMissingArchitecture;
678678
679 if (!opt_os.is_some)
680 return ErrorMissingOperatingSystem;
681
682679 if ((err = target_parse_archsub(&target->arch, &target->sub_arch,
683680 (char*)opt_archsub.value.ptr, opt_archsub.value.len)))
684681 {
685682 return err;
686683 }
687684
685 if (!opt_os.is_some)
686 return ErrorMissingOperatingSystem;
687
688688 if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
689689 return err;
690690 }
src/translate_c.cpp+5-4
......@@ -76,7 +76,7 @@ struct TransScopeWhile {
7676};
7777
7878struct Context {
79 ImportTableEntry *import;
79 ZigType *import;
8080 ZigList<ErrorMsg *> *errors;
8181 VisibMod visib_mod;
8282 bool want_export;
......@@ -4779,7 +4779,7 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) {
47794779 }
47804780}
47814781
4782Error parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source,
4782Error parse_h_buf(ZigType *import, ZigList<ErrorMsg *> *errors, Buf *source,
47834783 CodeGen *codegen, AstNode *source_node)
47844784{
47854785 Error err;
......@@ -4795,7 +4795,7 @@ Error parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *so
47954795 return err;
47964796}
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,
47994799 CodeGen *codegen, AstNode *source_node)
48004800{
48014801 Context context = {0};
......@@ -5005,7 +5005,8 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
50055005 render_macros(c);
50065006 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
50105011 return ErrorNone;
50115012}
src/translate_c.hpp+2-2
......@@ -11,10 +11,10 @@
1111
1212#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,
1515 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,
1818 CodeGen *codegen, AstNode *source_node);
1919
2020#endif
src/util.hpp-12
......@@ -93,18 +93,6 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
9393 return ptr;
9494}
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
10896template<typename T>
10997static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
11098 T *ptr = reallocate_nonzero(old, old_count, new_count);
std/array_list.zig+2-2
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const debug = std.debug;
33const assert = debug.assert;
44const testing = std.testing;
......@@ -406,6 +406,6 @@ const Item = struct {
406406
407407test "std.ArrayList: ArrayList(T) of struct T" {
408408 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) });
410410 testing.expect(root.sub_items.items[0].integer == 42);
411411}
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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const AtomicOrder = builtin.AtomicOrder;
44const AtomicRmwOp = builtin.AtomicRmwOp;
std/atomic/stack.zig+1-1
......@@ -68,7 +68,7 @@ pub fn Stack(comptime T: type) type {
6868 };
6969}
7070
71const std = @import("../index.zig");
71const std = @import("../std.zig");
7272const Context = struct {
7373 allocator: *std.mem.Allocator,
7474 stack: *Stack(i32),
std/base64.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const mem = std.mem;
std/buf_map.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const HashMap = std.HashMap;
33const mem = std.mem;
44const Allocator = mem.Allocator;
std/buf_set.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const HashMap = @import("hash_map.zig").HashMap;
33const mem = @import("mem.zig");
44const Allocator = mem.Allocator;
std/buffer.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const debug = std.debug;
33const mem = std.mem;
44const Allocator = mem.Allocator;
std/build.zig+13-2
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const io = std.io;
44const mem = std.mem;
......@@ -859,6 +859,7 @@ pub const LibExeObjStep = struct {
859859 verbose_cc: bool,
860860 c_std: Builder.CStd,
861861 override_std_dir: ?[]const u8,
862 main_pkg_path: ?[]const u8,
862863 exec_cmd_args: ?[]const ?[]const u8,
863864 name_prefix: []const u8,
864865 filter: ?[]const u8,
......@@ -950,6 +951,7 @@ pub const LibExeObjStep = struct {
950951 .c_std = Builder.CStd.C99,
951952 .system_linker_hack = false,
952953 .override_std_dir = null,
954 .main_pkg_path = null,
953955 .exec_cmd_args = null,
954956 .name_prefix = "",
955957 .filter = null,
......@@ -1098,6 +1100,10 @@ pub const LibExeObjStep = struct {
10981100 self.override_std_dir = dir_path;
10991101 }
11001102
1103 pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void {
1104 self.main_pkg_path = dir_path;
1105 }
1106
11011107 pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
11021108 self.output_path = file_path;
11031109
......@@ -1320,7 +1326,7 @@ pub const LibExeObjStep = struct {
13201326 zig_args.append("--ver-patch") catch unreachable;
13211327 zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
13221328 }
1323 if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
1329 if (self.static) {
13241330 zig_args.append("--static") catch unreachable;
13251331 }
13261332
......@@ -1424,6 +1430,11 @@ pub const LibExeObjStep = struct {
14241430 try zig_args.append(builder.pathFromRoot(dir));
14251431 }
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
14271438 try builder.spawnChild(zig_args.toSliceConst());
14281439
14291440 if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
std/build/fmt.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const build = @import("../build.zig");
33const Step = build.Step;
44const 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 {
163163// sys/types.h on macos uses #pragma pack(4) so these checks are
164164// to make sure the struct is laid out the same. These values were
165165// produced from C code using the offsetof macro.
166const std = @import("../index.zig");
166const std = @import("../std.zig");
167167const assert = std.debug.assert;
168168
169169comptime {
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 @@
11const builtin = @import("builtin");
2const std = @import("index.zig");
2const std = @import("std.zig");
33const io = std.io;
44const mem = std.mem;
55const 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 @@
11const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
2const math = @import("../math.zig");
33const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
4const debug = @import("../debug.zig");
55const builtin = @import("builtin");
66const htest = @import("test.zig");
77
......@@ -34,8 +34,8 @@ pub const Blake2s256 = Blake2s(256);
3434fn Blake2s(comptime out_len: usize) type {
3535 return struct {
3636 const Self = @This();
37 const block_length = 64;
38 const digest_length = out_len / 8;
37 pub const block_length = 64;
38 pub const digest_length = out_len / 8;
3939
4040 const iv = [8]u32{
4141 0x6A09E667,
std/crypto/chacha20.zig+1-1
......@@ -1,6 +1,6 @@
11// Based on public domain Supercop by Daniel J. Bernstein
22
3const std = @import("../index.zig");
3const std = @import("../std.zig");
44const mem = std.mem;
55const endian = std.endian;
66const assert = std.debug.assert;
std/crypto/hmac.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const crypto = std.crypto;
33const debug = std.debug;
44const 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 @@
11const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
2const math = @import("../math.zig");
33const endian = @import("../endian.zig");
44const builtin = @import("builtin");
5const debug = @import("../debug/index.zig");
6const fmt = @import("../fmt/index.zig");
5const debug = @import("../debug.zig");
6const fmt = @import("../fmt.zig");
77
88const RoundParam = struct {
99 a: usize,
......@@ -29,8 +29,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
2929
3030pub const Md5 = struct {
3131 const Self = @This();
32 const block_length = 64;
33 const digest_length = 16;
32 pub const block_length = 64;
33 pub const digest_length = 16;
3434
3535 s: [4]u32,
3636 // Streaming Cache
std/crypto/poly1305.zig+1-1
......@@ -2,7 +2,7 @@
22//
33// https://monocypher.org/
44
5const std = @import("../index.zig");
5const std = @import("../std.zig");
66const builtin = @import("builtin");
77
88const Endian = builtin.Endian;
std/crypto/sha1.zig+4-4
......@@ -1,7 +1,7 @@
11const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
2const math = @import("../math.zig");
33const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
4const debug = @import("../debug.zig");
55const builtin = @import("builtin");
66
77const RoundParam = struct {
......@@ -26,8 +26,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
2626
2727pub const Sha1 = struct {
2828 const Self = @This();
29 const block_length = 64;
30 const digest_length = 20;
29 pub const block_length = 64;
30 pub const digest_length = 20;
3131
3232 s: [5]u32,
3333 // Streaming Cache
std/crypto/sha2.zig+4-4
......@@ -1,7 +1,7 @@
11const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
2const math = @import("../math.zig");
33const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
4const debug = @import("../debug.zig");
55const builtin = @import("builtin");
66const htest = @import("test.zig");
77
......@@ -78,8 +78,8 @@ pub const Sha256 = Sha2_32(Sha256Params);
7878fn Sha2_32(comptime params: Sha2Params32) type {
7979 return struct {
8080 const Self = @This();
81 const block_length = 64;
82 const digest_length = params.out_len / 8;
81 pub const block_length = 64;
82 pub const digest_length = params.out_len / 8;
8383
8484 s: [8]u32,
8585 // Streaming Cache
std/crypto/sha3.zig+4-4
......@@ -1,7 +1,7 @@
11const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
2const math = @import("../math.zig");
33const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
4const debug = @import("../debug.zig");
55const builtin = @import("builtin");
66const htest = @import("test.zig");
77
......@@ -13,8 +13,8 @@ pub const Sha3_512 = Keccak(512, 0x06);
1313fn Keccak(comptime bits: usize, comptime delim: u8) type {
1414 return struct {
1515 const Self = @This();
16 const block_length = 200;
17 const digest_length = bits / 8;
16 pub const block_length = 200;
17 pub const digest_length = bits / 8;
1818
1919 s: [200]u8,
2020 offset: usize,
std/crypto/test.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const testing = std.testing;
33const mem = std.mem;
44const fmt = std.fmt;
std/crypto/throughput_test.zig+1-1
......@@ -2,7 +2,7 @@ const builtin = @import("builtin");
22const std = @import("std");
33const time = std.os.time;
44const Timer = time.Timer;
5const crypto = @import("index.zig");
5const crypto = @import("../crypto.zig");
66
77const KiB = 1024;
88const MiB = 1024 * KiB;
std/crypto/x25519.zig+1-1
......@@ -2,7 +2,7 @@
22//
33// https://monocypher.org/
44
5const std = @import("../index.zig");
5const std = @import("../std.zig");
66const builtin = @import("builtin");
77const fmt = std.fmt;
88
std/cstr.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const debug = std.debug;
44const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const mem = std.mem;
33
44/// 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 @@
11const builtin = @import("builtin");
22const Os = builtin.Os;
33
4const std = @import("index.zig");
4const std = @import("std.zig");
55const mem = std.mem;
66const cstr = std.cstr;
77const os = std.os;
std/elf.zig+1-1
......@@ -1,5 +1,5 @@
11const builtin = @import("builtin");
2const std = @import("index.zig");
2const std = @import("std.zig");
33const io = std.io;
44const os = std.os;
55const math = std.math;
std/event/channel.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
std/event/fs.zig+3-10
......@@ -1,5 +1,5 @@
11const builtin = @import("builtin");
2const std = @import("../index.zig");
2const std = @import("../std.zig");
33const event = std.event;
44const assert = std.debug.assert;
55const testing = std.testing;
......@@ -404,11 +404,7 @@ pub async fn openPosix(
404404
405405pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
406406 switch (builtin.os) {
407 builtin.Os.macosx,
408 builtin.Os.linux,
409 builtin.Os.freebsd,
410 builtin.Os.netbsd
411 => {
407 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
412408 const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
413409 return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
414410 },
......@@ -876,10 +872,7 @@ pub fn Watch(comptime V: type) type {
876872
877873 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
878874 switch (builtin.os) {
879 builtin.Os.macosx,
880 builtin.Os.freebsd,
881 builtin.Os.netbsd
882 => return await (async addFileKEvent(self, file_path, value) catch unreachable),
875 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
883876 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
884877 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885878 else => @compileError("Unsupported OS"),
std/event/future.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const builtin = @import("builtin");
std/event/group.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const Lock = std.event.Lock;
44const Loop = std.event.Loop;
std/event/io.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const Allocator = std.mem.Allocator;
44const assert = std.debug.assert;
std/event/lock.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
std/event/locked.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const Lock = std.event.Lock;
33const Loop = std.event.Loop;
44
std/event/loop.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
std/event/net.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const testing = std.testing;
44const event = std.event;
std/event/rwlock.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
std/event/rwlocked.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const RwLock = std.event.RwLock;
33const 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 @@
2929// - Only supports round-to-zero
3030// - Does not handle denormals
3131
32const std = @import("../index.zig");
32const std = @import("../std.zig");
3333
3434const 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 @@
33// https://tools.ietf.org/html/rfc1950#section-9
44// https://github.com/madler/zlib/blob/master/adler32.c
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const testing = std.testing;
88
99pub const Adler32 = struct {
std/hash/crc.zig+1-1
......@@ -5,7 +5,7 @@
55// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
66// still moderately fast just slow relative to the slicing approach.
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const debug = std.debug;
1010const testing = std.testing;
1111
std/hash/fnv.zig+1-1
......@@ -4,7 +4,7 @@
44//
55// https://tools.ietf.org/html/draft-eastlake-fnv-14
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const testing = std.testing;
99
1010pub 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 @@
55//
66// https://131002.net/siphash/
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const assert = std.debug.assert;
1010const testing = std.testing;
1111const math = std.math;
std/hash_map.zig+1-3
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const debug = std.debug;
33const assert = debug.assert;
44const testing = std.testing;
......@@ -486,7 +486,6 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
486486 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng),
487487 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),
488488
489 builtin.TypeId.Namespace,
490489 builtin.TypeId.BoundFn,
491490 builtin.TypeId.ComptimeFloat,
492491 builtin.TypeId.ComptimeInt,
......@@ -532,7 +531,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
532531 builtin.TypeId.Float,
533532 builtin.TypeId.ComptimeFloat,
534533 builtin.TypeId.ComptimeInt,
535 builtin.TypeId.Namespace,
536534 builtin.TypeId.Promise,
537535 builtin.TypeId.Enum,
538536 builtin.TypeId.BoundFn,
std/heap.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const debug = std.debug;
33const assert = debug.assert;
44const 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 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const Os = builtin.Os;
44const c = std.c;
std/io/seekable_stream.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const InStream = std.io.InStream;
33
44pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
std/io_test.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const io = std.io;
33const meta = std.meta;
44const trait = std.trait;
std/json.zig+1-1
......@@ -2,7 +2,7 @@
22//
33// https://tools.ietf.org/html/rfc8259
44
5const std = @import("index.zig");
5const std = @import("std.zig");
66const debug = std.debug;
77const testing = std.testing;
88const mem = std.mem;
std/json_test.zig+1-1
......@@ -3,7 +3,7 @@
33// Tests are taken from https://github.com/nst/JSONTestSuite
44// Read also http://seriot.ch/parsing_json.php for a good overview.
55
6const std = @import("index.zig");
6const std = @import("std.zig");
77
88fn ok(comptime s: []const u8) void {
99 std.testing.expect(std.json.validate(s));
std/lazy_init.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
std/linked_list.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const debug = std.debug;
33const assert = debug.assert;
44const 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 @@
22//
33// - acos(x) = nan if x < -1 or x > 1
44
5const std = @import("../index.zig");
5const std = @import("../std.zig");
66const math = std.math;
77const expect = std.testing.expect;
88
std/math/acosh.zig+1-1
......@@ -4,7 +4,7 @@
44// - acosh(nan) = nan
55
66const builtin = @import("builtin");
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010
std/math/asin.zig+1-1
......@@ -3,7 +3,7 @@
33// - asin(+-0) = +-0
44// - asin(x) = nan if x < -1 or x > 1
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const math = std.math;
88const expect = std.testing.expect;
99
std/math/asinh.zig+1-1
......@@ -4,7 +4,7 @@
44// - asinh(+-inf) = +-inf
55// - asinh(nan) = nan
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010const maxInt = std.math.maxInt;
std/math/atan.zig+1-1
......@@ -3,7 +3,7 @@
33// - atan(+-0) = +-0
44// - atan(+-inf) = +-pi/2
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const math = std.math;
88const expect = std.testing.expect;
99
std/math/atan2.zig+1-1
......@@ -18,7 +18,7 @@
1818// atan2(+inf, x) = +pi/2
1919// atan2(-inf, x) = -pi/2
2020
21const std = @import("../index.zig");
21const std = @import("../std.zig");
2222const math = std.math;
2323const expect = std.testing.expect;
2424
std/math/atanh.zig+1-1
......@@ -4,7 +4,7 @@
44// - atanh(x) = nan if |x| > 1 with signal
55// - atanh(nan) = nan
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010const 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 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const builtin = @import("builtin");
33const debug = std.debug;
44const testing = std.testing;
std/math/cbrt.zig+1-1
......@@ -4,7 +4,7 @@
44// - cbrt(+-inf) = +-inf
55// - cbrt(nan) = nan
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010
std/math/ceil.zig+1-1
......@@ -5,7 +5,7 @@
55// - ceil(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const 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 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/acos.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/acosh.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/arg.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/asin.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/asinh.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/atan.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/atanh.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/conj.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/cos.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/cosh.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/exp.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const 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 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const debug = std.debug;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/log.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/pow.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/proj.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/sin.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/sinh.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/sqrt.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/tan.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/complex/tanh.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const testing = std.testing;
33const math = std.math;
44const cmath = math.complex;
std/math/copysign.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44const maxInt = std.math.maxInt;
std/math/cos.zig+1-1
......@@ -4,7 +4,7 @@
44// - cos(nan) = nan
55
66const builtin = @import("builtin");
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010
std/math/cosh.zig+1-1
......@@ -5,7 +5,7 @@
55// - cosh(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expo2 = @import("expo2.zig").expo2;
1111const expect = std.testing.expect;
std/math/exp.zig+1-1
......@@ -3,7 +3,7 @@
33// - exp(+inf) = +inf
44// - exp(nan) = nan
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const math = std.math;
88const assert = std.debug.assert;
99const builtin = @import("builtin");
std/math/exp2.zig+1-1
......@@ -3,7 +3,7 @@
33// - exp2(+inf) = +inf
44// - exp2(nan) = nan
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const math = std.math;
88const expect = std.testing.expect;
99
std/math/expm1.zig+1-1
......@@ -5,7 +5,7 @@
55// - expm1(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111
std/math/expo2.zig+1-1
......@@ -1,4 +1,4 @@
1const math = @import("index.zig");
1const math = @import("../math.zig");
22
33pub fn expo2(x: var) @typeOf(x) {
44 const T = @typeOf(x);
std/math/fabs.zig+1-1
......@@ -3,7 +3,7 @@
33// - fabs(+-inf) = +inf
44// - fabs(nan) = nan
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const math = std.math;
88const expect = std.testing.expect;
99const maxInt = std.math.maxInt;
std/math/floor.zig+1-1
......@@ -6,7 +6,7 @@
66
77const builtin = @import("builtin");
88const expect = std.testing.expect;
9const std = @import("../index.zig");
9const std = @import("../std.zig");
1010const math = std.math;
1111
1212pub fn floor(x: var) @typeOf(x) {
std/math/fma.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44
std/math/frexp.zig+1-1
......@@ -4,7 +4,7 @@
44// - frexp(+-inf) = +-inf, 0
55// - frexp(nan) = nan, undefined
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010
std/math/hypot.zig+1-1
......@@ -5,7 +5,7 @@
55// - hypot(nan, y) = nan
66// - hypot(x, nan) = nan
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111const maxInt = std.math.maxInt;
std/math/ilogb.zig+1-1
......@@ -4,7 +4,7 @@
44// - ilogb(0) = maxInt(i32)
55// - ilogb(nan) = maxInt(i32)
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33
44pub fn inf(comptime T: type) T {
std/math/isfinite.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44const maxInt = std.math.maxInt;
std/math/isinf.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44const maxInt = std.math.maxInt;
std/math/isnan.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44const maxInt = std.math.maxInt;
std/math/isnormal.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44const maxInt = std.math.maxInt;
std/math/ln.zig+1-1
......@@ -5,7 +5,7 @@
55// - ln(x) = nan if x < 0
66// - ln(nan) = nan
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111const builtin = @import("builtin");
std/math/log.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const builtin = @import("builtin");
44const TypeId = builtin.TypeId;
std/math/log10.zig+1-1
......@@ -5,7 +5,7 @@
55// - log10(x) = nan if x < 0
66// - log10(nan) = nan
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const testing = std.testing;
1111const builtin = @import("builtin");
std/math/log1p.zig+1-1
......@@ -7,7 +7,7 @@
77// - log1p(nan) = nan
88
99const builtin = @import("builtin");
10const std = @import("../index.zig");
10const std = @import("../std.zig");
1111const math = std.math;
1212const expect = std.testing.expect;
1313
std/math/log2.zig+1-1
......@@ -5,7 +5,7 @@
55// - log2(x) = nan if x < 0
66// - log2(nan) = nan
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111const builtin = @import("builtin");
std/math/modf.zig+1-1
......@@ -3,7 +3,7 @@
33// - modf(+-inf) = +-inf, nan
44// - modf(nan) = nan, nan
55
6const std = @import("../index.zig");
6const std = @import("../std.zig");
77const math = std.math;
88const expect = std.testing.expect;
99const maxInt = std.math.maxInt;
std/math/nan.zig+1-1
......@@ -1,4 +1,4 @@
1const math = @import("index.zig");
1const math = @import("../math.zig");
22
33pub fn nan(comptime T: type) T {
44 return switch (T) {
std/math/pow.zig+1-1
......@@ -22,7 +22,7 @@
2222// pow(x, y) = nan for finite x < 0 and finite non-integer y
2323
2424const builtin = @import("builtin");
25const std = @import("../index.zig");
25const std = @import("../std.zig");
2626const math = std.math;
2727const expect = std.testing.expect;
2828
std/math/powi.zig+1-1
......@@ -9,7 +9,7 @@
99// powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 0
1010
1111const builtin = @import("builtin");
12const std = @import("../index.zig");
12const std = @import("../std.zig");
1313const math = std.math;
1414const assert = std.debug.assert;
1515const testing = std.testing;
std/math/round.zig+1-1
......@@ -6,7 +6,7 @@
66
77const builtin = @import("builtin");
88const expect = std.testing.expect;
9const std = @import("../index.zig");
9const std = @import("../std.zig");
1010const math = std.math;
1111
1212pub fn round(x: var) @typeOf(x) {
std/math/scalbn.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44
std/math/signbit.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const math = std.math;
33const expect = std.testing.expect;
44
std/math/sin.zig+1-1
......@@ -5,7 +5,7 @@
55// - sin(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111
std/math/sinh.zig+1-1
......@@ -5,7 +5,7 @@
55// - sinh(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111const expo2 = @import("expo2.zig").expo2;
std/math/sqrt.zig+1-1
......@@ -5,7 +5,7 @@
55// - sqrt(x) = nan if x < 0
66// - sqrt(nan) = nan
77
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111const builtin = @import("builtin");
std/math/tan.zig+1-1
......@@ -5,7 +5,7 @@
55// - tan(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111
std/math/tanh.zig+1-1
......@@ -5,7 +5,7 @@
55// - sinh(nan) = nan
66
77const builtin = @import("builtin");
8const std = @import("../index.zig");
8const std = @import("../std.zig");
99const math = std.math;
1010const expect = std.testing.expect;
1111const expo2 = @import("expo2.zig").expo2;
std/math/trunc.zig+1-1
......@@ -4,7 +4,7 @@
44// - trunc(+-inf) = +-inf
55// - trunc(nan) = nan
66
7const std = @import("../index.zig");
7const std = @import("../std.zig");
88const math = std.math;
99const expect = std.testing.expect;
1010const maxInt = std.math.maxInt;
std/mem.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const debug = std.debug;
33const assert = debug.assert;
44const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const mem = std.mem;
44const debug = std.debug;
55const testing = std.testing;
66const warn = debug.warn;
77
8const meta = @import("index.zig");
8const meta = @import("../meta.zig");
99
1010//This is necessary if we want to return generic functions directly because of how the
1111// the type erasure works. see: #1375
std/mutex.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const AtomicOrder = builtin.AtomicOrder;
44const AtomicRmwOp = builtin.AtomicRmwOp;
std/net.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const cstr = std.cstr;
33const unicode = std.unicode;
44const io = std.io;
std/os/darwin.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const c = std.c;
33const assert = std.debug.assert;
44const maxInt = std.math.maxInt;
std/os/file.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const os = std.os;
44const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const unicode = std.unicode;
44const mem = std.mem;
std/os/get_user_id.zig+1-1
......@@ -1,6 +1,6 @@
11const builtin = @import("builtin");
22const Os = builtin.Os;
3const os = @import("index.zig");
3const os = @import("../os.zig");
44const io = @import("../io.zig");
55
66pub 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 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const linux = std.os.linux;
33const socklen_t = linux.socklen_t;
44const 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 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const builtin = @import("builtin");
33const linux = std.os.linux;
44const expect = std.testing.expect;
std/os/linux/vdso.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const elf = std.elf;
33const linux = std.os.linux;
44const cstr = std.cstr;
std/os/linux/x86_64.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const linux = std.os.linux;
33const socklen_t = linux.socklen_t;
44const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const Os = builtin.Os;
44const debug = std.debug;
std/os/test.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const os = std.os;
33const expect = std.testing.expect;
44const io = std.io;
std/os/time.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const Os = builtin.Os;
44const 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 @@
1use @import("index.zig");
1use @import("../windows.zig");
22
33pub 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 @@
1use @import("index.zig");
1use @import("../windows.zig");
22
33pub 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;
262262
263263pub 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
267267pub const RTL_RUN_ONCE = extern struct {
268268 Ptr: ?*c_void,
269269};
270270
271pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE {
272 .Ptr = null,
273};
271pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
std/os/windows/ntdll.zig+1-1
......@@ -1,3 +1,3 @@
1use @import("index.zig");
1use @import("../windows.zig");
22
33pub 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 @@
1use @import("index.zig");
1use @import("../windows.zig");
22
33pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
44pub extern "ole32" stdcallcc fn CoUninitialize() void;
std/os/windows/shell32.zig+1-1
......@@ -1,4 +1,4 @@
1use @import("index.zig");
1use @import("../windows.zig");
22
33pub 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 @@
1const std = @import("../../index.zig");
1const std = @import("../../std.zig");
22const builtin = @import("builtin");
33const os = std.os;
44const unicode = std.unicode;
std/os/zen.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const assert = std.debug.assert;
33
44//////////////////////////
std/pdb.zig+2-4
......@@ -1,5 +1,5 @@
11const builtin = @import("builtin");
2const std = @import("index.zig");
2const std = @import("std.zig");
33const io = std.io;
44const math = std.math;
55const mem = std.mem;
......@@ -12,7 +12,6 @@ const ArrayList = std.ArrayList;
1212// Note: most of this is based on information gathered from LLVM source code,
1313// documentation and/or contributors.
1414
15
1615// https://llvm.org/docs/PDB/DbiStream.html#stream-header
1716pub const DbiStreamHeader = packed struct {
1817 VersionSignature: i32,
......@@ -393,10 +392,9 @@ pub const LineNumberEntry = packed struct {
393392 Flags: u32,
394393
395394 /// TODO runtime crash when I make the actual type of Flags this
396 const Flags = packed struct {
395 pub const Flags = packed struct {
397396 /// Start line number
398397 Start: u24,
399
400398 /// Delta of lines to the end of the expression. Still unclear.
401399 // TODO figure out the point of this field.
402400 End: u7,
std/priority_queue.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const Allocator = std.mem.Allocator;
33const debug = std.debug;
44const 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 @@
88// NOTE: This seems interesting but reference code is a bit hard to grok:
99// https://sbarral.github.io/etf.
1010
11const std = @import("../index.zig");
11const std = @import("../std.zig");
1212const math = std.math;
1313const Random = std.rand.Random;
1414
std/rb.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const mem = std.mem; // For mem.Compare
std/segmented_list.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const Allocator = std.mem.Allocator;
std/sort.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const mem = std.mem;
std/special/bootstrap.zig+1-1
......@@ -46,7 +46,7 @@ nakedcc fn _start() noreturn {
4646extern fn WinMainCRTStartup() noreturn {
4747 @setAlignStack(16);
4848 if (!builtin.single_threaded) {
49 _ = @import("../os/windows/tls.zig");
49 _ = @import("bootstrap_windows_tls.zig");
5050 }
5151 std.os.windows.ExitProcess(callMain());
5252}
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 {
134134 }
135135}
136136
137const math = @import("../math/index.zig");
137const math = std.math;
138138
139139export fn fmodf(x: f32, y: f32) f32 {
140140 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 @@
44
55const std = @import("std");
66const builtin = @import("builtin");
7const compiler_rt = @import("index.zig");
7const compiler_rt = @import("../compiler_rt.zig");
88
99pub extern fn __addtf3(a: f128, b: f128) f128 {
1010 return addXf3(f128, a, b);
std/special/compiler_rt/divti3.zig+1-1
......@@ -1,6 +1,6 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
3const compiler_rt = @import("../compiler_rt.zig");
44
55pub extern fn __divti3(a: i128, b: i128) i128 {
66 @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 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
3const compiler_rt = @import("../compiler_rt.zig");
44
55pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {
66 @setRuntimeSafety(builtin.is_test);
std/special/compiler_rt/multi3.zig+1-1
......@@ -1,5 +1,5 @@
11const builtin = @import("builtin");
2const compiler_rt = @import("index.zig");
2const compiler_rt = @import("../compiler_rt.zig");
33
44// Ported from git@github.com:llvm-project/llvm-project-20170507.git
55// ae684fad6d34858c014c94da69c15e7774a633c3
std/special/compiler_rt/udivmodti4.zig+1-1
......@@ -1,6 +1,6 @@
11const udivmod = @import("udivmod.zig").udivmod;
22const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
3const compiler_rt = @import("../compiler_rt.zig");
44
55pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) u128 {
66 @setRuntimeSafety(builtin.is_test);
std/special/compiler_rt/umodti3.zig+1-1
......@@ -1,6 +1,6 @@
11const udivmodti4 = @import("udivmodti4.zig");
22const builtin = @import("builtin");
3const compiler_rt = @import("index.zig");
3const compiler_rt = @import("../compiler_rt.zig");
44
55pub extern fn __umodti3(a: u128, b: u128) u128 {
66 @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
1818 std.os.abort();
1919 },
2020 else => {
21 const first_trace_addr = @ptrToInt(@returnAddress());
21 const first_trace_addr = @returnAddress();
2222 std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
2323 },
2424 }
std/spinlock.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const AtomicOrder = builtin.AtomicOrder;
44const AtomicRmwOp = builtin.AtomicRmwOp;
std/statically_initialized_mutex.zig+5-8
......@@ -1,4 +1,4 @@
1const std = @import("index.zig");
1const std = @import("std.zig");
22const builtin = @import("builtin");
33const AtomicOrder = builtin.AtomicOrder;
44const AtomicRmwOp = builtin.AtomicRmwOp;
......@@ -13,7 +13,7 @@ const windows = std.os.windows;
1313/// On Windows, this mutex allocates resources when it is
1414/// first used, and the resources cannot be freed.
1515/// On Linux, this is an alias of std.Mutex.
16pub const StaticallyInitializedMutex = switch(builtin.os) {
16pub const StaticallyInitializedMutex = switch (builtin.os) {
1717 builtin.Os.linux => std.Mutex,
1818 builtin.Os.windows => struct {
1919 lock: windows.CRITICAL_SECTION,
......@@ -28,7 +28,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {
2828 };
2929
3030 pub fn init() StaticallyInitializedMutex {
31 return StaticallyInitializedMutex {
31 return StaticallyInitializedMutex{
3232 .lock = undefined,
3333 .init_once = windows.INIT_ONCE_STATIC_INIT,
3434 };
......@@ -54,7 +54,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {
5454 pub fn acquire(self: *StaticallyInitializedMutex) Held {
5555 assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
5656 windows.EnterCriticalSection(&self.lock);
57 return Held { .mutex = self };
57 return Held{ .mutex = self };
5858 }
5959 },
6060 else => std.Mutex,
......@@ -89,10 +89,7 @@ test "std.StaticallyInitializedMutex" {
8989 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
9090 var a = &fixed_buffer_allocator.allocator;
9191
92
93 var context = TestContext{
94 .data = 0,
95 };
92 var context = TestContext{ .data = 0 };
9693
9794 if (builtin.single_threaded) {
9895 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 @@
11const builtin = @import("builtin");
22const TypeId = builtin.TypeId;
3const std = @import("index.zig");
3const std = @import("std.zig");
44
55/// This function is intended to be used only in tests. It prints diagnostics to stderr
66/// and then aborts when actual_error_union is not expected_error.
......@@ -44,7 +44,6 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
4444 TypeId.ComptimeFloat,
4545 TypeId.ComptimeInt,
4646 TypeId.Enum,
47 TypeId.Namespace,
4847 TypeId.Fn,
4948 TypeId.Promise,
5049 TypeId.Vector,
std/unicode.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("./index.zig");
1const std = @import("./std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const SegmentedList = std.SegmentedList;
......@@ -617,7 +617,7 @@ pub const Node = struct {
617617
618618 pub const DeclList = Root.DeclList;
619619
620 const InitArg = union(enum) {
620 pub const InitArg = union(enum) {
621621 None,
622622 Enum: ?*Node,
623623 Type: *Node,
......@@ -1744,7 +1744,7 @@ pub const Node = struct {
17441744 kind: Kind,
17451745 rhs: ?*Node,
17461746
1747 const Kind = union(enum) {
1747 pub const Kind = union(enum) {
17481748 Break: ?*Node,
17491749 Continue: ?*Node,
17501750 Return,
......@@ -2022,7 +2022,7 @@ pub const Node = struct {
20222022 kind: Kind,
20232023 rparen: TokenIndex,
20242024
2025 const Kind = union(enum) {
2025 pub const Kind = union(enum) {
20262026 Variable: *Identifier,
20272027 Return: *Node,
20282028 };
......@@ -2101,9 +2101,9 @@ pub const Node = struct {
21012101 clobbers: ClobberList,
21022102 rparen: TokenIndex,
21032103
2104 const OutputList = SegmentedList(*AsmOutput, 2);
2105 const InputList = SegmentedList(*AsmInput, 2);
2106 const ClobberList = SegmentedList(TokenIndex, 2);
2104 pub const OutputList = SegmentedList(*AsmOutput, 2);
2105 pub const InputList = SegmentedList(*AsmInput, 2);
2106 pub const ClobberList = SegmentedList(TokenIndex, 2);
21072107
21082108 pub fn iterate(self: *Asm, index: usize) ?*Node {
21092109 var i = index;
std/zig/bench.zig+1-1
......@@ -5,7 +5,7 @@ const Tokenizer = std.zig.Tokenizer;
55const Parser = std.zig.Parser;
66const io = std.io;
77
8const source = @embedFile("../os/index.zig");
8const source = @embedFile("../os.zig");
99var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
1010
1111pub 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 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const assert = std.debug.assert;
33const mem = std.mem;
44const ast = std.zig.ast;
std/zig/parse_string_literal.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const assert = std.debug.assert;
33
44const State = enum {
std/zig/render.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const mem = std.mem;
std/zig/tokenizer.zig+1-1
......@@ -1,4 +1,4 @@
1const std = @import("../index.zig");
1const std = @import("../std.zig");
22const mem = std.mem;
33
44pub const Token = struct {
test/build_examples.zig+2
......@@ -7,8 +7,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
77 cases.addC("example/hello_world/hello_libc.zig");
88 cases.add("example/cat/main.zig");
99 cases.add("example/guess_number/main.zig");
10 cases.addBuildFile("test/standalone/main_pkg_path/build.zig");
1011 cases.addBuildFile("example/shared_library/build.zig");
1112 cases.addBuildFile("example/mix_o_files/build.zig");
13 cases.addBuildFile("test/standalone/static_c_lib/build.zig");
1214 if (builtin.os != builtin.Os.macosx) {
1315 // TODO https://github.com/ziglang/zig/issues/1126
1416 cases.addBuildFile("test/standalone/issue_339/build.zig");
test/compile_errors.zig+701-690
......@@ -2,6 +2,122 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub 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
5121 cases.addTest(
6122 "not an enum type",
7123 \\export fn entry() void {
......@@ -18,7 +134,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18134 \\const InvalidToken = struct {};
19135 \\const ExpectedVarDeclOrFn = struct {};
20136 ,
21 ".tmp_source.zig:4:9: error: not an enum type",
137 "tmp.zig:4:9: error: not an enum type",
22138 );
23139
24140 cases.addTest(
......@@ -29,7 +145,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29145 \\ var x: AB = undefined;
30146 \\}
31147 ,
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}'",
33149 );
34150
35151 if (builtin.os == builtin.Os.linux) {
......@@ -40,7 +156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40156 \\ exit(0);
41157 \\}
42158 ,
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",
44160 );
45161
46162 cases.addTest(
......@@ -50,8 +166,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50166 \\ _ = c.printf(c"hello, world!\n");
51167 \\}
52168 ,
53 ".tmp_source.zig:1:11: error: C import failed",
54 ".tmp_source.zig:1:11: note: libc headers not available; compilation does not link against libc",
169 "tmp.zig:1:11: error: C import failed",
170 "tmp.zig:1:11: note: libc headers not available; compilation does not link against libc",
55171 );
56172 }
57173
......@@ -63,8 +179,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
63179 \\ var x = a + b;
64180 \\}
65181 ,
66 ".tmp_source.zig:4:15: error: operation caused overflow",
67 ".tmp_source.zig:4:15: note: when computing vector element at index 2",
182 "tmp.zig:4:15: error: operation caused overflow",
183 "tmp.zig:4:15: note: when computing vector element at index 2",
68184 );
69185
70186 cases.addTest(
......@@ -111,14 +227,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
111227 \\ B,
112228 \\};
113229 ,
114 ".tmp_source.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",
116 ".tmp_source.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",
118 ".tmp_source.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",
120 ".tmp_source.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",
230 "tmp.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
231 "tmp.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",
232 "tmp.zig:8:5: error: type 'anyerror' 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",
234 "tmp.zig:14:5: error: non-packed, non-extern struct 'U' 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",
236 "tmp.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
237 "tmp.zig:38:14: note: enum declaration does not specify an integer tag type",
122238 );
123239
124240 cases.addCase(x: {
......@@ -131,7 +247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
131247 \\ x += 1;
132248 \\}
133249 ,
134 ".tmp_source.zig:2:5: error: use of undeclared identifier 'x'",
250 "tmp.zig:2:5: error: use of undeclared identifier 'x'",
135251 );
136252 tc.expect_exact = true;
137253 break :x tc;
......@@ -143,7 +259,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
143259 \\ return 0;
144260 \\}
145261 ,
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'",
147263 );
148264
149265 cases.addTest(
......@@ -153,7 +269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
153269 \\ var y: [*c]c_void = x;
154270 \\}
155271 ,
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",
157273 );
158274
159275 cases.addTest(
......@@ -173,8 +289,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
173289 \\ var bar: Bar = undefined;
174290 \\}
175291 ,
176 ".tmp_source.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",
292 "tmp.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
293 "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
178294 );
179295
180296 cases.addTest(
......@@ -204,13 +320,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
204320 \\ var x: [*c]u32 = y;
205321 \\}
206322 ,
207 ".tmp_source.zig:3:27: error: cast increases pointer alignment",
208 ".tmp_source.zig:7:18: error: cast discards const qualifier",
209 ".tmp_source.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'",
211 ".tmp_source.zig:15:22: error: cast increases pointer alignment",
212 ".tmp_source.zig:19:21: error: cast discards const qualifier",
213 ".tmp_source.zig:23:22: error: expected type '[*c]u32', found '*u8'",
323 "tmp.zig:3:27: error: cast increases pointer alignment",
324 "tmp.zig:7:18: error: cast discards const qualifier",
325 "tmp.zig:11:19: error: expected type '*u32', found '[*c]u8'",
326 "tmp.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
327 "tmp.zig:15:22: error: cast increases pointer alignment",
328 "tmp.zig:19:21: error: cast discards const qualifier",
329 "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'",
214330 );
215331
216332 cases.addTest(
......@@ -220,7 +336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
220336 \\ var zig_ptr: *u8 = c_ptr;
221337 \\}
222338 ,
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'",
224340 );
225341
226342 cases.addTest(
......@@ -230,7 +346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
230346 \\ var zig_ptr: *u8 = c_ptr;
231347 \\}
232348 ,
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",
234350 );
235351
236352 cases.addTest(
......@@ -250,12 +366,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
250366 \\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
251367 \\}
252368 ,
253 ".tmp_source.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'",
255 ".tmp_source.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'",
257 ".tmp_source.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'",
369 "tmp.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
370 "tmp.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
371 "tmp.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
372 "tmp.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
373 "tmp.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
374 "tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
259375 );
260376
261377 cases.addTest(
......@@ -268,8 +384,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
268384 \\ var ptr: [*c]u8 = x;
269385 \\}
270386 ,
271 ".tmp_source.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'",
387 "tmp.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",
388 "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
273389 );
274390
275391 cases.addTest(
......@@ -279,7 +395,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
279395 \\ const T = [*c]Foo;
280396 \\}
281397 ,
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'",
283399 );
284400
285401 cases.addCase(x: {
......@@ -294,7 +410,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
294410 \\ inline while (i < n) : (i += 1) { @compileLog("!@#$"); }
295411 \\}
296412 ,
297 ".tmp_source.zig:7:39: error: found compile log statement",
413 "tmp.zig:7:39: error: found compile log statement",
298414 );
299415 tc.expect_exact = true;
300416 break :x tc;
......@@ -306,7 +422,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
306422 \\ 'a'.* = 1;
307423 \\}
308424 ,
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'",
310426 );
311427
312428 cases.addTest(
......@@ -315,7 +431,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
315431 \\ const x = 'a'.*[0..];
316432 \\}
317433 ,
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'",
319435 );
320436
321437 cases.addTest(
......@@ -324,14 +440,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
324440 \\ var z = @truncate(u8, u16(undefined));
325441 \\}
326442 ,
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",
328444 );
329445
330446 cases.addTest(
331447 "return invalid type from test",
332448 \\test "example" { return 1; }
333449 ,
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'",
335451 );
336452
337453 cases.add(
......@@ -341,7 +457,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
341457 \\ return x;
342458 \\}
343459 ,
344 ".tmp_source.zig:1:13: error: threadlocal variable cannot be constant",
460 "tmp.zig:1:13: error: threadlocal variable cannot be constant",
345461 );
346462
347463 cases.add(
......@@ -350,7 +466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
350466 \\ threadlocal var x: i32 = 1234;
351467 \\}
352468 ,
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",
354470 );
355471
356472 cases.add(
......@@ -359,7 +475,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
359475 \\ var oops = @bitCast(u7, byte);
360476 \\}
361477 ,
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",
363479 );
364480
365481 cases.add(
......@@ -371,7 +487,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
371487 \\ return 5678;
372488 \\}
373489 ,
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.",
375491 );
376492
377493 cases.add(
......@@ -383,8 +499,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
383499 \\ return 5678;
384500 \\}
385501 ,
386 ".tmp_source.zig:2:9: error: expected error set type, found 'bool'",
387 ".tmp_source.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
502 "tmp.zig:2:9: error: expected error set type, found 'bool'",
503 "tmp.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
388504 );
389505
390506 cases.add(
......@@ -393,7 +509,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
393509 \\ @compileLog(@ptrCast(*const c_void, &entry));
394510 \\}
395511 ,
396 ".tmp_source.zig:2:5: error: found compile log statement",
512 "tmp.zig:2:5: error: found compile log statement",
397513 );
398514
399515 cases.add(
......@@ -413,8 +529,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
413529 \\ };
414530 \\}
415531 ,
416 ".tmp_source.zig:5:9: error: duplicate switch value",
417 ".tmp_source.zig:12:9: error: duplicate switch value",
532 "tmp.zig:5:9: error: duplicate switch value",
533 "tmp.zig:12:9: error: duplicate switch value",
418534 );
419535
420536 cases.add(
......@@ -430,8 +546,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
430546 \\ };
431547 \\}
432548 ,
433 ".tmp_source.zig:2:15: error: switch must handle all possibilities",
434 ".tmp_source.zig:7:15: error: switch must handle all possibilities",
549 "tmp.zig:2:15: error: switch must handle all possibilities",
550 "tmp.zig:7:15: error: switch must handle all possibilities",
435551 );
436552
437553 cases.add(
......@@ -443,7 +559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
443559 \\ const deref = int_ptr.*;
444560 \\}
445561 ,
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",
447563 );
448564
449565 cases.add(
......@@ -454,8 +570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
454570 \\ do_the_thing(bar);
455571 \\}
456572 ,
457 ".tmp_source.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'",
573 "tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
574 "tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
459575 );
460576
461577 cases.add(
......@@ -469,8 +585,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
469585 \\ const unsigned: u32 = value;
470586 \\}
471587 ,
472 ".tmp_source.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'",
588 "tmp.zig:3:36: 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'",
474590 );
475591
476592 cases.add(
......@@ -488,9 +604,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
488604 \\ var byte: u8 = spartan_count;
489605 \\}
490606 ,
491 ".tmp_source.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'",
493 ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'",
607 "tmp.zig:3:31: 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'",
609 "tmp.zig:11:20: error: expected type 'u8', found 'u16'",
494610 );
495611
496612 cases.add(
......@@ -500,7 +616,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
500616 \\ const y: f32 = x;
501617 \\}
502618 ,
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",
504620 );
505621
506622 cases.add(
......@@ -510,7 +626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
510626 \\
511627 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
512628 ,
513 ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'",
629 "tmp.zig:2:14: error: expected type 'f32', found 'f64'",
514630 );
515631
516632 cases.add(
......@@ -522,28 +638,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
522638 \\ var x: i65536 = 1;
523639 \\}
524640 ,
525 ".tmp_source.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",
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",
641 "tmp.zig:2:31: error: integer value 65536 cannot be implicitly casted to type 'u16'",
642 "tmp.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",
547643 );
548644
549645 cases.add(
......@@ -556,7 +652,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
556652 \\ const car = Car.init();
557653 \\}
558654 ,
559 ".tmp_source.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",
655 "tmp.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",
560656 );
561657
562658 cases.add(
......@@ -568,7 +664,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
568664 \\ var ptr2: *c_void = &b;
569665 \\}
570666 ,
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'",
572668 );
573669
574670 cases.add(
......@@ -584,7 +680,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
584680 \\ const field = @typeInfo(Struct).Struct.fields[index];
585681 \\}
586682 ,
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",
588684 );
589685
590686 cases.add(
......@@ -598,7 +694,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
598694 \\ _ = @typeName(Foo(i32));
599695 \\}
600696 ,
601 ".tmp_source.zig:2:5: error: found compile log statement",
697 "tmp.zig:2:5: error: found compile log statement",
602698 );
603699
604700 cases.add(
......@@ -608,7 +704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
608704 \\ var b = a[0..10];
609705 \\}
610706 ,
611 ".tmp_source.zig:3:14: error: slice of undefined",
707 "tmp.zig:3:14: error: slice of undefined",
612708 );
613709
614710 cases.add(
......@@ -618,7 +714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
618714 \\ const sliceA: []u8 = &buffer;
619715 \\}
620716 ,
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'",
622718 );
623719
624720 cases.add(
......@@ -628,7 +724,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
628724 \\ _ = a.*.len;
629725 \\}
630726 ,
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'",
632728 );
633729
634730 cases.add(
......@@ -639,9 +735,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
639735 \\ return p == null;
640736 \\}
641737 ,
642 ".tmp_source.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",
644 ".tmp_source.zig:3:24: note: '?*u0' has in-memory bits",
738 "tmp.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation",
739 "tmp.zig:3:31: note: '*u0' has no in-memory bits",
740 "tmp.zig:3:24: note: '?*u0' has in-memory bits",
645741 );
646742
647743 cases.add(
......@@ -651,7 +747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
651747 \\ _ = &x == null;
652748 \\}
653749 ,
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",
655751 );
656752
657753 cases.add(
......@@ -663,10 +759,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
663759 \\ const Errors = error{} || u16;
664760 \\}
665761 ,
666 ".tmp_source.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",
668 ".tmp_source.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",
762 "tmp.zig:2:20: error: expected error set type, found type 'u8'",
763 "tmp.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",
764 "tmp.zig:5:31: error: expected error set type, found type 'u16'",
765 "tmp.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",
670766 );
671767
672768 cases.add(
......@@ -684,7 +780,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
684780 \\ const S = Gen();
685781 \\}
686782 ,
687 ".tmp_source.zig:2:12: error: use of undeclared identifier 'T'",
783 "tmp.zig:2:12: error: use of undeclared identifier 'T'",
688784 );
689785
690786 cases.add(
......@@ -695,7 +791,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
695791 \\ f(i32);
696792 \\}
697793 ,
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",
699795 );
700796
701797 cases.add(
......@@ -713,9 +809,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
713809 \\ var x = func(3);
714810 \\}
715811 ,
716 ".tmp_source.zig:4:24: error: 'y' not accessible from inner function",
717 ".tmp_source.zig:3:28: note: crossed function definition here",
718 ".tmp_source.zig:1:10: note: declared here",
812 "tmp.zig:4:24: error: 'y' not accessible from inner function",
813 "tmp.zig:3:28: note: crossed function definition here",
814 "tmp.zig:1:10: note: declared here",
719815 );
720816
721817 cases.add(
......@@ -724,7 +820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
724820 \\ const x = @intToFloat(f32, 1.1);
725821 \\}
726822 ,
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'",
728824 );
729825
730826 cases.add(
......@@ -733,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
733829 \\ const x = @floatToInt(i32, i32(54));
734830 \\}
735831 ,
736 ".tmp_source.zig:2:35: error: expected float type, found 'i32'",
832 "tmp.zig:2:35: error: expected float type, found 'i32'",
737833 );
738834
739835 cases.add(
......@@ -742,7 +838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
742838 \\ const x = @floatToInt(i8, 200);
743839 \\}
744840 ,
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'",
746842 );
747843
748844 cases.add(
......@@ -754,7 +850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
754850 \\ const int_val = int_ptr.*;
755851 \\}
756852 ,
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",
758854 );
759855
760856 cases.add(
......@@ -767,7 +863,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
767863 \\ const a = items[0];
768864 \\}
769865 ,
770 ".tmp_source.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
866 "tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
771867 );
772868
773869 cases.add(
......@@ -778,7 +874,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
778874 \\ @noInlineCall(foo);
779875 \\}
780876 ,
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",
782878 );
783879
784880 cases.add(
......@@ -795,8 +891,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
795891 \\ }
796892 \\}
797893 ,
798 ".tmp_source.zig:6:19: error: comptime control flow inside runtime block",
799 ".tmp_source.zig:5:9: note: runtime block created here",
894 "tmp.zig:6:19: error: comptime control flow inside runtime block",
895 "tmp.zig:5:9: note: runtime block created here",
800896 );
801897
802898 cases.add(
......@@ -812,8 +908,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
812908 \\ }
813909 \\}
814910 ,
815 ".tmp_source.zig:6:13: error: comptime control flow inside runtime block",
816 ".tmp_source.zig:5:9: note: runtime block created here",
911 "tmp.zig:6:13: error: comptime control flow inside runtime block",
912 "tmp.zig:5:9: note: runtime block created here",
817913 );
818914
819915 cases.add(
......@@ -827,8 +923,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
827923 \\ }
828924 \\}
829925 ,
830 ".tmp_source.zig:5:23: error: comptime control flow inside runtime block",
831 ".tmp_source.zig:5:9: note: runtime block created here",
926 "tmp.zig:5:23: error: comptime control flow inside runtime block",
927 "tmp.zig:5:9: note: runtime block created here",
832928 );
833929
834930 cases.add(
......@@ -842,8 +938,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
842938 \\ }
843939 \\}
844940 ,
845 ".tmp_source.zig:5:25: error: comptime control flow inside runtime block",
846 ".tmp_source.zig:5:9: note: runtime block created here",
941 "tmp.zig:5:25: error: comptime control flow inside runtime block",
942 "tmp.zig:5:9: note: runtime block created here",
847943 );
848944
849945 cases.add(
......@@ -857,8 +953,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
857953 \\ }
858954 \\}
859955 ,
860 ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",
861 ".tmp_source.zig:5:9: note: runtime block created here",
956 "tmp.zig:5:20: error: comptime control flow inside runtime block",
957 "tmp.zig:5:9: note: runtime block created here",
862958 );
863959
864960 cases.add(
......@@ -872,8 +968,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
872968 \\ }
873969 \\}
874970 ,
875 ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",
876 ".tmp_source.zig:5:9: note: runtime block created here",
971 "tmp.zig:5:20: error: comptime control flow inside runtime block",
972 "tmp.zig:5:9: note: runtime block created here",
877973 );
878974
879975 cases.add(
......@@ -887,8 +983,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
887983 \\ }
888984 \\}
889985 ,
890 ".tmp_source.zig:5:22: error: comptime control flow inside runtime block",
891 ".tmp_source.zig:5:9: note: runtime block created here",
986 "tmp.zig:5:22: error: comptime control flow inside runtime block",
987 "tmp.zig:5:9: note: runtime block created here",
892988 );
893989
894990 cases.add(
......@@ -904,7 +1000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9041000 \\ };
9051001 \\}
9061002 ,
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",
9081004 );
9091005
9101006 cases.add(
......@@ -914,24 +1010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9141010 \\ foo();
9151011 \\}
9161012 ,
917 ".tmp_source.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",
1013 "tmp.zig:1:1: error: non-extern function has no body",
9351014 );
9361015
9371016 cases.add(
......@@ -942,7 +1021,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9421021 \\ return handle_undef == handle_dummy;
9431022 \\}
9441023 ,
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",
9461025 );
9471026
9481027 cases.add(
......@@ -952,7 +1031,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9521031 \\ return handle_undef == @handle();
9531032 \\}
9541033 ,
955 ".tmp_source.zig:3:28: error: @handle() in non-async function",
1034 "tmp.zig:3:28: error: @handle() in non-async function",
9561035 );
9571036
9581037 cases.add(
......@@ -962,8 +1041,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9621041 \\ return _;
9631042 \\}
9641043 ,
965 ".tmp_source.zig:2:5: error: `_` is not a declarable symbol",
966 ".tmp_source.zig:3:12: error: use of undeclared identifier '_'",
1044 "tmp.zig:2:5: error: `_` is not a declarable symbol",
1045 "tmp.zig:3:12: error: use of undeclared identifier '_'",
9671046 );
9681047
9691048 cases.add(
......@@ -976,7 +1055,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9761055 \\ }
9771056 \\}
9781057 ,
979 ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",
1058 "tmp.zig:4:20: error: use of undeclared identifier '_'",
9801059 );
9811060
9821061 cases.add(
......@@ -992,7 +1071,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
9921071 \\ return 1;
9931072 \\}
9941073 ,
995 ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",
1074 "tmp.zig:4:20: error: use of undeclared identifier '_'",
9961075 );
9971076
9981077 cases.add(
......@@ -1010,7 +1089,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10101089 \\ return error.optionalReturnError;
10111090 \\}
10121091 ,
1013 ".tmp_source.zig:6:17: error: use of undeclared identifier '_'",
1092 "tmp.zig:6:17: error: use of undeclared identifier '_'",
10141093 );
10151094
10161095 cases.add(
......@@ -1030,9 +1109,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10301109 \\ while (x) |_| returns() else |_| unreachable;
10311110 \\}
10321111 ,
1033 ".tmp_source.zig:5:25: error: expression value is ignored",
1034 ".tmp_source.zig:9:26: error: expression value is ignored",
1035 ".tmp_source.zig:13:26: error: expression value is ignored",
1112 "tmp.zig:5:25: error: expression value is ignored",
1113 "tmp.zig:9:26: error: expression value is ignored",
1114 "tmp.zig:13:26: error: expression value is ignored",
10361115 );
10371116
10381117 cases.add(
......@@ -1043,7 +1122,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10431122 \\ dump(a);
10441123 \\}
10451124 ,
1046 ".tmp_source.zig:1:9: error: missing parameter name",
1125 "tmp.zig:1:9: error: missing parameter name",
10471126 );
10481127
10491128 cases.add(
......@@ -1057,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10571136 \\ for (xx) |f| {}
10581137 \\}
10591138 ,
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",
10611140 );
10621141
10631142 cases.add(
......@@ -1068,7 +1147,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10681147 \\ f(g);
10691148 \\}
10701149 ,
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",
10721151 );
10731152
10741153 cases.add(
......@@ -1082,7 +1161,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10821161 \\};
10831162 \\export fn entry(bar: *Bar) void {}
10841163 ,
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'",
10861165 );
10871166
10881167 cases.add(
......@@ -1095,7 +1174,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10951174 \\ command.exec();
10961175 \\}
10971176 ,
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",
10991178 );
11001179
11011180 cases.add(
......@@ -1108,7 +1187,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11081187 \\ command.exec();
11091188 \\}
11101189 ,
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",
11121191 );
11131192
11141193 cases.add(
......@@ -1118,7 +1197,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11181197 \\ const aligned = @alignCast(4, ptr);
11191198 \\}
11201199 ,
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",
11221201 );
11231202
11241203 cases.add(
......@@ -1127,7 +1206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11271206 \\ return @ptrToInt(&{}) == @ptrToInt(&{});
11281207 \\}
11291208 ,
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",
11311210 );
11321211
11331212 cases.add(
......@@ -1136,7 +1215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11361215 \\ return @popCount(x);
11371216 \\}
11381217 ,
1139 ".tmp_source.zig:2:22: error: expected integer type, found 'f32'",
1218 "tmp.zig:2:22: error: expected integer type, found 'f32'",
11401219 );
11411220
11421221 cases.add(
......@@ -1145,7 +1224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11451224 \\ _ = @popCount(-1);
11461225 \\}
11471226 ,
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",
11491228 );
11501229
11511230 cases.addCase(x: {
......@@ -1161,10 +1240,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11611240 \\
11621241 \\fn bar(x: *b.Foo) void {}
11631242 ,
1164 ".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'",
1165 ".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'",
1166 "a.zig:1:17: note: Foo declared here",
1167 "b.zig:1:17: note: Foo declared here",
1243 "tmp.zig:6:10: error: expected type '*b.Foo', found '*a.Foo'",
1244 "tmp.zig:6:10: note: pointer type child 'a.Foo' cannot cast into pointer type child 'b.Foo'",
1245 "a.zig:1:17: note: a.Foo declared here",
1246 "b.zig:1:17: note: b.Foo declared here",
11681247 );
11691248
11701249 tc.addSourceFile("a.zig",
......@@ -1182,19 +1261,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11821261 break :x tc;
11831262 });
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
11981264 cases.add(
11991265 "@floatToInt comptime safety",
12001266 \\comptime {
......@@ -1207,9 +1273,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12071273 \\ _ = @floatToInt(u8, f32(256.1));
12081274 \\}
12091275 ,
1210 ".tmp_source.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'",
1212 ".tmp_source.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
1276 "tmp.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",
1277 "tmp.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",
1278 "tmp.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
12131279 );
12141280
12151281 cases.add(
......@@ -1218,7 +1284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12181284 \\ const a: fn () c_void = undefined;
12191285 \\}
12201286 ,
1221 ".tmp_source.zig:2:20: error: return type cannot be opaque",
1287 "tmp.zig:2:20: error: return type cannot be opaque",
12221288 );
12231289
12241290 cases.add(
......@@ -1231,7 +1297,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12311297 \\ var y = p.*;
12321298 \\}
12331299 ,
1234 ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'",
1300 "tmp.zig:4:23: error: expected type '*?*i32', found '**i32'",
12351301 );
12361302
12371303 cases.add(
......@@ -1240,7 +1306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12401306 \\ const x: [*]const bool = true;
12411307 \\}
12421308 ,
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'",
12441310 );
12451311
12461312 cases.add(
......@@ -1249,7 +1315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12491315 \\ return x.*;
12501316 \\}
12511317 ,
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'",
12531319 );
12541320
12551321 cases.add(
......@@ -1262,14 +1328,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12621328 \\ foo.a += 1;
12631329 \\}
12641330 ,
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",
12661332 );
12671333
12681334 cases.add(
12691335 "unknown length pointer to opaque",
12701336 \\export const T = [*]@OpaqueType();
12711337 ,
1272 ".tmp_source.zig:1:18: error: unknown-length pointer to opaque",
1338 "tmp.zig:1:18: error: unknown-length pointer to opaque",
12731339 );
12741340
12751341 cases.add(
......@@ -1285,7 +1351,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12851351 \\ var rule_set = try Foo.init();
12861352 \\}
12871353 ,
1288 ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'",
1354 "tmp.zig:2:13: error: expected type 'i32', found 'type'",
12891355 );
12901356
12911357 cases.add(
......@@ -1294,7 +1360,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12941360 \\ const slice = ptr[0..2];
12951361 \\}
12961362 ,
1297 ".tmp_source.zig:2:22: error: slice of single-item pointer",
1363 "tmp.zig:2:22: error: slice of single-item pointer",
12981364 );
12991365
13001366 cases.add(
......@@ -1303,7 +1369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13031369 \\ return ptr[1];
13041370 \\}
13051371 ,
1306 ".tmp_source.zig:2:15: error: index of single-item pointer",
1372 "tmp.zig:2:15: error: index of single-item pointer",
13071373 );
13081374
13091375 cases.add(
......@@ -1319,10 +1385,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13191385 \\ return null;
13201386 \\}
13211387 ,
1322 ".tmp_source.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'",
1324 ".tmp_source.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",
1388 "tmp.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",
1389 "tmp.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",
1390 "tmp.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",
1391 "tmp.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
13261392 );
13271393
13281394 cases.add(
......@@ -1339,14 +1405,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13391405 \\ Filled,
13401406 \\};
13411407 ,
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'",
13431409 );
13441410
13451411 cases.add(
13461412 "invalid field access in comptime",
13471413 \\comptime { var x = doesnt_exist.whatever; }
13481414 ,
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'",
13501416 );
13511417
13521418 cases.add(
......@@ -1367,8 +1433,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13671433 \\ }
13681434 \\}
13691435 ,
1370 ".tmp_source.zig:12:9: error: cannot suspend inside suspend block",
1371 ".tmp_source.zig:11:5: note: other suspend block here",
1436 "tmp.zig:12:9: error: cannot suspend inside suspend block",
1437 "tmp.zig:11:5: note: other suspend block here",
13721438 );
13731439
13741440 cases.add(
......@@ -1378,8 +1444,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13781444 \\}
13791445 \\inline fn b() void { }
13801446 ,
1381 ".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",
1382 ".tmp_source.zig:4:1: note: declared here",
1447 "tmp.zig:2:5: error: functions marked inline must be stored in const or comptime var",
1448 "tmp.zig:4:1: note: declared here",
13831449 );
13841450
13851451 cases.add(
......@@ -1389,7 +1455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13891455 \\ @panic(e);
13901456 \\}
13911457 ,
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}'",
13931459 );
13941460
13951461 cases.add(
......@@ -1403,8 +1469,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14031469 \\ var tagName = @tagName(fi);
14041470 \\}
14051471 ,
1406 ".tmp_source.zig:7:19: error: union has no associated enum",
1407 ".tmp_source.zig:1:18: note: declared here",
1472 "tmp.zig:7:19: error: union has no associated enum",
1473 "tmp.zig:1:18: note: declared here",
14081474 );
14091475
14101476 cases.add(
......@@ -1417,7 +1483,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14171483 \\ return error.ShouldBeCompileError;
14181484 \\}
14191485 ,
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}'",
14211487 );
14221488
14231489 cases.add(
......@@ -1426,7 +1492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14261492 \\ var s = (struct{v: var}){.v=i32(10)};
14271493 \\}
14281494 ,
1429 ".tmp_source.zig:2:23: error: invalid token: 'var'",
1495 "tmp.zig:2:23: error: invalid token: 'var'",
14301496 );
14311497
14321498 cases.add(
......@@ -1436,7 +1502,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14361502 \\ const y = @ptrCast(*i32, &x);
14371503 \\}
14381504 ,
1439 ".tmp_source.zig:3:15: error: cast discards const qualifier",
1505 "tmp.zig:3:15: error: cast discards const qualifier",
14401506 );
14411507
14421508 cases.add(
......@@ -1445,7 +1511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14451511 \\ const slice = ([*]i32)(undefined)[0..1];
14461512 \\}
14471513 ,
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",
14491515 );
14501516
14511517 cases.add(
......@@ -1460,7 +1526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14601526 \\ a(c);
14611527 \\}
14621528 ,
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'",
14641530 );
14651531
14661532 cases.add(
......@@ -1474,7 +1540,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14741540 \\ }
14751541 \\}
14761542 ,
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'",
14781544 );
14791545
14801546 cases.add(
......@@ -1485,7 +1551,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14851551 \\fn foo() !void {
14861552 \\}
14871553 ,
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",
14891555 );
14901556
14911557 cases.add(
......@@ -1504,8 +1570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15041570 \\ }
15051571 \\}
15061572 ,
1507 ".tmp_source.zig:2:26: error: error.Baz not handled in switch",
1508 ".tmp_source.zig:2:26: error: error.Bar not handled in switch",
1573 "tmp.zig:2:26: error: error.Baz not handled in switch",
1574 "tmp.zig:2:26: error: error.Bar not handled in switch",
15091575 );
15101576
15111577 cases.add(
......@@ -1526,8 +1592,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15261592 \\ }
15271593 \\}
15281594 ,
1529 ".tmp_source.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
1530 ".tmp_source.zig:3:14: note: other value is here",
1595 "tmp.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
1596 "tmp.zig:3:14: note: other value is here",
15311597 );
15321598
15331599 cases.add("invalid cast from integral type to enum",
......@@ -1542,7 +1608,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15421608 \\ E.One => {},
15431609 \\ }
15441610 \\}
1545 , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'");
1611 , "tmp.zig:9:10: error: expected type 'usize', found 'E'");
15461612
15471613 cases.add(
15481614 "range operator in switch used on error set",
......@@ -1560,7 +1626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15601626 \\ }
15611627 \\}
15621628 ,
1563 ".tmp_source.zig:3:17: error: operator not allowed for errors",
1629 "tmp.zig:3:17: error: operator not allowed for errors",
15641630 );
15651631
15661632 cases.add(
......@@ -1569,7 +1635,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15691635 \\ const z: ?fn()!void = null;
15701636 \\}
15711637 ,
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",
15731639 );
15741640
15751641 cases.add(
......@@ -1579,7 +1645,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15791645 \\ const z = Foo.Bar;
15801646 \\}
15811647 ,
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'",
15831649 );
15841650
15851651 cases.add(
......@@ -1588,7 +1654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
15881654 \\ const z = i32!i32;
15891655 \\}
15901656 ,
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'",
15921658 );
15931659
15941660 cases.add(
......@@ -1604,7 +1670,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16041670 \\ }
16051671 \\}
16061672 ,
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",
16081674 );
16091675
16101676 cases.add(
......@@ -1613,7 +1679,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16131679 \\ const z = error.A > error.B;
16141680 \\}
16151681 ,
1616 ".tmp_source.zig:2:23: error: operator not allowed for errors",
1682 "tmp.zig:2:23: error: operator not allowed for errors",
16171683 );
16181684
16191685 cases.add(
......@@ -1625,7 +1691,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16251691 \\ var y = @errSetCast(Set2, x);
16261692 \\}
16271693 ,
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'",
16291695 );
16301696
16311697 cases.add(
......@@ -1638,9 +1704,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16381704 \\ return error.B;
16391705 \\}
16401706 ,
1641 ".tmp_source.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'",
1643 ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set",
1707 "tmp.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'",
1708 "tmp.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'",
1709 "tmp.zig:3:35: note: cannot cast global error set into smaller set",
16441710 );
16451711
16461712 cases.add(
......@@ -1653,10 +1719,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16531719 \\ return error.B;
16541720 \\}
16551721 ,
1656 ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",
1657 ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set",
1722 "tmp.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",
1723 "tmp.zig:3:31: note: cannot cast global error set into smaller set",
16581724 );
1659
16601725 cases.add(
16611726 "recursive inferred error set",
16621727 \\export fn entry() void {
......@@ -1666,7 +1731,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16661731 \\ try foo();
16671732 \\}
16681733 ,
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",
16701735 );
16711736
16721737 cases.add(
......@@ -1680,8 +1745,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16801745 \\ var x: Set2 = set1;
16811746 \\}
16821747 ,
1683 ".tmp_source.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",
1748 "tmp.zig:7:19: error: expected type 'Set2', found 'Set1'",
1749 "tmp.zig:1:23: note: 'error.B' not a member of destination error set",
16851750 );
16861751
16871752 cases.add(
......@@ -1695,7 +1760,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16951760 \\ var y = @intToError(x);
16961761 \\}
16971762 ,
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",
16991764 );
17001765
17011766 cases.add(
......@@ -1713,7 +1778,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17131778 \\ var y = @errSetCast(Set2, @intToError(x));
17141779 \\}
17151780 ,
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'",
17171782 );
17181783
17191784 cases.add(
......@@ -1722,7 +1787,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17221787 \\ _ = @memberCount(anyerror);
17231788 \\}
17241789 ,
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",
17261791 );
17271792
17281793 cases.add(
......@@ -1735,8 +1800,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17351800 \\ const a: Foo = undefined;
17361801 \\}
17371802 ,
1738 ".tmp_source.zig:3:5: error: duplicate error: 'Bar'",
1739 ".tmp_source.zig:2:5: note: other error here",
1803 "tmp.zig:3:5: error: duplicate error: 'Bar'",
1804 "tmp.zig:2:5: note: other error here",
17401805 );
17411806
17421807 cases.add(
......@@ -1745,7 +1810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17451810 \\ const x = usize(-10);
17461811 \\}
17471812 ,
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'",
17491814 );
17501815
17511816 cases.add(
......@@ -1755,7 +1820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17551820 \\ var arr: [v]u8 = undefined;
17561821 \\}
17571822 ,
1758 ".tmp_source.zig:1:1: error: unable to infer variable type",
1823 "tmp.zig:1:1: error: unable to infer variable type",
17591824 );
17601825
17611826 cases.add(
......@@ -1768,8 +1833,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17681833 \\ const a: Foo = undefined;
17691834 \\}
17701835 ,
1771 ".tmp_source.zig:3:5: error: duplicate struct field: 'Bar'",
1772 ".tmp_source.zig:2:5: note: other field here",
1836 "tmp.zig:3:5: error: duplicate struct field: 'Bar'",
1837 "tmp.zig:2:5: note: other field here",
17731838 );
17741839
17751840 cases.add(
......@@ -1782,8 +1847,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17821847 \\ const a: Foo = undefined;
17831848 \\}
17841849 ,
1785 ".tmp_source.zig:3:5: error: duplicate union field: 'Bar'",
1786 ".tmp_source.zig:2:5: note: other field here",
1850 "tmp.zig:3:5: error: duplicate union field: 'Bar'",
1851 "tmp.zig:2:5: note: other field here",
17871852 );
17881853
17891854 cases.add(
......@@ -1797,8 +1862,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17971862 \\ const a: Foo = undefined;
17981863 \\}
17991864 ,
1800 ".tmp_source.zig:3:5: error: duplicate enum field: 'Bar'",
1801 ".tmp_source.zig:2:5: note: other field here",
1865 "tmp.zig:3:5: error: duplicate enum field: 'Bar'",
1866 "tmp.zig:2:5: note: other field here",
18021867 );
18031868
18041869 cases.add(
......@@ -1808,15 +1873,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18081873 \\}
18091874 \\nakedcc fn foo() void { }
18101875 ,
1811 ".tmp_source.zig:2:5: error: unable to call function with naked calling convention",
1812 ".tmp_source.zig:4:1: note: declared here",
1876 "tmp.zig:2:5: error: unable to call function with naked calling convention",
1877 "tmp.zig:4:1: note: declared here",
18131878 );
18141879
18151880 cases.add(
18161881 "function with invalid return type",
18171882 \\export fn foo() boid {}
18181883 ,
1819 ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'",
1884 "tmp.zig:1:17: error: use of undeclared identifier 'boid'",
18201885 );
18211886
18221887 cases.add(
......@@ -1824,7 +1889,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18241889 \\const Foo = enum { A, B, C };
18251890 \\export fn entry(foo: Foo) void { }
18261891 ,
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'",
18281893 );
18291894
18301895 cases.add(
......@@ -1836,7 +1901,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18361901 \\};
18371902 \\export fn entry(foo: Foo) void { }
18381903 ,
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'",
18401905 );
18411906
18421907 cases.add(
......@@ -1848,7 +1913,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18481913 \\};
18491914 \\export fn entry(foo: Foo) void { }
18501915 ,
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'",
18521917 );
18531918
18541919 cases.add(
......@@ -1860,7 +1925,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18601925 \\ switch (f) {}
18611926 \\}
18621927 ,
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",
18641929 );
18651930
18661931 cases.add(
......@@ -1869,7 +1934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18691934 \\ var a = 1 >> -1;
18701935 \\}
18711936 ,
1872 ".tmp_source.zig:2:18: error: shift by negative value -1",
1937 "tmp.zig:2:18: error: shift by negative value -1",
18731938 );
18741939
18751940 cases.add(
......@@ -1880,7 +1945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18801945 \\ }
18811946 \\}
18821947 ,
1883 ".tmp_source.zig:3:9: error: encountered @panic at compile-time",
1948 "tmp.zig:3:9: error: encountered @panic at compile-time",
18841949 );
18851950
18861951 cases.add(
......@@ -1910,7 +1975,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19101975 \\ bogus;
19111976 \\}
19121977 ,
1913 ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'",
1978 "tmp.zig:8:5: error: use of undeclared identifier 'bogus'",
19141979 );
19151980
19161981 cases.add(
......@@ -1923,7 +1988,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19231988 \\ }
19241989 \\}
19251990 ,
1926 ".tmp_source.zig:4:13: error: label not found: 'outer'",
1991 "tmp.zig:4:13: error: label not found: 'outer'",
19271992 );
19281993
19291994 cases.add(
......@@ -1937,7 +2002,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19372002 \\ }
19382003 \\}
19392004 ,
1940 ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'",
2005 "tmp.zig:5:13: error: labeled loop not found: 'outer'",
19412006 );
19422007
19432008 cases.add(
......@@ -1950,8 +2015,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19502015 \\
19512016 \\extern fn bar(x: *void) void { }
19522017 ,
1953 ".tmp_source.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'",
2018 "tmp.zig:1:30: 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'",
19552020 );
19562021
19572022 cases.add(
......@@ -1963,7 +2028,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19632028 \\ var bad = {};
19642029 \\}
19652030 ,
1966 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2031 "tmp.zig:5:5: error: expected token ';', found 'var'",
19672032 );
19682033
19692034 cases.add(
......@@ -1975,7 +2040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19752040 \\ var bad = {};
19762041 \\}
19772042 ,
1978 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2043 "tmp.zig:5:5: error: expected token ';', found 'var'",
19792044 );
19802045
19812046 cases.add(
......@@ -1987,7 +2052,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19872052 \\ var bad = {};
19882053 \\}
19892054 ,
1990 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2055 "tmp.zig:5:5: error: expected token ';', found 'var'",
19912056 );
19922057
19932058 cases.add(
......@@ -1999,7 +2064,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
19992064 \\ var bad = {};
20002065 \\}
20012066 ,
2002 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2067 "tmp.zig:5:5: error: expected token ';', found 'var'",
20032068 );
20042069
20052070 cases.add(
......@@ -2011,7 +2076,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20112076 \\ var bad = {};
20122077 \\}
20132078 ,
2014 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2079 "tmp.zig:5:5: error: expected token ';', found 'var'",
20152080 );
20162081
20172082 cases.add(
......@@ -2023,7 +2088,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20232088 \\ var bad = {};
20242089 \\}
20252090 ,
2026 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2091 "tmp.zig:5:5: error: expected token ';', found 'var'",
20272092 );
20282093
20292094 cases.add(
......@@ -2035,7 +2100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20352100 \\ var bad = {};
20362101 \\}
20372102 ,
2038 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2103 "tmp.zig:5:5: error: expected token ';', found 'var'",
20392104 );
20402105
20412106 cases.add(
......@@ -2047,7 +2112,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20472112 \\ var bad = {};
20482113 \\}
20492114 ,
2050 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2115 "tmp.zig:5:5: error: expected token ';', found 'var'",
20512116 );
20522117
20532118 cases.add(
......@@ -2059,7 +2124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20592124 \\ var bad = {};
20602125 \\}
20612126 ,
2062 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2127 "tmp.zig:5:5: error: expected token ';', found 'var'",
20632128 );
20642129
20652130 cases.add(
......@@ -2071,7 +2136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20712136 \\ var bad = {};
20722137 \\}
20732138 ,
2074 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2139 "tmp.zig:5:5: error: expected token ';', found 'var'",
20752140 );
20762141
20772142 cases.add(
......@@ -2083,7 +2148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20832148 \\ var bad = {};
20842149 \\}
20852150 ,
2086 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2151 "tmp.zig:5:5: error: expected token ';', found 'var'",
20872152 );
20882153
20892154 cases.add(
......@@ -2095,7 +2160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20952160 \\ var bad = {};
20962161 \\}
20972162 ,
2098 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2163 "tmp.zig:5:5: error: expected token ';', found 'var'",
20992164 );
21002165
21012166 cases.add(
......@@ -2107,7 +2172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21072172 \\ var bad = {};
21082173 \\}
21092174 ,
2110 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2175 "tmp.zig:5:5: error: expected token ';', found 'var'",
21112176 );
21122177
21132178 cases.add(
......@@ -2119,7 +2184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21192184 \\ var bad = {};
21202185 \\}
21212186 ,
2122 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2187 "tmp.zig:5:5: error: expected token ';', found 'var'",
21232188 );
21242189
21252190 cases.add(
......@@ -2131,7 +2196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21312196 \\ var bad = {};
21322197 \\}
21332198 ,
2134 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2199 "tmp.zig:5:5: error: expected token ';', found 'var'",
21352200 );
21362201
21372202 cases.add(
......@@ -2143,7 +2208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21432208 \\ var bad = {};
21442209 \\}
21452210 ,
2146 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2211 "tmp.zig:5:5: error: expected token ';', found 'var'",
21472212 );
21482213
21492214 cases.add(
......@@ -2155,7 +2220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21552220 \\ var bad = {};
21562221 \\}
21572222 ,
2158 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2223 "tmp.zig:5:5: error: expected token ';', found 'var'",
21592224 );
21602225
21612226 cases.add(
......@@ -2167,7 +2232,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21672232 \\ var bad = {};
21682233 \\}
21692234 ,
2170 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2235 "tmp.zig:5:5: error: expected token ';', found 'var'",
21712236 );
21722237
21732238 cases.add(
......@@ -2179,7 +2244,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21792244 \\ var bad = {};
21802245 \\}
21812246 ,
2182 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2247 "tmp.zig:5:5: error: expected token ';', found 'var'",
21832248 );
21842249
21852250 cases.add(
......@@ -2191,7 +2256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21912256 \\ var bad = {};
21922257 \\}
21932258 ,
2194 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2259 "tmp.zig:5:5: error: expected token ';', found 'var'",
21952260 );
21962261
21972262 cases.add(
......@@ -2203,7 +2268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22032268 \\ var bad = {};
22042269 \\}
22052270 ,
2206 ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
2271 "tmp.zig:5:5: error: expected token ';', found 'var'",
22072272 );
22082273
22092274 cases.add(
......@@ -2212,7 +2277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22122277 \\fn a() void {}
22132278 \\export fn entry() void { a(); }
22142279 ,
2215 ".tmp_source.zig:2:1: error: redefinition of 'a'",
2280 "tmp.zig:2:1: error: redefinition of 'a'",
22162281 );
22172282
22182283 cases.add(
......@@ -2220,7 +2285,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22202285 \\fn a() noreturn {return;}
22212286 \\export fn entry() void { a(); }
22222287 ,
2223 ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'",
2288 "tmp.zig:1:18: error: expected type 'noreturn', found 'void'",
22242289 );
22252290
22262291 cases.add(
......@@ -2228,7 +2293,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22282293 \\fn a() i32 {}
22292294 \\export fn entry() void { _ = a(); }
22302295 ,
2231 ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'",
2296 "tmp.zig:1:12: error: expected type 'i32', found 'void'",
22322297 );
22332298
22342299 cases.add(
......@@ -2237,7 +2302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22372302 \\ b();
22382303 \\}
22392304 ,
2240 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
2305 "tmp.zig:2:5: error: use of undeclared identifier 'b'",
22412306 );
22422307
22432308 cases.add(
......@@ -2247,7 +2312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22472312 \\}
22482313 \\fn b(a: i32, b: i32, c: i32) void { }
22492314 ,
2250 ".tmp_source.zig:2:6: error: expected 3 arguments, found 1",
2315 "tmp.zig:2:6: error: expected 3 arguments, found 1",
22512316 );
22522317
22532318 cases.add(
......@@ -2255,7 +2320,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22552320 \\fn a() bogus {}
22562321 \\export fn entry() void { _ = a(); }
22572322 ,
2258 ".tmp_source.zig:1:8: error: use of undeclared identifier 'bogus'",
2323 "tmp.zig:1:8: error: use of undeclared identifier 'bogus'",
22592324 );
22602325
22612326 cases.add(
......@@ -2263,7 +2328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22632328 \\fn a() *noreturn {}
22642329 \\export fn entry() void { _ = a(); }
22652330 ,
2266 ".tmp_source.zig:1:8: error: pointer to noreturn not allowed",
2331 "tmp.zig:1:8: error: pointer to noreturn not allowed",
22672332 );
22682333
22692334 cases.add(
......@@ -2275,7 +2340,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22752340 \\
22762341 \\fn b() void {}
22772342 ,
2278 ".tmp_source.zig:3:5: error: unreachable code",
2343 "tmp.zig:3:5: error: unreachable code",
22792344 );
22802345
22812346 cases.add(
......@@ -2283,7 +2348,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22832348 \\const bogus = @import("bogus-does-not-exist.zig",);
22842349 \\export fn entry() void { bogus.bogo(); }
22852350 ,
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'",
22872352 );
22882353
22892354 cases.add(
......@@ -2294,8 +2359,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22942359 \\ c;
22952360 \\}
22962361 ,
2297 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
2298 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'",
2362 "tmp.zig:3:5: error: use of undeclared identifier 'b'",
2363 "tmp.zig:4:5: error: use of undeclared identifier 'c'",
22992364 );
23002365
23012366 cases.add(
......@@ -2304,7 +2369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23042369 \\}
23052370 \\export fn entry() void { f(1, 2); }
23062371 ,
2307 ".tmp_source.zig:1:15: error: redeclaration of variable 'a'",
2372 "tmp.zig:1:15: error: redeclaration of variable 'a'",
23082373 );
23092374
23102375 cases.add(
......@@ -2314,7 +2379,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23142379 \\ const a = 0;
23152380 \\}
23162381 ,
2317 ".tmp_source.zig:3:5: error: redeclaration of variable 'a'",
2382 "tmp.zig:3:5: error: redeclaration of variable 'a'",
23182383 );
23192384
23202385 cases.add(
......@@ -2324,7 +2389,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23242389 \\}
23252390 \\export fn entry() void { f(1); }
23262391 ,
2327 ".tmp_source.zig:2:5: error: redeclaration of variable 'a'",
2392 "tmp.zig:2:5: error: redeclaration of variable 'a'",
23282393 );
23292394
23302395 cases.add(
......@@ -2334,7 +2399,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23342399 \\ return a;
23352400 \\}
23362401 ,
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'",
23382403 );
23392404
23402405 cases.add(
......@@ -2343,7 +2408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23432408 \\ if (0) {}
23442409 \\}
23452410 ,
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'",
23472412 );
23482413
23492414 cases.add(
......@@ -2352,7 +2417,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23522417 \\ const a = return;
23532418 \\}
23542419 ,
2355 ".tmp_source.zig:2:5: error: unreachable code",
2420 "tmp.zig:2:5: error: unreachable code",
23562421 );
23572422
23582423 cases.add(
......@@ -2361,7 +2426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23612426 \\ const a: noreturn = {};
23622427 \\}
23632428 ,
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",
23652430 );
23662431
23672432 cases.add(
......@@ -2369,7 +2434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23692434 \\fn f(a: noreturn) void {}
23702435 \\export fn entry() void { f(); }
23712436 ,
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",
23732438 );
23742439
23752440 cases.add(
......@@ -2378,7 +2443,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23782443 \\ 3 = 3;
23792444 \\}
23802445 ,
2381 ".tmp_source.zig:2:7: error: cannot assign to constant",
2446 "tmp.zig:2:7: error: cannot assign to constant",
23822447 );
23832448
23842449 cases.add(
......@@ -2388,7 +2453,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23882453 \\ a = 4;
23892454 \\}
23902455 ,
2391 ".tmp_source.zig:3:7: error: cannot assign to constant",
2456 "tmp.zig:3:7: error: cannot assign to constant",
23922457 );
23932458
23942459 cases.add(
......@@ -2397,7 +2462,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23972462 \\ b = 3;
23982463 \\}
23992464 ,
2400 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
2465 "tmp.zig:2:5: error: use of undeclared identifier 'b'",
24012466 );
24022467
24032468 cases.add(
......@@ -2406,7 +2471,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24062471 \\ (const a = 0);
24072472 \\}
24082473 ,
2409 ".tmp_source.zig:2:6: error: invalid token: 'const'",
2474 "tmp.zig:2:6: error: invalid token: 'const'",
24102475 );
24112476
24122477 cases.add(
......@@ -2415,7 +2480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24152480 \\ i[i] = i[i];
24162481 \\}
24172482 ,
2418 ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
2483 "tmp.zig:2:5: error: use of undeclared identifier 'i'",
24192484 );
24202485
24212486 cases.add(
......@@ -2425,8 +2490,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24252490 \\ bad[bad] = bad[bad];
24262491 \\}
24272492 ,
2428 ".tmp_source.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'",
2493 "tmp.zig:3:8: error: array access of non-array type 'bool'",
2494 "tmp.zig:3:19: error: array access of non-array type 'bool'",
24302495 );
24312496
24322497 cases.add(
......@@ -2437,8 +2502,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24372502 \\ array[bad] = array[bad];
24382503 \\}
24392504 ,
2440 ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'",
2441 ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'",
2505 "tmp.zig:4:11: error: expected type 'usize', found 'bool'",
2506 "tmp.zig:4:24: error: expected type 'usize', found 'bool'",
24422507 );
24432508
24442509 cases.add(
......@@ -2449,7 +2514,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24492514 \\}
24502515 \\export fn entry() void { f(); }
24512516 ,
2452 ".tmp_source.zig:3:7: error: cannot assign to constant",
2517 "tmp.zig:3:7: error: cannot assign to constant",
24532518 );
24542519
24552520 cases.add(
......@@ -2460,26 +2525,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24602525 \\}
24612526 \\export fn entry() void { f(true); }
24622527 ,
2463 ".tmp_source.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'",
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",
2528 "tmp.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
2529 "tmp.zig:3:15: error: incompatible types: 'i32' and 'void'",
24832530 );
24842531
24852532 cases.add(
......@@ -2491,8 +2538,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
24912538 \\ const y = a.bar;
24922539 \\}
24932540 ,
2494 ".tmp_source.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'",
2541 "tmp.zig:4:6: error: no member named 'foo' in struct 'A'",
2542 "tmp.zig:5:16: error: no member named 'bar' in struct 'A'",
24962543 );
24972544
24982545 cases.add(
......@@ -2500,7 +2547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25002547 \\const A = struct { x : i32, };
25012548 \\const A = struct { y : i32, };
25022549 ,
2503 ".tmp_source.zig:2:1: error: redefinition of 'A'",
2550 "tmp.zig:2:1: error: redefinition of 'A'",
25042551 );
25052552
25062553 cases.add(
......@@ -2508,7 +2555,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25082555 \\const A = enum {};
25092556 \\const A = enum {};
25102557 ,
2511 ".tmp_source.zig:2:1: error: redefinition of 'A'",
2558 "tmp.zig:2:1: error: redefinition of 'A'",
25122559 );
25132560
25142561 cases.add(
......@@ -2516,8 +2563,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25162563 \\var a : i32 = 1;
25172564 \\var a : i32 = 2;
25182565 ,
2519 ".tmp_source.zig:2:1: error: redefinition of 'a'",
2520 ".tmp_source.zig:1:1: note: previous definition is here",
2566 "tmp.zig:2:1: error: redefinition of 'a'",
2567 "tmp.zig:1:1: note: previous definition is here",
25212568 );
25222569
25232570 cases.add(
......@@ -2536,7 +2583,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25362583 \\ };
25372584 \\}
25382585 ,
2539 ".tmp_source.zig:11:9: error: duplicate field",
2586 "tmp.zig:11:9: error: duplicate field",
25402587 );
25412588
25422589 cases.add(
......@@ -2555,7 +2602,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25552602 \\ };
25562603 \\}
25572604 ,
2558 ".tmp_source.zig:9:17: error: missing field: 'x'",
2605 "tmp.zig:9:17: error: missing field: 'x'",
25592606 );
25602607
25612608 cases.add(
......@@ -2573,7 +2620,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25732620 \\ };
25742621 \\}
25752622 ,
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'",
25772624 );
25782625
25792626 cases.add(
......@@ -2582,7 +2629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25822629 \\ break;
25832630 \\}
25842631 ,
2585 ".tmp_source.zig:2:5: error: break expression outside loop",
2632 "tmp.zig:2:5: error: break expression outside loop",
25862633 );
25872634
25882635 cases.add(
......@@ -2591,7 +2638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25912638 \\ continue;
25922639 \\}
25932640 ,
2594 ".tmp_source.zig:2:5: error: continue expression outside loop",
2641 "tmp.zig:2:5: error: continue expression outside loop",
25952642 );
25962643
25972644 cases.add(
......@@ -2600,7 +2647,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26002647 \\ if (true) |x| { }
26012648 \\}
26022649 ,
2603 ".tmp_source.zig:2:9: error: expected optional type, found 'bool'",
2650 "tmp.zig:2:9: error: expected optional type, found 'bool'",
26042651 );
26052652
26062653 cases.add(
......@@ -2610,7 +2657,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26102657 \\}
26112658 \\export fn entry() void { _ = f(); }
26122659 ,
2613 ".tmp_source.zig:2:15: error: unreachable code",
2660 "tmp.zig:2:15: error: unreachable code",
26142661 );
26152662
26162663 cases.add(
......@@ -2619,18 +2666,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26192666 \\}
26202667 \\export fn entry() void { _ = f(); }
26212668 ,
2622 ".tmp_source.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",
2669 "tmp.zig:1:8: error: invalid builtin function: 'bogus'",
26342670 );
26352671
26362672 cases.add(
......@@ -2638,7 +2674,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26382674 \\fn f(noalias x: i32) void {}
26392675 \\export fn entry() void { f(1234); }
26402676 ,
2641 ".tmp_source.zig:1:6: error: noalias on non-pointer parameter",
2677 "tmp.zig:1:6: error: noalias on non-pointer parameter",
26422678 );
26432679
26442680 cases.add(
......@@ -2646,7 +2682,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26462682 \\const foo = []u16{.x = 1024,};
26472683 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
26482684 ,
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",
26502686 );
26512687
26522688 cases.add(
......@@ -2656,7 +2692,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26562692 \\ return 1;
26572693 \\}
26582694 ,
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",
26602696 );
26612697
26622698 cases.add(
......@@ -2672,10 +2708,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26722708 \\ f(1234);
26732709 \\}
26742710 ,
2675 ".tmp_source.zig:4:6: error: redefinition of 'Foo'",
2676 ".tmp_source.zig:1:1: note: previous definition is here",
2677 ".tmp_source.zig:5:5: error: redefinition of 'Bar'",
2678 ".tmp_source.zig:2:1: note: previous definition is here",
2711 "tmp.zig:4:6: error: redefinition of 'Foo'",
2712 "tmp.zig:1:1: note: previous definition is here",
2713 "tmp.zig:5:5: error: redefinition of 'Bar'",
2714 "tmp.zig:2:1: note: previous definition is here",
26792715 );
26802716
26812717 cases.add(
......@@ -2696,7 +2732,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26962732 \\
26972733 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
26982734 ,
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",
27002736 );
27012737
27022738 cases.add(
......@@ -2719,8 +2755,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27192755 \\
27202756 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
27212757 ,
2722 ".tmp_source.zig:13:15: error: duplicate switch value",
2723 ".tmp_source.zig:10:15: note: other value is here",
2758 "tmp.zig:13:15: error: duplicate switch value",
2759 "tmp.zig:10:15: note: other value is here",
27242760 );
27252761
27262762 cases.add(
......@@ -2744,8 +2780,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27442780 \\
27452781 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
27462782 ,
2747 ".tmp_source.zig:13:15: error: duplicate switch value",
2748 ".tmp_source.zig:10:15: note: other value is here",
2783 "tmp.zig:13:15: error: duplicate switch value",
2784 "tmp.zig:10:15: note: other value is here",
27492785 );
27502786
27512787 cases.add(
......@@ -2761,7 +2797,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27612797 \\ f(1234);
27622798 \\}
27632799 ,
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",
27652801 );
27662802
27672803 cases.add(
......@@ -2773,7 +2809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27732809 \\}
27742810 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
27752811 ,
2776 ".tmp_source.zig:2:5: error: switch must handle all possibilities",
2812 "tmp.zig:2:5: error: switch must handle all possibilities",
27772813 );
27782814
27792815 cases.add(
......@@ -2788,8 +2824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
27882824 \\}
27892825 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
27902826 ,
2791 ".tmp_source.zig:6:9: error: duplicate switch value",
2792 ".tmp_source.zig:5:14: note: previous value is here",
2827 "tmp.zig:6:9: error: duplicate switch value",
2828 "tmp.zig:5:14: note: previous value is here",
27932829 );
27942830
27952831 cases.add(
......@@ -2802,7 +2838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28022838 \\const y: u8 = 100;
28032839 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
28042840 ,
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'",
28062842 );
28072843
28082844 cases.add(
......@@ -2811,7 +2847,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28112847 \\const x = foo();
28122848 \\export fn entry() i32 { return x; }
28132849 ,
2814 ".tmp_source.zig:2:11: error: unable to evaluate constant expression",
2850 "tmp.zig:2:11: error: unable to evaluate constant expression",
28152851 );
28162852
28172853 cases.add(
......@@ -2822,7 +2858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28222858 \\
28232859 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
28242860 ,
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'",
28262862 );
28272863
28282864 cases.add(
......@@ -2833,7 +2869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28332869 \\var s: [10]u8 = undefined;
28342870 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
28352871 ,
2836 ".tmp_source.zig:2:12: error: unable to evaluate constant expression",
2872 "tmp.zig:2:12: error: unable to evaluate constant expression",
28372873 );
28382874
28392875 cases.add(
......@@ -2841,7 +2877,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28412877 \\const c = @cImport(@cInclude("bogus.h"));
28422878 \\export fn entry() usize { return @sizeOf(@typeOf(c.bogo)); }
28432879 ,
2844 ".tmp_source.zig:1:11: error: C import failed",
2880 "tmp.zig:1:11: error: C import failed",
28452881 ".h:1:10: note: 'bogus.h' file not found",
28462882 );
28472883
......@@ -2852,7 +2888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28522888 \\fn foo() *const i32 { return y; }
28532889 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
28542890 ,
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'",
28562892 );
28572893
28582894 cases.add(
......@@ -2860,7 +2896,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28602896 \\const x : u8 = 300;
28612897 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
28622898 ,
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'",
28642900 );
28652901
28662902 cases.add(
......@@ -2871,8 +2907,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28712907 \\}
28722908 \\export fn entry() u16 { return f(); }
28732909 ,
2874 ".tmp_source.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",
2910 "tmp.zig:3:14: error: RHS of shift is too large for LHS type",
2911 "tmp.zig:3:17: note: value 8 cannot fit into type u3",
28762912 );
28772913
28782914 cases.add(
......@@ -2880,7 +2916,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
28802916 \\const x = 2 == 2.0;
28812917 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
28822918 ,
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'",
28842920 );
28852921
28862922 cases.add(
......@@ -2909,7 +2945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29092945 \\
29102946 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
29112947 ,
2912 ".tmp_source.zig:20:34: error: expected 1 arguments, found 0",
2948 "tmp.zig:20:34: error: expected 1 arguments, found 0",
29132949 );
29142950
29152951 cases.add(
......@@ -2918,8 +2954,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29182954 \\fn f(i32) void {}
29192955 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
29202956 ,
2921 ".tmp_source.zig:1:1: error: missing function name",
2922 ".tmp_source.zig:2:6: error: missing parameter name",
2957 "tmp.zig:1:1: error: missing function name",
2958 "tmp.zig:2:6: error: missing parameter name",
29232959 );
29242960
29252961 cases.add(
......@@ -2930,7 +2966,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29302966 \\fn c() i32 {return 2;}
29312967 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
29322968 ,
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'",
29342970 );
29352971
29362972 cases.add(
......@@ -2942,7 +2978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29422978 \\
29432979 \\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
29442980 ,
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'",
29462982 );
29472983
29482984 cases.add(
......@@ -2951,16 +2987,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29512987 \\fn func() bogus {}
29522988 \\export fn entry() usize { return @sizeOf(@typeOf(func)); }
29532989 ,
2954 ".tmp_source.zig:2:1: error: redefinition of 'func'",
2955 ".tmp_source.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 '",
2990 "tmp.zig:2:1: error: redefinition of 'func'",
2991 "tmp.zig:1:11: error: use of undeclared identifier 'bogus'",
29642992 );
29652993
29662994 cases.add(
......@@ -2973,9 +3001,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29733001 \\
29743002 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
29753003 ,
2976 ".tmp_source.zig:5:25: error: unable to evaluate constant expression",
2977 ".tmp_source.zig:2:12: note: called from here",
2978 ".tmp_source.zig:2:8: note: called from here",
3004 "tmp.zig:5:25: error: unable to evaluate constant expression",
3005 "tmp.zig:2:12: note: called from here",
3006 "tmp.zig:2:8: note: called from here",
29793007 );
29803008
29813009 cases.add(
......@@ -2987,7 +3015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29873015 \\
29883016 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
29893017 ,
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'",
29913019 );
29923020
29933021 cases.add(
......@@ -3002,10 +3030,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30023030 \\export fn entry3() usize { return @sizeOf(@typeOf(int_x)); }
30033031 \\export fn entry4() usize { return @sizeOf(@typeOf(float_x)); }
30043032 ,
3005 ".tmp_source.zig:1:21: error: division by zero",
3006 ".tmp_source.zig:2:25: error: division by zero",
3007 ".tmp_source.zig:3:22: error: division by zero",
3008 ".tmp_source.zig:4:26: error: division by zero",
3033 "tmp.zig:1:21: error: division by zero",
3034 "tmp.zig:2:25: error: division by zero",
3035 "tmp.zig:3:22: error: division by zero",
3036 "tmp.zig:4:26: error: division by zero",
30093037 );
30103038
30113039 cases.add(
......@@ -3015,7 +3043,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30153043 \\
30163044 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
30173045 ,
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",
30193047 );
30203048
30213049 cases.add(
......@@ -3025,7 +3053,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30253053 \\
30263054 \\export fn entry() usize { return @sizeOf(@typeOf(invalid)); }
30273055 ,
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'",
30293057 );
30303058
30313059 cases.add(
......@@ -3037,7 +3065,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30373065 \\
30383066 \\export fn entry() usize { return @sizeOf(@typeOf(test1)); }
30393067 ,
3040 ".tmp_source.zig:3:16: error: unable to evaluate constant expression",
3068 "tmp.zig:3:16: error: unable to evaluate constant expression",
30413069 );
30423070
30433071 cases.add(
......@@ -3046,7 +3074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30463074 \\
30473075 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
30483076 ,
3049 ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'",
3077 "tmp.zig:1:16: error: expected type '*u8', found '(null)'",
30503078 );
30513079
30523080 cases.add(
......@@ -3056,7 +3084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30563084 \\ const pointer = &array[0];
30573085 \\}
30583086 ,
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",
30603088 );
30613089
30623090 cases.add(
......@@ -3068,8 +3096,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30683096 \\
30693097 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
30703098 ,
3071 ".tmp_source.zig:3:14: error: division by zero",
3072 ".tmp_source.zig:1:14: note: called from here",
3099 "tmp.zig:3:14: error: division by zero",
3100 "tmp.zig:1:14: note: called from here",
30733101 );
30743102
30753103 cases.add(
......@@ -3078,7 +3106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30783106 \\
30793107 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
30803108 ,
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",
30823110 );
30833111
30843112 cases.add(
......@@ -3088,7 +3116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30883116 \\ _ = a / a;
30893117 \\}
30903118 ,
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",
30923120 );
30933121
30943122 cases.add(
......@@ -3098,7 +3126,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
30983126 \\ a /= a;
30993127 \\}
31003128 ,
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",
31023130 );
31033131
31043132 cases.add(
......@@ -3108,7 +3136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31083136 \\ _ = a % a;
31093137 \\}
31103138 ,
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",
31123140 );
31133141
31143142 cases.add(
......@@ -3118,7 +3146,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31183146 \\ a %= a;
31193147 \\}
31203148 ,
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",
31223150 );
31233151
31243152 cases.add(
......@@ -3128,7 +3156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31283156 \\ _ = a + a;
31293157 \\}
31303158 ,
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",
31323160 );
31333161
31343162 cases.add(
......@@ -3138,7 +3166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31383166 \\ a += a;
31393167 \\}
31403168 ,
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",
31423170 );
31433171
31443172 cases.add(
......@@ -3148,7 +3176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31483176 \\ _ = a +% a;
31493177 \\}
31503178 ,
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",
31523180 );
31533181
31543182 cases.add(
......@@ -3158,7 +3186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31583186 \\ a +%= a;
31593187 \\}
31603188 ,
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",
31623190 );
31633191
31643192 cases.add(
......@@ -3168,7 +3196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31683196 \\ _ = a - a;
31693197 \\}
31703198 ,
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",
31723200 );
31733201
31743202 cases.add(
......@@ -3178,7 +3206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31783206 \\ a -= a;
31793207 \\}
31803208 ,
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",
31823210 );
31833211
31843212 cases.add(
......@@ -3188,7 +3216,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31883216 \\ _ = a -% a;
31893217 \\}
31903218 ,
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",
31923220 );
31933221
31943222 cases.add(
......@@ -3198,7 +3226,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31983226 \\ a -%= a;
31993227 \\}
32003228 ,
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",
32023230 );
32033231
32043232 cases.add(
......@@ -3208,7 +3236,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32083236 \\ _ = a * a;
32093237 \\}
32103238 ,
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",
32123240 );
32133241
32143242 cases.add(
......@@ -3218,7 +3246,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32183246 \\ a *= a;
32193247 \\}
32203248 ,
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",
32223250 );
32233251
32243252 cases.add(
......@@ -3228,7 +3256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32283256 \\ _ = a *% a;
32293257 \\}
32303258 ,
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",
32323260 );
32333261
32343262 cases.add(
......@@ -3238,7 +3266,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32383266 \\ a *%= a;
32393267 \\}
32403268 ,
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",
32423270 );
32433271
32443272 cases.add(
......@@ -3248,7 +3276,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32483276 \\ _ = a << 2;
32493277 \\}
32503278 ,
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",
32523280 );
32533281
32543282 cases.add(
......@@ -3258,7 +3286,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32583286 \\ a <<= 2;
32593287 \\}
32603288 ,
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",
32623290 );
32633291
32643292 cases.add(
......@@ -3268,7 +3296,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32683296 \\ _ = a >> 2;
32693297 \\}
32703298 ,
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",
32723300 );
32733301
32743302 cases.add(
......@@ -3278,7 +3306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32783306 \\ a >>= 2;
32793307 \\}
32803308 ,
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",
32823310 );
32833311
32843312 cases.add(
......@@ -3288,7 +3316,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32883316 \\ _ = a & a;
32893317 \\}
32903318 ,
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",
32923320 );
32933321
32943322 cases.add(
......@@ -3298,7 +3326,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32983326 \\ a &= a;
32993327 \\}
33003328 ,
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",
33023330 );
33033331
33043332 cases.add(
......@@ -3308,7 +3336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33083336 \\ _ = a | a;
33093337 \\}
33103338 ,
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",
33123340 );
33133341
33143342 cases.add(
......@@ -3318,7 +3346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33183346 \\ a |= a;
33193347 \\}
33203348 ,
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",
33223350 );
33233351
33243352 cases.add(
......@@ -3328,7 +3356,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33283356 \\ _ = a ^ a;
33293357 \\}
33303358 ,
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",
33323360 );
33333361
33343362 cases.add(
......@@ -3338,7 +3366,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33383366 \\ a ^= a;
33393367 \\}
33403368 ,
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",
33423370 );
33433371
33443372 cases.add(
......@@ -3348,7 +3376,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33483376 \\ _ = a == a;
33493377 \\}
33503378 ,
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",
33523380 );
33533381
33543382 cases.add(
......@@ -3358,7 +3386,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33583386 \\ _ = a != a;
33593387 \\}
33603388 ,
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",
33623390 );
33633391
33643392 cases.add(
......@@ -3368,7 +3396,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33683396 \\ _ = a > a;
33693397 \\}
33703398 ,
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",
33723400 );
33733401
33743402 cases.add(
......@@ -3378,7 +3406,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33783406 \\ _ = a >= a;
33793407 \\}
33803408 ,
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",
33823410 );
33833411
33843412 cases.add(
......@@ -3388,7 +3416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33883416 \\ _ = a < a;
33893417 \\}
33903418 ,
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",
33923420 );
33933421
33943422 cases.add(
......@@ -3398,7 +3426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33983426 \\ _ = a <= a;
33993427 \\}
34003428 ,
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",
34023430 );
34033431
34043432 cases.add(
......@@ -3408,7 +3436,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34083436 \\ _ = a and a;
34093437 \\}
34103438 ,
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",
34123440 );
34133441
34143442 cases.add(
......@@ -3418,7 +3446,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34183446 \\ _ = a or a;
34193447 \\}
34203448 ,
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",
34223450 );
34233451
34243452 cases.add(
......@@ -3428,7 +3456,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34283456 \\ _ = -a;
34293457 \\}
34303458 ,
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",
34323460 );
34333461
34343462 cases.add(
......@@ -3438,7 +3466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34383466 \\ _ = -%a;
34393467 \\}
34403468 ,
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",
34423470 );
34433471
34443472 cases.add(
......@@ -3448,7 +3476,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34483476 \\ _ = ~a;
34493477 \\}
34503478 ,
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",
34523480 );
34533481
34543482 cases.add(
......@@ -3458,7 +3486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34583486 \\ _ = !a;
34593487 \\}
34603488 ,
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",
34623490 );
34633491
34643492 cases.add(
......@@ -3468,7 +3496,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34683496 \\ _ = a orelse false;
34693497 \\}
34703498 ,
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",
34723500 );
34733501
34743502 cases.add(
......@@ -3478,7 +3506,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34783506 \\ _ = a catch |err| false;
34793507 \\}
34803508 ,
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",
34823510 );
34833511
34843512 cases.add(
......@@ -3488,7 +3516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
34883516 \\ _ = a.*;
34893517 \\}
34903518 ,
3491 ".tmp_source.zig:3:9: error: attempt to dereference undefined value",
3519 "tmp.zig:3:9: error: attempt to dereference undefined value",
34923520 );
34933521
34943522 cases.add(
......@@ -3500,8 +3528,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35003528 \\
35013529 \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); }
35023530 ,
3503 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
3504 ".tmp_source.zig:3:21: note: called from here",
3531 "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches",
3532 "tmp.zig:3:21: note: called from here",
35053533 );
35063534
35073535 cases.add(
......@@ -3510,7 +3538,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35103538 \\
35113539 \\export fn entry() usize { return @sizeOf(@typeOf(resource)); }
35123540 ,
3513 ".tmp_source.zig:1:29: error: unable to find '",
3541 "tmp.zig:1:29: error: unable to find '",
35143542 "bogus.txt'",
35153543 );
35163544
......@@ -3524,7 +3552,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35243552 \\
35253553 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
35263554 ,
3527 ".tmp_source.zig:4:21: error: unable to evaluate constant expression",
3555 "tmp.zig:4:21: error: unable to evaluate constant expression",
35283556 );
35293557
35303558 cases.add(
......@@ -3541,8 +3569,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35413569 \\
35423570 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
35433571 ,
3544 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
3545 ".tmp_source.zig:4:17: note: called from here",
3572 "tmp.zig:6:24: error: unable to evaluate constant expression",
3573 "tmp.zig:4:17: note: called from here",
35463574 );
35473575
35483576 cases.add(
......@@ -3554,7 +3582,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35543582 \\ bad_fn_call();
35553583 \\}
35563584 ,
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'",
35583586 );
35593587
35603588 cases.add(
......@@ -3573,8 +3601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35733601 \\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }
35743602 \\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }
35753603 ,
3576 ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
3577 ".tmp_source.zig:9:16: error: operator not allowed for type 'EnumWithData'",
3604 "tmp.zig:2:14: error: operator not allowed for type '[]u8'",
3605 "tmp.zig:9:16: error: operator not allowed for type 'EnumWithData'",
35783606 );
35793607
35803608 cases.add(
......@@ -3590,7 +3618,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
35903618 \\ return 2;
35913619 \\}
35923620 ,
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",
35943622 );
35953623
35963624 cases.add(
......@@ -3601,7 +3629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36013629 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
36023630 \\}
36033631 ,
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",
36053633 );
36063634
36073635 cases.add(
......@@ -3612,7 +3640,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36123640 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
36133641 \\}
36143642 ,
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",
36163644 );
36173645
36183646 cases.add(
......@@ -3624,8 +3652,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36243652 \\
36253653 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
36263654 ,
3627 ".tmp_source.zig:3:12: error: negation caused overflow",
3628 ".tmp_source.zig:1:14: note: called from here",
3655 "tmp.zig:3:12: error: negation caused overflow",
3656 "tmp.zig:1:14: note: called from here",
36293657 );
36303658
36313659 cases.add(
......@@ -3637,8 +3665,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36373665 \\
36383666 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
36393667 ,
3640 ".tmp_source.zig:3:14: error: operation caused overflow",
3641 ".tmp_source.zig:1:14: note: called from here",
3668 "tmp.zig:3:14: error: operation caused overflow",
3669 "tmp.zig:1:14: note: called from here",
36423670 );
36433671
36443672 cases.add(
......@@ -3650,8 +3678,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36503678 \\
36513679 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
36523680 ,
3653 ".tmp_source.zig:3:14: error: operation caused overflow",
3654 ".tmp_source.zig:1:14: note: called from here",
3681 "tmp.zig:3:14: error: operation caused overflow",
3682 "tmp.zig:1:14: note: called from here",
36553683 );
36563684
36573685 cases.add(
......@@ -3663,8 +3691,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36633691 \\
36643692 \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
36653693 ,
3666 ".tmp_source.zig:3:14: error: operation caused overflow",
3667 ".tmp_source.zig:1:14: note: called from here",
3694 "tmp.zig:3:14: error: operation caused overflow",
3695 "tmp.zig:1:14: note: called from here",
36683696 );
36693697
36703698 cases.add(
......@@ -3676,7 +3704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36763704 \\
36773705 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
36783706 ,
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'",
36803708 );
36813709
36823710 cases.add(
......@@ -3686,8 +3714,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
36863714 \\}
36873715 \\fn something() anyerror!void { }
36883716 ,
3689 ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'",
3690 ".tmp_source.zig:1:15: note: return type declared here",
3717 "tmp.zig:2:5: error: expected type 'void', found 'anyerror'",
3718 "tmp.zig:1:15: note: return type declared here",
36913719 );
36923720
36933721 cases.add(
......@@ -3700,7 +3728,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37003728 \\ }
37013729 \\}
37023730 ,
3703 ".tmp_source.zig:2:13: error: unable to evaluate constant expression",
3731 "tmp.zig:2:13: error: unable to evaluate constant expression",
37043732 );
37053733
37063734 cases.add(
......@@ -3709,7 +3737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37093737 \\ return x + y;
37103738 \\}
37113739 ,
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'",
37133741 );
37143742
37153743 cases.add(
......@@ -3720,7 +3748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37203748 \\}
37213749 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
37223750 ,
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'",
37243752 );
37253753
37263754 cases.add(
......@@ -3730,8 +3758,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37303758 \\ var foo = @bytesToSlice(u32, array)[0];
37313759 \\}
37323760 ,
3733 ".tmp_source.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",
3761 "tmp.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
3762 "tmp.zig:3:29: note: u32 has size 4; remaining bytes: 1",
37353763 );
37363764
37373765 cases.add(
......@@ -3755,8 +3783,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37553783 \\ list.length = 10;
37563784 \\}
37573785 ,
3758 ".tmp_source.zig:3:7: error: unable to evaluate constant expression",
3759 ".tmp_source.zig:16:19: note: called from here",
3786 "tmp.zig:3:7: error: unable to evaluate constant expression",
3787 "tmp.zig:16:19: note: called from here",
37603788 );
37613789
37623790 cases.add(
......@@ -3767,7 +3795,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37673795 \\}
37683796 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
37693797 ,
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'",
37713799 );
37723800
37733801 cases.add(
......@@ -3781,7 +3809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37813809 \\}
37823810 \\export fn entry() usize { return @sizeOf(@typeOf(f)); }
37833811 ,
3784 ".tmp_source.zig:6:15: error: expected 2 arguments, found 3",
3812 "tmp.zig:6:15: error: expected 2 arguments, found 3",
37853813 );
37863814
37873815 cases.add(
......@@ -3791,7 +3819,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37913819 \\ cstr[0] = 'W';
37923820 \\}
37933821 ,
3794 ".tmp_source.zig:3:11: error: cannot assign to constant",
3822 "tmp.zig:3:11: error: cannot assign to constant",
37953823 );
37963824
37973825 cases.add(
......@@ -3801,14 +3829,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
38013829 \\ cstr[0] = 'W';
38023830 \\}
38033831 ,
3804 ".tmp_source.zig:3:11: error: cannot assign to constant",
3832 "tmp.zig:3:11: error: cannot assign to constant",
38053833 );
38063834
38073835 cases.add(
38083836 "main function with bogus args type",
38093837 \\pub fn main(args: [][]bogus) !void {}
38103838 ,
3811 ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'",
3839 "tmp.zig:1:23: error: use of undeclared identifier 'bogus'",
38123840 );
38133841
38143842 cases.add(
......@@ -3844,7 +3872,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
38443872 \\
38453873 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
38463874 ,
3847 ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'",
3875 "tmp.zig:5:16: error: use of undeclared identifier 'JsonList'",
38483876 );
38493877
38503878 cases.add(
......@@ -3865,7 +3893,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
38653893 \\ derp.init();
38663894 \\}
38673895 ,
3868 ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",
3896 "tmp.zig:14:5: error: expected type 'i32', found 'Foo'",
38693897 );
38703898
38713899 cases.add(
......@@ -3895,7 +3923,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
38953923 \\ x.init();
38963924 \\}
38973925 ,
3898 ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'",
3926 "tmp.zig:23:5: error: expected type '*Allocator', found '*List'",
38993927 );
39003928
39013929 cases.add(
......@@ -3906,7 +3934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
39063934 \\
39073935 \\export fn entry() usize { return @sizeOf(@typeOf(block_aligned_stuff)); }
39083936 ,
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'",
39103938 );
39113939
39123940 cases.addCase(x: {
......@@ -3918,7 +3946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
39183946 \\ foo.privateFunction();
39193947 \\}
39203948 ,
3921 ".tmp_source.zig:4:8: error: 'privateFunction' is private",
3949 "tmp.zig:4:8: error: 'privateFunction' is private",
39223950 "foo.zig:1:1: note: declared here",
39233951 );
39243952
......@@ -3936,7 +3964,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
39363964 \\
39373965 \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
39383966 ,
3939 ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'",
3967 "tmp.zig:2:11: error: expected type 'type', found 'i32'",
39403968 );
39413969
39423970 cases.add(
......@@ -3949,7 +3977,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
39493977 \\ f.field = 0;
39503978 \\}
39513979 ,
3952 ".tmp_source.zig:6:13: error: cannot assign to constant",
3980 "tmp.zig:6:13: error: cannot assign to constant",
39533981 );
39543982
39553983 cases.add(
......@@ -3970,7 +3998,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
39703998 \\
39713999 \\export fn entry() usize { return @sizeOf(@typeOf(testTrickyDefer)); }
39724000 ,
3973 ".tmp_source.zig:4:11: error: cannot return from defer expression",
4001 "tmp.zig:4:11: error: cannot return from defer expression",
39744002 );
39754003
39764004 cases.add(
......@@ -3985,8 +4013,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
39854013 \\
39864014 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
39874015 ,
3988 ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",
3989 ".tmp_source.zig:6:15: note: called from here",
4016 "tmp.zig:2:26: error: index 1 outside argument list of size 1",
4017 "tmp.zig:6:15: note: called from here",
39904018 );
39914019
39924020 cases.add(
......@@ -4005,7 +4033,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40054033 \\
40064034 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
40074035 ,
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",
40094037 );
40104038
40114039 cases.add(
......@@ -4014,7 +4042,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40144042 \\ var vga_mem: u16 = 0xB8000;
40154043 \\}
40164044 ,
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'",
40184046 );
40194047
40204048 cases.add(
......@@ -4022,7 +4050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40224050 \\const some_data: [100]u8 align(3) = undefined;
40234051 \\export fn entry() usize { return @sizeOf(@typeOf(some_data)); }
40244052 ,
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",
40264054 );
40274055
40284056 cases.add(
......@@ -4030,7 +4058,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40304058 \\extern fn foo() align(3) void;
40314059 \\export fn entry() void { return foo(); }
40324060 ,
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",
40344062 );
40354063
40364064 cases.add(
......@@ -4044,9 +4072,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40444072 \\ @compileLog("end",);
40454073 \\}
40464074 ,
4047 ".tmp_source.zig:5:5: error: found compile log statement",
4048 ".tmp_source.zig:6:5: error: found compile log statement",
4049 ".tmp_source.zig:7:5: error: found compile log statement",
4075 "tmp.zig:5:5: error: found compile log statement",
4076 "tmp.zig:6:5: error: found compile log statement",
4077 "tmp.zig:7:5: error: found compile log statement",
40504078 );
40514079
40524080 cases.add(
......@@ -4067,7 +4095,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40674095 \\
40684096 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
40694097 ,
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'",
40714099 );
40724100
40734101 cases.add(
......@@ -4084,8 +4112,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40844112 \\ if (!ok) unreachable;
40854113 \\}
40864114 ,
4087 ".tmp_source.zig:10:14: error: unable to evaluate constant expression",
4088 ".tmp_source.zig:6:20: note: called from here",
4115 "tmp.zig:10:14: error: unable to evaluate constant expression",
4116 "tmp.zig:6:20: note: called from here",
40894117 );
40904118
40914119 cases.add(
......@@ -4099,8 +4127,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40994127 \\
41004128 \\fn bar() void { }
41014129 ,
4102 ".tmp_source.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",
4130 "tmp.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
4131 "tmp.zig:3:24: note: compile-time variable assigned here",
41044132 );
41054133
41064134 cases.add(
......@@ -4110,7 +4138,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41104138 \\}
41114139 \\fn bar() i32 { return 0; }
41124140 ,
4113 ".tmp_source.zig:2:8: error: expression value is ignored",
4141 "tmp.zig:2:8: error: expression value is ignored",
41144142 );
41154143
41164144 cases.add(
......@@ -4120,7 +4148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41204148 \\}
41214149 \\fn bar() anyerror!i32 { return 0; }
41224150 ,
4123 ".tmp_source.zig:2:11: error: expression value is ignored",
4151 "tmp.zig:2:11: error: expression value is ignored",
41244152 );
41254153
41264154 cases.add(
......@@ -4129,7 +4157,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41294157 \\ 1;
41304158 \\}
41314159 ,
4132 ".tmp_source.zig:2:5: error: expression value is ignored",
4160 "tmp.zig:2:5: error: expression value is ignored",
41334161 );
41344162
41354163 cases.add(
......@@ -4138,7 +4166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41384166 \\ comptime {1;}
41394167 \\}
41404168 ,
4141 ".tmp_source.zig:2:15: error: expression value is ignored",
4169 "tmp.zig:2:15: error: expression value is ignored",
41424170 );
41434171
41444172 cases.add(
......@@ -4147,7 +4175,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41474175 \\ comptime 1;
41484176 \\}
41494177 ,
4150 ".tmp_source.zig:2:5: error: expression value is ignored",
4178 "tmp.zig:2:5: error: expression value is ignored",
41514179 );
41524180
41534181 cases.add(
......@@ -4156,7 +4184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41564184 \\ defer {1;}
41574185 \\}
41584186 ,
4159 ".tmp_source.zig:2:12: error: expression value is ignored",
4187 "tmp.zig:2:12: error: expression value is ignored",
41604188 );
41614189
41624190 cases.add(
......@@ -4166,7 +4194,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41664194 \\}
41674195 \\fn bar() anyerror!i32 { return 0; }
41684196 ,
4169 ".tmp_source.zig:2:14: error: expression value is ignored",
4197 "tmp.zig:2:14: error: expression value is ignored",
41704198 );
41714199
41724200 cases.add(
......@@ -4180,7 +4208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41804208 \\
41814209 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
41824210 ,
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'",
41844212 );
41854213
41864214 cases.add(
......@@ -4196,7 +4224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
41964224 \\
41974225 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
41984226 ,
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'",
42004228 );
42014229
42024230 cases.addCase(x: {
......@@ -4209,7 +4237,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42094237 \\}
42104238 ,
42114239 "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",
42134241 );
42144242
42154243 tc.addSourceFile("foo.zig",
......@@ -4228,7 +4256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42284256 \\ foo(global_array);
42294257 \\}
42304258 ,
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'",
42324260 );
42334261
42344262 cases.add(
......@@ -4237,7 +4265,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42374265 \\ return @ptrCast(usize, a);
42384266 \\}
42394267 ,
4240 ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",
4268 "tmp.zig:2:21: error: expected pointer, found 'usize'",
42414269 );
42424270
42434271 cases.add(
......@@ -4254,7 +4282,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42544282 \\ );
42554283 \\}
42564284 ,
4257 ".tmp_source.zig:6:5: error: unable to evaluate constant expression",
4285 "tmp.zig:6:5: error: unable to evaluate constant expression",
42584286 );
42594287
42604288 cases.add(
......@@ -4264,7 +4292,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42644292 \\ const foo = builtin.Arch.x86;
42654293 \\}
42664294 ,
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'",
42684296 );
42694297
42704298 cases.add(
......@@ -4274,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42744302 \\ var y: *void = @intToPtr(*void, x);
42754303 \\}
42764304 ,
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",
42784306 );
42794307
42804308 cases.add(
......@@ -4284,7 +4312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42844312 \\ return @fieldParentPtr(Foo, "a", a);
42854313 \\}
42864314 ,
4287 ".tmp_source.zig:3:28: error: expected struct type, found 'i32'",
4315 "tmp.zig:3:28: error: expected struct type, found 'i32'",
42884316 );
42894317
42904318 cases.add(
......@@ -4296,7 +4324,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
42964324 \\ return @fieldParentPtr(Foo, "a", a);
42974325 \\}
42984326 ,
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'",
43004328 );
43014329
43024330 cases.add(
......@@ -4308,7 +4336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43084336 \\ return @fieldParentPtr(Foo, "a", a);
43094337 \\}
43104338 ,
4311 ".tmp_source.zig:5:38: error: expected pointer, found 'i32'",
4339 "tmp.zig:5:38: error: expected pointer, found 'i32'",
43124340 );
43134341
43144342 cases.add(
......@@ -4324,7 +4352,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43244352 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
43254353 \\}
43264354 ,
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",
43284356 );
43294357
43304358 cases.add(
......@@ -4339,7 +4367,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43394367 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
43404368 \\}
43414369 ,
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'",
43434371 );
43444372
43454373 cases.add(
......@@ -4349,7 +4377,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43494377 \\ return @byteOffsetOf(Foo, "a",);
43504378 \\}
43514379 ,
4352 ".tmp_source.zig:3:26: error: expected struct type, found 'i32'",
4380 "tmp.zig:3:26: error: expected struct type, found 'i32'",
43534381 );
43544382
43554383 cases.add(
......@@ -4361,14 +4389,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43614389 \\ return @byteOffsetOf(Foo, "a",);
43624390 \\}
43634391 ,
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'",
43654393 );
43664394
43674395 cases.addExe(
43684396 "missing main fn in executable",
43694397 \\
43704398 ,
4371 "error: no member named 'main' in '",
4399 "error: root source file has no member called 'main'",
43724400 );
43734401
43744402 cases.addExe(
......@@ -4376,7 +4404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43764404 \\fn main() void {}
43774405 ,
43784406 "error: 'main' is private",
4379 ".tmp_source.zig:1:1: note: declared here",
4407 "tmp.zig:1:1: note: declared here",
43804408 );
43814409
43824410 cases.add(
......@@ -4386,7 +4414,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43864414 \\ return foo;
43874415 \\}
43884416 ,
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'",
43904418 );
43914419
43924420 cases.add(
......@@ -4396,7 +4424,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
43964424 \\ return foo;
43974425 \\}
43984426 ,
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'",
44004428 );
44014429
44024430 cases.add(
......@@ -4406,7 +4434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44064434 \\ foo();
44074435 \\}
44084436 ,
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'",
44104438 );
44114439
44124440 cases.add(
......@@ -4416,7 +4444,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44164444 \\ return &a;
44174445 \\}
44184446 ,
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",
44204448 );
44214449
44224450 cases.add(
......@@ -4427,7 +4455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44274455 \\ return if (c) &a else &b;
44284456 \\}
44294457 ,
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",
44314459 );
44324460
44334461 cases.add(
......@@ -4452,8 +4480,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44524480 \\ if (!ok) unreachable;
44534481 \\}
44544482 ,
4455 ".tmp_source.zig:9:17: error: redefinition of 'Self'",
4456 ".tmp_source.zig:5:9: note: previous definition is here",
4483 "tmp.zig:9:17: error: redefinition of 'Self'",
4484 "tmp.zig:5:9: note: previous definition is here",
44574485 );
44584486
44594487 cases.add(
......@@ -4463,7 +4491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44634491 \\}
44644492 \\fn bar() ?i32 { return 1; }
44654493 ,
4466 ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'",
4494 "tmp.zig:2:15: error: expected type 'bool', found '?i32'",
44674495 );
44684496
44694497 cases.add(
......@@ -4473,7 +4501,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44734501 \\}
44744502 \\fn bar() anyerror!i32 { return 1; }
44754503 ,
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'",
44774505 );
44784506
44794507 cases.add(
......@@ -4483,7 +4511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44834511 \\}
44844512 \\fn bar() bool { return true; }
44854513 ,
4486 ".tmp_source.zig:2:15: error: expected optional type, found 'bool'",
4514 "tmp.zig:2:15: error: expected optional type, found 'bool'",
44874515 );
44884516
44894517 cases.add(
......@@ -4493,7 +4521,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
44934521 \\}
44944522 \\fn bar() anyerror!i32 { return 1; }
44954523 ,
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'",
44974525 );
44984526
44994527 cases.add(
......@@ -4503,7 +4531,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45034531 \\}
45044532 \\fn bar() bool { return true; }
45054533 ,
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'",
45074535 );
45084536
45094537 cases.add(
......@@ -4513,7 +4541,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45134541 \\}
45144542 \\fn bar() ?i32 { return 1; }
45154543 ,
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'",
45174545 );
45184546
45194547 cases.add(
......@@ -4531,7 +4559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45314559 \\}
45324560 \\extern fn quux() void;
45334561 ,
4534 ".tmp_source.zig:4:1: error: unable to inline function",
4562 "tmp.zig:4:1: error: unable to inline function",
45354563 );
45364564
45374565 cases.add(
......@@ -4542,7 +4570,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45424570 \\inline fn bar() void { }
45434571 \\extern fn quux(usize) void;
45444572 ,
4545 ".tmp_source.zig:4:1: error: unable to inline function",
4573 "tmp.zig:4:1: error: unable to inline function",
45464574 );
45474575
45484576 cases.add(
......@@ -4551,7 +4579,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45514579 \\ return a / b;
45524580 \\}
45534581 ,
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",
45554583 );
45564584
45574585 cases.add(
......@@ -4560,7 +4588,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45604588 \\ return a % b;
45614589 \\}
45624590 ,
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",
45644592 );
45654593
45664594 cases.add(
......@@ -4571,7 +4599,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45714599 \\ const c = a / b;
45724600 \\}
45734601 ,
4574 ".tmp_source.zig:4:17: error: division by zero",
4602 "tmp.zig:4:17: error: division by zero",
45754603 );
45764604
45774605 cases.add(
......@@ -4582,7 +4610,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45824610 \\ const c = a % b;
45834611 \\}
45844612 ,
4585 ".tmp_source.zig:4:17: error: division by zero",
4613 "tmp.zig:4:17: error: division by zero",
45864614 );
45874615
45884616 cases.add(
......@@ -4592,8 +4620,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
45924620 \\ @setRuntimeSafety(false);
45934621 \\}
45944622 ,
4595 ".tmp_source.zig:3:5: error: runtime safety set twice for same scope",
4596 ".tmp_source.zig:2:5: note: first set here",
4623 "tmp.zig:3:5: error: runtime safety set twice for same scope",
4624 "tmp.zig:2:5: note: first set here",
45974625 );
45984626
45994627 cases.add(
......@@ -4603,8 +4631,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46034631 \\ @setFloatMode(@import("builtin").FloatMode.Optimized);
46044632 \\}
46054633 ,
4606 ".tmp_source.zig:3:5: error: float mode set twice for same scope",
4607 ".tmp_source.zig:2:5: note: first set here",
4634 "tmp.zig:3:5: error: float mode set twice for same scope",
4635 "tmp.zig:2:5: note: first set here",
46084636 );
46094637
46104638 cases.add(
......@@ -4613,7 +4641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46134641 \\ var b: u8[40] = undefined;
46144642 \\}
46154643 ,
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'",
46174645 );
46184646
46194647 cases.add(
......@@ -4626,7 +4654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46264654 \\ }
46274655 \\}
46284656 ,
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",
46304658 );
46314659
46324660 cases.add(
......@@ -4639,7 +4667,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46394667 \\ }
46404668 \\}
46414669 ,
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",
46434671 );
46444672
46454673 cases.add(
......@@ -4653,7 +4681,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46534681 \\ foos[0]();
46544682 \\}
46554683 ,
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",
46574685 );
46584686
46594687 cases.add(
......@@ -4667,7 +4695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46674695 \\ foos[0](true);
46684696 \\}
46694697 ,
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",
46714699 );
46724700
46734701 cases.add(
......@@ -4681,24 +4709,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
46814709 \\ return bar;
46824710 \\}
46834711 ,
4684 ".tmp_source.zig:1:13: error: aoeu",
4685 ".tmp_source.zig:3:19: note: referenced here",
4686 ".tmp_source.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",
4712 "tmp.zig:1:13: error: aoeu",
4713 "tmp.zig:3:19: note: referenced here",
4714 "tmp.zig:7:12: note: referenced here",
47024715 );
47034716
47044717 cases.add(
......@@ -4707,7 +4720,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47074720 \\ const a = 0x1.0p16384;
47084721 \\}
47094722 ,
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",
47114724 );
47124725
47134726 cases.add(
......@@ -4716,7 +4729,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47164729 \\ const a = 0x1.0p-16384;
47174730 \\}
47184731 ,
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",
47204733 );
47214734
47224735 cases.add(
......@@ -4725,7 +4738,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47254738 \\ return i32(12.34);
47264739 \\}
47274740 ,
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'",
47294742 );
47304743
47314744 cases.add(
......@@ -4734,7 +4747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47344747 \\ return @ptrToInt(x);
47354748 \\}
47364749 ,
4737 ".tmp_source.zig:2:22: error: expected pointer, found 'i32'",
4750 "tmp.zig:2:22: error: expected pointer, found 'i32'",
47384751 );
47394752
47404753 cases.add(
......@@ -4743,7 +4756,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47434756 \\ const x = @shlExact(u8(0b01010101), 2);
47444757 \\}
47454758 ,
4746 ".tmp_source.zig:2:15: error: operation caused overflow",
4759 "tmp.zig:2:15: error: operation caused overflow",
47474760 );
47484761
47494762 cases.add(
......@@ -4752,7 +4765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47524765 \\ const x = @shrExact(u8(0b10101010), 2);
47534766 \\}
47544767 ,
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",
47564769 );
47574770
47584771 cases.add(
......@@ -4761,7 +4774,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47614774 \\ return 0x11 << x;
47624775 \\}
47634776 ,
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",
47654778 );
47664779
47674780 cases.add(
......@@ -4770,7 +4783,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47704783 \\ return x << y;
47714784 \\}
47724785 ,
4773 ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'",
4786 "tmp.zig:2:17: error: expected type 'u3', found 'u8'",
47744787 );
47754788
47764789 cases.add(
......@@ -4780,7 +4793,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47804793 \\ const a: u16 = 300;
47814794 \\}
47824795 ,
4783 ".tmp_source.zig:1:1: error: declaration shadows primitive type 'u16'",
4796 "tmp.zig:1:1: error: declaration shadows primitive type 'u16'",
47844797 );
47854798
47864799 cases.add(
......@@ -4799,7 +4812,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
47994812 \\ x.* += 1;
48004813 \\}
48014814 ,
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'",
48034816 );
48044817
48054818 cases.add(
......@@ -4819,9 +4832,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48194832 \\ x[0] += 1;
48204833 \\}
48214834 ,
4822 ".tmp_source.zig:9:18: error: cast increases pointer alignment",
4823 ".tmp_source.zig:9:23: note: '*align(1) u32' has alignment 1",
4824 ".tmp_source.zig:9:18: note: '*[1]u32' has alignment 4",
4835 "tmp.zig:9:18: error: cast increases pointer alignment",
4836 "tmp.zig:9:23: note: '*align(1) u32' has alignment 1",
4837 "tmp.zig:9:18: note: '*[1]u32' has alignment 4",
48254838 );
48264839
48274840 cases.add(
......@@ -4832,9 +4845,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48324845 \\ return ptr.*;
48334846 \\}
48344847 ,
4835 ".tmp_source.zig:3:17: error: cast increases pointer alignment",
4836 ".tmp_source.zig:3:38: note: '*u8' has alignment 1",
4837 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",
4848 "tmp.zig:3:17: error: cast increases pointer alignment",
4849 "tmp.zig:3:38: note: '*u8' has alignment 1",
4850 "tmp.zig:3:26: note: '*u32' has alignment 4",
48384851 );
48394852
48404853 cases.add(
......@@ -4843,7 +4856,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48434856 \\ @alignCast(4, u32(3));
48444857 \\}
48454858 ,
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'",
48474860 );
48484861
48494862 cases.add(
......@@ -4856,7 +4869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48564869 \\}
48574870 \\fn alignedSmall() align(4) i32 { return 1234; }
48584871 ,
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'",
48604873 );
48614874
48624875 cases.add(
......@@ -4868,7 +4881,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48684881 \\ return x == 5678;
48694882 \\}
48704883 ,
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'",
48724885 );
48734886
48744887 cases.add(
......@@ -4877,7 +4890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48774890 \\ const array = [2]u8{1, 2, 3};
48784891 \\}
48794892 ,
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",
48814894 );
48824895
48834896 cases.add(
......@@ -4889,7 +4902,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
48894902 \\ bar(@ptrCast(*c_void, &x));
48904903 \\}
48914904 ,
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'",
48934906 );
48944907
48954908 cases.add(
......@@ -4906,7 +4919,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49064919 \\ var d = null;
49074920 \\ var e = opaque.*;
49084921 \\ var f = i32;
4909 \\ var g = @import("std",);
49104922 \\ var h = (Foo {}).bar;
49114923 \\
49124924 \\ var z: noreturn = return;
......@@ -4916,16 +4928,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49164928 \\ fn bar(self: *const Foo) void {}
49174929 \\};
49184930 ,
4919 ".tmp_source.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",
4921 ".tmp_source.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",
4923 ".tmp_source.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",
4925 ".tmp_source.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",
4927 ".tmp_source.zig:14:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
4928 ".tmp_source.zig:16:4: error: unreachable code",
4931 "tmp.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",
4932 "tmp.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
4933 "tmp.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
4934 "tmp.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
4935 "tmp.zig:10:4: error: variable of type '(null)' must be const or comptime",
4936 "tmp.zig:11:4: error: variable of type 'Opaque' not allowed",
4937 "tmp.zig:12:4: error: variable of type 'type' must be const or comptime",
4938 "tmp.zig:13:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
4939 "tmp.zig:15:4: error: unreachable code",
49294940 );
49304941
49314942 cases.add(
......@@ -4935,7 +4946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49354946 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}
49364947 \\}
49374948 ,
4938 ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'",
4949 "tmp.zig:3:50: error: expected type 'builtin.AtomicOrder', found 'u32'",
49394950 );
49404951
49414952 cases.add(
......@@ -4945,7 +4956,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49454956 \\ @export("entry", entry, u32(1234));
49464957 \\}
49474958 ,
4948 ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'",
4959 "tmp.zig:3:32: error: expected type 'builtin.GlobalLinkage', found 'u32'",
49494960 );
49504961
49514962 cases.add(
......@@ -4974,7 +4985,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49744985 \\ };
49754986 \\}
49764987 ,
4977 ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
4988 "tmp.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
49784989 );
49794990
49804991 cases.add(
......@@ -4983,7 +4994,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49834994 \\ @setAlignStack(16);
49844995 \\}
49854996 ,
4986 ".tmp_source.zig:2:5: error: @setAlignStack outside function",
4997 "tmp.zig:2:5: error: @setAlignStack outside function",
49874998 );
49884999
49895000 cases.add(
......@@ -4992,7 +5003,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
49925003 \\ @setAlignStack(16);
49935004 \\}
49945005 ,
4995 ".tmp_source.zig:2:5: error: @setAlignStack in naked function",
5006 "tmp.zig:2:5: error: @setAlignStack in naked function",
49965007 );
49975008
49985009 cases.add(
......@@ -5004,7 +5015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50045015 \\ @setAlignStack(16);
50055016 \\}
50065017 ,
5007 ".tmp_source.zig:5:5: error: @setAlignStack in inline function",
5018 "tmp.zig:5:5: error: @setAlignStack in inline function",
50085019 );
50095020
50105021 cases.add(
......@@ -5014,8 +5025,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50145025 \\ @setAlignStack(16);
50155026 \\}
50165027 ,
5017 ".tmp_source.zig:3:5: error: alignstack set twice",
5018 ".tmp_source.zig:2:5: note: first set here",
5028 "tmp.zig:3:5: error: alignstack set twice",
5029 "tmp.zig:2:5: note: first set here",
50195030 );
50205031
50215032 cases.add(
......@@ -5024,7 +5035,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50245035 \\ @setAlignStack(511 + 1);
50255036 \\}
50265037 ,
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",
50285039 );
50295040
50305041 cases.add(
......@@ -5071,7 +5082,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50715082 \\ }
50725083 \\}
50735084 ,
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",
50755086 );
50765087
50775088 cases.add(
......@@ -5087,7 +5098,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50875098 \\ return x.blah;
50885099 \\}
50895100 ,
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",
50915102 );
50925103
50935104 cases.add(
......@@ -5095,7 +5106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
50955106 "fn test() bool {\r\n" ++
50965107 " true\r\n" ++
50975108 "}\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",
50995110 );
51005111
51015112 cases.add(
......@@ -5105,7 +5116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51055116 \\ true\r
51065117 \\}
51075118 ,
5108 ".tmp_source.zig:1:1: error: invalid character: '\\xff'",
5119 "tmp.zig:1:1: error: invalid character: '\\xff'",
51095120 );
51105121
51115122 cases.add(
......@@ -5113,7 +5124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51135124 "fn test() bool {\n" ++
51145125 "\ttrue\n" ++
51155126 "}\n",
5116 ".tmp_source.zig:2:1: error: invalid character: '\\t'",
5127 "tmp.zig:2:1: error: invalid character: '\\t'",
51175128 );
51185129
51195130 cases.add(
......@@ -5122,7 +5133,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51225133 \\ _ = @ArgType(i32, 3);
51235134 \\}
51245135 ,
5125 ".tmp_source.zig:2:18: error: expected function, found 'i32'",
5136 "tmp.zig:2:18: error: expected function, found 'i32'",
51265137 );
51275138
51285139 cases.add(
......@@ -5132,7 +5143,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51325143 \\}
51335144 \\fn add(a: i32, b: i32) i32 { return a + b; }
51345145 ,
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",
51365147 );
51375148
51385149 cases.add(
......@@ -5141,7 +5152,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51415152 \\ _ = @memberType(i32, 0);
51425153 \\}
51435154 ,
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",
51455156 );
51465157
51475158 cases.add(
......@@ -5151,7 +5162,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51515162 \\}
51525163 \\const Foo = enum {A,};
51535164 ,
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",
51555166 );
51565167
51575168 cases.add(
......@@ -5161,7 +5172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51615172 \\}
51625173 \\const Foo = struct {};
51635174 ,
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",
51655176 );
51665177
51675178 cases.add(
......@@ -5171,7 +5182,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51715182 \\}
51725183 \\const Foo = union {A: void,};
51735184 ,
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",
51755186 );
51765187
51775188 cases.add(
......@@ -5180,7 +5191,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51805191 \\ _ = @memberName(i32, 0);
51815192 \\}
51825193 ,
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",
51845195 );
51855196
51865197 cases.add(
......@@ -5190,7 +5201,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
51905201 \\}
51915202 \\const Foo = struct {};
51925203 ,
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",
51945205 );
51955206
51965207 cases.add(
......@@ -5200,7 +5211,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52005211 \\}
52015212 \\const Foo = enum {A,};
52025213 ,
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",
52045215 );
52055216
52065217 cases.add(
......@@ -5210,7 +5221,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52105221 \\}
52115222 \\const Foo = union {A:i32,};
52125223 ,
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",
52145225 );
52155226
52165227 cases.add(
......@@ -5220,7 +5231,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52205231 \\}
52215232 \\pub extern fn foo(format: *const u8, ...) void;
52225233 ,
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'",
52245235 );
52255236
52265237 cases.add(
......@@ -5239,9 +5250,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52395250 \\ var allocator: ContextAllocator = undefined;
52405251 \\}
52415252 ,
5242 ".tmp_source.zig:4:25: error: aoeu",
5243 ".tmp_source.zig:1:36: note: called from here",
5244 ".tmp_source.zig:12:20: note: referenced here",
5253 "tmp.zig:4:25: error: aoeu",
5254 "tmp.zig:1:36: note: called from here",
5255 "tmp.zig:12:20: note: referenced here",
52455256 );
52465257
52475258 cases.add(
......@@ -5258,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52585269 \\ var x = Small.One;
52595270 \\}
52605271 ,
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'",
52625273 );
52635274
52645275 cases.add(
......@@ -5273,7 +5284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52735284 \\ var x = Small.One;
52745285 \\}
52755286 ,
5276 ".tmp_source.zig:1:21: error: expected integer, found 'f32'",
5287 "tmp.zig:1:21: error: expected integer, found 'f32'",
52775288 );
52785289
52795290 cases.add(
......@@ -5289,7 +5300,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
52895300 \\ var x: u2 = Small.Two;
52905301 \\}
52915302 ,
5292 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",
5303 "tmp.zig:9:22: error: expected type 'u2', found 'Small'",
52935304 );
52945305
52955306 cases.add(
......@@ -5306,7 +5317,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53065317 \\ var x = @intToEnum(Small, y);
53075318 \\}
53085319 ,
5309 ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'",
5320 "tmp.zig:10:31: error: expected type 'u2', found 'u3'",
53105321 );
53115322
53125323 cases.add(
......@@ -5322,7 +5333,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53225333 \\ var y = Small.Two;
53235334 \\}
53245335 ,
5325 ".tmp_source.zig:1:20: error: expected unsigned integer, found 'i2'",
5336 "tmp.zig:1:20: error: expected unsigned integer, found 'i2'",
53265337 );
53275338
53285339 cases.add(
......@@ -5334,7 +5345,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53345345 \\ var x: MultipleChoice = undefined;
53355346 \\}
53365347 ,
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",
53385349 );
53395350
53405351 cases.add(
......@@ -5346,8 +5357,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53465357 \\ var x: MultipleChoice = undefined;
53475358 \\}
53485359 ,
5349 ".tmp_source.zig:2:14: error: non-enum union field assignment",
5350 ".tmp_source.zig:1:24: note: consider 'union(enum)' here",
5360 "tmp.zig:2:14: error: non-enum union field assignment",
5361 "tmp.zig:1:24: note: consider 'union(enum)' here",
53515362 );
53525363
53535364 cases.add(
......@@ -5357,7 +5368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53575368 \\ return @sizeOf(Foo);
53585369 \\}
53595370 ,
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",
53615372 );
53625373
53635374 cases.add(
......@@ -5367,7 +5378,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53675378 \\ return @sizeOf(Foo);
53685379 \\}
53695380 ,
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",
53715382 );
53725383
53735384 cases.add(
......@@ -5383,8 +5394,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
53835394 \\ var x = MultipleChoice.C;
53845395 \\}
53855396 ,
5386 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
5387 ".tmp_source.zig:4:9: note: other occurrence here",
5397 "tmp.zig:6:9: error: enum tag value 60 already taken",
5398 "tmp.zig:4:9: note: other occurrence here",
53885399 );
53895400
53905401 cases.add(
......@@ -5402,8 +5413,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54025413 \\ return @sizeOf(Payload);
54035414 \\}
54045415 ,
5405 ".tmp_source.zig:6:17: error: enum field missing: 'C'",
5406 ".tmp_source.zig:4:5: note: declared here",
5416 "tmp.zig:6:17: error: enum field missing: 'C'",
5417 "tmp.zig:4:5: note: declared here",
54075418 );
54085419
54095420 cases.add(
......@@ -5415,8 +5426,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54155426 \\ const x = @TagType(Foo);
54165427 \\}
54175428 ,
5418 ".tmp_source.zig:5:24: error: union 'Foo' has no tag",
5419 ".tmp_source.zig:1:13: note: consider 'union(enum)' here",
5429 "tmp.zig:5:24: error: union 'Foo' has no tag",
5430 "tmp.zig:1:13: note: consider 'union(enum)' here",
54205431 );
54215432
54225433 cases.add(
......@@ -5428,7 +5439,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54285439 \\ const x = @TagType(Foo);
54295440 \\}
54305441 ,
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'",
54325443 );
54335444
54345445 cases.add(
......@@ -5440,7 +5451,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54405451 \\ const x = @TagType(Foo);
54415452 \\}
54425453 ,
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'",
54445455 );
54455456
54465457 cases.add(
......@@ -5456,8 +5467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54565467 \\ var x = MultipleChoice { .C = {} };
54575468 \\}
54585469 ,
5459 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
5460 ".tmp_source.zig:4:9: note: other occurrence here",
5470 "tmp.zig:6:9: error: enum tag value 60 already taken",
5471 "tmp.zig:4:9: note: other occurrence here",
54615472 );
54625473
54635474 cases.add(
......@@ -5477,8 +5488,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54775488 \\ var a = Payload {.A = 1234};
54785489 \\}
54795490 ,
5480 ".tmp_source.zig:10:5: error: enum field not found: 'D'",
5481 ".tmp_source.zig:1:16: note: enum declared here",
5491 "tmp.zig:10:5: error: enum field not found: 'D'",
5492 "tmp.zig:1:16: note: enum declared here",
54825493 );
54835494
54845495 cases.add(
......@@ -5492,8 +5503,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
54925503 \\ var b = Letter.B;
54935504 \\}
54945505 ,
5495 ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types",
5496 ".tmp_source.zig:1:16: note: consider 'union(enum)' here",
5506 "tmp.zig:2:8: error: structs and unions, not enums, support field types",
5507 "tmp.zig:1:16: note: consider 'union(enum)' here",
54975508 );
54985509
54995510 cases.add(
......@@ -5505,7 +5516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
55055516 \\ var a = Letter { .A = {} };
55065517 \\}
55075518 ,
5508 ".tmp_source.zig:2:5: error: struct field missing type",
5519 "tmp.zig:2:5: error: struct field missing type",
55095520 );
55105521
55115522 cases.add(
......@@ -5517,7 +5528,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
55175528 \\ var a = Letter { .A = {} };
55185529 \\}
55195530 ,
5520 ".tmp_source.zig:2:5: error: union field missing type",
5531 "tmp.zig:2:5: error: union field missing type",
55215532 );
55225533
55235534 cases.add(
......@@ -5536,7 +5547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
55365547 \\ var a = Payload { .A = 1234 };
55375548 \\}
55385549 ,
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",
55405551 );
55415552
55425553 cases.add(
......@@ -5555,7 +5566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
55555566 \\ var a = Payload { .A = 1234 };
55565567 \\}
55575568 ,
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",
55595570 );
55605571
55615572 cases.add(
......@@ -5576,8 +5587,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
55765587 \\ }
55775588 \\}
55785589 ,
5579 ".tmp_source.zig:11:14: error: switch on union which has no attached enum",
5580 ".tmp_source.zig:1:17: note: consider 'union(enum)' here",
5590 "tmp.zig:11:14: error: switch on union which has no attached enum",
5591 "tmp.zig:1:17: note: consider 'union(enum)' here",
55815592 );
55825593
55835594 cases.add(
......@@ -5590,8 +5601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
55905601 \\ var x = @intToEnum(Foo, 0);
55915602 \\}
55925603 ,
5593 ".tmp_source.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
5594 ".tmp_source.zig:1:13: note: 'Foo' declared here",
5604 "tmp.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
5605 "tmp.zig:1:13: note: 'Foo' declared here",
55955606 );
55965607
55975608 cases.add(
......@@ -5606,8 +5617,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56065617 \\ var x: Value = Letter.A;
56075618 \\}
56085619 ,
5609 ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
5610 ".tmp_source.zig:3:5: note: field 'A' declared here",
5620 "tmp.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
5621 "tmp.zig:3:5: note: field 'A' declared here",
56115622 );
56125623
56135624 cases.add(
......@@ -5625,8 +5636,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56255636 \\ var x: Value = l;
56265637 \\}
56275638 ,
5628 ".tmp_source.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'",
5639 "tmp.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
5640 "tmp.zig:3:5: note: field 'A' has type 'i32'",
56305641 );
56315642
56325643 cases.add(
......@@ -5638,7 +5649,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56385649 \\ const fieldOffset = @byteOffsetOf(Empty, "val",);
56395650 \\}
56405651 ,
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",
56425653 );
56435654
56445655 cases.add(
......@@ -5650,7 +5661,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56505661 \\ const fieldOffset = @bitOffsetOf(Empty, "val",);
56515662 \\}
56525663 ,
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",
56545665 );
56555666
56565667 cases.add(
......@@ -5664,7 +5675,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56645675 \\ const bar_val = foo.Bar;
56655676 \\}
56665677 ,
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",
56685679 );
56695680
56705681 cases.add(
......@@ -5674,7 +5685,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56745685 \\ _ = @typeOf(generic).ReturnType;
56755686 \\}
56765687 ,
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",
56785689 );
56795690
56805691 cases.add(
......@@ -5684,7 +5695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56845695 \\ _ = @ArgType(@typeOf(generic), 0);
56855696 \\}
56865697 ,
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",
56885699 );
56895700
56905701 cases.add(
......@@ -5694,7 +5705,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
56945705 \\ asm volatile ("" : [baz]"+r"(bar) : : "");
56955706 \\}
56965707 ,
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",
56985709 );
56995710
57005711 cases.add(
......@@ -5703,7 +5714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
57035714 \\ asm volatile ("" : : [bar]"r"(3) : "");
57045715 \\}
57055716 ,
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",
57075718 );
57085719
57095720 cases.add(
......@@ -5712,7 +5723,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
57125723 \\ asm volatile ("" : : [bar]"r"(3.17) : "");
57135724 \\}
57145725 ,
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",
57165727 );
57175728
57185729 cases.add(
......@@ -5726,7 +5737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
57265737 \\ const foo = Foo { .Bar = x, .Baz = u8 };
57275738 \\}
57285739 ,
5729 ".tmp_source.zig:7:30: error: unable to evaluate constant expression",
5740 "tmp.zig:7:30: error: unable to evaluate constant expression",
57305741 );
57315742
57325743 cases.add(
......@@ -5740,7 +5751,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
57405751 \\ const foo = Foo { .Bar = x };
57415752 \\}
57425753 ,
5743 ".tmp_source.zig:7:30: error: unable to evaluate constant expression",
5754 "tmp.zig:7:30: error: unable to evaluate constant expression",
57445755 );
57455756
57465757 cases.addTest(
......@@ -5750,7 +5761,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
57505761 \\ var v: V = undefined;
57515762 \\}
57525763 ,
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",
57545765 );
57555766
57565767 cases.add("compileLog of tagged enum doesn't crash the compiler",
......@@ -5765,5 +5776,5 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
57655776 \\pub fn main () void {
57665777 \\ comptime testCompileLog(Bar{.X = 123});
57675778 \\}
5768 , ".tmp_source.zig:6:5: error: found compile log statement");
5779 , "tmp.zig:6:5: error: found compile log statement");
57695780}
test/stage1/behavior.zig+5-2
......@@ -18,6 +18,7 @@ comptime {
1818 _ = @import("behavior/bugs/1421.zig");
1919 _ = @import("behavior/bugs/1442.zig");
2020 _ = @import("behavior/bugs/1486.zig");
21 _ = @import("behavior/bugs/1500.zig");
2122 _ = @import("behavior/bugs/1851.zig");
2223 _ = @import("behavior/bugs/2006.zig");
2324 _ = @import("behavior/bugs/394.zig");
......@@ -25,6 +26,7 @@ comptime {
2526 _ = @import("behavior/bugs/529.zig");
2627 _ = @import("behavior/bugs/655.zig");
2728 _ = @import("behavior/bugs/656.zig");
29 _ = @import("behavior/bugs/679.zig");
2830 _ = @import("behavior/bugs/704.zig");
2931 _ = @import("behavior/bugs/718.zig");
3032 _ = @import("behavior/bugs/726.zig");
......@@ -54,14 +56,14 @@ comptime {
5456 _ = @import("behavior/math.zig");
5557 _ = @import("behavior/merge_error_sets.zig");
5658 _ = @import("behavior/misc.zig");
57 _ = @import("behavior/namespace_depends_on_compile_var/index.zig");
59 _ = @import("behavior/namespace_depends_on_compile_var.zig");
5860 _ = @import("behavior/new_stack_call.zig");
5961 _ = @import("behavior/null.zig");
6062 _ = @import("behavior/optional.zig");
6163 _ = @import("behavior/pointers.zig");
6264 _ = @import("behavior/popcount.zig");
6365 _ = @import("behavior/ptrcast.zig");
64 _ = @import("behavior/pub_enum/index.zig");
66 _ = @import("behavior/pub_enum.zig");
6567 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
6668 _ = @import("behavior/reflection.zig");
6769 _ = @import("behavior/sizeof_and_typeof.zig");
......@@ -78,6 +80,7 @@ comptime {
7880 _ = @import("behavior/truncate.zig");
7981 _ = @import("behavior/try.zig");
8082 _ = @import("behavior/type_info.zig");
83 _ = @import("behavior/typename.zig");
8184 _ = @import("behavior/undefined.zig");
8285 _ = @import("behavior/underscore.zig");
8386 _ = @import("behavior/union.zig");
test/stage1/behavior/asm.zig+5-5
......@@ -4,16 +4,16 @@ const expect = @import("std").testing.expect;
44comptime {
55 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
66 asm volatile (
7 \\.globl aoeu;
8 \\.type aoeu, @function;
9 \\.set aoeu, derp;
7 \\.globl this_is_my_alias;
8 \\.type this_is_my_alias, @function;
9 \\.set this_is_my_alias, derp;
1010 );
1111 }
1212}
1313
1414test "module level assembly" {
1515 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
16 expect(aoeu() == 1234);
16 expect(this_is_my_alias() == 1234);
1717 }
1818}
1919
......@@ -85,7 +85,7 @@ test "sized integer/float in asm input" {
8585 );
8686}
8787
88extern fn aoeu() i32;
88extern fn this_is_my_alias() i32;
8989
9090export fn derp() i32 {
9191 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 @@
11const std = @import("std");
22const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
34const mem = std.mem;
45const cstr = std.cstr;
56const builtin = @import("builtin");
......@@ -469,7 +470,7 @@ test "@typeId" {
469470 expect(@typeId(AUnionEnum) == Tid.Union);
470471 expect(@typeId(AUnion) == Tid.Union);
471472 expect(@typeId(fn () void) == Tid.Fn);
472 expect(@typeId(@typeOf(builtin)) == Tid.Namespace);
473 expect(@typeId(@typeOf(builtin)) == Tid.Type);
473474 // TODO bound fn
474475 // TODO arg tuple
475476 // TODO opaque
......@@ -488,7 +489,7 @@ test "@typeName" {
488489 expect(mem.eql(u8, @typeName(i64), "i64"));
489490 expect(mem.eql(u8, @typeName(*usize), "*usize"));
490491 // 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)));
492493 expect(mem.eql(u8, @typeName(Struct), "Struct"));
493494 expect(mem.eql(u8, @typeName(Union), "Union"));
494495 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" {
124124 S.doTheTest();
125125 comptime S.doTheTest();
126126}
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 @@
1const expect = @import("std").testing.expect;
2const mem = @import("std").mem;
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
4const mem = std.mem;
35
46const x = @intToPtr([*]i32, 0x1000)[0..0x500];
57const y = x[0x100..];
......@@ -38,3 +40,10 @@ test "implicitly cast array of size 0 to slice" {
3840fn assertLenIsZero(msg: []const u8) void {
3941 expect(msg.len == 0);
4042}
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 {
186186 expect(TypeId(typeinfo_info) == TypeId.Union);
187187 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
188188 expect(typeinfo_info.Union.tag_type.? == TypeId);
189 expect(typeinfo_info.Union.fields.len == 25);
189 expect(typeinfo_info.Union.fields.len == 24);
190190 expect(typeinfo_info.Union.fields[4].enum_field != null);
191191 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
192192 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 {
569569 const ErrLineIter = struct {
570570 lines: mem.SplitIterator,
571571
572 const source_file = ".tmp_source.zig";
572 const source_file = "tmp.zig";
573573
574574 fn init(input: []const u8) ErrLineIter {
575575 return ErrLineIter{ .lines = mem.separate(input, "\n") };
......@@ -759,7 +759,7 @@ pub const CompileErrorContext = struct {
759759 .is_test = false,
760760 };
761761
762 tc.addSourceFile(".tmp_source.zig", source);
762 tc.addSourceFile("tmp.zig", source);
763763 comptime var arg_i = 0;
764764 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
765765 tc.addExpectedError(expected_lines[arg_i]);
......@@ -980,15 +980,18 @@ pub const TranslateCContext = struct {
980980 Term.Exited => |code| {
981981 if (code != 0) {
982982 warn("Compilation failed with exit code {}\n", code);
983 printInvocation(zig_args.toSliceConst());
983984 return error.TestFailed;
984985 }
985986 },
986987 Term.Signal => |code| {
987988 warn("Compilation failed with signal {}\n", code);
989 printInvocation(zig_args.toSliceConst());
988990 return error.TestFailed;
989991 },
990992 else => {
991993 warn("Compilation terminated unexpectedly\n");
994 printInvocation(zig_args.toSliceConst());
992995 return error.TestFailed;
993996 },
994997 }